diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 322d46f1b920..085720cf4590 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -20,12 +20,14 @@ FBSD_1.3 { procstat_freeauxv; procstat_freeenvv; procstat_freegroups; + procstat_freekstack; procstat_freevmmap; procstat_get_shm_info; procstat_getargv; procstat_getauxv; procstat_getenvv; procstat_getgroups; + procstat_getkstack; procstat_getosrel; procstat_getpathname; procstat_getrlimit; diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3 index 5a425e727367..136774126183 100644 --- a/lib/libprocstat/libprocstat.3 +++ b/lib/libprocstat/libprocstat.3 @@ -37,6 +37,7 @@ .Nm procstat_getenvv , .Nm procstat_getfiles , .Nm procstat_getgroups , +.Nm procstat_getkstack , .Nm procstat_getosrel , .Nm procstat_getpathname , .Nm procstat_getprocs , @@ -47,6 +48,7 @@ .Nm procstat_freeenvv , .Nm procstat_freefiles , .Nm procstat_freegroups , +.Nm procstat_freekstack , .Nm procstat_freeprocs , .Nm procstat_freevmmap , .Nm procstat_get_pipe_info , @@ -88,6 +90,11 @@ .Fa "gid_t *groups" .Fc .Ft void +.Fo procstat_freekstack +.Fa "struct procstat *procstat" +.Fa "struct kinfo_kstack *kkstp" +.Fc +.Ft void .Fn procstat_freeprocs "struct procstat *procstat" "struct kinfo_proc *p" .Ft void .Fo procstat_freevmmap @@ -166,6 +173,12 @@ .Fa "struct kinfo_proc *kp" .Fa "int *osrelp" .Fc +.Ft "struct kinfo_kstack *" +.Fo procstat_getkstack +.Fa "struct procstat *procstat" +.Fa "struct kinfo_proc *kp" +.Fa "unsigned int *count" +.Fc .Ft "struct kinfo_proc *" .Fo procstat_getprocs .Fa "struct procstat *procstat" @@ -378,6 +391,22 @@ The caller is responsible to free the allocated memory with a subsequent function call. .Pp The +.Fn procstat_getkstack +function gets a pointer to the +.Vt procstat +structure initialized with one of the +.Fn procstat_open_* +functions, a pointer to +.Vt kinfo_proc +structure, and returns kernel stacks of the process as a dynamically allocated +array of +.Vt kinfo_kstack +structures. +The caller is responsible to free the allocated memory with a subsequent +.Fn procstat_freekstack +function call. +.Pp +The .Fn procstat_getosrel function gets a pointer to the .Vt procstat diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index b70586d37912..a54b90d93bb3 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -142,6 +142,8 @@ static int procstat_get_vnode_info_sysctl(struct filestat *fst, static gid_t *procstat_getgroups_core(struct procstat_core *core, unsigned int *count); static gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count); +static struct kinfo_kstack *procstat_getkstack_sysctl(pid_t pid, + int *cntp); static int procstat_getpathname_core(struct procstat_core *core, char *pathname, size_t maxlen); static int procstat_getpathname_sysctl(pid_t pid, char *pathname, @@ -1764,6 +1766,7 @@ struct kinfo_vmentry * procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *cntp) { + switch(procstat->type) { case PROCSTAT_KVM: warnx("kvm method is not supported"); @@ -2227,3 +2230,70 @@ procstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv) free(auxv); } + +static struct kinfo_kstack * +procstat_getkstack_sysctl(pid_t pid, int *cntp) +{ + struct kinfo_kstack *kkstp; + int error, name[4]; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_KSTACK; + name[3] = pid; + + len = 0; + error = sysctl(name, 4, NULL, &len, NULL, 0); + if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) { + warn("sysctl: kern.proc.kstack: %d", pid); + return (NULL); + } + if (error == -1 && errno == ENOENT) { + warnx("sysctl: kern.proc.kstack unavailable" + " (options DDB or options STACK required in kernel)"); + return (NULL); + } + if (error == -1) + return (NULL); + kkstp = malloc(len); + if (kkstp == NULL) { + warn("malloc(%zu)", len); + return (NULL); + } + if (sysctl(name, 4, kkstp, &len, NULL, 0) == -1) { + warn("sysctl: kern.proc.pid: %d", pid); + free(kkstp); + return (NULL); + } + *cntp = len / sizeof(*kkstp); + + return (kkstp); +} + +struct kinfo_kstack * +procstat_getkstack(struct procstat *procstat, struct kinfo_proc *kp, + unsigned int *cntp) +{ + switch(procstat->type) { + case PROCSTAT_KVM: + warnx("kvm method is not supported"); + return (NULL); + case PROCSTAT_SYSCTL: + return (procstat_getkstack_sysctl(kp->ki_pid, cntp)); + case PROCSTAT_CORE: + warnx("core method is not supported"); + return (NULL); + default: + warnx("unknown access method: %d", procstat->type); + return (NULL); + } +} + +void +procstat_freekstack(struct procstat *procstat __unused, + struct kinfo_kstack *kkstp) +{ + + free(kkstp); +} diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 3ac51e138ebd..2c2662d5dbeb 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -97,6 +97,7 @@ #define PS_FST_FFLAG_EXEC 0x2000 #define PS_FST_FFLAG_HASLOCK 0x4000 +struct kinfo_kstack; struct kinfo_vmentry; struct procstat; struct rlimit; @@ -161,6 +162,8 @@ void procstat_freeauxv(struct procstat *procstat, Elf_Auxinfo *auxv); #endif void procstat_freeenvv(struct procstat *procstat); void procstat_freegroups(struct procstat *procstat, gid_t *groups); +void procstat_freekstack(struct procstat *procstat, + struct kinfo_kstack *kkstp); void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p); void procstat_freefiles(struct procstat *procstat, struct filestat_list *head); @@ -190,6 +193,8 @@ char **procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr); gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, unsigned int *count); +struct kinfo_kstack *procstat_getkstack(struct procstat *procstat, + struct kinfo_proc *kp, unsigned int *count); int procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp); int procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp,