152e7cc0aSJohn Polstra /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
486be94fcSTycho Nightingale * Copyright (c) 2017 Dell EMC
52e7ecbfbSAttilio Rao * Copyright (c) 2007 Sandvine Incorporated
652e7cc0aSJohn Polstra * Copyright (c) 1998 John D. Polstra
752e7cc0aSJohn Polstra * All rights reserved.
852e7cc0aSJohn Polstra *
952e7cc0aSJohn Polstra * Redistribution and use in source and binary forms, with or without
1052e7cc0aSJohn Polstra * modification, are permitted provided that the following conditions
1152e7cc0aSJohn Polstra * are met:
1252e7cc0aSJohn Polstra * 1. Redistributions of source code must retain the above copyright
1352e7cc0aSJohn Polstra * notice, this list of conditions and the following disclaimer.
1452e7cc0aSJohn Polstra * 2. Redistributions in binary form must reproduce the above copyright
1552e7cc0aSJohn Polstra * notice, this list of conditions and the following disclaimer in the
1652e7cc0aSJohn Polstra * documentation and/or other materials provided with the distribution.
1752e7cc0aSJohn Polstra *
1852e7cc0aSJohn Polstra * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1952e7cc0aSJohn Polstra * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2052e7cc0aSJohn Polstra * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2152e7cc0aSJohn Polstra * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2252e7cc0aSJohn Polstra * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2352e7cc0aSJohn Polstra * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2452e7cc0aSJohn Polstra * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2552e7cc0aSJohn Polstra * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2652e7cc0aSJohn Polstra * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2752e7cc0aSJohn Polstra * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2852e7cc0aSJohn Polstra * SUCH DAMAGE.
2952e7cc0aSJohn Polstra */
3052e7cc0aSJohn Polstra
31ed68d15dSPhilippe Charnier #include <sys/cdefs.h>
3231d743dfSMarcel Moolenaar #include <sys/endian.h>
3352e7cc0aSJohn Polstra #include <sys/param.h>
3452e7cc0aSJohn Polstra #include <sys/procfs.h>
352e7ecbfbSAttilio Rao #include <sys/ptrace.h>
369e0a9e98SPeter Wemm #include <sys/queue.h>
37e0491636SPeter Wemm #include <sys/linker_set.h>
387fe6d16eSMikolaj Golub #include <sys/sbuf.h>
392e7ecbfbSAttilio Rao #include <sys/sysctl.h>
402e7ecbfbSAttilio Rao #include <sys/user.h>
412e7ecbfbSAttilio Rao #include <sys/wait.h>
425e6220d9SDavid E. O'Brien #include <machine/elf.h>
4352e7cc0aSJohn Polstra #include <vm/vm_param.h>
4452e7cc0aSJohn Polstra #include <vm/vm.h>
457fe6d16eSMikolaj Golub #include <assert.h>
4652e7cc0aSJohn Polstra #include <err.h>
4752e7cc0aSJohn Polstra #include <errno.h>
4852e7cc0aSJohn Polstra #include <fcntl.h>
49180e57e5SJohn Baldwin #include <stdbool.h>
5056d037c6SIan Dowse #include <stdint.h>
5152e7cc0aSJohn Polstra #include <stdio.h>
5252e7cc0aSJohn Polstra #include <stdlib.h>
5352e7cc0aSJohn Polstra #include <string.h>
5452e7cc0aSJohn Polstra #include <unistd.h>
552e7ecbfbSAttilio Rao #include <libutil.h>
5652e7cc0aSJohn Polstra
5752e7cc0aSJohn Polstra #include "extern.h"
5852e7cc0aSJohn Polstra
5952e7cc0aSJohn Polstra /*
6052e7cc0aSJohn Polstra * Code for generating ELF core dumps.
6152e7cc0aSJohn Polstra */
6252e7cc0aSJohn Polstra
63eae3ca5aSMark Johnston struct map_entry {
64eae3ca5aSMark Johnston struct map_entry *next;
65eae3ca5aSMark Johnston vm_offset_t start;
66eae3ca5aSMark Johnston vm_offset_t end;
67eae3ca5aSMark Johnston vm_prot_t protection;
68eae3ca5aSMark Johnston };
69eae3ca5aSMark Johnston
70eae3ca5aSMark Johnston typedef void (*segment_callback)(struct map_entry *, void *);
7152e7cc0aSJohn Polstra
7252e7cc0aSJohn Polstra /* Closure for cb_put_phdr(). */
7352e7cc0aSJohn Polstra struct phdr_closure {
7452e7cc0aSJohn Polstra Elf_Phdr *phdr; /* Program header to fill in */
7552e7cc0aSJohn Polstra Elf_Off offset; /* Offset of segment in core file */
7652e7cc0aSJohn Polstra };
7752e7cc0aSJohn Polstra
7852e7cc0aSJohn Polstra /* Closure for cb_size_segment(). */
7952e7cc0aSJohn Polstra struct sseg_closure {
8052e7cc0aSJohn Polstra int count; /* Count of writable segments. */
8152e7cc0aSJohn Polstra size_t size; /* Total size of all writable segments. */
8252e7cc0aSJohn Polstra };
8352e7cc0aSJohn Polstra
8431d743dfSMarcel Moolenaar #ifdef ELFCORE_COMPAT_32
8531d743dfSMarcel Moolenaar typedef struct prpsinfo32 elfcore_prpsinfo_t;
8631d743dfSMarcel Moolenaar #else
8731d743dfSMarcel Moolenaar typedef prpsinfo_t elfcore_prpsinfo_t;
8831d743dfSMarcel Moolenaar #endif
8931d743dfSMarcel Moolenaar
907fe6d16eSMikolaj Golub typedef void* (*notefunc_t)(void *, size_t *);
917fe6d16eSMikolaj Golub
92eae3ca5aSMark Johnston static void cb_put_phdr(struct map_entry *, void *);
93eae3ca5aSMark Johnston static void cb_size_segment(struct map_entry *, void *);
94eae3ca5aSMark Johnston static void each_dumpable_segment(struct map_entry *, segment_callback,
9552e7cc0aSJohn Polstra void *closure);
962e7ecbfbSAttilio Rao static void elf_detach(void); /* atexit() handler. */
977fe6d16eSMikolaj Golub static void *elf_note_prpsinfo(void *, size_t *);
98180e57e5SJohn Baldwin #if defined(__i386__) || defined(__amd64__)
99180e57e5SJohn Baldwin static void *elf_note_x86_xstate(void *, size_t *);
100180e57e5SJohn Baldwin #endif
101b5d4909eSJustin Hibbits #if defined(__powerpc__)
102b5d4909eSJustin Hibbits static void *elf_note_powerpc_vmx(void *, size_t *);
1035167f178SJustin Hibbits static void *elf_note_powerpc_vsx(void *, size_t *);
104b5d4909eSJustin Hibbits #endif
1057fe6d16eSMikolaj Golub static void *elf_note_procstat_auxv(void *, size_t *);
1067fe6d16eSMikolaj Golub static void *elf_note_procstat_files(void *, size_t *);
1077fe6d16eSMikolaj Golub static void *elf_note_procstat_groups(void *, size_t *);
1087fe6d16eSMikolaj Golub static void *elf_note_procstat_osrel(void *, size_t *);
1097fe6d16eSMikolaj Golub static void *elf_note_procstat_proc(void *, size_t *);
1107fe6d16eSMikolaj Golub static void *elf_note_procstat_psstrings(void *, size_t *);
1117fe6d16eSMikolaj Golub static void *elf_note_procstat_rlimit(void *, size_t *);
1127fe6d16eSMikolaj Golub static void *elf_note_procstat_umask(void *, size_t *);
1137fe6d16eSMikolaj Golub static void *elf_note_procstat_vmmap(void *, size_t *);
114eae3ca5aSMark Johnston static void elf_puthdr(int, pid_t, struct map_entry *, void *, size_t, size_t,
115885f13dcSJohn Baldwin size_t, int);
1167fe6d16eSMikolaj Golub static void elf_putnote(int, notefunc_t, void *, struct sbuf *);
1177fe6d16eSMikolaj Golub static void elf_putnotes(pid_t, struct sbuf *, size_t *);
1184965ac05SJohn Baldwin static void elf_putregnote(int, lwpid_t, struct sbuf *);
119eae3ca5aSMark Johnston static void freemap(struct map_entry *);
120eae3ca5aSMark Johnston static struct map_entry *readmap(pid_t);
1217fe6d16eSMikolaj Golub static void *procstat_sysctl(void *, int, size_t, size_t *sizep);
12252e7cc0aSJohn Polstra
1232e7ecbfbSAttilio Rao static pid_t g_pid; /* Pid being dumped, global for elf_detach */
1240367ff56SMark Johnston static int g_status; /* proc status after ptrace attach */
1252e7ecbfbSAttilio Rao
126e0491636SPeter Wemm static int
elf_ident(int efd,pid_t pid __unused,char * binfile __unused)127c4dd6db1SDavid Malone elf_ident(int efd, pid_t pid __unused, char *binfile __unused)
128e0491636SPeter Wemm {
129e0491636SPeter Wemm Elf_Ehdr hdr;
130e0491636SPeter Wemm int cnt;
13131d743dfSMarcel Moolenaar uint16_t machine;
132e0491636SPeter Wemm
133e0491636SPeter Wemm cnt = read(efd, &hdr, sizeof(hdr));
134e0491636SPeter Wemm if (cnt != sizeof(hdr))
135e0491636SPeter Wemm return (0);
13631d743dfSMarcel Moolenaar if (!IS_ELF(hdr))
137e0491636SPeter Wemm return (0);
13831d743dfSMarcel Moolenaar switch (hdr.e_ident[EI_DATA]) {
13931d743dfSMarcel Moolenaar case ELFDATA2LSB:
14031d743dfSMarcel Moolenaar machine = le16toh(hdr.e_machine);
14131d743dfSMarcel Moolenaar break;
14231d743dfSMarcel Moolenaar case ELFDATA2MSB:
14331d743dfSMarcel Moolenaar machine = be16toh(hdr.e_machine);
14431d743dfSMarcel Moolenaar break;
14531d743dfSMarcel Moolenaar default:
14631d743dfSMarcel Moolenaar return (0);
14731d743dfSMarcel Moolenaar }
14831d743dfSMarcel Moolenaar if (!ELF_MACHINE_OK(machine))
14931d743dfSMarcel Moolenaar return (0);
15031d743dfSMarcel Moolenaar
15131d743dfSMarcel Moolenaar /* Looks good. */
15231d743dfSMarcel Moolenaar return (1);
153e0491636SPeter Wemm }
154e0491636SPeter Wemm
1552e7ecbfbSAttilio Rao static void
elf_detach(void)1562e7ecbfbSAttilio Rao elf_detach(void)
1572e7ecbfbSAttilio Rao {
1580367ff56SMark Johnston int sig;
1592e7ecbfbSAttilio Rao
1600367ff56SMark Johnston if (g_pid != 0) {
1610367ff56SMark Johnston /*
1620367ff56SMark Johnston * Forward any pending signals. SIGSTOP is generated by ptrace
1630367ff56SMark Johnston * itself, so ignore it.
1640367ff56SMark Johnston */
1650367ff56SMark Johnston sig = WIFSTOPPED(g_status) ? WSTOPSIG(g_status) : 0;
1660367ff56SMark Johnston if (sig == SIGSTOP)
1670367ff56SMark Johnston sig = 0;
1680367ff56SMark Johnston ptrace(PT_DETACH, g_pid, (caddr_t)1, sig);
1690367ff56SMark Johnston }
1702e7ecbfbSAttilio Rao }
1712e7ecbfbSAttilio Rao
17252e7cc0aSJohn Polstra /*
17352e7cc0aSJohn Polstra * Write an ELF coredump for the given pid to the given fd.
17452e7cc0aSJohn Polstra */
175c4dd6db1SDavid Malone static void
elf_coredump(int efd,int fd,pid_t pid)176885f13dcSJohn Baldwin elf_coredump(int efd, int fd, pid_t pid)
17752e7cc0aSJohn Polstra {
178eae3ca5aSMark Johnston struct map_entry *map;
17952e7cc0aSJohn Polstra struct sseg_closure seginfo;
1807fe6d16eSMikolaj Golub struct sbuf *sb;
18152e7cc0aSJohn Polstra void *hdr;
1827fe6d16eSMikolaj Golub size_t hdrsize, notesz, segoff;
1837fe6d16eSMikolaj Golub ssize_t n, old_len;
18452e7cc0aSJohn Polstra Elf_Phdr *php;
18552e7cc0aSJohn Polstra int i;
18652e7cc0aSJohn Polstra
1872e7ecbfbSAttilio Rao /* Attach to process to dump. */
1882e7ecbfbSAttilio Rao g_pid = pid;
1892e7ecbfbSAttilio Rao if (atexit(elf_detach) != 0)
1902e7ecbfbSAttilio Rao err(1, "atexit");
1912e7ecbfbSAttilio Rao errno = 0;
1922e7ecbfbSAttilio Rao ptrace(PT_ATTACH, pid, NULL, 0);
1932e7ecbfbSAttilio Rao if (errno)
1942e7ecbfbSAttilio Rao err(1, "PT_ATTACH");
1950367ff56SMark Johnston if (waitpid(pid, &g_status, 0) == -1)
1962e7ecbfbSAttilio Rao err(1, "waitpid");
1972e7ecbfbSAttilio Rao
19852e7cc0aSJohn Polstra /* Get the program's memory map. */
19952e7cc0aSJohn Polstra map = readmap(pid);
20052e7cc0aSJohn Polstra
20152e7cc0aSJohn Polstra /* Size the program segments. */
20252e7cc0aSJohn Polstra seginfo.count = 0;
20352e7cc0aSJohn Polstra seginfo.size = 0;
2048a263d91SConrad Meyer each_dumpable_segment(map, cb_size_segment, &seginfo);
20552e7cc0aSJohn Polstra
20652e7cc0aSJohn Polstra /*
2077fe6d16eSMikolaj Golub * Build the header and the notes using sbuf and write to the file.
20852e7cc0aSJohn Polstra */
2097fe6d16eSMikolaj Golub sb = sbuf_new_auto();
2107fe6d16eSMikolaj Golub hdrsize = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * (1 + seginfo.count);
211bd0371c9SConrad Meyer if (seginfo.count + 1 >= PN_XNUM)
212bd0371c9SConrad Meyer hdrsize += sizeof(Elf_Shdr);
2137fe6d16eSMikolaj Golub /* Start header + notes section. */
2147fe6d16eSMikolaj Golub sbuf_start_section(sb, NULL);
2157fe6d16eSMikolaj Golub /* Make empty header subsection. */
2167fe6d16eSMikolaj Golub sbuf_start_section(sb, &old_len);
2177fe6d16eSMikolaj Golub sbuf_putc(sb, 0);
2187fe6d16eSMikolaj Golub sbuf_end_section(sb, old_len, hdrsize, 0);
2197fe6d16eSMikolaj Golub /* Put notes. */
2207fe6d16eSMikolaj Golub elf_putnotes(pid, sb, ¬esz);
2217fe6d16eSMikolaj Golub /* Align up to a page boundary for the program segments. */
222f9ca52baSAndrew Turner sbuf_end_section(sb, -1, getpagesize(), 0);
2237fe6d16eSMikolaj Golub if (sbuf_finish(sb) != 0)
2247fe6d16eSMikolaj Golub err(1, "sbuf_finish");
2257fe6d16eSMikolaj Golub hdr = sbuf_data(sb);
2267fe6d16eSMikolaj Golub segoff = sbuf_len(sb);
2272e7ecbfbSAttilio Rao /* Fill in the header. */
228885f13dcSJohn Baldwin elf_puthdr(efd, pid, map, hdr, hdrsize, notesz, segoff, seginfo.count);
2292e7ecbfbSAttilio Rao
2307fe6d16eSMikolaj Golub n = write(fd, hdr, segoff);
2317fe6d16eSMikolaj Golub if (n == -1)
2322e7ecbfbSAttilio Rao err(1, "write");
2337fe6d16eSMikolaj Golub if (n < segoff)
2347fe6d16eSMikolaj Golub errx(1, "short write");
23552e7cc0aSJohn Polstra
23652e7cc0aSJohn Polstra /* Write the contents of all of the writable segments. */
23752e7cc0aSJohn Polstra php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1;
23852e7cc0aSJohn Polstra for (i = 0; i < seginfo.count; i++) {
2392e7ecbfbSAttilio Rao struct ptrace_io_desc iorequest;
240f4ac32deSDavid Malone uintmax_t nleft = php->p_filesz;
24152e7cc0aSJohn Polstra
2422e7ecbfbSAttilio Rao iorequest.piod_op = PIOD_READ_D;
24331d743dfSMarcel Moolenaar iorequest.piod_offs = (caddr_t)(uintptr_t)php->p_vaddr;
24452e7cc0aSJohn Polstra while (nleft > 0) {
24552e7cc0aSJohn Polstra char buf[8*1024];
246f4ac32deSDavid Malone size_t nwant;
247f4ac32deSDavid Malone ssize_t ngot;
24852e7cc0aSJohn Polstra
249f4ac32deSDavid Malone if (nleft > sizeof(buf))
25052e7cc0aSJohn Polstra nwant = sizeof buf;
251f4ac32deSDavid Malone else
252f4ac32deSDavid Malone nwant = nleft;
2532e7ecbfbSAttilio Rao iorequest.piod_addr = buf;
2542e7ecbfbSAttilio Rao iorequest.piod_len = nwant;
2552e7ecbfbSAttilio Rao ptrace(PT_IO, pid, (caddr_t)&iorequest, 0);
2562e7ecbfbSAttilio Rao ngot = iorequest.piod_len;
257f4ac32deSDavid Malone if ((size_t)ngot < nwant)
258d1d6559bSXin LI errx(1, "short read wanted %zu, got %zd",
25900bf1f30SJohn Polstra nwant, ngot);
26052e7cc0aSJohn Polstra ngot = write(fd, buf, nwant);
26152e7cc0aSJohn Polstra if (ngot == -1)
26252e7cc0aSJohn Polstra err(1, "write of segment %d failed", i);
263f4ac32deSDavid Malone if ((size_t)ngot != nwant)
26452e7cc0aSJohn Polstra errx(1, "short write");
26552e7cc0aSJohn Polstra nleft -= nwant;
2662e7ecbfbSAttilio Rao iorequest.piod_offs += ngot;
26752e7cc0aSJohn Polstra }
26852e7cc0aSJohn Polstra php++;
26952e7cc0aSJohn Polstra }
2707fe6d16eSMikolaj Golub sbuf_delete(sb);
27152e7cc0aSJohn Polstra freemap(map);
27252e7cc0aSJohn Polstra }
27352e7cc0aSJohn Polstra
27452e7cc0aSJohn Polstra /*
2758a263d91SConrad Meyer * A callback for each_dumpable_segment() to write out the segment's
27652e7cc0aSJohn Polstra * program header entry.
27752e7cc0aSJohn Polstra */
27852e7cc0aSJohn Polstra static void
cb_put_phdr(struct map_entry * entry,void * closure)279eae3ca5aSMark Johnston cb_put_phdr(struct map_entry *entry, void *closure)
28052e7cc0aSJohn Polstra {
28152e7cc0aSJohn Polstra struct phdr_closure *phc = (struct phdr_closure *)closure;
28252e7cc0aSJohn Polstra Elf_Phdr *phdr = phc->phdr;
283f9ca52baSAndrew Turner size_t page_size;
28452e7cc0aSJohn Polstra
285f9ca52baSAndrew Turner page_size = getpagesize();
286f9ca52baSAndrew Turner phc->offset = roundup2(phc->offset, page_size);
28752e7cc0aSJohn Polstra
28852e7cc0aSJohn Polstra phdr->p_type = PT_LOAD;
28952e7cc0aSJohn Polstra phdr->p_offset = phc->offset;
29052e7cc0aSJohn Polstra phdr->p_vaddr = entry->start;
29152e7cc0aSJohn Polstra phdr->p_paddr = 0;
29252e7cc0aSJohn Polstra phdr->p_filesz = phdr->p_memsz = entry->end - entry->start;
293f9ca52baSAndrew Turner phdr->p_align = page_size;
29452e7cc0aSJohn Polstra phdr->p_flags = 0;
29552e7cc0aSJohn Polstra if (entry->protection & VM_PROT_READ)
29652e7cc0aSJohn Polstra phdr->p_flags |= PF_R;
29752e7cc0aSJohn Polstra if (entry->protection & VM_PROT_WRITE)
29852e7cc0aSJohn Polstra phdr->p_flags |= PF_W;
29952e7cc0aSJohn Polstra if (entry->protection & VM_PROT_EXECUTE)
30052e7cc0aSJohn Polstra phdr->p_flags |= PF_X;
30152e7cc0aSJohn Polstra
30252e7cc0aSJohn Polstra phc->offset += phdr->p_filesz;
30352e7cc0aSJohn Polstra phc->phdr++;
30452e7cc0aSJohn Polstra }
30552e7cc0aSJohn Polstra
30652e7cc0aSJohn Polstra /*
3078a263d91SConrad Meyer * A callback for each_dumpable_segment() to gather information about
30852e7cc0aSJohn Polstra * the number of segments and their total size.
30952e7cc0aSJohn Polstra */
31052e7cc0aSJohn Polstra static void
cb_size_segment(struct map_entry * entry,void * closure)311eae3ca5aSMark Johnston cb_size_segment(struct map_entry *entry, void *closure)
31252e7cc0aSJohn Polstra {
31352e7cc0aSJohn Polstra struct sseg_closure *ssc = (struct sseg_closure *)closure;
31452e7cc0aSJohn Polstra
31552e7cc0aSJohn Polstra ssc->count++;
31652e7cc0aSJohn Polstra ssc->size += entry->end - entry->start;
31752e7cc0aSJohn Polstra }
31852e7cc0aSJohn Polstra
31952e7cc0aSJohn Polstra /*
32052e7cc0aSJohn Polstra * For each segment in the given memory map, call the given function
32152e7cc0aSJohn Polstra * with a pointer to the map entry and some arbitrary caller-supplied
32252e7cc0aSJohn Polstra * data.
32352e7cc0aSJohn Polstra */
32452e7cc0aSJohn Polstra static void
each_dumpable_segment(struct map_entry * map,segment_callback func,void * closure)325eae3ca5aSMark Johnston each_dumpable_segment(struct map_entry *map, segment_callback func,
326eae3ca5aSMark Johnston void *closure)
32752e7cc0aSJohn Polstra {
328eae3ca5aSMark Johnston struct map_entry *entry;
32952e7cc0aSJohn Polstra
33052e7cc0aSJohn Polstra for (entry = map; entry != NULL; entry = entry->next)
33152e7cc0aSJohn Polstra (*func)(entry, closure);
33252e7cc0aSJohn Polstra }
33352e7cc0aSJohn Polstra
33452e7cc0aSJohn Polstra static void
elf_putnotes(pid_t pid,struct sbuf * sb,size_t * sizep)3357fe6d16eSMikolaj Golub elf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep)
33652e7cc0aSJohn Polstra {
3372e7ecbfbSAttilio Rao lwpid_t *tids;
3387fe6d16eSMikolaj Golub size_t threads, old_len;
3397fe6d16eSMikolaj Golub ssize_t size;
3402e7ecbfbSAttilio Rao int i;
3412e7ecbfbSAttilio Rao
3422e7ecbfbSAttilio Rao errno = 0;
3432e7ecbfbSAttilio Rao threads = ptrace(PT_GETNUMLWPS, pid, NULL, 0);
3442e7ecbfbSAttilio Rao if (errno)
3452e7ecbfbSAttilio Rao err(1, "PT_GETNUMLWPS");
3462e7ecbfbSAttilio Rao tids = malloc(threads * sizeof(*tids));
3472e7ecbfbSAttilio Rao if (tids == NULL)
3482e7ecbfbSAttilio Rao errx(1, "out of memory");
3492e7ecbfbSAttilio Rao errno = 0;
3502e7ecbfbSAttilio Rao ptrace(PT_GETLWPLIST, pid, (void *)tids, threads);
3512e7ecbfbSAttilio Rao if (errno)
3522e7ecbfbSAttilio Rao err(1, "PT_GETLWPLIST");
3537fe6d16eSMikolaj Golub
3547fe6d16eSMikolaj Golub sbuf_start_section(sb, &old_len);
3557fe6d16eSMikolaj Golub elf_putnote(NT_PRPSINFO, elf_note_prpsinfo, &pid, sb);
3567fe6d16eSMikolaj Golub
3572e7ecbfbSAttilio Rao for (i = 0; i < threads; ++i) {
3584965ac05SJohn Baldwin elf_putregnote(NT_PRSTATUS, tids[i], sb);
3594965ac05SJohn Baldwin elf_putregnote(NT_FPREGSET, tids[i], sb);
360d95657a1SJohn Baldwin elf_putregnote(NT_THRMISC, tids[i], sb);
361d95657a1SJohn Baldwin elf_putregnote(NT_PTLWPINFO, tids[i], sb);
362b2cb74c2SJohn Baldwin #if defined(__aarch64__) || defined(__arm__)
363b2cb74c2SJohn Baldwin elf_putregnote(NT_ARM_TLS, tids[i], sb);
364b2cb74c2SJohn Baldwin #endif
365add00c38SJohn Baldwin #if (defined(ELFCORE_COMPAT_32) && defined(__aarch64__)) || defined(__arm__)
366add00c38SJohn Baldwin elf_putregnote(NT_ARM_VFP, tids[i], sb);
36727efb0a2SJohn Baldwin #endif
368180e57e5SJohn Baldwin #if defined(__i386__) || defined(__amd64__)
369931983eeSJohn Baldwin elf_putregnote(NT_X86_SEGBASES, tids[i], sb);
370180e57e5SJohn Baldwin elf_putnote(NT_X86_XSTATE, elf_note_x86_xstate, tids + i, sb);
371180e57e5SJohn Baldwin #endif
372b5d4909eSJustin Hibbits #if defined(__powerpc__)
373b5d4909eSJustin Hibbits elf_putnote(NT_PPC_VMX, elf_note_powerpc_vmx, tids + i, sb);
3746a51741fSJustin Hibbits #ifndef __SPE__
3755167f178SJustin Hibbits elf_putnote(NT_PPC_VSX, elf_note_powerpc_vsx, tids + i, sb);
376b5d4909eSJustin Hibbits #endif
3776a51741fSJustin Hibbits #endif
3782e7ecbfbSAttilio Rao }
3792e7ecbfbSAttilio Rao
38031d743dfSMarcel Moolenaar #ifndef ELFCORE_COMPAT_32
3817fe6d16eSMikolaj Golub elf_putnote(NT_PROCSTAT_PROC, elf_note_procstat_proc, &pid, sb);
3827fe6d16eSMikolaj Golub elf_putnote(NT_PROCSTAT_FILES, elf_note_procstat_files, &pid, sb);
3837fe6d16eSMikolaj Golub elf_putnote(NT_PROCSTAT_VMMAP, elf_note_procstat_vmmap, &pid, sb);
3847fe6d16eSMikolaj Golub elf_putnote(NT_PROCSTAT_GROUPS, elf_note_procstat_groups, &pid, sb);
3857fe6d16eSMikolaj Golub elf_putnote(NT_PROCSTAT_UMASK, elf_note_procstat_umask, &pid, sb);
3867fe6d16eSMikolaj Golub elf_putnote(NT_PROCSTAT_RLIMIT, elf_note_procstat_rlimit, &pid, sb);
3877fe6d16eSMikolaj Golub elf_putnote(NT_PROCSTAT_OSREL, elf_note_procstat_osrel, &pid, sb);
3887fe6d16eSMikolaj Golub elf_putnote(NT_PROCSTAT_PSSTRINGS, elf_note_procstat_psstrings, &pid,
3897fe6d16eSMikolaj Golub sb);
3907fe6d16eSMikolaj Golub elf_putnote(NT_PROCSTAT_AUXV, elf_note_procstat_auxv, &pid, sb);
39131d743dfSMarcel Moolenaar #endif
39252e7cc0aSJohn Polstra
3937fe6d16eSMikolaj Golub size = sbuf_end_section(sb, old_len, 1, 0);
3947fe6d16eSMikolaj Golub if (size == -1)
3957fe6d16eSMikolaj Golub err(1, "sbuf_end_section");
3962e7ecbfbSAttilio Rao free(tids);
3977fe6d16eSMikolaj Golub *sizep = size;
3982e7ecbfbSAttilio Rao }
3992e7ecbfbSAttilio Rao
4007fe6d16eSMikolaj Golub /*
4014965ac05SJohn Baldwin * Emit one register set note section to sbuf.
4024965ac05SJohn Baldwin */
4034965ac05SJohn Baldwin static void
elf_putregnote(int type,lwpid_t tid,struct sbuf * sb)4044965ac05SJohn Baldwin elf_putregnote(int type, lwpid_t tid, struct sbuf *sb)
4054965ac05SJohn Baldwin {
4064965ac05SJohn Baldwin Elf_Note note;
4074965ac05SJohn Baldwin struct iovec iov;
4084965ac05SJohn Baldwin ssize_t old_len;
4094965ac05SJohn Baldwin
4104965ac05SJohn Baldwin iov.iov_base = NULL;
4114965ac05SJohn Baldwin iov.iov_len = 0;
4124965ac05SJohn Baldwin if (ptrace(PT_GETREGSET, tid, (void *)&iov, type) != 0)
4134965ac05SJohn Baldwin return;
4144965ac05SJohn Baldwin iov.iov_base = calloc(1, iov.iov_len);
4154965ac05SJohn Baldwin if (iov.iov_base == NULL)
4164965ac05SJohn Baldwin errx(1, "out of memory");
4174965ac05SJohn Baldwin if (ptrace(PT_GETREGSET, tid, (void *)&iov, type) != 0)
4184965ac05SJohn Baldwin errx(1, "failed to fetch register set %d", type);
4194965ac05SJohn Baldwin
4204965ac05SJohn Baldwin note.n_namesz = 8; /* strlen("FreeBSD") + 1 */
4214965ac05SJohn Baldwin note.n_descsz = iov.iov_len;
4224965ac05SJohn Baldwin note.n_type = type;
4234965ac05SJohn Baldwin
4244965ac05SJohn Baldwin sbuf_bcat(sb, ¬e, sizeof(note));
4254965ac05SJohn Baldwin sbuf_start_section(sb, &old_len);
4264965ac05SJohn Baldwin sbuf_bcat(sb, "FreeBSD", note.n_namesz);
4274965ac05SJohn Baldwin sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
4284965ac05SJohn Baldwin sbuf_start_section(sb, &old_len);
4294965ac05SJohn Baldwin sbuf_bcat(sb, iov.iov_base, iov.iov_len);
4304965ac05SJohn Baldwin sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
4314965ac05SJohn Baldwin free(iov.iov_base);
4324965ac05SJohn Baldwin }
4334965ac05SJohn Baldwin
4344965ac05SJohn Baldwin /*
4357fe6d16eSMikolaj Golub * Emit one note section to sbuf.
4367fe6d16eSMikolaj Golub */
4377fe6d16eSMikolaj Golub static void
elf_putnote(int type,notefunc_t notefunc,void * arg,struct sbuf * sb)4387fe6d16eSMikolaj Golub elf_putnote(int type, notefunc_t notefunc, void *arg, struct sbuf *sb)
4397fe6d16eSMikolaj Golub {
4407fe6d16eSMikolaj Golub Elf_Note note;
4417fe6d16eSMikolaj Golub size_t descsz;
4427fe6d16eSMikolaj Golub ssize_t old_len;
4437fe6d16eSMikolaj Golub void *desc;
44452e7cc0aSJohn Polstra
4457fe6d16eSMikolaj Golub desc = notefunc(arg, &descsz);
4467fe6d16eSMikolaj Golub note.n_namesz = 8; /* strlen("FreeBSD") + 1 */
4477fe6d16eSMikolaj Golub note.n_descsz = descsz;
4487fe6d16eSMikolaj Golub note.n_type = type;
4497fe6d16eSMikolaj Golub
4507fe6d16eSMikolaj Golub sbuf_bcat(sb, ¬e, sizeof(note));
4517fe6d16eSMikolaj Golub sbuf_start_section(sb, &old_len);
4527fe6d16eSMikolaj Golub sbuf_bcat(sb, "FreeBSD", note.n_namesz);
4537fe6d16eSMikolaj Golub sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
4547fe6d16eSMikolaj Golub if (descsz == 0)
4557fe6d16eSMikolaj Golub return;
4567fe6d16eSMikolaj Golub sbuf_start_section(sb, &old_len);
4577fe6d16eSMikolaj Golub sbuf_bcat(sb, desc, descsz);
4587fe6d16eSMikolaj Golub sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
4597fe6d16eSMikolaj Golub free(desc);
4607fe6d16eSMikolaj Golub }
4617fe6d16eSMikolaj Golub
4627fe6d16eSMikolaj Golub /*
4637fe6d16eSMikolaj Golub * Generate the ELF coredump header.
4647fe6d16eSMikolaj Golub */
4657fe6d16eSMikolaj Golub static void
elf_puthdr(int efd,pid_t pid,struct map_entry * map,void * hdr,size_t hdrsize,size_t notesz,size_t segoff,int numsegs)466eae3ca5aSMark Johnston elf_puthdr(int efd, pid_t pid, struct map_entry *map, void *hdr, size_t hdrsize,
4677fe6d16eSMikolaj Golub size_t notesz, size_t segoff, int numsegs)
4687fe6d16eSMikolaj Golub {
469885f13dcSJohn Baldwin Elf_Ehdr *ehdr, binhdr;
47052e7cc0aSJohn Polstra Elf_Phdr *phdr;
471bd0371c9SConrad Meyer Elf_Shdr *shdr;
47252e7cc0aSJohn Polstra struct phdr_closure phc;
473885f13dcSJohn Baldwin ssize_t cnt;
474885f13dcSJohn Baldwin
475885f13dcSJohn Baldwin cnt = read(efd, &binhdr, sizeof(binhdr));
476885f13dcSJohn Baldwin if (cnt < 0)
477885f13dcSJohn Baldwin err(1, "Failed to re-read ELF header");
478885f13dcSJohn Baldwin else if (cnt != sizeof(binhdr))
479885f13dcSJohn Baldwin errx(1, "Failed to re-read ELF header");
48052e7cc0aSJohn Polstra
4817fe6d16eSMikolaj Golub ehdr = (Elf_Ehdr *)hdr;
4827fe6d16eSMikolaj Golub
48352e7cc0aSJohn Polstra ehdr->e_ident[EI_MAG0] = ELFMAG0;
48452e7cc0aSJohn Polstra ehdr->e_ident[EI_MAG1] = ELFMAG1;
48552e7cc0aSJohn Polstra ehdr->e_ident[EI_MAG2] = ELFMAG2;
48652e7cc0aSJohn Polstra ehdr->e_ident[EI_MAG3] = ELFMAG3;
48752e7cc0aSJohn Polstra ehdr->e_ident[EI_CLASS] = ELF_CLASS;
48852e7cc0aSJohn Polstra ehdr->e_ident[EI_DATA] = ELF_DATA;
48952e7cc0aSJohn Polstra ehdr->e_ident[EI_VERSION] = EV_CURRENT;
490c815a20cSDavid E. O'Brien ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
491c815a20cSDavid E. O'Brien ehdr->e_ident[EI_ABIVERSION] = 0;
49252e7cc0aSJohn Polstra ehdr->e_ident[EI_PAD] = 0;
49352e7cc0aSJohn Polstra ehdr->e_type = ET_CORE;
494885f13dcSJohn Baldwin ehdr->e_machine = binhdr.e_machine;
49552e7cc0aSJohn Polstra ehdr->e_version = EV_CURRENT;
49652e7cc0aSJohn Polstra ehdr->e_entry = 0;
4977fe6d16eSMikolaj Golub ehdr->e_phoff = sizeof(Elf_Ehdr);
498885f13dcSJohn Baldwin ehdr->e_flags = binhdr.e_flags;
49952e7cc0aSJohn Polstra ehdr->e_ehsize = sizeof(Elf_Ehdr);
50052e7cc0aSJohn Polstra ehdr->e_phentsize = sizeof(Elf_Phdr);
50152e7cc0aSJohn Polstra ehdr->e_shentsize = sizeof(Elf_Shdr);
50252e7cc0aSJohn Polstra ehdr->e_shstrndx = SHN_UNDEF;
503bd0371c9SConrad Meyer if (numsegs + 1 < PN_XNUM) {
504bd0371c9SConrad Meyer ehdr->e_phnum = numsegs + 1;
505bd0371c9SConrad Meyer ehdr->e_shnum = 0;
506bd0371c9SConrad Meyer } else {
507bd0371c9SConrad Meyer ehdr->e_phnum = PN_XNUM;
508bd0371c9SConrad Meyer ehdr->e_shnum = 1;
509bd0371c9SConrad Meyer
510bd0371c9SConrad Meyer ehdr->e_shoff = ehdr->e_phoff +
511bd0371c9SConrad Meyer (numsegs + 1) * ehdr->e_phentsize;
512bd0371c9SConrad Meyer
513bd0371c9SConrad Meyer shdr = (Elf_Shdr *)((char *)hdr + ehdr->e_shoff);
514bd0371c9SConrad Meyer memset(shdr, 0, sizeof(*shdr));
515bd0371c9SConrad Meyer /*
516bd0371c9SConrad Meyer * A special first section is used to hold large segment and
517bd0371c9SConrad Meyer * section counts. This was proposed by Sun Microsystems in
518bd0371c9SConrad Meyer * Solaris and has been adopted by Linux; the standard ELF
519bd0371c9SConrad Meyer * tools are already familiar with the technique.
520bd0371c9SConrad Meyer *
521bd0371c9SConrad Meyer * See table 7-7 of the Solaris "Linker and Libraries Guide"
522bd0371c9SConrad Meyer * (or 12-7 depending on the version of the document) for more
523bd0371c9SConrad Meyer * details.
524bd0371c9SConrad Meyer */
525bd0371c9SConrad Meyer shdr->sh_type = SHT_NULL;
526bd0371c9SConrad Meyer shdr->sh_size = ehdr->e_shnum;
527bd0371c9SConrad Meyer shdr->sh_link = ehdr->e_shstrndx;
528bd0371c9SConrad Meyer shdr->sh_info = numsegs + 1;
529bd0371c9SConrad Meyer }
53052e7cc0aSJohn Polstra
53152e7cc0aSJohn Polstra /*
53252e7cc0aSJohn Polstra * Fill in the program header entries.
53352e7cc0aSJohn Polstra */
534bd0371c9SConrad Meyer phdr = (Elf_Phdr *)((char *)hdr + ehdr->e_phoff);
53552e7cc0aSJohn Polstra
536c8ca80e2SGordon Bergling /* The note segment. */
53752e7cc0aSJohn Polstra phdr->p_type = PT_NOTE;
5387fe6d16eSMikolaj Golub phdr->p_offset = hdrsize;
53952e7cc0aSJohn Polstra phdr->p_vaddr = 0;
54052e7cc0aSJohn Polstra phdr->p_paddr = 0;
54152e7cc0aSJohn Polstra phdr->p_filesz = notesz;
54252e7cc0aSJohn Polstra phdr->p_memsz = 0;
5437fe6d16eSMikolaj Golub phdr->p_flags = PF_R;
5447fe6d16eSMikolaj Golub phdr->p_align = sizeof(Elf32_Size);
54552e7cc0aSJohn Polstra phdr++;
54652e7cc0aSJohn Polstra
54752e7cc0aSJohn Polstra /* All the writable segments from the program. */
54852e7cc0aSJohn Polstra phc.phdr = phdr;
5497fe6d16eSMikolaj Golub phc.offset = segoff;
5508a263d91SConrad Meyer each_dumpable_segment(map, cb_put_phdr, &phc);
55152e7cc0aSJohn Polstra }
55252e7cc0aSJohn Polstra
55352e7cc0aSJohn Polstra /*
55452e7cc0aSJohn Polstra * Free the memory map.
55552e7cc0aSJohn Polstra */
55652e7cc0aSJohn Polstra static void
freemap(struct map_entry * map)557eae3ca5aSMark Johnston freemap(struct map_entry *map)
55852e7cc0aSJohn Polstra {
559eae3ca5aSMark Johnston struct map_entry *next;
560e0491636SPeter Wemm
56152e7cc0aSJohn Polstra while (map != NULL) {
562eae3ca5aSMark Johnston next = map->next;
56352e7cc0aSJohn Polstra free(map);
56452e7cc0aSJohn Polstra map = next;
56552e7cc0aSJohn Polstra }
56652e7cc0aSJohn Polstra }
56752e7cc0aSJohn Polstra
56852e7cc0aSJohn Polstra /*
5692e7ecbfbSAttilio Rao * Read the process's memory map using kinfo_getvmmap(), and return a list of
57052e7cc0aSJohn Polstra * VM map entries. Only the non-device read/writable segments are
57152e7cc0aSJohn Polstra * returned. The map entries in the list aren't fully filled in; only
57252e7cc0aSJohn Polstra * the items we need are present.
57352e7cc0aSJohn Polstra */
574eae3ca5aSMark Johnston static struct map_entry *
readmap(pid_t pid)57552e7cc0aSJohn Polstra readmap(pid_t pid)
57652e7cc0aSJohn Polstra {
577eae3ca5aSMark Johnston struct map_entry *ent, **linkp, *map;
5782e7ecbfbSAttilio Rao struct kinfo_vmentry *vmentl, *kve;
5792e7ecbfbSAttilio Rao int i, nitems;
58052e7cc0aSJohn Polstra
5812e7ecbfbSAttilio Rao vmentl = kinfo_getvmmap(pid, &nitems);
5822e7ecbfbSAttilio Rao if (vmentl == NULL)
5832e7ecbfbSAttilio Rao err(1, "cannot retrieve mappings for %u process", pid);
58452e7cc0aSJohn Polstra
58552e7cc0aSJohn Polstra map = NULL;
58652e7cc0aSJohn Polstra linkp = ↦
5872e7ecbfbSAttilio Rao for (i = 0; i < nitems; i++) {
5882e7ecbfbSAttilio Rao kve = &vmentl[i];
58952e7cc0aSJohn Polstra
5902e7ecbfbSAttilio Rao /*
5911d73ef97SAttilio Rao * Ignore 'malformed' segments or ones representing memory
5921d73ef97SAttilio Rao * mapping with MAP_NOCORE on.
5931d73ef97SAttilio Rao * If the 'full' support is disabled, just dump the most
5941d73ef97SAttilio Rao * meaningful data segments.
5952e7ecbfbSAttilio Rao */
5961d73ef97SAttilio Rao if ((kve->kve_protection & KVME_PROT_READ) == 0 ||
5971d73ef97SAttilio Rao (kve->kve_flags & KVME_FLAG_NOCOREDUMP) != 0 ||
5981d73ef97SAttilio Rao kve->kve_type == KVME_TYPE_DEAD ||
5991d73ef97SAttilio Rao kve->kve_type == KVME_TYPE_UNKNOWN ||
6001d73ef97SAttilio Rao ((pflags & PFLAGS_FULL) == 0 &&
6011d73ef97SAttilio Rao kve->kve_type != KVME_TYPE_DEFAULT &&
6022e7ecbfbSAttilio Rao kve->kve_type != KVME_TYPE_VNODE &&
603bc411bc2SJohn Baldwin kve->kve_type != KVME_TYPE_SWAP &&
604bc411bc2SJohn Baldwin kve->kve_type != KVME_TYPE_PHYS))
60552e7cc0aSJohn Polstra continue;
60652e7cc0aSJohn Polstra
6072e7ecbfbSAttilio Rao ent = calloc(1, sizeof(*ent));
6082e7ecbfbSAttilio Rao if (ent == NULL)
60952e7cc0aSJohn Polstra errx(1, "out of memory");
6102e7ecbfbSAttilio Rao ent->start = (vm_offset_t)kve->kve_start;
6112e7ecbfbSAttilio Rao ent->end = (vm_offset_t)kve->kve_end;
61281c857ddSJohn Baldwin ent->protection = VM_PROT_READ;
61381c857ddSJohn Baldwin if ((kve->kve_protection & KVME_PROT_WRITE) != 0)
61481c857ddSJohn Baldwin ent->protection |= VM_PROT_WRITE;
6152e7ecbfbSAttilio Rao if ((kve->kve_protection & KVME_PROT_EXEC) != 0)
61652e7cc0aSJohn Polstra ent->protection |= VM_PROT_EXECUTE;
61752e7cc0aSJohn Polstra
61852e7cc0aSJohn Polstra *linkp = ent;
61952e7cc0aSJohn Polstra linkp = &ent->next;
62052e7cc0aSJohn Polstra }
6212e7ecbfbSAttilio Rao free(vmentl);
6222e7ecbfbSAttilio Rao return (map);
62352e7cc0aSJohn Polstra }
624e0491636SPeter Wemm
6257fe6d16eSMikolaj Golub /*
6267fe6d16eSMikolaj Golub * Miscellaneous note out functions.
6277fe6d16eSMikolaj Golub */
6287fe6d16eSMikolaj Golub
6297fe6d16eSMikolaj Golub static void *
elf_note_prpsinfo(void * arg,size_t * sizep)6307fe6d16eSMikolaj Golub elf_note_prpsinfo(void *arg, size_t *sizep)
6317fe6d16eSMikolaj Golub {
632c77547d2SJohn Baldwin char *cp, *end;
6337fe6d16eSMikolaj Golub pid_t pid;
63431d743dfSMarcel Moolenaar elfcore_prpsinfo_t *psinfo;
6357fe6d16eSMikolaj Golub struct kinfo_proc kip;
6367fe6d16eSMikolaj Golub size_t len;
6377fe6d16eSMikolaj Golub int name[4];
6387fe6d16eSMikolaj Golub
6397fe6d16eSMikolaj Golub pid = *(pid_t *)arg;
6407fe6d16eSMikolaj Golub psinfo = calloc(1, sizeof(*psinfo));
6417fe6d16eSMikolaj Golub if (psinfo == NULL)
6427fe6d16eSMikolaj Golub errx(1, "out of memory");
6437fe6d16eSMikolaj Golub psinfo->pr_version = PRPSINFO_VERSION;
64431d743dfSMarcel Moolenaar psinfo->pr_psinfosz = sizeof(*psinfo);
6457fe6d16eSMikolaj Golub
6467fe6d16eSMikolaj Golub name[0] = CTL_KERN;
6477fe6d16eSMikolaj Golub name[1] = KERN_PROC;
6487fe6d16eSMikolaj Golub name[2] = KERN_PROC_PID;
6497fe6d16eSMikolaj Golub name[3] = pid;
6507fe6d16eSMikolaj Golub len = sizeof(kip);
6517fe6d16eSMikolaj Golub if (sysctl(name, 4, &kip, &len, NULL, 0) == -1)
6527fe6d16eSMikolaj Golub err(1, "kern.proc.pid.%u", pid);
6537fe6d16eSMikolaj Golub if (kip.ki_pid != pid)
6547fe6d16eSMikolaj Golub err(1, "kern.proc.pid.%u", pid);
6556a4b6353SConrad Meyer strlcpy(psinfo->pr_fname, kip.ki_comm, sizeof(psinfo->pr_fname));
656c77547d2SJohn Baldwin name[2] = KERN_PROC_ARGS;
657c77547d2SJohn Baldwin len = sizeof(psinfo->pr_psargs) - 1;
658c77547d2SJohn Baldwin if (sysctl(name, 4, psinfo->pr_psargs, &len, NULL, 0) == 0 && len > 0) {
659c77547d2SJohn Baldwin cp = psinfo->pr_psargs;
660c77547d2SJohn Baldwin end = cp + len - 1;
661c77547d2SJohn Baldwin for (;;) {
662c77547d2SJohn Baldwin cp = memchr(cp, '\0', end - cp);
663c77547d2SJohn Baldwin if (cp == NULL)
664c77547d2SJohn Baldwin break;
665c77547d2SJohn Baldwin *cp = ' ';
666c77547d2SJohn Baldwin }
667c77547d2SJohn Baldwin } else
668c77547d2SJohn Baldwin strlcpy(psinfo->pr_psargs, kip.ki_comm,
669c77547d2SJohn Baldwin sizeof(psinfo->pr_psargs));
670ccb83afdSJohn Baldwin psinfo->pr_pid = pid;
6717fe6d16eSMikolaj Golub
6727fe6d16eSMikolaj Golub *sizep = sizeof(*psinfo);
6737fe6d16eSMikolaj Golub return (psinfo);
6747fe6d16eSMikolaj Golub }
6757fe6d16eSMikolaj Golub
676180e57e5SJohn Baldwin #if defined(__i386__) || defined(__amd64__)
677180e57e5SJohn Baldwin static void *
elf_note_x86_xstate(void * arg,size_t * sizep)678180e57e5SJohn Baldwin elf_note_x86_xstate(void *arg, size_t *sizep)
679180e57e5SJohn Baldwin {
680180e57e5SJohn Baldwin lwpid_t tid;
681180e57e5SJohn Baldwin char *xstate;
682180e57e5SJohn Baldwin static bool xsave_checked = false;
683180e57e5SJohn Baldwin static struct ptrace_xstate_info info;
684180e57e5SJohn Baldwin
685180e57e5SJohn Baldwin tid = *(lwpid_t *)arg;
686180e57e5SJohn Baldwin if (!xsave_checked) {
687180e57e5SJohn Baldwin if (ptrace(PT_GETXSTATE_INFO, tid, (void *)&info,
688180e57e5SJohn Baldwin sizeof(info)) != 0)
689180e57e5SJohn Baldwin info.xsave_len = 0;
690180e57e5SJohn Baldwin xsave_checked = true;
691180e57e5SJohn Baldwin }
692180e57e5SJohn Baldwin if (info.xsave_len == 0) {
693180e57e5SJohn Baldwin *sizep = 0;
694180e57e5SJohn Baldwin return (NULL);
695180e57e5SJohn Baldwin }
696180e57e5SJohn Baldwin xstate = calloc(1, info.xsave_len);
697180e57e5SJohn Baldwin ptrace(PT_GETXSTATE, tid, xstate, 0);
698180e57e5SJohn Baldwin *(uint64_t *)(xstate + X86_XSTATE_XCR0_OFFSET) = info.xsave_mask;
699180e57e5SJohn Baldwin *sizep = info.xsave_len;
700180e57e5SJohn Baldwin return (xstate);
701180e57e5SJohn Baldwin }
702180e57e5SJohn Baldwin #endif
703180e57e5SJohn Baldwin
704b5d4909eSJustin Hibbits #if defined(__powerpc__)
705b5d4909eSJustin Hibbits static void *
elf_note_powerpc_vmx(void * arg,size_t * sizep)706b5d4909eSJustin Hibbits elf_note_powerpc_vmx(void *arg, size_t *sizep)
707b5d4909eSJustin Hibbits {
708b5d4909eSJustin Hibbits lwpid_t tid;
709b5d4909eSJustin Hibbits struct vmxreg *vmx;
710b5d4909eSJustin Hibbits static bool has_vmx = true;
711b5d4909eSJustin Hibbits struct vmxreg info;
712b5d4909eSJustin Hibbits
713b5d4909eSJustin Hibbits tid = *(lwpid_t *)arg;
714b5d4909eSJustin Hibbits if (has_vmx) {
715b5d4909eSJustin Hibbits if (ptrace(PT_GETVRREGS, tid, (void *)&info,
716b5d4909eSJustin Hibbits sizeof(info)) != 0)
717b5d4909eSJustin Hibbits has_vmx = false;
718b5d4909eSJustin Hibbits }
719b5d4909eSJustin Hibbits if (!has_vmx) {
720b5d4909eSJustin Hibbits *sizep = 0;
721b5d4909eSJustin Hibbits return (NULL);
722b5d4909eSJustin Hibbits }
723b5d4909eSJustin Hibbits vmx = calloc(1, sizeof(*vmx));
724b5d4909eSJustin Hibbits memcpy(vmx, &info, sizeof(*vmx));
725b5d4909eSJustin Hibbits *sizep = sizeof(*vmx);
726b5d4909eSJustin Hibbits return (vmx);
727b5d4909eSJustin Hibbits }
7285167f178SJustin Hibbits
7295167f178SJustin Hibbits static void *
elf_note_powerpc_vsx(void * arg,size_t * sizep)7305167f178SJustin Hibbits elf_note_powerpc_vsx(void *arg, size_t *sizep)
7315167f178SJustin Hibbits {
7325167f178SJustin Hibbits lwpid_t tid;
7335167f178SJustin Hibbits char *vshr_data;
7345167f178SJustin Hibbits static bool has_vsx = true;
7355167f178SJustin Hibbits uint64_t vshr[32];
7365167f178SJustin Hibbits
7375167f178SJustin Hibbits tid = *(lwpid_t *)arg;
7385167f178SJustin Hibbits if (has_vsx) {
7395167f178SJustin Hibbits if (ptrace(PT_GETVSRREGS, tid, (void *)vshr,
7405167f178SJustin Hibbits sizeof(vshr)) != 0)
7415167f178SJustin Hibbits has_vsx = false;
7425167f178SJustin Hibbits }
7435167f178SJustin Hibbits if (!has_vsx) {
7445167f178SJustin Hibbits *sizep = 0;
7455167f178SJustin Hibbits return (NULL);
7465167f178SJustin Hibbits }
7475167f178SJustin Hibbits vshr_data = calloc(1, sizeof(vshr));
7485167f178SJustin Hibbits memcpy(vshr_data, vshr, sizeof(vshr));
7495167f178SJustin Hibbits *sizep = sizeof(vshr);
7505167f178SJustin Hibbits return (vshr_data);
7515167f178SJustin Hibbits }
752b5d4909eSJustin Hibbits #endif
753b5d4909eSJustin Hibbits
7547fe6d16eSMikolaj Golub static void *
procstat_sysctl(void * arg,int what,size_t structsz,size_t * sizep)7557fe6d16eSMikolaj Golub procstat_sysctl(void *arg, int what, size_t structsz, size_t *sizep)
7567fe6d16eSMikolaj Golub {
757798d238fSKevin Lo size_t len;
7587fe6d16eSMikolaj Golub pid_t pid;
7597fe6d16eSMikolaj Golub int name[4], structsize;
7607fe6d16eSMikolaj Golub void *buf, *p;
7617fe6d16eSMikolaj Golub
7627fe6d16eSMikolaj Golub pid = *(pid_t *)arg;
7637fe6d16eSMikolaj Golub structsize = structsz;
7647fe6d16eSMikolaj Golub name[0] = CTL_KERN;
7657fe6d16eSMikolaj Golub name[1] = KERN_PROC;
7667fe6d16eSMikolaj Golub name[2] = what;
7677fe6d16eSMikolaj Golub name[3] = pid;
7687fe6d16eSMikolaj Golub len = 0;
7697fe6d16eSMikolaj Golub if (sysctl(name, 4, NULL, &len, NULL, 0) == -1)
7707fe6d16eSMikolaj Golub err(1, "kern.proc.%d.%u", what, pid);
7717fe6d16eSMikolaj Golub buf = calloc(1, sizeof(structsize) + len * 4 / 3);
7727fe6d16eSMikolaj Golub if (buf == NULL)
7737fe6d16eSMikolaj Golub errx(1, "out of memory");
7747fe6d16eSMikolaj Golub bcopy(&structsize, buf, sizeof(structsize));
7757fe6d16eSMikolaj Golub p = (char *)buf + sizeof(structsize);
7767fe6d16eSMikolaj Golub if (sysctl(name, 4, p, &len, NULL, 0) == -1)
7777fe6d16eSMikolaj Golub err(1, "kern.proc.%d.%u", what, pid);
7787fe6d16eSMikolaj Golub
7797fe6d16eSMikolaj Golub *sizep = sizeof(structsize) + len;
7807fe6d16eSMikolaj Golub return (buf);
7817fe6d16eSMikolaj Golub }
7827fe6d16eSMikolaj Golub
7837fe6d16eSMikolaj Golub static void *
elf_note_procstat_proc(void * arg,size_t * sizep)7847fe6d16eSMikolaj Golub elf_note_procstat_proc(void *arg, size_t *sizep)
7857fe6d16eSMikolaj Golub {
7867fe6d16eSMikolaj Golub
7877fe6d16eSMikolaj Golub return (procstat_sysctl(arg, KERN_PROC_PID | KERN_PROC_INC_THREAD,
7887fe6d16eSMikolaj Golub sizeof(struct kinfo_proc), sizep));
7897fe6d16eSMikolaj Golub }
7907fe6d16eSMikolaj Golub
7917fe6d16eSMikolaj Golub static void *
elf_note_procstat_files(void * arg,size_t * sizep)7927fe6d16eSMikolaj Golub elf_note_procstat_files(void *arg, size_t *sizep)
7937fe6d16eSMikolaj Golub {
7947fe6d16eSMikolaj Golub
7957fe6d16eSMikolaj Golub return (procstat_sysctl(arg, KERN_PROC_FILEDESC,
7967fe6d16eSMikolaj Golub sizeof(struct kinfo_file), sizep));
7977fe6d16eSMikolaj Golub }
7987fe6d16eSMikolaj Golub
7997fe6d16eSMikolaj Golub static void *
elf_note_procstat_vmmap(void * arg,size_t * sizep)8007fe6d16eSMikolaj Golub elf_note_procstat_vmmap(void *arg, size_t *sizep)
8017fe6d16eSMikolaj Golub {
8027fe6d16eSMikolaj Golub
8037fe6d16eSMikolaj Golub return (procstat_sysctl(arg, KERN_PROC_VMMAP,
8047fe6d16eSMikolaj Golub sizeof(struct kinfo_vmentry), sizep));
8057fe6d16eSMikolaj Golub }
8067fe6d16eSMikolaj Golub
8077fe6d16eSMikolaj Golub static void *
elf_note_procstat_groups(void * arg,size_t * sizep)8087fe6d16eSMikolaj Golub elf_note_procstat_groups(void *arg, size_t *sizep)
8097fe6d16eSMikolaj Golub {
8107fe6d16eSMikolaj Golub
811e344fb02SMikolaj Golub return (procstat_sysctl(arg, KERN_PROC_GROUPS, sizeof(gid_t), sizep));
8127fe6d16eSMikolaj Golub }
8137fe6d16eSMikolaj Golub
8147fe6d16eSMikolaj Golub static void *
elf_note_procstat_umask(void * arg,size_t * sizep)8157fe6d16eSMikolaj Golub elf_note_procstat_umask(void *arg, size_t *sizep)
8167fe6d16eSMikolaj Golub {
8177fe6d16eSMikolaj Golub
8187fe6d16eSMikolaj Golub return (procstat_sysctl(arg, KERN_PROC_UMASK, sizeof(u_short), sizep));
8197fe6d16eSMikolaj Golub }
8207fe6d16eSMikolaj Golub
8217fe6d16eSMikolaj Golub static void *
elf_note_procstat_osrel(void * arg,size_t * sizep)8227fe6d16eSMikolaj Golub elf_note_procstat_osrel(void *arg, size_t *sizep)
8237fe6d16eSMikolaj Golub {
8247fe6d16eSMikolaj Golub
8257fe6d16eSMikolaj Golub return (procstat_sysctl(arg, KERN_PROC_OSREL, sizeof(int), sizep));
8267fe6d16eSMikolaj Golub }
8277fe6d16eSMikolaj Golub
8287fe6d16eSMikolaj Golub static void *
elf_note_procstat_psstrings(void * arg,size_t * sizep)8297fe6d16eSMikolaj Golub elf_note_procstat_psstrings(void *arg, size_t *sizep)
8307fe6d16eSMikolaj Golub {
8317fe6d16eSMikolaj Golub
8327fe6d16eSMikolaj Golub return (procstat_sysctl(arg, KERN_PROC_PS_STRINGS,
8337fe6d16eSMikolaj Golub sizeof(vm_offset_t), sizep));
8347fe6d16eSMikolaj Golub }
8357fe6d16eSMikolaj Golub
8367fe6d16eSMikolaj Golub static void *
elf_note_procstat_auxv(void * arg,size_t * sizep)8377fe6d16eSMikolaj Golub elf_note_procstat_auxv(void *arg, size_t *sizep)
8387fe6d16eSMikolaj Golub {
8397fe6d16eSMikolaj Golub
8407fe6d16eSMikolaj Golub return (procstat_sysctl(arg, KERN_PROC_AUXV,
8417fe6d16eSMikolaj Golub sizeof(Elf_Auxinfo), sizep));
8427fe6d16eSMikolaj Golub }
8437fe6d16eSMikolaj Golub
8447fe6d16eSMikolaj Golub static void *
elf_note_procstat_rlimit(void * arg,size_t * sizep)8457fe6d16eSMikolaj Golub elf_note_procstat_rlimit(void *arg, size_t *sizep)
8467fe6d16eSMikolaj Golub {
8477fe6d16eSMikolaj Golub pid_t pid;
8487fe6d16eSMikolaj Golub size_t len;
8497fe6d16eSMikolaj Golub int i, name[5], structsize;
8507fe6d16eSMikolaj Golub void *buf, *p;
8517fe6d16eSMikolaj Golub
8527fe6d16eSMikolaj Golub pid = *(pid_t *)arg;
8537fe6d16eSMikolaj Golub structsize = sizeof(struct rlimit) * RLIM_NLIMITS;
8547fe6d16eSMikolaj Golub buf = calloc(1, sizeof(structsize) + structsize);
8557fe6d16eSMikolaj Golub if (buf == NULL)
8567fe6d16eSMikolaj Golub errx(1, "out of memory");
8577fe6d16eSMikolaj Golub bcopy(&structsize, buf, sizeof(structsize));
8587fe6d16eSMikolaj Golub p = (char *)buf + sizeof(structsize);
8597fe6d16eSMikolaj Golub name[0] = CTL_KERN;
8607fe6d16eSMikolaj Golub name[1] = KERN_PROC;
8617fe6d16eSMikolaj Golub name[2] = KERN_PROC_RLIMIT;
8627fe6d16eSMikolaj Golub name[3] = pid;
8637fe6d16eSMikolaj Golub len = sizeof(struct rlimit);
8647fe6d16eSMikolaj Golub for (i = 0; i < RLIM_NLIMITS; i++) {
8657fe6d16eSMikolaj Golub name[4] = i;
8667fe6d16eSMikolaj Golub if (sysctl(name, 5, p, &len, NULL, 0) == -1)
8677fe6d16eSMikolaj Golub err(1, "kern.proc.rlimit.%u", pid);
8687fe6d16eSMikolaj Golub if (len != sizeof(struct rlimit))
8697fe6d16eSMikolaj Golub errx(1, "kern.proc.rlimit.%u: short read", pid);
8707fe6d16eSMikolaj Golub p += len;
8717fe6d16eSMikolaj Golub }
8727fe6d16eSMikolaj Golub
8737fe6d16eSMikolaj Golub *sizep = sizeof(structsize) + structsize;
8747fe6d16eSMikolaj Golub return (buf);
8757fe6d16eSMikolaj Golub }
8767fe6d16eSMikolaj Golub
87731d743dfSMarcel Moolenaar struct dumpers __elfN(dump) = { elf_ident, elf_coredump };
87831d743dfSMarcel Moolenaar TEXT_SET(dumpset, __elfN(dump));
879