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, &notesz);
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, &note, 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 = &map;
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