140525Sjdp/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4324932Sbdrewery * Copyright (c) 2017 Dell EMC 5199805Sattilio * Copyright (c) 2007 Sandvine Incorporated 640525Sjdp * Copyright (c) 1998 John D. Polstra 740525Sjdp * All rights reserved. 840525Sjdp * 940525Sjdp * Redistribution and use in source and binary forms, with or without 1040525Sjdp * modification, are permitted provided that the following conditions 1140525Sjdp * are met: 1240525Sjdp * 1. Redistributions of source code must retain the above copyright 1340525Sjdp * notice, this list of conditions and the following disclaimer. 1440525Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1540525Sjdp * notice, this list of conditions and the following disclaimer in the 1640525Sjdp * documentation and/or other materials provided with the distribution. 1740525Sjdp * 1840525Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1940525Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2040525Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2140525Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2240525Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2340525Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2440525Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2540525Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2640525Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2740525Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2840525Sjdp * SUCH DAMAGE. 2940525Sjdp */ 3040525Sjdp 3193215Scharnier#include <sys/cdefs.h> 3293215Scharnier__FBSDID("$FreeBSD: stable/11/usr.bin/gcore/elfcore.c 330449 2018-03-05 07:26:05Z eadler $"); 3393215Scharnier 34269128Smarcel#include <sys/endian.h> 3540525Sjdp#include <sys/param.h> 3640525Sjdp#include <sys/procfs.h> 37199805Sattilio#include <sys/ptrace.h> 38103302Speter#include <sys/queue.h> 39103299Speter#include <sys/linker_set.h> 40249687Strociny#include <sys/sbuf.h> 41199805Sattilio#include <sys/sysctl.h> 42199805Sattilio#include <sys/user.h> 43199805Sattilio#include <sys/wait.h> 4476224Sobrien#include <machine/elf.h> 4540525Sjdp#include <vm/vm_param.h> 4640525Sjdp#include <vm/vm.h> 4740525Sjdp#include <vm/pmap.h> 4840525Sjdp#include <vm/vm_map.h> 49249687Strociny#include <assert.h> 5040525Sjdp#include <err.h> 5140525Sjdp#include <errno.h> 5240525Sjdp#include <fcntl.h> 53274817Sjhb#include <stdbool.h> 54102951Siedowse#include <stdint.h> 5540525Sjdp#include <stdio.h> 5640525Sjdp#include <stdlib.h> 5740525Sjdp#include <string.h> 5840525Sjdp#include <unistd.h> 59199805Sattilio#include <libutil.h> 6040525Sjdp 6140525Sjdp#include "extern.h" 6240525Sjdp 6340525Sjdp/* 6440525Sjdp * Code for generating ELF core dumps. 6540525Sjdp */ 6640525Sjdp 6740525Sjdptypedef void (*segment_callback)(vm_map_entry_t, void *); 6840525Sjdp 6940525Sjdp/* Closure for cb_put_phdr(). */ 7040525Sjdpstruct phdr_closure { 7140525Sjdp Elf_Phdr *phdr; /* Program header to fill in */ 7240525Sjdp Elf_Off offset; /* Offset of segment in core file */ 7340525Sjdp}; 7440525Sjdp 7540525Sjdp/* Closure for cb_size_segment(). */ 7640525Sjdpstruct sseg_closure { 7740525Sjdp int count; /* Count of writable segments. */ 7840525Sjdp size_t size; /* Total size of all writable segments. */ 7940525Sjdp}; 8040525Sjdp 81269128Smarcel#ifdef ELFCORE_COMPAT_32 82269128Smarceltypedef struct fpreg32 elfcore_fpregset_t; 83269128Smarceltypedef struct reg32 elfcore_gregset_t; 84269128Smarceltypedef struct prpsinfo32 elfcore_prpsinfo_t; 85269128Smarceltypedef struct prstatus32 elfcore_prstatus_t; 86325029Sbdrewerytypedef struct ptrace_lwpinfo32 elfcore_lwpinfo_t; 87269128Smarcelstatic void elf_convert_gregset(elfcore_gregset_t *rd, struct reg *rs); 88269128Smarcelstatic void elf_convert_fpregset(elfcore_fpregset_t *rd, struct fpreg *rs); 89325029Sbdrewerystatic void elf_convert_lwpinfo(struct ptrace_lwpinfo32 *pld, 90325029Sbdrewery struct ptrace_lwpinfo *pls); 91269128Smarcel#else 92269128Smarceltypedef fpregset_t elfcore_fpregset_t; 93269128Smarceltypedef gregset_t elfcore_gregset_t; 94269128Smarceltypedef prpsinfo_t elfcore_prpsinfo_t; 95269128Smarceltypedef prstatus_t elfcore_prstatus_t; 96325029Sbdrewerytypedef struct ptrace_lwpinfo elfcore_lwpinfo_t; 97269128Smarcel#define elf_convert_gregset(d,s) *d = *s 98269128Smarcel#define elf_convert_fpregset(d,s) *d = *s 99325029Sbdrewery#define elf_convert_lwpinfo(d,s) *d = *s 100269128Smarcel#endif 101269128Smarcel 102249687Strocinytypedef void* (*notefunc_t)(void *, size_t *); 103249687Strociny 10440525Sjdpstatic void cb_put_phdr(vm_map_entry_t, void *); 10540525Sjdpstatic void cb_size_segment(vm_map_entry_t, void *); 10640525Sjdpstatic void each_writable_segment(vm_map_entry_t, segment_callback, 10740525Sjdp void *closure); 108199805Sattiliostatic void elf_detach(void); /* atexit() handler. */ 109249687Strocinystatic void *elf_note_fpregset(void *, size_t *); 110249687Strocinystatic void *elf_note_prpsinfo(void *, size_t *); 111249687Strocinystatic void *elf_note_prstatus(void *, size_t *); 112249687Strocinystatic void *elf_note_thrmisc(void *, size_t *); 113324932Sbdrewerystatic void *elf_note_ptlwpinfo(void *, size_t *); 114325837Sjhb#if defined(__arm__) 115325837Sjhbstatic void *elf_note_arm_vfp(void *, size_t *); 116325837Sjhb#endif 117274817Sjhb#if defined(__i386__) || defined(__amd64__) 118274817Sjhbstatic void *elf_note_x86_xstate(void *, size_t *); 119274817Sjhb#endif 120277167Sjhibbits#if defined(__powerpc__) 121277167Sjhibbitsstatic void *elf_note_powerpc_vmx(void *, size_t *); 122277167Sjhibbits#endif 123249687Strocinystatic void *elf_note_procstat_auxv(void *, size_t *); 124249687Strocinystatic void *elf_note_procstat_files(void *, size_t *); 125249687Strocinystatic void *elf_note_procstat_groups(void *, size_t *); 126249687Strocinystatic void *elf_note_procstat_osrel(void *, size_t *); 127249687Strocinystatic void *elf_note_procstat_proc(void *, size_t *); 128249687Strocinystatic void *elf_note_procstat_psstrings(void *, size_t *); 129249687Strocinystatic void *elf_note_procstat_rlimit(void *, size_t *); 130249687Strocinystatic void *elf_note_procstat_umask(void *, size_t *); 131249687Strocinystatic void *elf_note_procstat_vmmap(void *, size_t *); 132318192Sjhbstatic void elf_puthdr(int, pid_t, vm_map_entry_t, void *, size_t, size_t, 133318192Sjhb size_t, int); 134249687Strocinystatic void elf_putnote(int, notefunc_t, void *, struct sbuf *); 135249687Strocinystatic void elf_putnotes(pid_t, struct sbuf *, size_t *); 13640525Sjdpstatic void freemap(vm_map_entry_t); 13740525Sjdpstatic vm_map_entry_t readmap(pid_t); 138249687Strocinystatic void *procstat_sysctl(void *, int, size_t, size_t *sizep); 13940525Sjdp 140199805Sattiliostatic pid_t g_pid; /* Pid being dumped, global for elf_detach */ 141302179Smarkjstatic int g_status; /* proc status after ptrace attach */ 142199805Sattilio 143103299Speterstatic int 144125859Sdwmaloneelf_ident(int efd, pid_t pid __unused, char *binfile __unused) 145103299Speter{ 146103299Speter Elf_Ehdr hdr; 147103299Speter int cnt; 148269128Smarcel uint16_t machine; 149103299Speter 150103299Speter cnt = read(efd, &hdr, sizeof(hdr)); 151103299Speter if (cnt != sizeof(hdr)) 152103299Speter return (0); 153269128Smarcel if (!IS_ELF(hdr)) 154269128Smarcel return (0); 155269128Smarcel switch (hdr.e_ident[EI_DATA]) { 156269128Smarcel case ELFDATA2LSB: 157269128Smarcel machine = le16toh(hdr.e_machine); 158269128Smarcel break; 159269128Smarcel case ELFDATA2MSB: 160269128Smarcel machine = be16toh(hdr.e_machine); 161269128Smarcel break; 162269128Smarcel default: 163269128Smarcel return (0); 164269128Smarcel } 165269128Smarcel if (!ELF_MACHINE_OK(machine)) 166269128Smarcel return (0); 167269128Smarcel 168269128Smarcel /* Looks good. */ 169269128Smarcel return (1); 170103299Speter} 171103299Speter 172199805Sattiliostatic void 173199805Sattilioelf_detach(void) 174199805Sattilio{ 175302179Smarkj int sig; 176199805Sattilio 177302179Smarkj if (g_pid != 0) { 178302179Smarkj /* 179302179Smarkj * Forward any pending signals. SIGSTOP is generated by ptrace 180302179Smarkj * itself, so ignore it. 181302179Smarkj */ 182302179Smarkj sig = WIFSTOPPED(g_status) ? WSTOPSIG(g_status) : 0; 183302179Smarkj if (sig == SIGSTOP) 184302179Smarkj sig = 0; 185302179Smarkj ptrace(PT_DETACH, g_pid, (caddr_t)1, sig); 186302179Smarkj } 187199805Sattilio} 188199805Sattilio 18940525Sjdp/* 19040525Sjdp * Write an ELF coredump for the given pid to the given fd. 19140525Sjdp */ 192125859Sdwmalonestatic void 193318192Sjhbelf_coredump(int efd, int fd, pid_t pid) 19440525Sjdp{ 19540525Sjdp vm_map_entry_t map; 19640525Sjdp struct sseg_closure seginfo; 197249687Strociny struct sbuf *sb; 19840525Sjdp void *hdr; 199249687Strociny size_t hdrsize, notesz, segoff; 200249687Strociny ssize_t n, old_len; 20140525Sjdp Elf_Phdr *php; 20240525Sjdp int i; 20340525Sjdp 204199805Sattilio /* Attach to process to dump. */ 205199805Sattilio g_pid = pid; 206199805Sattilio if (atexit(elf_detach) != 0) 207199805Sattilio err(1, "atexit"); 208199805Sattilio errno = 0; 209199805Sattilio ptrace(PT_ATTACH, pid, NULL, 0); 210199805Sattilio if (errno) 211199805Sattilio err(1, "PT_ATTACH"); 212302179Smarkj if (waitpid(pid, &g_status, 0) == -1) 213199805Sattilio err(1, "waitpid"); 214199805Sattilio 21540525Sjdp /* Get the program's memory map. */ 21640525Sjdp map = readmap(pid); 21740525Sjdp 21840525Sjdp /* Size the program segments. */ 21940525Sjdp seginfo.count = 0; 22040525Sjdp seginfo.size = 0; 22140525Sjdp each_writable_segment(map, cb_size_segment, &seginfo); 22240525Sjdp 22340525Sjdp /* 224249687Strociny * Build the header and the notes using sbuf and write to the file. 22540525Sjdp */ 226249687Strociny sb = sbuf_new_auto(); 227249687Strociny hdrsize = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * (1 + seginfo.count); 228249687Strociny /* Start header + notes section. */ 229249687Strociny sbuf_start_section(sb, NULL); 230249687Strociny /* Make empty header subsection. */ 231249687Strociny sbuf_start_section(sb, &old_len); 232249687Strociny sbuf_putc(sb, 0); 233249687Strociny sbuf_end_section(sb, old_len, hdrsize, 0); 234249687Strociny /* Put notes. */ 235249687Strociny elf_putnotes(pid, sb, ¬esz); 236249687Strociny /* Align up to a page boundary for the program segments. */ 237249687Strociny sbuf_end_section(sb, -1, PAGE_SIZE, 0); 238249687Strociny if (sbuf_finish(sb) != 0) 239249687Strociny err(1, "sbuf_finish"); 240249687Strociny hdr = sbuf_data(sb); 241249687Strociny segoff = sbuf_len(sb); 242199805Sattilio /* Fill in the header. */ 243318192Sjhb elf_puthdr(efd, pid, map, hdr, hdrsize, notesz, segoff, seginfo.count); 244199805Sattilio 245249687Strociny n = write(fd, hdr, segoff); 246249687Strociny if (n == -1) 247199805Sattilio err(1, "write"); 248249687Strociny if (n < segoff) 249249687Strociny errx(1, "short write"); 250199805Sattilio 25140525Sjdp /* Write the contents of all of the writable segments. */ 25240525Sjdp php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 25340525Sjdp for (i = 0; i < seginfo.count; i++) { 254199805Sattilio struct ptrace_io_desc iorequest; 255102944Sdwmalone uintmax_t nleft = php->p_filesz; 25640525Sjdp 257199805Sattilio iorequest.piod_op = PIOD_READ_D; 258269128Smarcel iorequest.piod_offs = (caddr_t)(uintptr_t)php->p_vaddr; 25940525Sjdp while (nleft > 0) { 26040525Sjdp char buf[8*1024]; 261102944Sdwmalone size_t nwant; 262102944Sdwmalone ssize_t ngot; 26340525Sjdp 264102944Sdwmalone if (nleft > sizeof(buf)) 26540525Sjdp nwant = sizeof buf; 266102944Sdwmalone else 267102944Sdwmalone nwant = nleft; 268199805Sattilio iorequest.piod_addr = buf; 269199805Sattilio iorequest.piod_len = nwant; 270199805Sattilio ptrace(PT_IO, pid, (caddr_t)&iorequest, 0); 271199805Sattilio ngot = iorequest.piod_len; 272102944Sdwmalone if ((size_t)ngot < nwant) 273223924Sdelphij errx(1, "short read wanted %zu, got %zd", 27440803Sjdp nwant, ngot); 27540525Sjdp ngot = write(fd, buf, nwant); 27640525Sjdp if (ngot == -1) 27740525Sjdp err(1, "write of segment %d failed", i); 278102944Sdwmalone if ((size_t)ngot != nwant) 27940525Sjdp errx(1, "short write"); 28040525Sjdp nleft -= nwant; 281199805Sattilio iorequest.piod_offs += ngot; 28240525Sjdp } 28340525Sjdp php++; 28440525Sjdp } 285249687Strociny sbuf_delete(sb); 28640525Sjdp freemap(map); 28740525Sjdp} 28840525Sjdp 28940525Sjdp/* 29040525Sjdp * A callback for each_writable_segment() to write out the segment's 29140525Sjdp * program header entry. 29240525Sjdp */ 29340525Sjdpstatic void 29440525Sjdpcb_put_phdr(vm_map_entry_t entry, void *closure) 29540525Sjdp{ 29640525Sjdp struct phdr_closure *phc = (struct phdr_closure *)closure; 29740525Sjdp Elf_Phdr *phdr = phc->phdr; 29840525Sjdp 29940525Sjdp phc->offset = round_page(phc->offset); 30040525Sjdp 30140525Sjdp phdr->p_type = PT_LOAD; 30240525Sjdp phdr->p_offset = phc->offset; 30340525Sjdp phdr->p_vaddr = entry->start; 30440525Sjdp phdr->p_paddr = 0; 30540525Sjdp phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 30640525Sjdp phdr->p_align = PAGE_SIZE; 30740525Sjdp phdr->p_flags = 0; 30840525Sjdp if (entry->protection & VM_PROT_READ) 30940525Sjdp phdr->p_flags |= PF_R; 31040525Sjdp if (entry->protection & VM_PROT_WRITE) 31140525Sjdp phdr->p_flags |= PF_W; 31240525Sjdp if (entry->protection & VM_PROT_EXECUTE) 31340525Sjdp phdr->p_flags |= PF_X; 31440525Sjdp 31540525Sjdp phc->offset += phdr->p_filesz; 31640525Sjdp phc->phdr++; 31740525Sjdp} 31840525Sjdp 31940525Sjdp/* 32040525Sjdp * A callback for each_writable_segment() to gather information about 32140525Sjdp * the number of segments and their total size. 32240525Sjdp */ 32340525Sjdpstatic void 32440525Sjdpcb_size_segment(vm_map_entry_t entry, void *closure) 32540525Sjdp{ 32640525Sjdp struct sseg_closure *ssc = (struct sseg_closure *)closure; 32740525Sjdp 32840525Sjdp ssc->count++; 32940525Sjdp ssc->size += entry->end - entry->start; 33040525Sjdp} 33140525Sjdp 33240525Sjdp/* 33340525Sjdp * For each segment in the given memory map, call the given function 33440525Sjdp * with a pointer to the map entry and some arbitrary caller-supplied 33540525Sjdp * data. 33640525Sjdp */ 33740525Sjdpstatic void 33840525Sjdpeach_writable_segment(vm_map_entry_t map, segment_callback func, void *closure) 33940525Sjdp{ 34040525Sjdp vm_map_entry_t entry; 34140525Sjdp 34240525Sjdp for (entry = map; entry != NULL; entry = entry->next) 34340525Sjdp (*func)(entry, closure); 34440525Sjdp} 34540525Sjdp 34640525Sjdpstatic void 347249687Strocinyelf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep) 34840525Sjdp{ 349199805Sattilio lwpid_t *tids; 350249687Strociny size_t threads, old_len; 351249687Strociny ssize_t size; 352199805Sattilio int i; 35340525Sjdp 354199805Sattilio errno = 0; 355199805Sattilio threads = ptrace(PT_GETNUMLWPS, pid, NULL, 0); 356199805Sattilio if (errno) 357199805Sattilio err(1, "PT_GETNUMLWPS"); 358249687Strociny tids = malloc(threads * sizeof(*tids)); 359249687Strociny if (tids == NULL) 360249687Strociny errx(1, "out of memory"); 361249687Strociny errno = 0; 362249687Strociny ptrace(PT_GETLWPLIST, pid, (void *)tids, threads); 363249687Strociny if (errno) 364249687Strociny err(1, "PT_GETLWPLIST"); 365199805Sattilio 366249687Strociny sbuf_start_section(sb, &old_len); 367249687Strociny elf_putnote(NT_PRPSINFO, elf_note_prpsinfo, &pid, sb); 368199805Sattilio 369199805Sattilio for (i = 0; i < threads; ++i) { 370249687Strociny elf_putnote(NT_PRSTATUS, elf_note_prstatus, tids + i, sb); 371249687Strociny elf_putnote(NT_FPREGSET, elf_note_fpregset, tids + i, sb); 372249687Strociny elf_putnote(NT_THRMISC, elf_note_thrmisc, tids + i, sb); 373324932Sbdrewery elf_putnote(NT_PTLWPINFO, elf_note_ptlwpinfo, tids + i, sb); 374325837Sjhb#if defined(__arm__) 375325837Sjhb elf_putnote(NT_ARM_VFP, elf_note_arm_vfp, tids + i, sb); 376325837Sjhb#endif 377274817Sjhb#if defined(__i386__) || defined(__amd64__) 378274817Sjhb elf_putnote(NT_X86_XSTATE, elf_note_x86_xstate, tids + i, sb); 379274817Sjhb#endif 380277167Sjhibbits#if defined(__powerpc__) 381277167Sjhibbits elf_putnote(NT_PPC_VMX, elf_note_powerpc_vmx, tids + i, sb); 382277167Sjhibbits#endif 383199805Sattilio } 384199805Sattilio 385269128Smarcel#ifndef ELFCORE_COMPAT_32 386249687Strociny elf_putnote(NT_PROCSTAT_PROC, elf_note_procstat_proc, &pid, sb); 387249687Strociny elf_putnote(NT_PROCSTAT_FILES, elf_note_procstat_files, &pid, sb); 388249687Strociny elf_putnote(NT_PROCSTAT_VMMAP, elf_note_procstat_vmmap, &pid, sb); 389249687Strociny elf_putnote(NT_PROCSTAT_GROUPS, elf_note_procstat_groups, &pid, sb); 390249687Strociny elf_putnote(NT_PROCSTAT_UMASK, elf_note_procstat_umask, &pid, sb); 391249687Strociny elf_putnote(NT_PROCSTAT_RLIMIT, elf_note_procstat_rlimit, &pid, sb); 392249687Strociny elf_putnote(NT_PROCSTAT_OSREL, elf_note_procstat_osrel, &pid, sb); 393249687Strociny elf_putnote(NT_PROCSTAT_PSSTRINGS, elf_note_procstat_psstrings, &pid, 394249687Strociny sb); 395249687Strociny elf_putnote(NT_PROCSTAT_AUXV, elf_note_procstat_auxv, &pid, sb); 396269128Smarcel#endif 39740525Sjdp 398249687Strociny size = sbuf_end_section(sb, old_len, 1, 0); 399249687Strociny if (size == -1) 400249687Strociny err(1, "sbuf_end_section"); 401249687Strociny free(tids); 402249687Strociny *sizep = size; 40340525Sjdp} 40440525Sjdp 40540525Sjdp/* 406249687Strociny * Emit one note section to sbuf. 40740525Sjdp */ 40840525Sjdpstatic void 409249687Strocinyelf_putnote(int type, notefunc_t notefunc, void *arg, struct sbuf *sb) 41040525Sjdp{ 41140525Sjdp Elf_Note note; 412249687Strociny size_t descsz; 413249687Strociny ssize_t old_len; 414249687Strociny void *desc; 41540525Sjdp 416249687Strociny desc = notefunc(arg, &descsz); 417249687Strociny note.n_namesz = 8; /* strlen("FreeBSD") + 1 */ 41840525Sjdp note.n_descsz = descsz; 41940525Sjdp note.n_type = type; 420249687Strociny 421249687Strociny sbuf_bcat(sb, ¬e, sizeof(note)); 422249687Strociny sbuf_start_section(sb, &old_len); 423249687Strociny sbuf_bcat(sb, "FreeBSD", note.n_namesz); 424249687Strociny sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0); 425249687Strociny if (descsz == 0) 426249687Strociny return; 427249687Strociny sbuf_start_section(sb, &old_len); 428249687Strociny sbuf_bcat(sb, desc, descsz); 429249687Strociny sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0); 430249687Strociny free(desc); 43140525Sjdp} 43240525Sjdp 43340525Sjdp/* 434249687Strociny * Generate the ELF coredump header. 435249687Strociny */ 436249687Strocinystatic void 437318192Sjhbelf_puthdr(int efd, pid_t pid, vm_map_entry_t map, void *hdr, size_t hdrsize, 438249687Strociny size_t notesz, size_t segoff, int numsegs) 439249687Strociny{ 440318192Sjhb Elf_Ehdr *ehdr, binhdr; 441249687Strociny Elf_Phdr *phdr; 442249687Strociny struct phdr_closure phc; 443318192Sjhb ssize_t cnt; 444249687Strociny 445318192Sjhb cnt = read(efd, &binhdr, sizeof(binhdr)); 446318192Sjhb if (cnt < 0) 447318192Sjhb err(1, "Failed to re-read ELF header"); 448318192Sjhb else if (cnt != sizeof(binhdr)) 449318192Sjhb errx(1, "Failed to re-read ELF header"); 450318192Sjhb 451249687Strociny ehdr = (Elf_Ehdr *)hdr; 452249687Strociny phdr = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)); 453249687Strociny 454249687Strociny ehdr->e_ident[EI_MAG0] = ELFMAG0; 455249687Strociny ehdr->e_ident[EI_MAG1] = ELFMAG1; 456249687Strociny ehdr->e_ident[EI_MAG2] = ELFMAG2; 457249687Strociny ehdr->e_ident[EI_MAG3] = ELFMAG3; 458249687Strociny ehdr->e_ident[EI_CLASS] = ELF_CLASS; 459249687Strociny ehdr->e_ident[EI_DATA] = ELF_DATA; 460249687Strociny ehdr->e_ident[EI_VERSION] = EV_CURRENT; 461249687Strociny ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 462249687Strociny ehdr->e_ident[EI_ABIVERSION] = 0; 463249687Strociny ehdr->e_ident[EI_PAD] = 0; 464249687Strociny ehdr->e_type = ET_CORE; 465318192Sjhb ehdr->e_machine = binhdr.e_machine; 466249687Strociny ehdr->e_version = EV_CURRENT; 467249687Strociny ehdr->e_entry = 0; 468249687Strociny ehdr->e_phoff = sizeof(Elf_Ehdr); 469318192Sjhb ehdr->e_flags = binhdr.e_flags; 470249687Strociny ehdr->e_ehsize = sizeof(Elf_Ehdr); 471249687Strociny ehdr->e_phentsize = sizeof(Elf_Phdr); 472249687Strociny ehdr->e_phnum = numsegs + 1; 473249687Strociny ehdr->e_shentsize = sizeof(Elf_Shdr); 474249687Strociny ehdr->e_shnum = 0; 475249687Strociny ehdr->e_shstrndx = SHN_UNDEF; 476249687Strociny 477249687Strociny /* 478249687Strociny * Fill in the program header entries. 479249687Strociny */ 480249687Strociny 481249687Strociny /* The note segement. */ 482249687Strociny phdr->p_type = PT_NOTE; 483249687Strociny phdr->p_offset = hdrsize; 484249687Strociny phdr->p_vaddr = 0; 485249687Strociny phdr->p_paddr = 0; 486249687Strociny phdr->p_filesz = notesz; 487249687Strociny phdr->p_memsz = 0; 488249687Strociny phdr->p_flags = PF_R; 489249687Strociny phdr->p_align = sizeof(Elf32_Size); 490249687Strociny phdr++; 491249687Strociny 492249687Strociny /* All the writable segments from the program. */ 493249687Strociny phc.phdr = phdr; 494249687Strociny phc.offset = segoff; 495249687Strociny each_writable_segment(map, cb_put_phdr, &phc); 496249687Strociny} 497249687Strociny 498249687Strociny/* 49940525Sjdp * Free the memory map. 50040525Sjdp */ 50140525Sjdpstatic void 50240525Sjdpfreemap(vm_map_entry_t map) 50340525Sjdp{ 504103299Speter 50540525Sjdp while (map != NULL) { 50640525Sjdp vm_map_entry_t next = map->next; 50740525Sjdp free(map); 50840525Sjdp map = next; 50940525Sjdp } 51040525Sjdp} 51140525Sjdp 51240525Sjdp/* 513199805Sattilio * Read the process's memory map using kinfo_getvmmap(), and return a list of 51440525Sjdp * VM map entries. Only the non-device read/writable segments are 51540525Sjdp * returned. The map entries in the list aren't fully filled in; only 51640525Sjdp * the items we need are present. 51740525Sjdp */ 51840525Sjdpstatic vm_map_entry_t 51940525Sjdpreadmap(pid_t pid) 52040525Sjdp{ 521199805Sattilio vm_map_entry_t ent, *linkp, map; 522199805Sattilio struct kinfo_vmentry *vmentl, *kve; 523199805Sattilio int i, nitems; 52440525Sjdp 525199805Sattilio vmentl = kinfo_getvmmap(pid, &nitems); 526199805Sattilio if (vmentl == NULL) 527199805Sattilio err(1, "cannot retrieve mappings for %u process", pid); 52840525Sjdp 52940525Sjdp map = NULL; 53040525Sjdp linkp = ↦ 531199805Sattilio for (i = 0; i < nitems; i++) { 532199805Sattilio kve = &vmentl[i]; 53340525Sjdp 534199805Sattilio /* 535210063Sattilio * Ignore 'malformed' segments or ones representing memory 536210063Sattilio * mapping with MAP_NOCORE on. 537210063Sattilio * If the 'full' support is disabled, just dump the most 538210063Sattilio * meaningful data segments. 539199805Sattilio */ 540210063Sattilio if ((kve->kve_protection & KVME_PROT_READ) == 0 || 541210063Sattilio (kve->kve_flags & KVME_FLAG_NOCOREDUMP) != 0 || 542210063Sattilio kve->kve_type == KVME_TYPE_DEAD || 543210063Sattilio kve->kve_type == KVME_TYPE_UNKNOWN || 544210063Sattilio ((pflags & PFLAGS_FULL) == 0 && 545210063Sattilio kve->kve_type != KVME_TYPE_DEFAULT && 546199805Sattilio kve->kve_type != KVME_TYPE_VNODE && 547278761Sjhb kve->kve_type != KVME_TYPE_SWAP && 548278761Sjhb kve->kve_type != KVME_TYPE_PHYS)) 54940525Sjdp continue; 55040525Sjdp 551199805Sattilio ent = calloc(1, sizeof(*ent)); 552199805Sattilio if (ent == NULL) 55340525Sjdp errx(1, "out of memory"); 554199805Sattilio ent->start = (vm_offset_t)kve->kve_start; 555199805Sattilio ent->end = (vm_offset_t)kve->kve_end; 55640525Sjdp ent->protection = VM_PROT_READ | VM_PROT_WRITE; 557199805Sattilio if ((kve->kve_protection & KVME_PROT_EXEC) != 0) 558199805Sattilio ent->protection |= VM_PROT_EXECUTE; 55940525Sjdp 56040525Sjdp *linkp = ent; 56140525Sjdp linkp = &ent->next; 56240525Sjdp } 563199805Sattilio free(vmentl); 564199805Sattilio return (map); 56540525Sjdp} 566103299Speter 567249687Strociny/* 568249687Strociny * Miscellaneous note out functions. 569249687Strociny */ 570249687Strociny 571249687Strocinystatic void * 572249687Strocinyelf_note_prpsinfo(void *arg, size_t *sizep) 573249687Strociny{ 574306786Sjhb char *cp, *end; 575249687Strociny pid_t pid; 576269128Smarcel elfcore_prpsinfo_t *psinfo; 577249687Strociny struct kinfo_proc kip; 578249687Strociny size_t len; 579249687Strociny int name[4]; 580249687Strociny 581249687Strociny pid = *(pid_t *)arg; 582249687Strociny psinfo = calloc(1, sizeof(*psinfo)); 583249687Strociny if (psinfo == NULL) 584249687Strociny errx(1, "out of memory"); 585249687Strociny psinfo->pr_version = PRPSINFO_VERSION; 586269128Smarcel psinfo->pr_psinfosz = sizeof(*psinfo); 587249687Strociny 588249687Strociny name[0] = CTL_KERN; 589249687Strociny name[1] = KERN_PROC; 590249687Strociny name[2] = KERN_PROC_PID; 591249687Strociny name[3] = pid; 592249687Strociny len = sizeof(kip); 593249687Strociny if (sysctl(name, 4, &kip, &len, NULL, 0) == -1) 594249687Strociny err(1, "kern.proc.pid.%u", pid); 595249687Strociny if (kip.ki_pid != pid) 596249687Strociny err(1, "kern.proc.pid.%u", pid); 597299458Scem strlcpy(psinfo->pr_fname, kip.ki_comm, sizeof(psinfo->pr_fname)); 598306786Sjhb name[2] = KERN_PROC_ARGS; 599306786Sjhb len = sizeof(psinfo->pr_psargs) - 1; 600306786Sjhb if (sysctl(name, 4, psinfo->pr_psargs, &len, NULL, 0) == 0 && len > 0) { 601306786Sjhb cp = psinfo->pr_psargs; 602306786Sjhb end = cp + len - 1; 603306786Sjhb for (;;) { 604306786Sjhb cp = memchr(cp, '\0', end - cp); 605306786Sjhb if (cp == NULL) 606306786Sjhb break; 607306786Sjhb *cp = ' '; 608306786Sjhb } 609306786Sjhb } else 610306786Sjhb strlcpy(psinfo->pr_psargs, kip.ki_comm, 611306786Sjhb sizeof(psinfo->pr_psargs)); 612308009Sjhb psinfo->pr_pid = pid; 613249687Strociny 614249687Strociny *sizep = sizeof(*psinfo); 615249687Strociny return (psinfo); 616249687Strociny} 617249687Strociny 618249687Strocinystatic void * 619249687Strocinyelf_note_prstatus(void *arg, size_t *sizep) 620249687Strociny{ 621249687Strociny lwpid_t tid; 622269128Smarcel elfcore_prstatus_t *status; 623269128Smarcel struct reg greg; 624249687Strociny 625249687Strociny tid = *(lwpid_t *)arg; 626249687Strociny status = calloc(1, sizeof(*status)); 627249687Strociny if (status == NULL) 628249687Strociny errx(1, "out of memory"); 629249687Strociny status->pr_version = PRSTATUS_VERSION; 630269128Smarcel status->pr_statussz = sizeof(*status); 631269128Smarcel status->pr_gregsetsz = sizeof(elfcore_gregset_t); 632269128Smarcel status->pr_fpregsetsz = sizeof(elfcore_fpregset_t); 633249687Strociny status->pr_osreldate = __FreeBSD_version; 634249687Strociny status->pr_pid = tid; 635269128Smarcel ptrace(PT_GETREGS, tid, (void *)&greg, 0); 636269128Smarcel elf_convert_gregset(&status->pr_reg, &greg); 637249687Strociny 638249687Strociny *sizep = sizeof(*status); 639249687Strociny return (status); 640249687Strociny} 641249687Strociny 642249687Strocinystatic void * 643249687Strocinyelf_note_fpregset(void *arg, size_t *sizep) 644249687Strociny{ 645249687Strociny lwpid_t tid; 646269128Smarcel elfcore_fpregset_t *fpregset; 647269128Smarcel fpregset_t fpreg; 648249687Strociny 649249687Strociny tid = *(lwpid_t *)arg; 650249687Strociny fpregset = calloc(1, sizeof(*fpregset)); 651249687Strociny if (fpregset == NULL) 652249687Strociny errx(1, "out of memory"); 653269128Smarcel ptrace(PT_GETFPREGS, tid, (void *)&fpreg, 0); 654269128Smarcel elf_convert_fpregset(fpregset, &fpreg); 655249687Strociny 656249687Strociny *sizep = sizeof(*fpregset); 657249687Strociny return (fpregset); 658249687Strociny} 659249687Strociny 660249687Strocinystatic void * 661249687Strocinyelf_note_thrmisc(void *arg, size_t *sizep) 662249687Strociny{ 663249687Strociny lwpid_t tid; 664249687Strociny struct ptrace_lwpinfo lwpinfo; 665249687Strociny thrmisc_t *thrmisc; 666249687Strociny 667249687Strociny tid = *(lwpid_t *)arg; 668249687Strociny thrmisc = calloc(1, sizeof(*thrmisc)); 669249687Strociny if (thrmisc == NULL) 670249687Strociny errx(1, "out of memory"); 671249687Strociny ptrace(PT_LWPINFO, tid, (void *)&lwpinfo, 672249687Strociny sizeof(lwpinfo)); 673249687Strociny memset(&thrmisc->_pad, 0, sizeof(thrmisc->_pad)); 674249687Strociny strcpy(thrmisc->pr_tname, lwpinfo.pl_tdname); 675249687Strociny 676249687Strociny *sizep = sizeof(*thrmisc); 677249687Strociny return (thrmisc); 678249687Strociny} 679249687Strociny 680324932Sbdrewerystatic void * 681324932Sbdreweryelf_note_ptlwpinfo(void *arg, size_t *sizep) 682324932Sbdrewery{ 683324932Sbdrewery lwpid_t tid; 684325029Sbdrewery elfcore_lwpinfo_t *elf_info; 685325029Sbdrewery struct ptrace_lwpinfo lwpinfo; 686324932Sbdrewery void *p; 687324932Sbdrewery 688324932Sbdrewery tid = *(lwpid_t *)arg; 689325029Sbdrewery p = calloc(1, sizeof(int) + sizeof(elfcore_lwpinfo_t)); 690324932Sbdrewery if (p == NULL) 691324932Sbdrewery errx(1, "out of memory"); 692325029Sbdrewery *(int *)p = sizeof(elfcore_lwpinfo_t); 693325029Sbdrewery elf_info = (void *)((int *)p + 1); 694325029Sbdrewery ptrace(PT_LWPINFO, tid, (void *)&lwpinfo, sizeof(lwpinfo)); 695325029Sbdrewery elf_convert_lwpinfo(elf_info, &lwpinfo); 696324932Sbdrewery 697324932Sbdrewery *sizep = sizeof(int) + sizeof(struct ptrace_lwpinfo); 698324932Sbdrewery return (p); 699324932Sbdrewery} 700324932Sbdrewery 701325837Sjhb#if defined(__arm__) 702325837Sjhbstatic void * 703325837Sjhbelf_note_arm_vfp(void *arg, size_t *sizep) 704325837Sjhb{ 705325837Sjhb lwpid_t tid; 706325837Sjhb struct vfpreg *vfp; 707325837Sjhb static bool has_vfp = true; 708325837Sjhb struct vfpreg info; 709325837Sjhb 710325837Sjhb tid = *(lwpid_t *)arg; 711325837Sjhb if (has_vfp) { 712325837Sjhb if (ptrace(PT_GETVFPREGS, tid, (void *)&info, 0) != 0) 713325837Sjhb has_vfp = false; 714325837Sjhb } 715325837Sjhb if (!has_vfp) { 716325837Sjhb *sizep = 0; 717325837Sjhb return (NULL); 718325837Sjhb } 719325837Sjhb vfp = calloc(1, sizeof(*vfp)); 720325837Sjhb memcpy(vfp, &info, sizeof(*vfp)); 721325837Sjhb *sizep = sizeof(*vfp); 722325837Sjhb return (vfp); 723325837Sjhb} 724325837Sjhb#endif 725325837Sjhb 726274817Sjhb#if defined(__i386__) || defined(__amd64__) 727249687Strocinystatic void * 728274817Sjhbelf_note_x86_xstate(void *arg, size_t *sizep) 729274817Sjhb{ 730274817Sjhb lwpid_t tid; 731274817Sjhb char *xstate; 732274817Sjhb static bool xsave_checked = false; 733274817Sjhb static struct ptrace_xstate_info info; 734274817Sjhb 735274817Sjhb tid = *(lwpid_t *)arg; 736274817Sjhb if (!xsave_checked) { 737274817Sjhb if (ptrace(PT_GETXSTATE_INFO, tid, (void *)&info, 738274817Sjhb sizeof(info)) != 0) 739274817Sjhb info.xsave_len = 0; 740274817Sjhb xsave_checked = true; 741274817Sjhb } 742274817Sjhb if (info.xsave_len == 0) { 743274817Sjhb *sizep = 0; 744274817Sjhb return (NULL); 745274817Sjhb } 746274817Sjhb xstate = calloc(1, info.xsave_len); 747274817Sjhb ptrace(PT_GETXSTATE, tid, xstate, 0); 748274817Sjhb *(uint64_t *)(xstate + X86_XSTATE_XCR0_OFFSET) = info.xsave_mask; 749274817Sjhb *sizep = info.xsave_len; 750274817Sjhb return (xstate); 751274817Sjhb} 752274817Sjhb#endif 753274817Sjhb 754277167Sjhibbits#if defined(__powerpc__) 755274817Sjhbstatic void * 756277167Sjhibbitself_note_powerpc_vmx(void *arg, size_t *sizep) 757277167Sjhibbits{ 758277167Sjhibbits lwpid_t tid; 759277167Sjhibbits struct vmxreg *vmx; 760277167Sjhibbits static bool has_vmx = true; 761277167Sjhibbits struct vmxreg info; 762277167Sjhibbits 763277167Sjhibbits tid = *(lwpid_t *)arg; 764277167Sjhibbits if (has_vmx) { 765277167Sjhibbits if (ptrace(PT_GETVRREGS, tid, (void *)&info, 766277167Sjhibbits sizeof(info)) != 0) 767277167Sjhibbits has_vmx = false; 768277167Sjhibbits } 769277167Sjhibbits if (!has_vmx) { 770277167Sjhibbits *sizep = 0; 771277167Sjhibbits return (NULL); 772277167Sjhibbits } 773277167Sjhibbits vmx = calloc(1, sizeof(*vmx)); 774277167Sjhibbits memcpy(vmx, &info, sizeof(*vmx)); 775277167Sjhibbits *sizep = sizeof(*vmx); 776277167Sjhibbits return (vmx); 777277167Sjhibbits} 778277167Sjhibbits#endif 779277167Sjhibbits 780277167Sjhibbitsstatic void * 781249687Strocinyprocstat_sysctl(void *arg, int what, size_t structsz, size_t *sizep) 782249687Strociny{ 783269320Skevlo size_t len; 784249687Strociny pid_t pid; 785249687Strociny int name[4], structsize; 786249687Strociny void *buf, *p; 787249687Strociny 788249687Strociny pid = *(pid_t *)arg; 789249687Strociny structsize = structsz; 790249687Strociny name[0] = CTL_KERN; 791249687Strociny name[1] = KERN_PROC; 792249687Strociny name[2] = what; 793249687Strociny name[3] = pid; 794249687Strociny len = 0; 795249687Strociny if (sysctl(name, 4, NULL, &len, NULL, 0) == -1) 796249687Strociny err(1, "kern.proc.%d.%u", what, pid); 797249687Strociny buf = calloc(1, sizeof(structsize) + len * 4 / 3); 798249687Strociny if (buf == NULL) 799249687Strociny errx(1, "out of memory"); 800249687Strociny bcopy(&structsize, buf, sizeof(structsize)); 801249687Strociny p = (char *)buf + sizeof(structsize); 802249687Strociny if (sysctl(name, 4, p, &len, NULL, 0) == -1) 803249687Strociny err(1, "kern.proc.%d.%u", what, pid); 804249687Strociny 805249687Strociny *sizep = sizeof(structsize) + len; 806249687Strociny return (buf); 807249687Strociny} 808249687Strociny 809249687Strocinystatic void * 810249687Strocinyelf_note_procstat_proc(void *arg, size_t *sizep) 811249687Strociny{ 812249687Strociny 813249687Strociny return (procstat_sysctl(arg, KERN_PROC_PID | KERN_PROC_INC_THREAD, 814249687Strociny sizeof(struct kinfo_proc), sizep)); 815249687Strociny} 816249687Strociny 817249687Strocinystatic void * 818249687Strocinyelf_note_procstat_files(void *arg, size_t *sizep) 819249687Strociny{ 820249687Strociny 821249687Strociny return (procstat_sysctl(arg, KERN_PROC_FILEDESC, 822249687Strociny sizeof(struct kinfo_file), sizep)); 823249687Strociny} 824249687Strociny 825249687Strocinystatic void * 826249687Strocinyelf_note_procstat_vmmap(void *arg, size_t *sizep) 827249687Strociny{ 828249687Strociny 829249687Strociny return (procstat_sysctl(arg, KERN_PROC_VMMAP, 830249687Strociny sizeof(struct kinfo_vmentry), sizep)); 831249687Strociny} 832249687Strociny 833249687Strocinystatic void * 834249687Strocinyelf_note_procstat_groups(void *arg, size_t *sizep) 835249687Strociny{ 836249687Strociny 837249704Strociny return (procstat_sysctl(arg, KERN_PROC_GROUPS, sizeof(gid_t), sizep)); 838249687Strociny} 839249687Strociny 840249687Strocinystatic void * 841249687Strocinyelf_note_procstat_umask(void *arg, size_t *sizep) 842249687Strociny{ 843249687Strociny 844249687Strociny return (procstat_sysctl(arg, KERN_PROC_UMASK, sizeof(u_short), sizep)); 845249687Strociny} 846249687Strociny 847249687Strocinystatic void * 848249687Strocinyelf_note_procstat_osrel(void *arg, size_t *sizep) 849249687Strociny{ 850249687Strociny 851249687Strociny return (procstat_sysctl(arg, KERN_PROC_OSREL, sizeof(int), sizep)); 852249687Strociny} 853249687Strociny 854249687Strocinystatic void * 855249687Strocinyelf_note_procstat_psstrings(void *arg, size_t *sizep) 856249687Strociny{ 857249687Strociny 858249687Strociny return (procstat_sysctl(arg, KERN_PROC_PS_STRINGS, 859249687Strociny sizeof(vm_offset_t), sizep)); 860249687Strociny} 861249687Strociny 862249687Strocinystatic void * 863249687Strocinyelf_note_procstat_auxv(void *arg, size_t *sizep) 864249687Strociny{ 865249687Strociny 866249687Strociny return (procstat_sysctl(arg, KERN_PROC_AUXV, 867249687Strociny sizeof(Elf_Auxinfo), sizep)); 868249687Strociny} 869249687Strociny 870249687Strocinystatic void * 871249687Strocinyelf_note_procstat_rlimit(void *arg, size_t *sizep) 872249687Strociny{ 873249687Strociny pid_t pid; 874249687Strociny size_t len; 875249687Strociny int i, name[5], structsize; 876249687Strociny void *buf, *p; 877249687Strociny 878249687Strociny pid = *(pid_t *)arg; 879249687Strociny structsize = sizeof(struct rlimit) * RLIM_NLIMITS; 880249687Strociny buf = calloc(1, sizeof(structsize) + structsize); 881249687Strociny if (buf == NULL) 882249687Strociny errx(1, "out of memory"); 883249687Strociny bcopy(&structsize, buf, sizeof(structsize)); 884249687Strociny p = (char *)buf + sizeof(structsize); 885249687Strociny name[0] = CTL_KERN; 886249687Strociny name[1] = KERN_PROC; 887249687Strociny name[2] = KERN_PROC_RLIMIT; 888249687Strociny name[3] = pid; 889249687Strociny len = sizeof(struct rlimit); 890249687Strociny for (i = 0; i < RLIM_NLIMITS; i++) { 891249687Strociny name[4] = i; 892249687Strociny if (sysctl(name, 5, p, &len, NULL, 0) == -1) 893249687Strociny err(1, "kern.proc.rlimit.%u", pid); 894249687Strociny if (len != sizeof(struct rlimit)) 895249687Strociny errx(1, "kern.proc.rlimit.%u: short read", pid); 896249687Strociny p += len; 897249687Strociny } 898249687Strociny 899249687Strociny *sizep = sizeof(structsize) + structsize; 900249687Strociny return (buf); 901249687Strociny} 902249687Strociny 903269128Smarcelstruct dumpers __elfN(dump) = { elf_ident, elf_coredump }; 904269128SmarcelTEXT_SET(dumpset, __elfN(dump)); 905