From 4b13cb33c40720888fe967367bf009ca6cf272fd Mon Sep 17 00:00:00 2001 From: bdrewery Date: Mon, 23 Oct 2017 18:25:21 +0000 Subject: MFC r316286: Add support for capturing 'struct ptrace_lwpinfo' for signals resulting in a process dumping core in the corefile. Direct stable changed: Padding added to struct thread and td_si added to end with explicit bzeroing when forking/initializing a thread to preserve KBI. --- lib/libprocstat/Symbol.map | 5 ++ lib/libprocstat/core.c | 136 ++++++++++++++++++++++++++++-------------- lib/libprocstat/core.h | 4 ++ lib/libprocstat/libprocstat.c | 44 ++++++++++++++ lib/libprocstat/libprocstat.h | 6 ++ 5 files changed, 149 insertions(+), 46 deletions(-) (limited to 'lib/libprocstat') diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 1495bfc..75a8916 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -36,3 +36,8 @@ FBSD_1.3 { procstat_getvmmap; procstat_open_core; }; + +FBSD_1.5 { + procstat_freeptlwpinfo; + procstat_getptlwpinfo; +}; diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c index 70ab86d..9baa0cd 100644 --- a/lib/libprocstat/core.c +++ b/lib/libprocstat/core.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2013 Mikolaj Golub + * Copyright (c) 2017 Dell EMC * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -56,6 +58,24 @@ struct procstat_core GElf_Phdr pc_phdr; }; +static struct psc_type_info { + unsigned int n_type; + int structsize; +} psc_type_info[PSC_TYPE_MAX] = { + { .n_type = NT_PROCSTAT_PROC, .structsize = sizeof(struct kinfo_proc) }, + { .n_type = NT_PROCSTAT_FILES, .structsize = sizeof(struct kinfo_file) }, + { .n_type = NT_PROCSTAT_VMMAP, .structsize = sizeof(struct kinfo_vmentry) }, + { .n_type = NT_PROCSTAT_GROUPS, .structsize = sizeof(gid_t) }, + { .n_type = NT_PROCSTAT_UMASK, .structsize = sizeof(u_short) }, + { .n_type = NT_PROCSTAT_RLIMIT, .structsize = sizeof(struct rlimit) * RLIM_NLIMITS }, + { .n_type = NT_PROCSTAT_OSREL, .structsize = sizeof(int) }, + { .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) }, + { .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) }, + { .n_type = NT_PROCSTAT_PSSTRINGS, .structsize = sizeof(vm_offset_t) }, + { .n_type = NT_PROCSTAT_AUXV, .structsize = sizeof(Elf_Auxinfo) }, + { .n_type = NT_PTLWPINFO, .structsize = sizeof(struct ptrace_lwpinfo) }, +}; + static bool core_offset(struct procstat_core *core, off_t offset); static bool core_read(struct procstat_core *core, void *buf, size_t len); static ssize_t core_read_mem(struct procstat_core *core, void *buf, @@ -154,59 +174,20 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, off_t offset, eoffset; vm_offset_t psstrings; void *freebuf; - size_t len; - u_int32_t n_type; - int cstructsize, structsize; + size_t len, curlen; + int cstructsize; char nbuf[8]; assert(core->pc_magic == PROCSTAT_CORE_MAGIC); - switch(type) { - case PSC_TYPE_PROC: - n_type = NT_PROCSTAT_PROC; - structsize = sizeof(struct kinfo_proc); - break; - case PSC_TYPE_FILES: - n_type = NT_PROCSTAT_FILES; - structsize = sizeof(struct kinfo_file); - break; - case PSC_TYPE_VMMAP: - n_type = NT_PROCSTAT_VMMAP; - structsize = sizeof(struct kinfo_vmentry); - break; - case PSC_TYPE_GROUPS: - n_type = NT_PROCSTAT_GROUPS; - structsize = sizeof(gid_t); - break; - case PSC_TYPE_UMASK: - n_type = NT_PROCSTAT_UMASK; - structsize = sizeof(u_short); - break; - case PSC_TYPE_RLIMIT: - n_type = NT_PROCSTAT_RLIMIT; - structsize = sizeof(struct rlimit) * RLIM_NLIMITS; - break; - case PSC_TYPE_OSREL: - n_type = NT_PROCSTAT_OSREL; - structsize = sizeof(int); - break; - case PSC_TYPE_PSSTRINGS: - case PSC_TYPE_ARGV: - case PSC_TYPE_ENVV: - n_type = NT_PROCSTAT_PSSTRINGS; - structsize = sizeof(vm_offset_t); - break; - case PSC_TYPE_AUXV: - n_type = NT_PROCSTAT_AUXV; - structsize = sizeof(Elf_Auxinfo); - break; - default: + if (type >= PSC_TYPE_MAX) { warnx("unknown core stat type: %d", type); return (NULL); } offset = core->pc_phdr.p_offset; eoffset = offset + core->pc_phdr.p_filesz; + curlen = 0; while (offset < eoffset) { if (!core_offset(core, offset)) @@ -220,7 +201,7 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, if (nhdr.n_namesz == 0 && nhdr.n_descsz == 0) break; - if (nhdr.n_type != n_type) + if (nhdr.n_type != psc_type_info[type].n_type) continue; if (nhdr.n_namesz != 8) continue; @@ -234,7 +215,7 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, } if (!core_read(core, &cstructsize, sizeof(cstructsize))) return (NULL); - if (cstructsize != structsize) { + if (cstructsize != psc_type_info[type].structsize) { warnx("version mismatch"); return (NULL); } @@ -251,7 +232,7 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, return (NULL); } } - if (!core_read(core, buf, len)) { + if (!core_read(core, (char *)buf + curlen, len)) { free(freebuf); return (NULL); } @@ -267,11 +248,20 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, buf = NULL; free(freebuf); buf = get_args(core, psstrings, type, buf, &len); + } else if (type == PSC_TYPE_PTLWPINFO) { + *lenp -= len; + curlen += len; + continue; } *lenp = len; return (buf); } + if (curlen != 0) { + *lenp = curlen; + return (buf); + } + return (NULL); } @@ -431,3 +421,57 @@ done: free(argv); return (args); } + +int +procstat_core_note_count(struct procstat_core *core, enum psc_type type) +{ + Elf_Note nhdr; + off_t offset, eoffset; + int cstructsize; + char nbuf[8]; + int n; + + if (type >= PSC_TYPE_MAX) { + warnx("unknown core stat type: %d", type); + return (0); + } + + offset = core->pc_phdr.p_offset; + eoffset = offset + core->pc_phdr.p_filesz; + + for (n = 0; offset < eoffset; n++) { + if (!core_offset(core, offset)) + return (0); + if (!core_read(core, &nhdr, sizeof(nhdr))) + return (0); + + offset += sizeof(nhdr) + + roundup2(nhdr.n_namesz, sizeof(Elf32_Size)) + + roundup2(nhdr.n_descsz, sizeof(Elf32_Size)); + + if (nhdr.n_namesz == 0 && nhdr.n_descsz == 0) + break; + if (nhdr.n_type != psc_type_info[type].n_type) + continue; + if (nhdr.n_namesz != 8) + continue; + if (!core_read(core, nbuf, sizeof(nbuf))) + return (0); + if (strcmp(nbuf, "FreeBSD") != 0) + continue; + if (nhdr.n_descsz < sizeof(cstructsize)) { + warnx("corrupted core file"); + return (0); + } + if (!core_read(core, &cstructsize, sizeof(cstructsize))) + return (0); + if (cstructsize != psc_type_info[type].structsize) { + warnx("version mismatch"); + return (0); + } + if (nhdr.n_descsz - sizeof(cstructsize) == 0) + return (0); + } + + return (n); +} diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h index 6639abc..701697b 100644 --- a/lib/libprocstat/core.h +++ b/lib/libprocstat/core.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 2013 Mikolaj Golub + * Copyright (c) 2017 Dell EMC * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,6 +42,8 @@ enum psc_type { PSC_TYPE_ARGV, PSC_TYPE_ENVV, PSC_TYPE_AUXV, + PSC_TYPE_PTLWPINFO, + PSC_TYPE_MAX }; struct procstat_core; @@ -48,6 +51,7 @@ struct procstat_core; void procstat_core_close(struct procstat_core *core); void *procstat_core_get(struct procstat_core *core, enum psc_type type, void * buf, size_t *lenp); +int procstat_core_note_count(struct procstat_core *core, enum psc_type type); struct procstat_core *procstat_core_open(const char *filename); #endif /* !_CORE_H_ */ diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 9dc9800..9c6877c 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2017 Dell EMC * Copyright (c) 2009 Stanislav Sedov * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -65,6 +66,7 @@ __FBSDID("$FreeBSD$"); #define _KERNEL #include #include +#include #include #include #include @@ -2469,6 +2471,48 @@ procstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv) free(auxv); } +static struct ptrace_lwpinfo * +procstat_getptlwpinfo_core(struct procstat_core *core, unsigned int *cntp) +{ + void *buf; + struct ptrace_lwpinfo *pl; + unsigned int cnt; + size_t len; + + cnt = procstat_core_note_count(core, PSC_TYPE_PTLWPINFO); + if (cnt == 0) + return (NULL); + + len = cnt * sizeof(*pl); + buf = calloc(1, len); + pl = procstat_core_get(core, PSC_TYPE_PTLWPINFO, buf, &len); + if (pl == NULL) { + free(buf); + return (NULL); + } + *cntp = len / sizeof(*pl); + return (pl); +} + +struct ptrace_lwpinfo * +procstat_getptlwpinfo(struct procstat *procstat, unsigned int *cntp) +{ + switch (procstat->type) { + case PROCSTAT_CORE: + return (procstat_getptlwpinfo_core(procstat->core, cntp)); + default: + warnx("unknown access method: %d", procstat->type); + return (NULL); + } +} + +void +procstat_freeptlwpinfo(struct procstat *procstat __unused, + struct ptrace_lwpinfo *pl) +{ + free(pl); +} + static struct kinfo_kstack * procstat_getkstack_sysctl(pid_t pid, int *cntp) { diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 7af6ccb..00b6f1c 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 2009 Stanislav Sedov + * Copyright (c) 2017 Dell EMC * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -101,6 +102,7 @@ struct kinfo_kstack; struct kinfo_vmentry; struct procstat; +struct ptrace_lwpinfo; struct rlimit; struct filestat { int fs_type; /* Descriptor type. */ @@ -172,6 +174,8 @@ void procstat_freekstack(struct procstat *procstat, void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p); void procstat_freefiles(struct procstat *procstat, struct filestat_list *head); +void procstat_freeptlwpinfo(struct procstat *procstat, + struct ptrace_lwpinfo *pl); void procstat_freevmmap(struct procstat *procstat, struct kinfo_vmentry *vmmap); struct filestat_list *procstat_getfiles(struct procstat *procstat, @@ -196,6 +200,8 @@ char **procstat_getargv(struct procstat *procstat, struct kinfo_proc *p, Elf_Auxinfo *procstat_getauxv(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *cntp); #endif +struct ptrace_lwpinfo *procstat_getptlwpinfo(struct procstat *procstat, + unsigned int *cntp); char **procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr); gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, -- cgit v1.1