summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorbdrewery <bdrewery@FreeBSD.org>2017-10-23 18:25:21 +0000
committerbdrewery <bdrewery@FreeBSD.org>2017-10-23 18:25:21 +0000
commit4b13cb33c40720888fe967367bf009ca6cf272fd (patch)
tree4491d3f5e0ad545aca21ef8c4ab7b103f46b625f /lib
parentb916159a6fa3858710d1a0f75cb5a26825ccc698 (diff)
downloadFreeBSD-src-4b13cb33c40720888fe967367bf009ca6cf272fd.zip
FreeBSD-src-4b13cb33c40720888fe967367bf009ca6cf272fd.tar.gz
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/libprocstat/Symbol.map5
-rw-r--r--lib/libprocstat/core.c136
-rw-r--r--lib/libprocstat/core.h4
-rw-r--r--lib/libprocstat/libprocstat.c44
-rw-r--r--lib/libprocstat/libprocstat.h6
5 files changed, 149 insertions, 46 deletions
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 <trociny@FreeBSD.org>
+ * 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 <sys/param.h>
#include <sys/elf.h>
#include <sys/exec.h>
+#include <sys/ptrace.h>
#include <sys/user.h>
#include <assert.h>
@@ -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 <trociny@FreeBSD.org>
+ * 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 <stas@FreeBSD.org>
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
@@ -65,6 +66,7 @@ __FBSDID("$FreeBSD$");
#define _KERNEL
#include <sys/mount.h>
#include <sys/pipe.h>
+#include <sys/ptrace.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <fs/devfs/devfs.h>
@@ -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 <stas@FreeBSD.org>
+ * 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,
OpenPOWER on IntegriCloud