140525Sjdp/*- 2199805Sattilio * Copyright (c) 2007 Sandvine Incorporated 340525Sjdp * Copyright (c) 1998 John D. Polstra 440525Sjdp * All rights reserved. 540525Sjdp * 640525Sjdp * Redistribution and use in source and binary forms, with or without 740525Sjdp * modification, are permitted provided that the following conditions 840525Sjdp * are met: 940525Sjdp * 1. Redistributions of source code must retain the above copyright 1040525Sjdp * notice, this list of conditions and the following disclaimer. 1140525Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1240525Sjdp * notice, this list of conditions and the following disclaimer in the 1340525Sjdp * documentation and/or other materials provided with the distribution. 1440525Sjdp * 1540525Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1640525Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1740525Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1840525Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1940525Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2040525Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2140525Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2240525Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2340525Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2440525Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2540525Sjdp * SUCH DAMAGE. 2640525Sjdp */ 2740525Sjdp 2893215Scharnier#include <sys/cdefs.h> 2993215Scharnier__FBSDID("$FreeBSD: stable/10/usr.bin/gcore/elfcore.c 318192 2017-05-11 17:26:34Z jhb $"); 3093215Scharnier 31283909Sjhb#include <sys/endian.h> 3240525Sjdp#include <sys/param.h> 3340525Sjdp#include <sys/procfs.h> 34199805Sattilio#include <sys/ptrace.h> 35103302Speter#include <sys/queue.h> 36103299Speter#include <sys/linker_set.h> 37249687Strociny#include <sys/sbuf.h> 38199805Sattilio#include <sys/sysctl.h> 39199805Sattilio#include <sys/user.h> 40199805Sattilio#include <sys/wait.h> 4176224Sobrien#include <machine/elf.h> 4240525Sjdp#include <vm/vm_param.h> 4340525Sjdp#include <vm/vm.h> 4440525Sjdp#include <vm/pmap.h> 4540525Sjdp#include <vm/vm_map.h> 46249687Strociny#include <assert.h> 4740525Sjdp#include <err.h> 4840525Sjdp#include <errno.h> 4940525Sjdp#include <fcntl.h> 50279211Sjhb#include <stdbool.h> 51102951Siedowse#include <stdint.h> 5240525Sjdp#include <stdio.h> 5340525Sjdp#include <stdlib.h> 5440525Sjdp#include <string.h> 5540525Sjdp#include <unistd.h> 56199805Sattilio#include <libutil.h> 5740525Sjdp 5840525Sjdp#include "extern.h" 5940525Sjdp 6040525Sjdp/* 6140525Sjdp * Code for generating ELF core dumps. 6240525Sjdp */ 6340525Sjdp 6440525Sjdptypedef void (*segment_callback)(vm_map_entry_t, void *); 6540525Sjdp 6640525Sjdp/* Closure for cb_put_phdr(). */ 6740525Sjdpstruct phdr_closure { 6840525Sjdp Elf_Phdr *phdr; /* Program header to fill in */ 6940525Sjdp Elf_Off offset; /* Offset of segment in core file */ 7040525Sjdp}; 7140525Sjdp 7240525Sjdp/* Closure for cb_size_segment(). */ 7340525Sjdpstruct sseg_closure { 7440525Sjdp int count; /* Count of writable segments. */ 7540525Sjdp size_t size; /* Total size of all writable segments. */ 7640525Sjdp}; 7740525Sjdp 78283909Sjhb#ifdef ELFCORE_COMPAT_32 79283909Sjhbtypedef struct fpreg32 elfcore_fpregset_t; 80283909Sjhbtypedef struct reg32 elfcore_gregset_t; 81283909Sjhbtypedef struct prpsinfo32 elfcore_prpsinfo_t; 82283909Sjhbtypedef struct prstatus32 elfcore_prstatus_t; 83283909Sjhbstatic void elf_convert_gregset(elfcore_gregset_t *rd, struct reg *rs); 84283909Sjhbstatic void elf_convert_fpregset(elfcore_fpregset_t *rd, struct fpreg *rs); 85283909Sjhb#else 86283909Sjhbtypedef fpregset_t elfcore_fpregset_t; 87283909Sjhbtypedef gregset_t elfcore_gregset_t; 88283909Sjhbtypedef prpsinfo_t elfcore_prpsinfo_t; 89283909Sjhbtypedef prstatus_t elfcore_prstatus_t; 90283909Sjhb#define elf_convert_gregset(d,s) *d = *s 91283909Sjhb#define elf_convert_fpregset(d,s) *d = *s 92283909Sjhb#endif 93283909Sjhb 94249687Strocinytypedef void* (*notefunc_t)(void *, size_t *); 95249687Strociny 9640525Sjdpstatic void cb_put_phdr(vm_map_entry_t, void *); 9740525Sjdpstatic void cb_size_segment(vm_map_entry_t, void *); 9840525Sjdpstatic void each_writable_segment(vm_map_entry_t, segment_callback, 9940525Sjdp void *closure); 100199805Sattiliostatic void elf_detach(void); /* atexit() handler. */ 101249687Strocinystatic void *elf_note_fpregset(void *, size_t *); 102249687Strocinystatic void *elf_note_prpsinfo(void *, size_t *); 103249687Strocinystatic void *elf_note_prstatus(void *, size_t *); 104249687Strocinystatic void *elf_note_thrmisc(void *, size_t *); 105279211Sjhb#if defined(__i386__) || defined(__amd64__) 106279211Sjhbstatic void *elf_note_x86_xstate(void *, size_t *); 107279211Sjhb#endif 108249687Strocinystatic void *elf_note_procstat_auxv(void *, size_t *); 109249687Strocinystatic void *elf_note_procstat_files(void *, size_t *); 110249687Strocinystatic void *elf_note_procstat_groups(void *, size_t *); 111249687Strocinystatic void *elf_note_procstat_osrel(void *, size_t *); 112249687Strocinystatic void *elf_note_procstat_proc(void *, size_t *); 113249687Strocinystatic void *elf_note_procstat_psstrings(void *, size_t *); 114249687Strocinystatic void *elf_note_procstat_rlimit(void *, size_t *); 115249687Strocinystatic void *elf_note_procstat_umask(void *, size_t *); 116249687Strocinystatic void *elf_note_procstat_vmmap(void *, size_t *); 117318192Sjhbstatic void elf_puthdr(int, pid_t, vm_map_entry_t, void *, size_t, size_t, 118318192Sjhb size_t, int); 119249687Strocinystatic void elf_putnote(int, notefunc_t, void *, struct sbuf *); 120249687Strocinystatic void elf_putnotes(pid_t, struct sbuf *, size_t *); 12140525Sjdpstatic void freemap(vm_map_entry_t); 12240525Sjdpstatic vm_map_entry_t readmap(pid_t); 123249687Strocinystatic void *procstat_sysctl(void *, int, size_t, size_t *sizep); 12440525Sjdp 125199805Sattiliostatic pid_t g_pid; /* Pid being dumped, global for elf_detach */ 126303058Smarkjstatic int g_status; /* proc status after ptrace attach */ 127199805Sattilio 128103299Speterstatic int 129125859Sdwmaloneelf_ident(int efd, pid_t pid __unused, char *binfile __unused) 130103299Speter{ 131103299Speter Elf_Ehdr hdr; 132103299Speter int cnt; 133283909Sjhb uint16_t machine; 134103299Speter 135103299Speter cnt = read(efd, &hdr, sizeof(hdr)); 136103299Speter if (cnt != sizeof(hdr)) 137103299Speter return (0); 138283909Sjhb if (!IS_ELF(hdr)) 139283909Sjhb return (0); 140283909Sjhb switch (hdr.e_ident[EI_DATA]) { 141283909Sjhb case ELFDATA2LSB: 142283909Sjhb machine = le16toh(hdr.e_machine); 143283909Sjhb break; 144283909Sjhb case ELFDATA2MSB: 145283909Sjhb machine = be16toh(hdr.e_machine); 146283909Sjhb break; 147283909Sjhb default: 148283909Sjhb return (0); 149283909Sjhb } 150283909Sjhb if (!ELF_MACHINE_OK(machine)) 151283909Sjhb return (0); 152283909Sjhb 153283909Sjhb /* Looks good. */ 154283909Sjhb return (1); 155103299Speter} 156103299Speter 157199805Sattiliostatic void 158199805Sattilioelf_detach(void) 159199805Sattilio{ 160303058Smarkj int sig; 161199805Sattilio 162303058Smarkj if (g_pid != 0) { 163303058Smarkj /* 164303058Smarkj * Forward any pending signals. SIGSTOP is generated by ptrace 165303058Smarkj * itself, so ignore it. 166303058Smarkj */ 167303058Smarkj sig = WIFSTOPPED(g_status) ? WSTOPSIG(g_status) : 0; 168303058Smarkj if (sig == SIGSTOP) 169303058Smarkj sig = 0; 170303058Smarkj ptrace(PT_DETACH, g_pid, (caddr_t)1, sig); 171303058Smarkj } 172199805Sattilio} 173199805Sattilio 17440525Sjdp/* 17540525Sjdp * Write an ELF coredump for the given pid to the given fd. 17640525Sjdp */ 177125859Sdwmalonestatic void 178318192Sjhbelf_coredump(int efd, int fd, pid_t pid) 17940525Sjdp{ 18040525Sjdp vm_map_entry_t map; 18140525Sjdp struct sseg_closure seginfo; 182249687Strociny struct sbuf *sb; 18340525Sjdp void *hdr; 184249687Strociny size_t hdrsize, notesz, segoff; 185249687Strociny ssize_t n, old_len; 18640525Sjdp Elf_Phdr *php; 18740525Sjdp int i; 18840525Sjdp 189199805Sattilio /* Attach to process to dump. */ 190199805Sattilio g_pid = pid; 191199805Sattilio if (atexit(elf_detach) != 0) 192199805Sattilio err(1, "atexit"); 193199805Sattilio errno = 0; 194199805Sattilio ptrace(PT_ATTACH, pid, NULL, 0); 195199805Sattilio if (errno) 196199805Sattilio err(1, "PT_ATTACH"); 197303058Smarkj if (waitpid(pid, &g_status, 0) == -1) 198199805Sattilio err(1, "waitpid"); 199199805Sattilio 20040525Sjdp /* Get the program's memory map. */ 20140525Sjdp map = readmap(pid); 20240525Sjdp 20340525Sjdp /* Size the program segments. */ 20440525Sjdp seginfo.count = 0; 20540525Sjdp seginfo.size = 0; 20640525Sjdp each_writable_segment(map, cb_size_segment, &seginfo); 20740525Sjdp 20840525Sjdp /* 209249687Strociny * Build the header and the notes using sbuf and write to the file. 21040525Sjdp */ 211249687Strociny sb = sbuf_new_auto(); 212249687Strociny hdrsize = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * (1 + seginfo.count); 213249687Strociny /* Start header + notes section. */ 214249687Strociny sbuf_start_section(sb, NULL); 215249687Strociny /* Make empty header subsection. */ 216249687Strociny sbuf_start_section(sb, &old_len); 217249687Strociny sbuf_putc(sb, 0); 218249687Strociny sbuf_end_section(sb, old_len, hdrsize, 0); 219249687Strociny /* Put notes. */ 220249687Strociny elf_putnotes(pid, sb, ¬esz); 221249687Strociny /* Align up to a page boundary for the program segments. */ 222249687Strociny sbuf_end_section(sb, -1, PAGE_SIZE, 0); 223249687Strociny if (sbuf_finish(sb) != 0) 224249687Strociny err(1, "sbuf_finish"); 225249687Strociny hdr = sbuf_data(sb); 226249687Strociny segoff = sbuf_len(sb); 227199805Sattilio /* Fill in the header. */ 228318192Sjhb elf_puthdr(efd, pid, map, hdr, hdrsize, notesz, segoff, seginfo.count); 229199805Sattilio 230249687Strociny n = write(fd, hdr, segoff); 231249687Strociny if (n == -1) 232199805Sattilio err(1, "write"); 233249687Strociny if (n < segoff) 234249687Strociny errx(1, "short write"); 235199805Sattilio 23640525Sjdp /* Write the contents of all of the writable segments. */ 23740525Sjdp php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 23840525Sjdp for (i = 0; i < seginfo.count; i++) { 239199805Sattilio struct ptrace_io_desc iorequest; 240102944Sdwmalone uintmax_t nleft = php->p_filesz; 24140525Sjdp 242199805Sattilio iorequest.piod_op = PIOD_READ_D; 243283909Sjhb iorequest.piod_offs = (caddr_t)(uintptr_t)php->p_vaddr; 24440525Sjdp while (nleft > 0) { 24540525Sjdp char buf[8*1024]; 246102944Sdwmalone size_t nwant; 247102944Sdwmalone ssize_t ngot; 24840525Sjdp 249102944Sdwmalone if (nleft > sizeof(buf)) 25040525Sjdp nwant = sizeof buf; 251102944Sdwmalone else 252102944Sdwmalone nwant = nleft; 253199805Sattilio iorequest.piod_addr = buf; 254199805Sattilio iorequest.piod_len = nwant; 255199805Sattilio ptrace(PT_IO, pid, (caddr_t)&iorequest, 0); 256199805Sattilio ngot = iorequest.piod_len; 257102944Sdwmalone if ((size_t)ngot < nwant) 258223924Sdelphij errx(1, "short read wanted %zu, got %zd", 25940803Sjdp nwant, ngot); 26040525Sjdp ngot = write(fd, buf, nwant); 26140525Sjdp if (ngot == -1) 26240525Sjdp err(1, "write of segment %d failed", i); 263102944Sdwmalone if ((size_t)ngot != nwant) 26440525Sjdp errx(1, "short write"); 26540525Sjdp nleft -= nwant; 266199805Sattilio iorequest.piod_offs += ngot; 26740525Sjdp } 26840525Sjdp php++; 26940525Sjdp } 270249687Strociny sbuf_delete(sb); 27140525Sjdp freemap(map); 27240525Sjdp} 27340525Sjdp 27440525Sjdp/* 27540525Sjdp * A callback for each_writable_segment() to write out the segment's 27640525Sjdp * program header entry. 27740525Sjdp */ 27840525Sjdpstatic void 27940525Sjdpcb_put_phdr(vm_map_entry_t entry, void *closure) 28040525Sjdp{ 28140525Sjdp struct phdr_closure *phc = (struct phdr_closure *)closure; 28240525Sjdp Elf_Phdr *phdr = phc->phdr; 28340525Sjdp 28440525Sjdp phc->offset = round_page(phc->offset); 28540525Sjdp 28640525Sjdp phdr->p_type = PT_LOAD; 28740525Sjdp phdr->p_offset = phc->offset; 28840525Sjdp phdr->p_vaddr = entry->start; 28940525Sjdp phdr->p_paddr = 0; 29040525Sjdp phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 29140525Sjdp phdr->p_align = PAGE_SIZE; 29240525Sjdp phdr->p_flags = 0; 29340525Sjdp if (entry->protection & VM_PROT_READ) 29440525Sjdp phdr->p_flags |= PF_R; 29540525Sjdp if (entry->protection & VM_PROT_WRITE) 29640525Sjdp phdr->p_flags |= PF_W; 29740525Sjdp if (entry->protection & VM_PROT_EXECUTE) 29840525Sjdp phdr->p_flags |= PF_X; 29940525Sjdp 30040525Sjdp phc->offset += phdr->p_filesz; 30140525Sjdp phc->phdr++; 30240525Sjdp} 30340525Sjdp 30440525Sjdp/* 30540525Sjdp * A callback for each_writable_segment() to gather information about 30640525Sjdp * the number of segments and their total size. 30740525Sjdp */ 30840525Sjdpstatic void 30940525Sjdpcb_size_segment(vm_map_entry_t entry, void *closure) 31040525Sjdp{ 31140525Sjdp struct sseg_closure *ssc = (struct sseg_closure *)closure; 31240525Sjdp 31340525Sjdp ssc->count++; 31440525Sjdp ssc->size += entry->end - entry->start; 31540525Sjdp} 31640525Sjdp 31740525Sjdp/* 31840525Sjdp * For each segment in the given memory map, call the given function 31940525Sjdp * with a pointer to the map entry and some arbitrary caller-supplied 32040525Sjdp * data. 32140525Sjdp */ 32240525Sjdpstatic void 32340525Sjdpeach_writable_segment(vm_map_entry_t map, segment_callback func, void *closure) 32440525Sjdp{ 32540525Sjdp vm_map_entry_t entry; 32640525Sjdp 32740525Sjdp for (entry = map; entry != NULL; entry = entry->next) 32840525Sjdp (*func)(entry, closure); 32940525Sjdp} 33040525Sjdp 33140525Sjdpstatic void 332249687Strocinyelf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep) 33340525Sjdp{ 334199805Sattilio lwpid_t *tids; 335249687Strociny size_t threads, old_len; 336249687Strociny ssize_t size; 337199805Sattilio int i; 33840525Sjdp 339199805Sattilio errno = 0; 340199805Sattilio threads = ptrace(PT_GETNUMLWPS, pid, NULL, 0); 341199805Sattilio if (errno) 342199805Sattilio err(1, "PT_GETNUMLWPS"); 343249687Strociny tids = malloc(threads * sizeof(*tids)); 344249687Strociny if (tids == NULL) 345249687Strociny errx(1, "out of memory"); 346249687Strociny errno = 0; 347249687Strociny ptrace(PT_GETLWPLIST, pid, (void *)tids, threads); 348249687Strociny if (errno) 349249687Strociny err(1, "PT_GETLWPLIST"); 350199805Sattilio 351249687Strociny sbuf_start_section(sb, &old_len); 352249687Strociny elf_putnote(NT_PRPSINFO, elf_note_prpsinfo, &pid, sb); 353199805Sattilio 354199805Sattilio for (i = 0; i < threads; ++i) { 355249687Strociny elf_putnote(NT_PRSTATUS, elf_note_prstatus, tids + i, sb); 356249687Strociny elf_putnote(NT_FPREGSET, elf_note_fpregset, tids + i, sb); 357249687Strociny elf_putnote(NT_THRMISC, elf_note_thrmisc, tids + i, sb); 358279211Sjhb#if defined(__i386__) || defined(__amd64__) 359279211Sjhb elf_putnote(NT_X86_XSTATE, elf_note_x86_xstate, tids + i, sb); 360279211Sjhb#endif 361199805Sattilio } 362199805Sattilio 363283909Sjhb#ifndef ELFCORE_COMPAT_32 364249687Strociny elf_putnote(NT_PROCSTAT_PROC, elf_note_procstat_proc, &pid, sb); 365249687Strociny elf_putnote(NT_PROCSTAT_FILES, elf_note_procstat_files, &pid, sb); 366249687Strociny elf_putnote(NT_PROCSTAT_VMMAP, elf_note_procstat_vmmap, &pid, sb); 367249687Strociny elf_putnote(NT_PROCSTAT_GROUPS, elf_note_procstat_groups, &pid, sb); 368249687Strociny elf_putnote(NT_PROCSTAT_UMASK, elf_note_procstat_umask, &pid, sb); 369249687Strociny elf_putnote(NT_PROCSTAT_RLIMIT, elf_note_procstat_rlimit, &pid, sb); 370249687Strociny elf_putnote(NT_PROCSTAT_OSREL, elf_note_procstat_osrel, &pid, sb); 371249687Strociny elf_putnote(NT_PROCSTAT_PSSTRINGS, elf_note_procstat_psstrings, &pid, 372249687Strociny sb); 373249687Strociny elf_putnote(NT_PROCSTAT_AUXV, elf_note_procstat_auxv, &pid, sb); 374283909Sjhb#endif 37540525Sjdp 376249687Strociny size = sbuf_end_section(sb, old_len, 1, 0); 377249687Strociny if (size == -1) 378249687Strociny err(1, "sbuf_end_section"); 379249687Strociny free(tids); 380249687Strociny *sizep = size; 38140525Sjdp} 38240525Sjdp 38340525Sjdp/* 384249687Strociny * Emit one note section to sbuf. 38540525Sjdp */ 38640525Sjdpstatic void 387249687Strocinyelf_putnote(int type, notefunc_t notefunc, void *arg, struct sbuf *sb) 38840525Sjdp{ 38940525Sjdp Elf_Note note; 390249687Strociny size_t descsz; 391249687Strociny ssize_t old_len; 392249687Strociny void *desc; 39340525Sjdp 394249687Strociny desc = notefunc(arg, &descsz); 395249687Strociny note.n_namesz = 8; /* strlen("FreeBSD") + 1 */ 39640525Sjdp note.n_descsz = descsz; 39740525Sjdp note.n_type = type; 398249687Strociny 399249687Strociny sbuf_bcat(sb, ¬e, sizeof(note)); 400249687Strociny sbuf_start_section(sb, &old_len); 401249687Strociny sbuf_bcat(sb, "FreeBSD", note.n_namesz); 402249687Strociny sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0); 403249687Strociny if (descsz == 0) 404249687Strociny return; 405249687Strociny sbuf_start_section(sb, &old_len); 406249687Strociny sbuf_bcat(sb, desc, descsz); 407249687Strociny sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0); 408249687Strociny free(desc); 40940525Sjdp} 41040525Sjdp 41140525Sjdp/* 412249687Strociny * Generate the ELF coredump header. 413249687Strociny */ 414249687Strocinystatic void 415318192Sjhbelf_puthdr(int efd, pid_t pid, vm_map_entry_t map, void *hdr, size_t hdrsize, 416249687Strociny size_t notesz, size_t segoff, int numsegs) 417249687Strociny{ 418318192Sjhb Elf_Ehdr *ehdr, binhdr; 419249687Strociny Elf_Phdr *phdr; 420249687Strociny struct phdr_closure phc; 421318192Sjhb ssize_t cnt; 422249687Strociny 423318192Sjhb cnt = read(efd, &binhdr, sizeof(binhdr)); 424318192Sjhb if (cnt < 0) 425318192Sjhb err(1, "Failed to re-read ELF header"); 426318192Sjhb else if (cnt != sizeof(binhdr)) 427318192Sjhb errx(1, "Failed to re-read ELF header"); 428318192Sjhb 429249687Strociny ehdr = (Elf_Ehdr *)hdr; 430249687Strociny phdr = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)); 431249687Strociny 432249687Strociny ehdr->e_ident[EI_MAG0] = ELFMAG0; 433249687Strociny ehdr->e_ident[EI_MAG1] = ELFMAG1; 434249687Strociny ehdr->e_ident[EI_MAG2] = ELFMAG2; 435249687Strociny ehdr->e_ident[EI_MAG3] = ELFMAG3; 436249687Strociny ehdr->e_ident[EI_CLASS] = ELF_CLASS; 437249687Strociny ehdr->e_ident[EI_DATA] = ELF_DATA; 438249687Strociny ehdr->e_ident[EI_VERSION] = EV_CURRENT; 439249687Strociny ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 440249687Strociny ehdr->e_ident[EI_ABIVERSION] = 0; 441249687Strociny ehdr->e_ident[EI_PAD] = 0; 442249687Strociny ehdr->e_type = ET_CORE; 443318192Sjhb ehdr->e_machine = binhdr.e_machine; 444249687Strociny ehdr->e_version = EV_CURRENT; 445249687Strociny ehdr->e_entry = 0; 446249687Strociny ehdr->e_phoff = sizeof(Elf_Ehdr); 447318192Sjhb ehdr->e_flags = binhdr.e_flags; 448249687Strociny ehdr->e_ehsize = sizeof(Elf_Ehdr); 449249687Strociny ehdr->e_phentsize = sizeof(Elf_Phdr); 450249687Strociny ehdr->e_phnum = numsegs + 1; 451249687Strociny ehdr->e_shentsize = sizeof(Elf_Shdr); 452249687Strociny ehdr->e_shnum = 0; 453249687Strociny ehdr->e_shstrndx = SHN_UNDEF; 454249687Strociny 455249687Strociny /* 456249687Strociny * Fill in the program header entries. 457249687Strociny */ 458249687Strociny 459249687Strociny /* The note segement. */ 460249687Strociny phdr->p_type = PT_NOTE; 461249687Strociny phdr->p_offset = hdrsize; 462249687Strociny phdr->p_vaddr = 0; 463249687Strociny phdr->p_paddr = 0; 464249687Strociny phdr->p_filesz = notesz; 465249687Strociny phdr->p_memsz = 0; 466249687Strociny phdr->p_flags = PF_R; 467249687Strociny phdr->p_align = sizeof(Elf32_Size); 468249687Strociny phdr++; 469249687Strociny 470249687Strociny /* All the writable segments from the program. */ 471249687Strociny phc.phdr = phdr; 472249687Strociny phc.offset = segoff; 473249687Strociny each_writable_segment(map, cb_put_phdr, &phc); 474249687Strociny} 475249687Strociny 476249687Strociny/* 47740525Sjdp * Free the memory map. 47840525Sjdp */ 47940525Sjdpstatic void 48040525Sjdpfreemap(vm_map_entry_t map) 48140525Sjdp{ 482103299Speter 48340525Sjdp while (map != NULL) { 48440525Sjdp vm_map_entry_t next = map->next; 48540525Sjdp free(map); 48640525Sjdp map = next; 48740525Sjdp } 48840525Sjdp} 48940525Sjdp 49040525Sjdp/* 491199805Sattilio * Read the process's memory map using kinfo_getvmmap(), and return a list of 49240525Sjdp * VM map entries. Only the non-device read/writable segments are 49340525Sjdp * returned. The map entries in the list aren't fully filled in; only 49440525Sjdp * the items we need are present. 49540525Sjdp */ 49640525Sjdpstatic vm_map_entry_t 49740525Sjdpreadmap(pid_t pid) 49840525Sjdp{ 499199805Sattilio vm_map_entry_t ent, *linkp, map; 500199805Sattilio struct kinfo_vmentry *vmentl, *kve; 501199805Sattilio int i, nitems; 50240525Sjdp 503199805Sattilio vmentl = kinfo_getvmmap(pid, &nitems); 504199805Sattilio if (vmentl == NULL) 505199805Sattilio err(1, "cannot retrieve mappings for %u process", pid); 50640525Sjdp 50740525Sjdp map = NULL; 50840525Sjdp linkp = ↦ 509199805Sattilio for (i = 0; i < nitems; i++) { 510199805Sattilio kve = &vmentl[i]; 51140525Sjdp 512199805Sattilio /* 513210063Sattilio * Ignore 'malformed' segments or ones representing memory 514210063Sattilio * mapping with MAP_NOCORE on. 515210063Sattilio * If the 'full' support is disabled, just dump the most 516210063Sattilio * meaningful data segments. 517199805Sattilio */ 518210063Sattilio if ((kve->kve_protection & KVME_PROT_READ) == 0 || 519210063Sattilio (kve->kve_flags & KVME_FLAG_NOCOREDUMP) != 0 || 520210063Sattilio kve->kve_type == KVME_TYPE_DEAD || 521210063Sattilio kve->kve_type == KVME_TYPE_UNKNOWN || 522210063Sattilio ((pflags & PFLAGS_FULL) == 0 && 523210063Sattilio kve->kve_type != KVME_TYPE_DEFAULT && 524199805Sattilio kve->kve_type != KVME_TYPE_VNODE && 525280966Sjhb kve->kve_type != KVME_TYPE_SWAP && 526280966Sjhb kve->kve_type != KVME_TYPE_PHYS)) 52740525Sjdp continue; 52840525Sjdp 529199805Sattilio ent = calloc(1, sizeof(*ent)); 530199805Sattilio if (ent == NULL) 53140525Sjdp errx(1, "out of memory"); 532199805Sattilio ent->start = (vm_offset_t)kve->kve_start; 533199805Sattilio ent->end = (vm_offset_t)kve->kve_end; 53440525Sjdp ent->protection = VM_PROT_READ | VM_PROT_WRITE; 535199805Sattilio if ((kve->kve_protection & KVME_PROT_EXEC) != 0) 536199805Sattilio ent->protection |= VM_PROT_EXECUTE; 53740525Sjdp 53840525Sjdp *linkp = ent; 53940525Sjdp linkp = &ent->next; 54040525Sjdp } 541199805Sattilio free(vmentl); 542199805Sattilio return (map); 54340525Sjdp} 544103299Speter 545249687Strociny/* 546249687Strociny * Miscellaneous note out functions. 547249687Strociny */ 548249687Strociny 549249687Strocinystatic void * 550249687Strocinyelf_note_prpsinfo(void *arg, size_t *sizep) 551249687Strociny{ 552306786Sjhb char *cp, *end; 553249687Strociny pid_t pid; 554283909Sjhb elfcore_prpsinfo_t *psinfo; 555249687Strociny struct kinfo_proc kip; 556249687Strociny size_t len; 557249687Strociny int name[4]; 558249687Strociny 559249687Strociny pid = *(pid_t *)arg; 560249687Strociny psinfo = calloc(1, sizeof(*psinfo)); 561249687Strociny if (psinfo == NULL) 562249687Strociny errx(1, "out of memory"); 563249687Strociny psinfo->pr_version = PRPSINFO_VERSION; 564283909Sjhb psinfo->pr_psinfosz = sizeof(*psinfo); 565249687Strociny 566249687Strociny name[0] = CTL_KERN; 567249687Strociny name[1] = KERN_PROC; 568249687Strociny name[2] = KERN_PROC_PID; 569249687Strociny name[3] = pid; 570249687Strociny len = sizeof(kip); 571249687Strociny if (sysctl(name, 4, &kip, &len, NULL, 0) == -1) 572249687Strociny err(1, "kern.proc.pid.%u", pid); 573249687Strociny if (kip.ki_pid != pid) 574249687Strociny err(1, "kern.proc.pid.%u", pid); 575306781Sjhb strlcpy(psinfo->pr_fname, kip.ki_comm, sizeof(psinfo->pr_fname)); 576306786Sjhb name[2] = KERN_PROC_ARGS; 577306786Sjhb len = sizeof(psinfo->pr_psargs) - 1; 578306786Sjhb if (sysctl(name, 4, psinfo->pr_psargs, &len, NULL, 0) == 0 && len > 0) { 579306786Sjhb cp = psinfo->pr_psargs; 580306786Sjhb end = cp + len - 1; 581306786Sjhb for (;;) { 582306786Sjhb cp = memchr(cp, '\0', end - cp); 583306786Sjhb if (cp == NULL) 584306786Sjhb break; 585306786Sjhb *cp = ' '; 586306786Sjhb } 587306786Sjhb } else 588306786Sjhb strlcpy(psinfo->pr_psargs, kip.ki_comm, 589306786Sjhb sizeof(psinfo->pr_psargs)); 590308009Sjhb psinfo->pr_pid = pid; 591249687Strociny 592249687Strociny *sizep = sizeof(*psinfo); 593249687Strociny return (psinfo); 594249687Strociny} 595249687Strociny 596249687Strocinystatic void * 597249687Strocinyelf_note_prstatus(void *arg, size_t *sizep) 598249687Strociny{ 599249687Strociny lwpid_t tid; 600283909Sjhb elfcore_prstatus_t *status; 601283909Sjhb struct reg greg; 602249687Strociny 603249687Strociny tid = *(lwpid_t *)arg; 604249687Strociny status = calloc(1, sizeof(*status)); 605249687Strociny if (status == NULL) 606249687Strociny errx(1, "out of memory"); 607249687Strociny status->pr_version = PRSTATUS_VERSION; 608283909Sjhb status->pr_statussz = sizeof(*status); 609283909Sjhb status->pr_gregsetsz = sizeof(elfcore_gregset_t); 610283909Sjhb status->pr_fpregsetsz = sizeof(elfcore_fpregset_t); 611249687Strociny status->pr_osreldate = __FreeBSD_version; 612249687Strociny status->pr_pid = tid; 613283909Sjhb ptrace(PT_GETREGS, tid, (void *)&greg, 0); 614283909Sjhb elf_convert_gregset(&status->pr_reg, &greg); 615249687Strociny 616249687Strociny *sizep = sizeof(*status); 617249687Strociny return (status); 618249687Strociny} 619249687Strociny 620249687Strocinystatic void * 621249687Strocinyelf_note_fpregset(void *arg, size_t *sizep) 622249687Strociny{ 623249687Strociny lwpid_t tid; 624283909Sjhb elfcore_fpregset_t *fpregset; 625283909Sjhb fpregset_t fpreg; 626249687Strociny 627249687Strociny tid = *(lwpid_t *)arg; 628249687Strociny fpregset = calloc(1, sizeof(*fpregset)); 629249687Strociny if (fpregset == NULL) 630249687Strociny errx(1, "out of memory"); 631283909Sjhb ptrace(PT_GETFPREGS, tid, (void *)&fpreg, 0); 632283909Sjhb elf_convert_fpregset(fpregset, &fpreg); 633249687Strociny 634249687Strociny *sizep = sizeof(*fpregset); 635249687Strociny return (fpregset); 636249687Strociny} 637249687Strociny 638249687Strocinystatic void * 639249687Strocinyelf_note_thrmisc(void *arg, size_t *sizep) 640249687Strociny{ 641249687Strociny lwpid_t tid; 642249687Strociny struct ptrace_lwpinfo lwpinfo; 643249687Strociny thrmisc_t *thrmisc; 644249687Strociny 645249687Strociny tid = *(lwpid_t *)arg; 646249687Strociny thrmisc = calloc(1, sizeof(*thrmisc)); 647249687Strociny if (thrmisc == NULL) 648249687Strociny errx(1, "out of memory"); 649249687Strociny ptrace(PT_LWPINFO, tid, (void *)&lwpinfo, 650249687Strociny sizeof(lwpinfo)); 651249687Strociny memset(&thrmisc->_pad, 0, sizeof(thrmisc->_pad)); 652249687Strociny strcpy(thrmisc->pr_tname, lwpinfo.pl_tdname); 653249687Strociny 654249687Strociny *sizep = sizeof(*thrmisc); 655249687Strociny return (thrmisc); 656249687Strociny} 657249687Strociny 658279211Sjhb#if defined(__i386__) || defined(__amd64__) 659249687Strocinystatic void * 660279211Sjhbelf_note_x86_xstate(void *arg, size_t *sizep) 661279211Sjhb{ 662279211Sjhb lwpid_t tid; 663279211Sjhb char *xstate; 664279211Sjhb static bool xsave_checked = false; 665279211Sjhb static struct ptrace_xstate_info info; 666279211Sjhb 667279211Sjhb tid = *(lwpid_t *)arg; 668279211Sjhb if (!xsave_checked) { 669279211Sjhb if (ptrace(PT_GETXSTATE_INFO, tid, (void *)&info, 670279211Sjhb sizeof(info)) != 0) 671279211Sjhb info.xsave_len = 0; 672279211Sjhb xsave_checked = true; 673279211Sjhb } 674279211Sjhb if (info.xsave_len == 0) { 675279211Sjhb *sizep = 0; 676279211Sjhb return (NULL); 677279211Sjhb } 678279211Sjhb xstate = calloc(1, info.xsave_len); 679279211Sjhb ptrace(PT_GETXSTATE, tid, xstate, 0); 680279211Sjhb *(uint64_t *)(xstate + X86_XSTATE_XCR0_OFFSET) = info.xsave_mask; 681279211Sjhb *sizep = info.xsave_len; 682279211Sjhb return (xstate); 683279211Sjhb} 684279211Sjhb#endif 685279211Sjhb 686279211Sjhbstatic void * 687249687Strocinyprocstat_sysctl(void *arg, int what, size_t structsz, size_t *sizep) 688249687Strociny{ 689249687Strociny size_t len, oldlen; 690249687Strociny pid_t pid; 691249687Strociny int name[4], structsize; 692249687Strociny void *buf, *p; 693249687Strociny 694249687Strociny pid = *(pid_t *)arg; 695249687Strociny structsize = structsz; 696249687Strociny name[0] = CTL_KERN; 697249687Strociny name[1] = KERN_PROC; 698249687Strociny name[2] = what; 699249687Strociny name[3] = pid; 700249687Strociny len = 0; 701249687Strociny if (sysctl(name, 4, NULL, &len, NULL, 0) == -1) 702249687Strociny err(1, "kern.proc.%d.%u", what, pid); 703249687Strociny buf = calloc(1, sizeof(structsize) + len * 4 / 3); 704249687Strociny if (buf == NULL) 705249687Strociny errx(1, "out of memory"); 706249687Strociny bcopy(&structsize, buf, sizeof(structsize)); 707249687Strociny p = (char *)buf + sizeof(structsize); 708249687Strociny if (sysctl(name, 4, p, &len, NULL, 0) == -1) 709249687Strociny err(1, "kern.proc.%d.%u", what, pid); 710249687Strociny 711249687Strociny *sizep = sizeof(structsize) + len; 712249687Strociny return (buf); 713249687Strociny} 714249687Strociny 715249687Strocinystatic void * 716249687Strocinyelf_note_procstat_proc(void *arg, size_t *sizep) 717249687Strociny{ 718249687Strociny 719249687Strociny return (procstat_sysctl(arg, KERN_PROC_PID | KERN_PROC_INC_THREAD, 720249687Strociny sizeof(struct kinfo_proc), sizep)); 721249687Strociny} 722249687Strociny 723249687Strocinystatic void * 724249687Strocinyelf_note_procstat_files(void *arg, size_t *sizep) 725249687Strociny{ 726249687Strociny 727249687Strociny return (procstat_sysctl(arg, KERN_PROC_FILEDESC, 728249687Strociny sizeof(struct kinfo_file), sizep)); 729249687Strociny} 730249687Strociny 731249687Strocinystatic void * 732249687Strocinyelf_note_procstat_vmmap(void *arg, size_t *sizep) 733249687Strociny{ 734249687Strociny 735249687Strociny return (procstat_sysctl(arg, KERN_PROC_VMMAP, 736249687Strociny sizeof(struct kinfo_vmentry), sizep)); 737249687Strociny} 738249687Strociny 739249687Strocinystatic void * 740249687Strocinyelf_note_procstat_groups(void *arg, size_t *sizep) 741249687Strociny{ 742249687Strociny 743249704Strociny return (procstat_sysctl(arg, KERN_PROC_GROUPS, sizeof(gid_t), sizep)); 744249687Strociny} 745249687Strociny 746249687Strocinystatic void * 747249687Strocinyelf_note_procstat_umask(void *arg, size_t *sizep) 748249687Strociny{ 749249687Strociny 750249687Strociny return (procstat_sysctl(arg, KERN_PROC_UMASK, sizeof(u_short), sizep)); 751249687Strociny} 752249687Strociny 753249687Strocinystatic void * 754249687Strocinyelf_note_procstat_osrel(void *arg, size_t *sizep) 755249687Strociny{ 756249687Strociny 757249687Strociny return (procstat_sysctl(arg, KERN_PROC_OSREL, sizeof(int), sizep)); 758249687Strociny} 759249687Strociny 760249687Strocinystatic void * 761249687Strocinyelf_note_procstat_psstrings(void *arg, size_t *sizep) 762249687Strociny{ 763249687Strociny 764249687Strociny return (procstat_sysctl(arg, KERN_PROC_PS_STRINGS, 765249687Strociny sizeof(vm_offset_t), sizep)); 766249687Strociny} 767249687Strociny 768249687Strocinystatic void * 769249687Strocinyelf_note_procstat_auxv(void *arg, size_t *sizep) 770249687Strociny{ 771249687Strociny 772249687Strociny return (procstat_sysctl(arg, KERN_PROC_AUXV, 773249687Strociny sizeof(Elf_Auxinfo), sizep)); 774249687Strociny} 775249687Strociny 776249687Strocinystatic void * 777249687Strocinyelf_note_procstat_rlimit(void *arg, size_t *sizep) 778249687Strociny{ 779249687Strociny pid_t pid; 780249687Strociny size_t len; 781249687Strociny int i, name[5], structsize; 782249687Strociny void *buf, *p; 783249687Strociny 784249687Strociny pid = *(pid_t *)arg; 785249687Strociny structsize = sizeof(struct rlimit) * RLIM_NLIMITS; 786249687Strociny buf = calloc(1, sizeof(structsize) + structsize); 787249687Strociny if (buf == NULL) 788249687Strociny errx(1, "out of memory"); 789249687Strociny bcopy(&structsize, buf, sizeof(structsize)); 790249687Strociny p = (char *)buf + sizeof(structsize); 791249687Strociny name[0] = CTL_KERN; 792249687Strociny name[1] = KERN_PROC; 793249687Strociny name[2] = KERN_PROC_RLIMIT; 794249687Strociny name[3] = pid; 795249687Strociny len = sizeof(struct rlimit); 796249687Strociny for (i = 0; i < RLIM_NLIMITS; i++) { 797249687Strociny name[4] = i; 798249687Strociny if (sysctl(name, 5, p, &len, NULL, 0) == -1) 799249687Strociny err(1, "kern.proc.rlimit.%u", pid); 800249687Strociny if (len != sizeof(struct rlimit)) 801249687Strociny errx(1, "kern.proc.rlimit.%u: short read", pid); 802249687Strociny p += len; 803249687Strociny } 804249687Strociny 805249687Strociny *sizep = sizeof(structsize) + structsize; 806249687Strociny return (buf); 807249687Strociny} 808249687Strociny 809283909Sjhbstruct dumpers __elfN(dump) = { elf_ident, elf_coredump }; 810283909SjhbTEXT_SET(dumpset, __elfN(dump)); 811