xref: /freebsd/lib/libprocstat/core.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
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