freebsd-skq/usr.bin/gcore/elfcore.c
jhb 1671ac9155 Improve support for XSAVE with debuggers.
- Dump an NT_X86_XSTATE note if XSAVE is in use. This note is designed
  to match what Linux does in that 1) it dumps the entire XSAVE area
  including the fxsave state, and 2) it stashes a copy of the current
  xsave mask in the unused padding between the fxsave state and the
  xstate header at the same location used by Linux.
- Teach readelf() to recognize NT_X86_XSTATE notes.
- Change PT_GET/SETXSTATE to take the entire XSAVE state instead of
  only the extra portion. This avoids having to always make two
  ptrace() calls to get or set the full XSAVE state.
- Add a PT_GET_XSTATE_INFO which returns the length of the current
  XSTATE save area (so the size of the buffer needed for PT_GETXSTATE)
  and the current XSAVE mask (%xcr0).

Differential Revision:	https://reviews.freebsd.org/D1193
Reviewed by:	kib
MFC after:	2 weeks
2014-11-21 20:53:17 +00:00

778 lines
20 KiB
C

/*-
* Copyright (c) 2007 Sandvine Incorporated
* Copyright (c) 1998 John D. Polstra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/endian.h>
#include <sys/param.h>
#include <sys/procfs.h>
#include <sys/ptrace.h>
#include <sys/queue.h>
#include <sys/linker_set.h>
#include <sys/sbuf.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <machine/elf.h>
#include <vm/vm_param.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libutil.h>
#include "extern.h"
/*
* Code for generating ELF core dumps.
*/
typedef void (*segment_callback)(vm_map_entry_t, void *);
/* Closure for cb_put_phdr(). */
struct phdr_closure {
Elf_Phdr *phdr; /* Program header to fill in */
Elf_Off offset; /* Offset of segment in core file */
};
/* Closure for cb_size_segment(). */
struct sseg_closure {
int count; /* Count of writable segments. */
size_t size; /* Total size of all writable segments. */
};
#ifdef ELFCORE_COMPAT_32
typedef struct fpreg32 elfcore_fpregset_t;
typedef struct reg32 elfcore_gregset_t;
typedef struct prpsinfo32 elfcore_prpsinfo_t;
typedef struct prstatus32 elfcore_prstatus_t;
static void elf_convert_gregset(elfcore_gregset_t *rd, struct reg *rs);
static void elf_convert_fpregset(elfcore_fpregset_t *rd, struct fpreg *rs);
#else
typedef fpregset_t elfcore_fpregset_t;
typedef gregset_t elfcore_gregset_t;
typedef prpsinfo_t elfcore_prpsinfo_t;
typedef prstatus_t elfcore_prstatus_t;
#define elf_convert_gregset(d,s) *d = *s
#define elf_convert_fpregset(d,s) *d = *s
#endif
typedef void* (*notefunc_t)(void *, size_t *);
static void cb_put_phdr(vm_map_entry_t, void *);
static void cb_size_segment(vm_map_entry_t, void *);
static void each_writable_segment(vm_map_entry_t, segment_callback,
void *closure);
static void elf_detach(void); /* atexit() handler. */
static void *elf_note_fpregset(void *, size_t *);
static void *elf_note_prpsinfo(void *, size_t *);
static void *elf_note_prstatus(void *, size_t *);
static void *elf_note_thrmisc(void *, size_t *);
#if defined(__i386__) || defined(__amd64__)
static void *elf_note_x86_xstate(void *, size_t *);
#endif
static void *elf_note_procstat_auxv(void *, size_t *);
static void *elf_note_procstat_files(void *, size_t *);
static void *elf_note_procstat_groups(void *, size_t *);
static void *elf_note_procstat_osrel(void *, size_t *);
static void *elf_note_procstat_proc(void *, size_t *);
static void *elf_note_procstat_psstrings(void *, size_t *);
static void *elf_note_procstat_rlimit(void *, size_t *);
static void *elf_note_procstat_umask(void *, size_t *);
static void *elf_note_procstat_vmmap(void *, size_t *);
static void elf_puthdr(pid_t, vm_map_entry_t, void *, size_t, size_t, size_t,
int);
static void elf_putnote(int, notefunc_t, void *, struct sbuf *);
static void elf_putnotes(pid_t, struct sbuf *, size_t *);
static void freemap(vm_map_entry_t);
static vm_map_entry_t readmap(pid_t);
static void *procstat_sysctl(void *, int, size_t, size_t *sizep);
static pid_t g_pid; /* Pid being dumped, global for elf_detach */
static int
elf_ident(int efd, pid_t pid __unused, char *binfile __unused)
{
Elf_Ehdr hdr;
int cnt;
uint16_t machine;
cnt = read(efd, &hdr, sizeof(hdr));
if (cnt != sizeof(hdr))
return (0);
if (!IS_ELF(hdr))
return (0);
switch (hdr.e_ident[EI_DATA]) {
case ELFDATA2LSB:
machine = le16toh(hdr.e_machine);
break;
case ELFDATA2MSB:
machine = be16toh(hdr.e_machine);
break;
default:
return (0);
}
if (!ELF_MACHINE_OK(machine))
return (0);
/* Looks good. */
return (1);
}
static void
elf_detach(void)
{
if (g_pid != 0)
ptrace(PT_DETACH, g_pid, (caddr_t)1, 0);
}
/*
* Write an ELF coredump for the given pid to the given fd.
*/
static void
elf_coredump(int efd __unused, int fd, pid_t pid)
{
vm_map_entry_t map;
struct sseg_closure seginfo;
struct sbuf *sb;
void *hdr;
size_t hdrsize, notesz, segoff;
ssize_t n, old_len;
Elf_Phdr *php;
int i;
/* Attach to process to dump. */
g_pid = pid;
if (atexit(elf_detach) != 0)
err(1, "atexit");
errno = 0;
ptrace(PT_ATTACH, pid, NULL, 0);
if (errno)
err(1, "PT_ATTACH");
if (waitpid(pid, NULL, 0) == -1)
err(1, "waitpid");
/* Get the program's memory map. */
map = readmap(pid);
/* Size the program segments. */
seginfo.count = 0;
seginfo.size = 0;
each_writable_segment(map, cb_size_segment, &seginfo);
/*
* Build the header and the notes using sbuf and write to the file.
*/
sb = sbuf_new_auto();
hdrsize = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * (1 + seginfo.count);
/* Start header + notes section. */
sbuf_start_section(sb, NULL);
/* Make empty header subsection. */
sbuf_start_section(sb, &old_len);
sbuf_putc(sb, 0);
sbuf_end_section(sb, old_len, hdrsize, 0);
/* Put notes. */
elf_putnotes(pid, sb, &notesz);
/* Align up to a page boundary for the program segments. */
sbuf_end_section(sb, -1, PAGE_SIZE, 0);
if (sbuf_finish(sb) != 0)
err(1, "sbuf_finish");
hdr = sbuf_data(sb);
segoff = sbuf_len(sb);
/* Fill in the header. */
elf_puthdr(pid, map, hdr, hdrsize, notesz, segoff, seginfo.count);
n = write(fd, hdr, segoff);
if (n == -1)
err(1, "write");
if (n < segoff)
errx(1, "short write");
/* Write the contents of all of the writable segments. */
php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1;
for (i = 0; i < seginfo.count; i++) {
struct ptrace_io_desc iorequest;
uintmax_t nleft = php->p_filesz;
iorequest.piod_op = PIOD_READ_D;
iorequest.piod_offs = (caddr_t)(uintptr_t)php->p_vaddr;
while (nleft > 0) {
char buf[8*1024];
size_t nwant;
ssize_t ngot;
if (nleft > sizeof(buf))
nwant = sizeof buf;
else
nwant = nleft;
iorequest.piod_addr = buf;
iorequest.piod_len = nwant;
ptrace(PT_IO, pid, (caddr_t)&iorequest, 0);
ngot = iorequest.piod_len;
if ((size_t)ngot < nwant)
errx(1, "short read wanted %zu, got %zd",
nwant, ngot);
ngot = write(fd, buf, nwant);
if (ngot == -1)
err(1, "write of segment %d failed", i);
if ((size_t)ngot != nwant)
errx(1, "short write");
nleft -= nwant;
iorequest.piod_offs += ngot;
}
php++;
}
sbuf_delete(sb);
freemap(map);
}
/*
* A callback for each_writable_segment() to write out the segment's
* program header entry.
*/
static void
cb_put_phdr(vm_map_entry_t entry, void *closure)
{
struct phdr_closure *phc = (struct phdr_closure *)closure;
Elf_Phdr *phdr = phc->phdr;
phc->offset = round_page(phc->offset);
phdr->p_type = PT_LOAD;
phdr->p_offset = phc->offset;
phdr->p_vaddr = entry->start;
phdr->p_paddr = 0;
phdr->p_filesz = phdr->p_memsz = entry->end - entry->start;
phdr->p_align = PAGE_SIZE;
phdr->p_flags = 0;
if (entry->protection & VM_PROT_READ)
phdr->p_flags |= PF_R;
if (entry->protection & VM_PROT_WRITE)
phdr->p_flags |= PF_W;
if (entry->protection & VM_PROT_EXECUTE)
phdr->p_flags |= PF_X;
phc->offset += phdr->p_filesz;
phc->phdr++;
}
/*
* A callback for each_writable_segment() to gather information about
* the number of segments and their total size.
*/
static void
cb_size_segment(vm_map_entry_t entry, void *closure)
{
struct sseg_closure *ssc = (struct sseg_closure *)closure;
ssc->count++;
ssc->size += entry->end - entry->start;
}
/*
* For each segment in the given memory map, call the given function
* with a pointer to the map entry and some arbitrary caller-supplied
* data.
*/
static void
each_writable_segment(vm_map_entry_t map, segment_callback func, void *closure)
{
vm_map_entry_t entry;
for (entry = map; entry != NULL; entry = entry->next)
(*func)(entry, closure);
}
static void
elf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep)
{
lwpid_t *tids;
size_t threads, old_len;
ssize_t size;
int i;
errno = 0;
threads = ptrace(PT_GETNUMLWPS, pid, NULL, 0);
if (errno)
err(1, "PT_GETNUMLWPS");
tids = malloc(threads * sizeof(*tids));
if (tids == NULL)
errx(1, "out of memory");
errno = 0;
ptrace(PT_GETLWPLIST, pid, (void *)tids, threads);
if (errno)
err(1, "PT_GETLWPLIST");
sbuf_start_section(sb, &old_len);
elf_putnote(NT_PRPSINFO, elf_note_prpsinfo, &pid, sb);
for (i = 0; i < threads; ++i) {
elf_putnote(NT_PRSTATUS, elf_note_prstatus, tids + i, sb);
elf_putnote(NT_FPREGSET, elf_note_fpregset, tids + i, sb);
elf_putnote(NT_THRMISC, elf_note_thrmisc, tids + i, sb);
#if defined(__i386__) || defined(__amd64__)
elf_putnote(NT_X86_XSTATE, elf_note_x86_xstate, tids + i, sb);
#endif
}
#ifndef ELFCORE_COMPAT_32
elf_putnote(NT_PROCSTAT_PROC, elf_note_procstat_proc, &pid, sb);
elf_putnote(NT_PROCSTAT_FILES, elf_note_procstat_files, &pid, sb);
elf_putnote(NT_PROCSTAT_VMMAP, elf_note_procstat_vmmap, &pid, sb);
elf_putnote(NT_PROCSTAT_GROUPS, elf_note_procstat_groups, &pid, sb);
elf_putnote(NT_PROCSTAT_UMASK, elf_note_procstat_umask, &pid, sb);
elf_putnote(NT_PROCSTAT_RLIMIT, elf_note_procstat_rlimit, &pid, sb);
elf_putnote(NT_PROCSTAT_OSREL, elf_note_procstat_osrel, &pid, sb);
elf_putnote(NT_PROCSTAT_PSSTRINGS, elf_note_procstat_psstrings, &pid,
sb);
elf_putnote(NT_PROCSTAT_AUXV, elf_note_procstat_auxv, &pid, sb);
#endif
size = sbuf_end_section(sb, old_len, 1, 0);
if (size == -1)
err(1, "sbuf_end_section");
free(tids);
*sizep = size;
}
/*
* Emit one note section to sbuf.
*/
static void
elf_putnote(int type, notefunc_t notefunc, void *arg, struct sbuf *sb)
{
Elf_Note note;
size_t descsz;
ssize_t old_len;
void *desc;
desc = notefunc(arg, &descsz);
note.n_namesz = 8; /* strlen("FreeBSD") + 1 */
note.n_descsz = descsz;
note.n_type = type;
sbuf_bcat(sb, &note, sizeof(note));
sbuf_start_section(sb, &old_len);
sbuf_bcat(sb, "FreeBSD", note.n_namesz);
sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
if (descsz == 0)
return;
sbuf_start_section(sb, &old_len);
sbuf_bcat(sb, desc, descsz);
sbuf_end_section(sb, old_len, sizeof(Elf32_Size), 0);
free(desc);
}
/*
* Generate the ELF coredump header.
*/
static void
elf_puthdr(pid_t pid, vm_map_entry_t map, void *hdr, size_t hdrsize,
size_t notesz, size_t segoff, int numsegs)
{
Elf_Ehdr *ehdr;
Elf_Phdr *phdr;
struct phdr_closure phc;
ehdr = (Elf_Ehdr *)hdr;
phdr = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr));
ehdr->e_ident[EI_MAG0] = ELFMAG0;
ehdr->e_ident[EI_MAG1] = ELFMAG1;
ehdr->e_ident[EI_MAG2] = ELFMAG2;
ehdr->e_ident[EI_MAG3] = ELFMAG3;
ehdr->e_ident[EI_CLASS] = ELF_CLASS;
ehdr->e_ident[EI_DATA] = ELF_DATA;
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
ehdr->e_ident[EI_ABIVERSION] = 0;
ehdr->e_ident[EI_PAD] = 0;
ehdr->e_type = ET_CORE;
ehdr->e_machine = ELF_ARCH;
ehdr->e_version = EV_CURRENT;
ehdr->e_entry = 0;
ehdr->e_phoff = sizeof(Elf_Ehdr);
ehdr->e_flags = 0;
ehdr->e_ehsize = sizeof(Elf_Ehdr);
ehdr->e_phentsize = sizeof(Elf_Phdr);
ehdr->e_phnum = numsegs + 1;
ehdr->e_shentsize = sizeof(Elf_Shdr);
ehdr->e_shnum = 0;
ehdr->e_shstrndx = SHN_UNDEF;
/*
* Fill in the program header entries.
*/
/* The note segement. */
phdr->p_type = PT_NOTE;
phdr->p_offset = hdrsize;
phdr->p_vaddr = 0;
phdr->p_paddr = 0;
phdr->p_filesz = notesz;
phdr->p_memsz = 0;
phdr->p_flags = PF_R;
phdr->p_align = sizeof(Elf32_Size);
phdr++;
/* All the writable segments from the program. */
phc.phdr = phdr;
phc.offset = segoff;
each_writable_segment(map, cb_put_phdr, &phc);
}
/*
* Free the memory map.
*/
static void
freemap(vm_map_entry_t map)
{
while (map != NULL) {
vm_map_entry_t next = map->next;
free(map);
map = next;
}
}
/*
* Read the process's memory map using kinfo_getvmmap(), and return a list of
* VM map entries. Only the non-device read/writable segments are
* returned. The map entries in the list aren't fully filled in; only
* the items we need are present.
*/
static vm_map_entry_t
readmap(pid_t pid)
{
vm_map_entry_t ent, *linkp, map;
struct kinfo_vmentry *vmentl, *kve;
int i, nitems;
vmentl = kinfo_getvmmap(pid, &nitems);
if (vmentl == NULL)
err(1, "cannot retrieve mappings for %u process", pid);
map = NULL;
linkp = &map;
for (i = 0; i < nitems; i++) {
kve = &vmentl[i];
/*
* Ignore 'malformed' segments or ones representing memory
* mapping with MAP_NOCORE on.
* If the 'full' support is disabled, just dump the most
* meaningful data segments.
*/
if ((kve->kve_protection & KVME_PROT_READ) == 0 ||
(kve->kve_flags & KVME_FLAG_NOCOREDUMP) != 0 ||
kve->kve_type == KVME_TYPE_DEAD ||
kve->kve_type == KVME_TYPE_UNKNOWN ||
((pflags & PFLAGS_FULL) == 0 &&
kve->kve_type != KVME_TYPE_DEFAULT &&
kve->kve_type != KVME_TYPE_VNODE &&
kve->kve_type != KVME_TYPE_SWAP))
continue;
ent = calloc(1, sizeof(*ent));
if (ent == NULL)
errx(1, "out of memory");
ent->start = (vm_offset_t)kve->kve_start;
ent->end = (vm_offset_t)kve->kve_end;
ent->protection = VM_PROT_READ | VM_PROT_WRITE;
if ((kve->kve_protection & KVME_PROT_EXEC) != 0)
ent->protection |= VM_PROT_EXECUTE;
*linkp = ent;
linkp = &ent->next;
}
free(vmentl);
return (map);
}
/*
* Miscellaneous note out functions.
*/
static void *
elf_note_prpsinfo(void *arg, size_t *sizep)
{
pid_t pid;
elfcore_prpsinfo_t *psinfo;
struct kinfo_proc kip;
size_t len;
int name[4];
pid = *(pid_t *)arg;
psinfo = calloc(1, sizeof(*psinfo));
if (psinfo == NULL)
errx(1, "out of memory");
psinfo->pr_version = PRPSINFO_VERSION;
psinfo->pr_psinfosz = sizeof(*psinfo);
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_PID;
name[3] = pid;
len = sizeof(kip);
if (sysctl(name, 4, &kip, &len, NULL, 0) == -1)
err(1, "kern.proc.pid.%u", pid);
if (kip.ki_pid != pid)
err(1, "kern.proc.pid.%u", pid);
strncpy(psinfo->pr_fname, kip.ki_comm, MAXCOMLEN);
strncpy(psinfo->pr_psargs, psinfo->pr_fname, PRARGSZ);
*sizep = sizeof(*psinfo);
return (psinfo);
}
static void *
elf_note_prstatus(void *arg, size_t *sizep)
{
lwpid_t tid;
elfcore_prstatus_t *status;
struct reg greg;
tid = *(lwpid_t *)arg;
status = calloc(1, sizeof(*status));
if (status == NULL)
errx(1, "out of memory");
status->pr_version = PRSTATUS_VERSION;
status->pr_statussz = sizeof(*status);
status->pr_gregsetsz = sizeof(elfcore_gregset_t);
status->pr_fpregsetsz = sizeof(elfcore_fpregset_t);
status->pr_osreldate = __FreeBSD_version;
status->pr_pid = tid;
ptrace(PT_GETREGS, tid, (void *)&greg, 0);
elf_convert_gregset(&status->pr_reg, &greg);
*sizep = sizeof(*status);
return (status);
}
static void *
elf_note_fpregset(void *arg, size_t *sizep)
{
lwpid_t tid;
elfcore_fpregset_t *fpregset;
fpregset_t fpreg;
tid = *(lwpid_t *)arg;
fpregset = calloc(1, sizeof(*fpregset));
if (fpregset == NULL)
errx(1, "out of memory");
ptrace(PT_GETFPREGS, tid, (void *)&fpreg, 0);
elf_convert_fpregset(fpregset, &fpreg);
*sizep = sizeof(*fpregset);
return (fpregset);
}
static void *
elf_note_thrmisc(void *arg, size_t *sizep)
{
lwpid_t tid;
struct ptrace_lwpinfo lwpinfo;
thrmisc_t *thrmisc;
tid = *(lwpid_t *)arg;
thrmisc = calloc(1, sizeof(*thrmisc));
if (thrmisc == NULL)
errx(1, "out of memory");
ptrace(PT_LWPINFO, tid, (void *)&lwpinfo,
sizeof(lwpinfo));
memset(&thrmisc->_pad, 0, sizeof(thrmisc->_pad));
strcpy(thrmisc->pr_tname, lwpinfo.pl_tdname);
*sizep = sizeof(*thrmisc);
return (thrmisc);
}
#if defined(__i386__) || defined(__amd64__)
static void *
elf_note_x86_xstate(void *arg, size_t *sizep)
{
lwpid_t tid;
char *xstate;
static bool xsave_checked = false;
static struct ptrace_xstate_info info;
tid = *(lwpid_t *)arg;
if (!xsave_checked) {
if (ptrace(PT_GETXSTATE_INFO, tid, (void *)&info,
sizeof(info)) != 0)
info.xsave_len = 0;
xsave_checked = true;
}
if (info.xsave_len == 0) {
*sizep = 0;
return (NULL);
}
xstate = calloc(1, info.xsave_len);
ptrace(PT_GETXSTATE, tid, xstate, 0);
*(uint64_t *)(xstate + X86_XSTATE_XCR0_OFFSET) = info.xsave_mask;
*sizep = info.xsave_len;
return (xstate);
}
#endif
static void *
procstat_sysctl(void *arg, int what, size_t structsz, size_t *sizep)
{
size_t len;
pid_t pid;
int name[4], structsize;
void *buf, *p;
pid = *(pid_t *)arg;
structsize = structsz;
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = what;
name[3] = pid;
len = 0;
if (sysctl(name, 4, NULL, &len, NULL, 0) == -1)
err(1, "kern.proc.%d.%u", what, pid);
buf = calloc(1, sizeof(structsize) + len * 4 / 3);
if (buf == NULL)
errx(1, "out of memory");
bcopy(&structsize, buf, sizeof(structsize));
p = (char *)buf + sizeof(structsize);
if (sysctl(name, 4, p, &len, NULL, 0) == -1)
err(1, "kern.proc.%d.%u", what, pid);
*sizep = sizeof(structsize) + len;
return (buf);
}
static void *
elf_note_procstat_proc(void *arg, size_t *sizep)
{
return (procstat_sysctl(arg, KERN_PROC_PID | KERN_PROC_INC_THREAD,
sizeof(struct kinfo_proc), sizep));
}
static void *
elf_note_procstat_files(void *arg, size_t *sizep)
{
return (procstat_sysctl(arg, KERN_PROC_FILEDESC,
sizeof(struct kinfo_file), sizep));
}
static void *
elf_note_procstat_vmmap(void *arg, size_t *sizep)
{
return (procstat_sysctl(arg, KERN_PROC_VMMAP,
sizeof(struct kinfo_vmentry), sizep));
}
static void *
elf_note_procstat_groups(void *arg, size_t *sizep)
{
return (procstat_sysctl(arg, KERN_PROC_GROUPS, sizeof(gid_t), sizep));
}
static void *
elf_note_procstat_umask(void *arg, size_t *sizep)
{
return (procstat_sysctl(arg, KERN_PROC_UMASK, sizeof(u_short), sizep));
}
static void *
elf_note_procstat_osrel(void *arg, size_t *sizep)
{
return (procstat_sysctl(arg, KERN_PROC_OSREL, sizeof(int), sizep));
}
static void *
elf_note_procstat_psstrings(void *arg, size_t *sizep)
{
return (procstat_sysctl(arg, KERN_PROC_PS_STRINGS,
sizeof(vm_offset_t), sizep));
}
static void *
elf_note_procstat_auxv(void *arg, size_t *sizep)
{
return (procstat_sysctl(arg, KERN_PROC_AUXV,
sizeof(Elf_Auxinfo), sizep));
}
static void *
elf_note_procstat_rlimit(void *arg, size_t *sizep)
{
pid_t pid;
size_t len;
int i, name[5], structsize;
void *buf, *p;
pid = *(pid_t *)arg;
structsize = sizeof(struct rlimit) * RLIM_NLIMITS;
buf = calloc(1, sizeof(structsize) + structsize);
if (buf == NULL)
errx(1, "out of memory");
bcopy(&structsize, buf, sizeof(structsize));
p = (char *)buf + sizeof(structsize);
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_RLIMIT;
name[3] = pid;
len = sizeof(struct rlimit);
for (i = 0; i < RLIM_NLIMITS; i++) {
name[4] = i;
if (sysctl(name, 5, p, &len, NULL, 0) == -1)
err(1, "kern.proc.rlimit.%u", pid);
if (len != sizeof(struct rlimit))
errx(1, "kern.proc.rlimit.%u: short read", pid);
p += len;
}
*sizep = sizeof(structsize) + structsize;
return (buf);
}
struct dumpers __elfN(dump) = { elf_ident, elf_coredump };
TEXT_SET(dumpset, __elfN(dump));