summaryrefslogtreecommitdiffstats
path: root/lib/libprocstat
diff options
context:
space:
mode:
authortrociny <trociny@FreeBSD.org>2013-04-20 08:10:47 +0000
committertrociny <trociny@FreeBSD.org>2013-04-20 08:10:47 +0000
commit5c12dda0cc52704c0cf548ef0a15f80a736d4ee6 (patch)
treef458748af9d8de777c27228b3593052a1ce4ebcf /lib/libprocstat
parent5a7b01c81a73882e035c38149a851ac183f07984 (diff)
downloadFreeBSD-src-5c12dda0cc52704c0cf548ef0a15f80a736d4ee6.zip
FreeBSD-src-5c12dda0cc52704c0cf548ef0a15f80a736d4ee6.tar.gz
Add procstat_getauxv function to retrieve a process auxiliary vector.
MFC after: 1 month
Diffstat (limited to 'lib/libprocstat')
-rw-r--r--lib/libprocstat/Symbol.map2
-rw-r--r--lib/libprocstat/core.c4
-rw-r--r--lib/libprocstat/core.h1
-rw-r--r--lib/libprocstat/libprocstat.326
-rw-r--r--lib/libprocstat/libprocstat.c152
-rw-r--r--lib/libprocstat/libprocstat.h15
6 files changed, 200 insertions, 0 deletions
diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map
index f2632c2..322d46f 100644
--- a/lib/libprocstat/Symbol.map
+++ b/lib/libprocstat/Symbol.map
@@ -17,11 +17,13 @@ FBSD_1.2 {
FBSD_1.3 {
procstat_freeargv;
+ procstat_freeauxv;
procstat_freeenvv;
procstat_freegroups;
procstat_freevmmap;
procstat_get_shm_info;
procstat_getargv;
+ procstat_getauxv;
procstat_getenvv;
procstat_getgroups;
procstat_getosrel;
diff --git a/lib/libprocstat/core.c b/lib/libprocstat/core.c
index 72dee88..b83cdfd 100644
--- a/lib/libprocstat/core.c
+++ b/lib/libprocstat/core.c
@@ -195,6 +195,10 @@ procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf,
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:
warnx("unknown core stat type: %d", type);
return (NULL);
diff --git a/lib/libprocstat/core.h b/lib/libprocstat/core.h
index 2361148..6639abc 100644
--- a/lib/libprocstat/core.h
+++ b/lib/libprocstat/core.h
@@ -40,6 +40,7 @@ enum psc_type {
PSC_TYPE_PSSTRINGS,
PSC_TYPE_ARGV,
PSC_TYPE_ENVV,
+ PSC_TYPE_AUXV,
};
struct procstat_core;
diff --git a/lib/libprocstat/libprocstat.3 b/lib/libprocstat/libprocstat.3
index e1dc987..5a425e7 100644
--- a/lib/libprocstat/libprocstat.3
+++ b/lib/libprocstat/libprocstat.3
@@ -33,6 +33,7 @@
.Nm procstat_open_sysctl ,
.Nm procstat_close ,
.Nm procstat_getargv ,
+.Nm procstat_getauxv ,
.Nm procstat_getenvv ,
.Nm procstat_getfiles ,
.Nm procstat_getgroups ,
@@ -42,6 +43,7 @@
.Nm procstat_getumask ,
.Nm procstat_getvmmap ,
.Nm procstat_freeargv ,
+.Nm procstat_freeauxv ,
.Nm procstat_freeenvv ,
.Nm procstat_freefiles ,
.Nm procstat_freegroups ,
@@ -67,6 +69,11 @@
.Fa "struct procstat *procstat"
.Fc
.Ft void
+.Fo procstat_freeauxv
+.Fa "struct procstat *procstat"
+.Fa "Elf_Auxinfo *auxv"
+.Fc
+.Ft void
.Fo procstat_freeenvv
.Fa "struct procstat *procstat"
.Fc
@@ -129,6 +136,12 @@
.Fa "size_t nchr"
.Fa "char *errbuf"
.Fc
+.Ft "Elf_Auxinfo *"
+.Fo procstat_getauxv
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned int *count"
+.Fc
.Ft "char **"
.Fo procstat_getenvv
.Fa "struct procstat *procstat"
@@ -321,6 +334,19 @@ The caller may free the allocated memory with a subsequent
function call.
.Pp
The
+.Fn procstat_getauxv
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and returns the auxiliary vector as a dynamically allocated array of
+.Vt Elf_Auxinfo
+elements.
+The caller is responsible to free the allocated memory with a subsequent
+.Fn procstat_freeauxv
+function call.
+.Pp
+The
.Fn procstat_getfiles
function gets a pointer to the
.Vt procstat
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c
index 52b9409..b70586d 100644
--- a/lib/libprocstat/libprocstat.c
+++ b/lib/libprocstat/libprocstat.c
@@ -36,6 +36,7 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/elf.h>
#include <sys/time.h>
#include <sys/resourcevar.h>
#include <sys/proc.h>
@@ -110,6 +111,9 @@ static char **getargv(struct procstat *procstat, struct kinfo_proc *kp,
static char *getmnton(kvm_t *kd, struct mount *m);
static struct kinfo_vmentry * kinfo_getvmmap_core(struct procstat_core *core,
int *cntp);
+static Elf_Auxinfo *procstat_getauxv_core(struct procstat_core *core,
+ unsigned int *cntp);
+static Elf_Auxinfo *procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp);
static struct filestat_list *procstat_getfiles_kvm(
struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
static struct filestat_list *procstat_getfiles_sysctl(
@@ -2075,3 +2079,151 @@ procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp)
return (-1);
}
}
+
+#define PROC_AUXV_MAX 256
+
+#if __ELF_WORD_SIZE == 64
+static const char *elf32_sv_names[] = {
+ "Linux ELF32",
+ "FreeBSD ELF32",
+};
+
+static int
+is_elf32_sysctl(pid_t pid)
+{
+ int error, name[4];
+ size_t len, i;
+ static char sv_name[256];
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_SV_NAME;
+ name[3] = pid;
+ len = sizeof(sv_name);
+ error = sysctl(name, 4, sv_name, &len, NULL, 0);
+ if (error != 0 || len == 0)
+ return (0);
+ for (i = 0; i < sizeof(elf32_sv_names) / sizeof(*elf32_sv_names); i++) {
+ if (strncmp(sv_name, elf32_sv_names[i], sizeof(sv_name)) == 0)
+ return (1);
+ }
+ return (0);
+}
+
+static Elf_Auxinfo *
+procstat_getauxv32_sysctl(pid_t pid, unsigned int *cntp)
+{
+ Elf_Auxinfo *auxv;
+ Elf32_Auxinfo *auxv32;
+ void *ptr;
+ size_t len;
+ unsigned int i, count;
+ int name[4];
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_AUXV;
+ name[3] = pid;
+ len = PROC_AUXV_MAX * sizeof(Elf32_Auxinfo);
+ auxv = NULL;
+ auxv32 = malloc(len);
+ if (auxv32 == NULL) {
+ warn("malloc(%zu)", len);
+ goto out;
+ }
+ if (sysctl(name, 4, auxv32, &len, NULL, 0) == -1) {
+ if (errno != ESRCH && errno != EPERM)
+ warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
+ goto out;
+ }
+ count = len / sizeof(Elf_Auxinfo);
+ auxv = malloc(count * sizeof(Elf_Auxinfo));
+ if (auxv == NULL) {
+ warn("malloc(%zu)", count * sizeof(Elf_Auxinfo));
+ goto out;
+ }
+ for (i = 0; i < count; i++) {
+ /*
+ * XXX: We expect that values for a_type on a 32-bit platform
+ * are directly mapped to values on 64-bit one, which is not
+ * necessarily true.
+ */
+ auxv[i].a_type = auxv32[i].a_type;
+ ptr = &auxv32[i].a_un;
+ auxv[i].a_un.a_val = *((uint32_t *)ptr);
+ }
+ *cntp = count;
+out:
+ free(auxv32);
+ return (auxv);
+}
+#endif /* __ELF_WORD_SIZE == 64 */
+
+static Elf_Auxinfo *
+procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp)
+{
+ Elf_Auxinfo *auxv;
+ int name[4];
+ size_t len;
+
+#if __ELF_WORD_SIZE == 64
+ if (is_elf32_sysctl(pid))
+ return (procstat_getauxv32_sysctl(pid, cntp));
+#endif
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_AUXV;
+ name[3] = pid;
+ len = PROC_AUXV_MAX * sizeof(Elf_Auxinfo);
+ auxv = malloc(len);
+ if (auxv == NULL) {
+ warn("malloc(%zu)", len);
+ return (NULL);
+ }
+ if (sysctl(name, 4, auxv, &len, NULL, 0) == -1) {
+ if (errno != ESRCH && errno != EPERM)
+ warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
+ free(auxv);
+ return (NULL);
+ }
+ *cntp = len / sizeof(Elf_Auxinfo);
+ return (auxv);
+}
+
+static Elf_Auxinfo *
+procstat_getauxv_core(struct procstat_core *core, unsigned int *cntp)
+{
+ Elf_Auxinfo *auxv;
+ size_t len;
+
+ auxv = procstat_core_get(core, PSC_TYPE_AUXV, NULL, &len);
+ if (auxv == NULL)
+ return (NULL);
+ *cntp = len / sizeof(Elf_Auxinfo);
+ return (auxv);
+}
+
+Elf_Auxinfo *
+procstat_getauxv(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_getauxv_sysctl(kp->ki_pid, cntp));
+ case PROCSTAT_CORE:
+ return (procstat_getauxv_core(procstat->core, cntp));
+ default:
+ warnx("unknown access method: %d", procstat->type);
+ return (NULL);
+ }
+}
+
+void
+procstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv)
+{
+
+ free(auxv);
+}
diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h
index b7719c0..3ac51e1 100644
--- a/lib/libprocstat/libprocstat.h
+++ b/lib/libprocstat/libprocstat.h
@@ -30,6 +30,14 @@
#define _LIBPROCSTAT_H_
/*
+ * XXX: sys/elf.h conflicts with zfs_context.h. Workaround this by not
+ * including conflicting parts when building zfs code.
+ */
+#ifndef ZFS
+#include <sys/elf.h>
+#endif
+
+/*
* Vnode types.
*/
#define PS_FST_VTYPE_VNON 1
@@ -148,6 +156,9 @@ STAILQ_HEAD(filestat_list, filestat);
__BEGIN_DECLS
void procstat_close(struct procstat *procstat);
void procstat_freeargv(struct procstat *procstat);
+#ifndef ZFS
+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_freeprocs(struct procstat *procstat, struct kinfo_proc *p);
@@ -171,6 +182,10 @@ int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
struct vnstat *vn, char *errbuf);
char **procstat_getargv(struct procstat *procstat, struct kinfo_proc *p,
size_t nchr);
+#ifndef ZFS
+Elf_Auxinfo *procstat_getauxv(struct procstat *procstat,
+ struct kinfo_proc *kp, unsigned int *cntp);
+#endif
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