xref: /freebsd-src/usr.bin/gcore/elfcore.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
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, &notesz);
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, &note, 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, &note, 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 = &map;
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