17153ad2bSMikolaj Golub /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni *
47153ad2bSMikolaj Golub * Copyright (c) 2013 Mikolaj Golub <trociny@FreeBSD.org>
586be94fcSTycho Nightingale * Copyright (c) 2017 Dell EMC
67153ad2bSMikolaj Golub * All rights reserved.
77153ad2bSMikolaj Golub *
87153ad2bSMikolaj Golub * Redistribution and use in source and binary forms, with or without
97153ad2bSMikolaj Golub * modification, are permitted provided that the following conditions
107153ad2bSMikolaj Golub * are met:
117153ad2bSMikolaj Golub * 1. Redistributions of source code must retain the above copyright
127153ad2bSMikolaj Golub * notice, this list of conditions and the following disclaimer.
137153ad2bSMikolaj Golub * 2. Redistributions in binary form must reproduce the above copyright
147153ad2bSMikolaj Golub * notice, this list of conditions and the following disclaimer in the
157153ad2bSMikolaj Golub * documentation and/or other materials provided with the distribution.
167153ad2bSMikolaj Golub *
177153ad2bSMikolaj Golub * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
187153ad2bSMikolaj Golub * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
197153ad2bSMikolaj Golub * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
207153ad2bSMikolaj Golub * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
217153ad2bSMikolaj Golub * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
227153ad2bSMikolaj Golub * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
237153ad2bSMikolaj Golub * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
247153ad2bSMikolaj Golub * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
257153ad2bSMikolaj Golub * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
267153ad2bSMikolaj Golub * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
277153ad2bSMikolaj Golub * SUCH DAMAGE.
287153ad2bSMikolaj Golub */
297153ad2bSMikolaj Golub
307153ad2bSMikolaj Golub #include <sys/param.h>
317153ad2bSMikolaj Golub #include <sys/elf.h>
324482b5e3SMikolaj Golub #include <sys/exec.h>
3386be94fcSTycho Nightingale #include <sys/ptrace.h>
347153ad2bSMikolaj Golub #include <sys/user.h>
357153ad2bSMikolaj Golub
367153ad2bSMikolaj Golub #include <assert.h>
377153ad2bSMikolaj Golub #include <err.h>
387153ad2bSMikolaj Golub #include <fcntl.h>
397153ad2bSMikolaj Golub #include <gelf.h>
407153ad2bSMikolaj Golub #include <libelf.h>
417153ad2bSMikolaj Golub #include <stdbool.h>
427153ad2bSMikolaj Golub #include <stdint.h>
437153ad2bSMikolaj Golub #include <stdio.h>
447153ad2bSMikolaj Golub #include <stdlib.h>
457153ad2bSMikolaj Golub #include <string.h>
467153ad2bSMikolaj Golub #include <unistd.h>
477153ad2bSMikolaj Golub
487153ad2bSMikolaj Golub #include "core.h"
497153ad2bSMikolaj Golub
507153ad2bSMikolaj Golub #define PROCSTAT_CORE_MAGIC 0x012DADB8
517153ad2bSMikolaj Golub struct procstat_core
527153ad2bSMikolaj Golub {
537153ad2bSMikolaj Golub int pc_magic;
547153ad2bSMikolaj Golub int pc_fd;
557153ad2bSMikolaj Golub Elf *pc_elf;
567153ad2bSMikolaj Golub GElf_Ehdr pc_ehdr;
577153ad2bSMikolaj Golub GElf_Phdr pc_phdr;
587153ad2bSMikolaj Golub };
597153ad2bSMikolaj Golub
6086be94fcSTycho Nightingale static struct psc_type_info {
6186be94fcSTycho Nightingale unsigned int n_type;
6286be94fcSTycho Nightingale int structsize;
6386be94fcSTycho Nightingale } psc_type_info[PSC_TYPE_MAX] = {
6486be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_PROC, .structsize = sizeof(struct kinfo_proc) },
6586be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_FILES, .structsize = sizeof(struct kinfo_file) },
6686be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_VMMAP, .structsize = sizeof(struct kinfo_vmentry) },
6786be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_GROUPS, .structsize = sizeof(gid_t) },
6886be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_UMASK, .structsize = sizeof(u_short) },
6986be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_RLIMIT, .structsize = sizeof(struct rlimit) * RLIM_NLIMITS },
7086be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_OSREL, .structsize = sizeof(int) },
7186be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) },
7286be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) },
7386be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) },
7486be94fcSTycho Nightingale { .n_type = NT_PROCSTAT_AUXV, .structsize = sizeof(Elf_Auxinfo) },
7586be94fcSTycho Nightingale { .n_type = NT_PTLWPINFO, .structsize = sizeof(struct ptrace_lwpinfo) },
7686be94fcSTycho Nightingale };
7786be94fcSTycho Nightingale
787153ad2bSMikolaj Golub static bool core_offset(struct procstat_core *core, off_t offset);
797153ad2bSMikolaj Golub static bool core_read(struct procstat_core *core, void *buf, size_t len);
804482b5e3SMikolaj Golub static ssize_t core_read_mem(struct procstat_core *core, void *buf,
814482b5e3SMikolaj Golub size_t len, vm_offset_t addr, bool readall);
824482b5e3SMikolaj Golub static void *get_args(struct procstat_core *core, vm_offset_t psstrings,
834482b5e3SMikolaj Golub enum psc_type type, void *buf, size_t *lenp);
847153ad2bSMikolaj Golub
857153ad2bSMikolaj Golub struct procstat_core *
procstat_core_open(const char * filename)867153ad2bSMikolaj Golub procstat_core_open(const char *filename)
877153ad2bSMikolaj Golub {
887153ad2bSMikolaj Golub struct procstat_core *core;
897153ad2bSMikolaj Golub Elf *e;
907153ad2bSMikolaj Golub GElf_Ehdr ehdr;
917153ad2bSMikolaj Golub GElf_Phdr phdr;
927153ad2bSMikolaj Golub size_t nph;
937153ad2bSMikolaj Golub int fd, i;
947153ad2bSMikolaj Golub
957153ad2bSMikolaj Golub if (elf_version(EV_CURRENT) == EV_NONE) {
967153ad2bSMikolaj Golub warnx("ELF library too old");
977153ad2bSMikolaj Golub return (NULL);
987153ad2bSMikolaj Golub }
997153ad2bSMikolaj Golub fd = open(filename, O_RDONLY, 0);
1007153ad2bSMikolaj Golub if (fd == -1) {
1017153ad2bSMikolaj Golub warn("open(%s)", filename);
1027153ad2bSMikolaj Golub return (NULL);
1037153ad2bSMikolaj Golub }
1047153ad2bSMikolaj Golub e = elf_begin(fd, ELF_C_READ, NULL);
1057153ad2bSMikolaj Golub if (e == NULL) {
1067153ad2bSMikolaj Golub warnx("elf_begin: %s", elf_errmsg(-1));
1077153ad2bSMikolaj Golub goto fail;
1087153ad2bSMikolaj Golub }
1097153ad2bSMikolaj Golub if (elf_kind(e) != ELF_K_ELF) {
1107153ad2bSMikolaj Golub warnx("%s is not an ELF object", filename);
1117153ad2bSMikolaj Golub goto fail;
1127153ad2bSMikolaj Golub }
1137153ad2bSMikolaj Golub if (gelf_getehdr(e, &ehdr) == NULL) {
1147153ad2bSMikolaj Golub warnx("gelf_getehdr: %s", elf_errmsg(-1));
1157153ad2bSMikolaj Golub goto fail;
1167153ad2bSMikolaj Golub }
1177153ad2bSMikolaj Golub if (ehdr.e_type != ET_CORE) {
1187153ad2bSMikolaj Golub warnx("%s is not a CORE file", filename);
1197153ad2bSMikolaj Golub goto fail;
1207153ad2bSMikolaj Golub }
121*633094c2SJohn Hein if (elf_getphdrnum(e, &nph) == -1) {
1227153ad2bSMikolaj Golub warnx("program headers not found");
1237153ad2bSMikolaj Golub goto fail;
1247153ad2bSMikolaj Golub }
1257153ad2bSMikolaj Golub for (i = 0; i < ehdr.e_phnum; i++) {
1267153ad2bSMikolaj Golub if (gelf_getphdr(e, i, &phdr) != &phdr) {
1277153ad2bSMikolaj Golub warnx("gelf_getphdr: %s", elf_errmsg(-1));
1287153ad2bSMikolaj Golub goto fail;
1297153ad2bSMikolaj Golub }
1307153ad2bSMikolaj Golub if (phdr.p_type == PT_NOTE)
1317153ad2bSMikolaj Golub break;
1327153ad2bSMikolaj Golub }
1337153ad2bSMikolaj Golub if (i == ehdr.e_phnum) {
1347153ad2bSMikolaj Golub warnx("NOTE program header not found");
1357153ad2bSMikolaj Golub goto fail;
1367153ad2bSMikolaj Golub }
1377153ad2bSMikolaj Golub core = malloc(sizeof(struct procstat_core));
1387153ad2bSMikolaj Golub if (core == NULL) {
1397153ad2bSMikolaj Golub warn("malloc(%zu)", sizeof(struct procstat_core));
1407153ad2bSMikolaj Golub goto fail;
1417153ad2bSMikolaj Golub }
1427153ad2bSMikolaj Golub core->pc_magic = PROCSTAT_CORE_MAGIC;
1437153ad2bSMikolaj Golub core->pc_fd = fd;
1447153ad2bSMikolaj Golub core->pc_elf = e;
1457153ad2bSMikolaj Golub core->pc_ehdr = ehdr;
1467153ad2bSMikolaj Golub core->pc_phdr = phdr;
1477153ad2bSMikolaj Golub
1487153ad2bSMikolaj Golub return (core);
1497153ad2bSMikolaj Golub fail:
1507153ad2bSMikolaj Golub if (e != NULL)
1517153ad2bSMikolaj Golub elf_end(e);
1527153ad2bSMikolaj Golub close(fd);
1537153ad2bSMikolaj Golub
1547153ad2bSMikolaj Golub return (NULL);
1557153ad2bSMikolaj Golub }
1567153ad2bSMikolaj Golub
1577153ad2bSMikolaj Golub void
procstat_core_close(struct procstat_core * core)1587153ad2bSMikolaj Golub procstat_core_close(struct procstat_core *core)
1597153ad2bSMikolaj Golub {
1607153ad2bSMikolaj Golub
1617153ad2bSMikolaj Golub assert(core->pc_magic == PROCSTAT_CORE_MAGIC);
1627153ad2bSMikolaj Golub
1637153ad2bSMikolaj Golub elf_end(core->pc_elf);
1647153ad2bSMikolaj Golub close(core->pc_fd);
1657153ad2bSMikolaj Golub free(core);
1667153ad2bSMikolaj Golub }
1677153ad2bSMikolaj Golub
1687153ad2bSMikolaj Golub void *
procstat_core_get(struct procstat_core * core,enum psc_type type,void * buf,size_t * lenp)1697153ad2bSMikolaj Golub procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf,
1707153ad2bSMikolaj Golub size_t *lenp)
1717153ad2bSMikolaj Golub {
1727153ad2bSMikolaj Golub Elf_Note nhdr;
1737153ad2bSMikolaj Golub off_t offset, eoffset;
1744482b5e3SMikolaj Golub vm_offset_t psstrings;
1757153ad2bSMikolaj Golub void *freebuf;
17686be94fcSTycho Nightingale size_t len, curlen;
17786be94fcSTycho Nightingale int cstructsize;
1787153ad2bSMikolaj Golub char nbuf[8];
1797153ad2bSMikolaj Golub
1807153ad2bSMikolaj Golub assert(core->pc_magic == PROCSTAT_CORE_MAGIC);
1817153ad2bSMikolaj Golub
18286be94fcSTycho Nightingale if (type >= PSC_TYPE_MAX) {
1837153ad2bSMikolaj Golub warnx("unknown core stat type: %d", type);
1847153ad2bSMikolaj Golub return (NULL);
1857153ad2bSMikolaj Golub }
1867153ad2bSMikolaj Golub
1877153ad2bSMikolaj Golub offset = core->pc_phdr.p_offset;
1887153ad2bSMikolaj Golub eoffset = offset + core->pc_phdr.p_filesz;
18986be94fcSTycho Nightingale curlen = 0;
1907153ad2bSMikolaj Golub
1917153ad2bSMikolaj Golub while (offset < eoffset) {
1927153ad2bSMikolaj Golub if (!core_offset(core, offset))
1937153ad2bSMikolaj Golub return (NULL);
1947153ad2bSMikolaj Golub if (!core_read(core, &nhdr, sizeof(nhdr)))
1957153ad2bSMikolaj Golub return (NULL);
1967153ad2bSMikolaj Golub
1977153ad2bSMikolaj Golub offset += sizeof(nhdr) +
1987153ad2bSMikolaj Golub roundup2(nhdr.n_namesz, sizeof(Elf32_Size)) +
1997153ad2bSMikolaj Golub roundup2(nhdr.n_descsz, sizeof(Elf32_Size));
2007153ad2bSMikolaj Golub
2017153ad2bSMikolaj Golub if (nhdr.n_namesz == 0 && nhdr.n_descsz == 0)
2027153ad2bSMikolaj Golub break;
20386be94fcSTycho Nightingale if (nhdr.n_type != psc_type_info[type].n_type)
2047153ad2bSMikolaj Golub continue;
2057153ad2bSMikolaj Golub if (nhdr.n_namesz != 8)
2067153ad2bSMikolaj Golub continue;
2077153ad2bSMikolaj Golub if (!core_read(core, nbuf, sizeof(nbuf)))
2087153ad2bSMikolaj Golub return (NULL);
2097153ad2bSMikolaj Golub if (strcmp(nbuf, "FreeBSD") != 0)
2107153ad2bSMikolaj Golub continue;
2117153ad2bSMikolaj Golub if (nhdr.n_descsz < sizeof(cstructsize)) {
2127153ad2bSMikolaj Golub warnx("corrupted core file");
2137153ad2bSMikolaj Golub return (NULL);
2147153ad2bSMikolaj Golub }
2157153ad2bSMikolaj Golub if (!core_read(core, &cstructsize, sizeof(cstructsize)))
2167153ad2bSMikolaj Golub return (NULL);
21786be94fcSTycho Nightingale if (cstructsize != psc_type_info[type].structsize) {
2187153ad2bSMikolaj Golub warnx("version mismatch");
2197153ad2bSMikolaj Golub return (NULL);
2207153ad2bSMikolaj Golub }
2217153ad2bSMikolaj Golub len = nhdr.n_descsz - sizeof(cstructsize);
2227153ad2bSMikolaj Golub if (len == 0)
2237153ad2bSMikolaj Golub return (NULL);
2247153ad2bSMikolaj Golub if (buf != NULL) {
2257153ad2bSMikolaj Golub len = MIN(len, *lenp);
2267153ad2bSMikolaj Golub freebuf = NULL;
2277153ad2bSMikolaj Golub } else {
2287153ad2bSMikolaj Golub freebuf = buf = malloc(len);
2297153ad2bSMikolaj Golub if (buf == NULL) {
2307153ad2bSMikolaj Golub warn("malloc(%zu)", len);
2317153ad2bSMikolaj Golub return (NULL);
2327153ad2bSMikolaj Golub }
2337153ad2bSMikolaj Golub }
23486be94fcSTycho Nightingale if (!core_read(core, (char *)buf + curlen, len)) {
2357153ad2bSMikolaj Golub free(freebuf);
2367153ad2bSMikolaj Golub return (NULL);
2377153ad2bSMikolaj Golub }
2384482b5e3SMikolaj Golub if (type == PSC_TYPE_ARGV || type == PSC_TYPE_ENVV) {
2394482b5e3SMikolaj Golub if (len < sizeof(psstrings)) {
2404482b5e3SMikolaj Golub free(freebuf);
2414482b5e3SMikolaj Golub return (NULL);
2424482b5e3SMikolaj Golub }
2434482b5e3SMikolaj Golub psstrings = *(vm_offset_t *)buf;
2444482b5e3SMikolaj Golub if (freebuf == NULL)
2454482b5e3SMikolaj Golub len = *lenp;
2464482b5e3SMikolaj Golub else
2474482b5e3SMikolaj Golub buf = NULL;
2484482b5e3SMikolaj Golub free(freebuf);
2494482b5e3SMikolaj Golub buf = get_args(core, psstrings, type, buf, &len);
25086be94fcSTycho Nightingale } else if (type == PSC_TYPE_PTLWPINFO) {
25186be94fcSTycho Nightingale *lenp -= len;
25286be94fcSTycho Nightingale curlen += len;
25386be94fcSTycho Nightingale continue;
2544482b5e3SMikolaj Golub }
2557153ad2bSMikolaj Golub *lenp = len;
2567153ad2bSMikolaj Golub return (buf);
2577153ad2bSMikolaj Golub }
2587153ad2bSMikolaj Golub
25986be94fcSTycho Nightingale if (curlen != 0) {
26086be94fcSTycho Nightingale *lenp = curlen;
26186be94fcSTycho Nightingale return (buf);
26286be94fcSTycho Nightingale }
26386be94fcSTycho Nightingale
2647153ad2bSMikolaj Golub return (NULL);
2657153ad2bSMikolaj Golub }
2667153ad2bSMikolaj Golub
2677153ad2bSMikolaj Golub static bool
core_offset(struct procstat_core * core,off_t offset)2687153ad2bSMikolaj Golub core_offset(struct procstat_core *core, off_t offset)
2697153ad2bSMikolaj Golub {
2707153ad2bSMikolaj Golub
2717153ad2bSMikolaj Golub assert(core->pc_magic == PROCSTAT_CORE_MAGIC);
2727153ad2bSMikolaj Golub
2737153ad2bSMikolaj Golub if (lseek(core->pc_fd, offset, SEEK_SET) == -1) {
2747153ad2bSMikolaj Golub warn("core: lseek(%jd)", (intmax_t)offset);
2757153ad2bSMikolaj Golub return (false);
2767153ad2bSMikolaj Golub }
2777153ad2bSMikolaj Golub return (true);
2787153ad2bSMikolaj Golub }
2797153ad2bSMikolaj Golub
2807153ad2bSMikolaj Golub static bool
core_read(struct procstat_core * core,void * buf,size_t len)2817153ad2bSMikolaj Golub core_read(struct procstat_core *core, void *buf, size_t len)
2827153ad2bSMikolaj Golub {
2837153ad2bSMikolaj Golub ssize_t n;
2847153ad2bSMikolaj Golub
2857153ad2bSMikolaj Golub assert(core->pc_magic == PROCSTAT_CORE_MAGIC);
2867153ad2bSMikolaj Golub
2877153ad2bSMikolaj Golub n = read(core->pc_fd, buf, len);
2887153ad2bSMikolaj Golub if (n == -1) {
2897153ad2bSMikolaj Golub warn("core: read");
2907153ad2bSMikolaj Golub return (false);
2917153ad2bSMikolaj Golub }
2927153ad2bSMikolaj Golub if (n < (ssize_t)len) {
2937153ad2bSMikolaj Golub warnx("core: short read");
2947153ad2bSMikolaj Golub return (false);
2957153ad2bSMikolaj Golub }
2967153ad2bSMikolaj Golub return (true);
2977153ad2bSMikolaj Golub }
2984482b5e3SMikolaj Golub
2994482b5e3SMikolaj Golub static ssize_t
core_read_mem(struct procstat_core * core,void * buf,size_t len,vm_offset_t addr,bool readall)3004482b5e3SMikolaj Golub core_read_mem(struct procstat_core *core, void *buf, size_t len,
3014482b5e3SMikolaj Golub vm_offset_t addr, bool readall)
3024482b5e3SMikolaj Golub {
3034482b5e3SMikolaj Golub GElf_Phdr phdr;
3044482b5e3SMikolaj Golub off_t offset;
3054482b5e3SMikolaj Golub int i;
3064482b5e3SMikolaj Golub
3074482b5e3SMikolaj Golub assert(core->pc_magic == PROCSTAT_CORE_MAGIC);
3084482b5e3SMikolaj Golub
3094482b5e3SMikolaj Golub for (i = 0; i < core->pc_ehdr.e_phnum; i++) {
3104482b5e3SMikolaj Golub if (gelf_getphdr(core->pc_elf, i, &phdr) != &phdr) {
3114482b5e3SMikolaj Golub warnx("gelf_getphdr: %s", elf_errmsg(-1));
3124482b5e3SMikolaj Golub return (-1);
3134482b5e3SMikolaj Golub }
3144482b5e3SMikolaj Golub if (phdr.p_type != PT_LOAD)
3154482b5e3SMikolaj Golub continue;
3164482b5e3SMikolaj Golub if (addr < phdr.p_vaddr || addr > phdr.p_vaddr + phdr.p_memsz)
3174482b5e3SMikolaj Golub continue;
3184482b5e3SMikolaj Golub offset = phdr.p_offset + (addr - phdr.p_vaddr);
3194482b5e3SMikolaj Golub if ((phdr.p_vaddr + phdr.p_memsz) - addr < len) {
3204482b5e3SMikolaj Golub if (readall) {
3214482b5e3SMikolaj Golub warnx("format error: "
3224482b5e3SMikolaj Golub "attempt to read out of segment");
3234482b5e3SMikolaj Golub return (-1);
3244482b5e3SMikolaj Golub }
3254482b5e3SMikolaj Golub len = (phdr.p_vaddr + phdr.p_memsz) - addr;
3264482b5e3SMikolaj Golub }
3274482b5e3SMikolaj Golub if (!core_offset(core, offset))
3284482b5e3SMikolaj Golub return (-1);
3294482b5e3SMikolaj Golub if (!core_read(core, buf, len))
3304482b5e3SMikolaj Golub return (-1);
3314482b5e3SMikolaj Golub return (len);
3324482b5e3SMikolaj Golub }
3334482b5e3SMikolaj Golub warnx("format error: address %ju not found", (uintmax_t)addr);
3344482b5e3SMikolaj Golub return (-1);
3354482b5e3SMikolaj Golub }
3364482b5e3SMikolaj Golub
3374482b5e3SMikolaj Golub #define ARGS_CHUNK_SZ 256 /* Chunk size (bytes) for get_args operations. */
3384482b5e3SMikolaj Golub
3394482b5e3SMikolaj Golub static void *
get_args(struct procstat_core * core,vm_offset_t psstrings,enum psc_type type,void * args,size_t * lenp)3404482b5e3SMikolaj Golub get_args(struct procstat_core *core, vm_offset_t psstrings, enum psc_type type,
3414482b5e3SMikolaj Golub void *args, size_t *lenp)
3424482b5e3SMikolaj Golub {
3434482b5e3SMikolaj Golub struct ps_strings pss;
3444482b5e3SMikolaj Golub void *freeargs;
3454482b5e3SMikolaj Golub vm_offset_t addr;
3464482b5e3SMikolaj Golub char **argv, *p;
3474482b5e3SMikolaj Golub size_t chunksz, done, len, nchr, size;
3484482b5e3SMikolaj Golub ssize_t n;
3494482b5e3SMikolaj Golub u_int i, nstr;
3504482b5e3SMikolaj Golub
3514482b5e3SMikolaj Golub assert(type == PSC_TYPE_ARGV || type == PSC_TYPE_ENVV);
3524482b5e3SMikolaj Golub
3534482b5e3SMikolaj Golub if (core_read_mem(core, &pss, sizeof(pss), psstrings, true) == -1)
3544482b5e3SMikolaj Golub return (NULL);
3554482b5e3SMikolaj Golub if (type == PSC_TYPE_ARGV) {
3564482b5e3SMikolaj Golub addr = (vm_offset_t)pss.ps_argvstr;
3574482b5e3SMikolaj Golub nstr = pss.ps_nargvstr;
3584482b5e3SMikolaj Golub } else /* type == PSC_TYPE_ENVV */ {
3594482b5e3SMikolaj Golub addr = (vm_offset_t)pss.ps_envstr;
3604482b5e3SMikolaj Golub nstr = pss.ps_nenvstr;
3614482b5e3SMikolaj Golub }
3624482b5e3SMikolaj Golub if (addr == 0 || nstr == 0)
3634482b5e3SMikolaj Golub return (NULL);
3644482b5e3SMikolaj Golub if (nstr > ARG_MAX) {
3654482b5e3SMikolaj Golub warnx("format error");
3664482b5e3SMikolaj Golub return (NULL);
3674482b5e3SMikolaj Golub }
3684482b5e3SMikolaj Golub size = nstr * sizeof(char *);
3694482b5e3SMikolaj Golub argv = malloc(size);
3704482b5e3SMikolaj Golub if (argv == NULL) {
3714482b5e3SMikolaj Golub warn("malloc(%zu)", size);
3724482b5e3SMikolaj Golub return (NULL);
3734482b5e3SMikolaj Golub }
3744482b5e3SMikolaj Golub done = 0;
3754482b5e3SMikolaj Golub freeargs = NULL;
3764482b5e3SMikolaj Golub if (core_read_mem(core, argv, size, addr, true) == -1)
3774482b5e3SMikolaj Golub goto fail;
3784482b5e3SMikolaj Golub if (args != NULL) {
3794482b5e3SMikolaj Golub nchr = MIN(ARG_MAX, *lenp);
3804482b5e3SMikolaj Golub } else {
3814482b5e3SMikolaj Golub nchr = ARG_MAX;
3824482b5e3SMikolaj Golub freeargs = args = malloc(nchr);
3834482b5e3SMikolaj Golub if (args == NULL) {
3844482b5e3SMikolaj Golub warn("malloc(%zu)", nchr);
3854482b5e3SMikolaj Golub goto fail;
3864482b5e3SMikolaj Golub }
3874482b5e3SMikolaj Golub }
3884482b5e3SMikolaj Golub p = args;
3894482b5e3SMikolaj Golub for (i = 0; ; i++) {
3904482b5e3SMikolaj Golub if (i == nstr)
3914482b5e3SMikolaj Golub goto done;
3924482b5e3SMikolaj Golub /*
3934482b5e3SMikolaj Golub * The program may have scribbled into its argv array, e.g. to
3944482b5e3SMikolaj Golub * remove some arguments. If that has happened, break out
3954482b5e3SMikolaj Golub * before trying to read from NULL.
3964482b5e3SMikolaj Golub */
3974482b5e3SMikolaj Golub if (argv[i] == NULL)
3984482b5e3SMikolaj Golub goto done;
3994482b5e3SMikolaj Golub for (addr = (vm_offset_t)argv[i]; ; addr += chunksz) {
4004482b5e3SMikolaj Golub chunksz = MIN(ARGS_CHUNK_SZ, nchr - 1 - done);
4014482b5e3SMikolaj Golub if (chunksz <= 0)
4024482b5e3SMikolaj Golub goto done;
4034482b5e3SMikolaj Golub n = core_read_mem(core, p, chunksz, addr, false);
4044482b5e3SMikolaj Golub if (n == -1)
4054482b5e3SMikolaj Golub goto fail;
4064482b5e3SMikolaj Golub len = strnlen(p, chunksz);
4074482b5e3SMikolaj Golub p += len;
4084482b5e3SMikolaj Golub done += len;
4094482b5e3SMikolaj Golub if (len != chunksz)
4104482b5e3SMikolaj Golub break;
4114482b5e3SMikolaj Golub }
4124482b5e3SMikolaj Golub *p++ = '\0';
4134482b5e3SMikolaj Golub done++;
4144482b5e3SMikolaj Golub }
4154482b5e3SMikolaj Golub fail:
4164482b5e3SMikolaj Golub free(freeargs);
4174482b5e3SMikolaj Golub args = NULL;
4184482b5e3SMikolaj Golub done:
4194482b5e3SMikolaj Golub *lenp = done;
4204482b5e3SMikolaj Golub free(argv);
4214482b5e3SMikolaj Golub return (args);
4224482b5e3SMikolaj Golub }
42386be94fcSTycho Nightingale
42486be94fcSTycho Nightingale int
procstat_core_note_count(struct procstat_core * core,enum psc_type type)42586be94fcSTycho Nightingale procstat_core_note_count(struct procstat_core *core, enum psc_type type)
42686be94fcSTycho Nightingale {
42786be94fcSTycho Nightingale Elf_Note nhdr;
42886be94fcSTycho Nightingale off_t offset, eoffset;
42986be94fcSTycho Nightingale int cstructsize;
43086be94fcSTycho Nightingale char nbuf[8];
43186be94fcSTycho Nightingale int n;
43286be94fcSTycho Nightingale
43386be94fcSTycho Nightingale if (type >= PSC_TYPE_MAX) {
43486be94fcSTycho Nightingale warnx("unknown core stat type: %d", type);
43586be94fcSTycho Nightingale return (0);
43686be94fcSTycho Nightingale }
43786be94fcSTycho Nightingale
43886be94fcSTycho Nightingale offset = core->pc_phdr.p_offset;
43986be94fcSTycho Nightingale eoffset = offset + core->pc_phdr.p_filesz;
44086be94fcSTycho Nightingale
44186be94fcSTycho Nightingale for (n = 0; offset < eoffset; n++) {
44286be94fcSTycho Nightingale if (!core_offset(core, offset))
44386be94fcSTycho Nightingale return (0);
44486be94fcSTycho Nightingale if (!core_read(core, &nhdr, sizeof(nhdr)))
44586be94fcSTycho Nightingale return (0);
44686be94fcSTycho Nightingale
44786be94fcSTycho Nightingale offset += sizeof(nhdr) +
44886be94fcSTycho Nightingale roundup2(nhdr.n_namesz, sizeof(Elf32_Size)) +
44986be94fcSTycho Nightingale roundup2(nhdr.n_descsz, sizeof(Elf32_Size));
45086be94fcSTycho Nightingale
45186be94fcSTycho Nightingale if (nhdr.n_namesz == 0 && nhdr.n_descsz == 0)
45286be94fcSTycho Nightingale break;
45386be94fcSTycho Nightingale if (nhdr.n_type != psc_type_info[type].n_type)
45486be94fcSTycho Nightingale continue;
45586be94fcSTycho Nightingale if (nhdr.n_namesz != 8)
45686be94fcSTycho Nightingale continue;
45786be94fcSTycho Nightingale if (!core_read(core, nbuf, sizeof(nbuf)))
45886be94fcSTycho Nightingale return (0);
45986be94fcSTycho Nightingale if (strcmp(nbuf, "FreeBSD") != 0)
46086be94fcSTycho Nightingale continue;
46186be94fcSTycho Nightingale if (nhdr.n_descsz < sizeof(cstructsize)) {
46286be94fcSTycho Nightingale warnx("corrupted core file");
46386be94fcSTycho Nightingale return (0);
46486be94fcSTycho Nightingale }
46586be94fcSTycho Nightingale if (!core_read(core, &cstructsize, sizeof(cstructsize)))
46686be94fcSTycho Nightingale return (0);
46786be94fcSTycho Nightingale if (cstructsize != psc_type_info[type].structsize) {
46886be94fcSTycho Nightingale warnx("version mismatch");
46986be94fcSTycho Nightingale return (0);
47086be94fcSTycho Nightingale }
47186be94fcSTycho Nightingale if (nhdr.n_descsz - sizeof(cstructsize) == 0)
47286be94fcSTycho Nightingale return (0);
47386be94fcSTycho Nightingale }
47486be94fcSTycho Nightingale
47586be94fcSTycho Nightingale return (n);
47686be94fcSTycho Nightingale }
477