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