From 4808a67805fe7287d8054934d978cd1076302689 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Sat, 30 Jul 2016 03:09:23 +0000 Subject: libproc: Add proc_getmodel(). This is used by libdtrace to determine the data model of target processes. This allows for the creation of pid provider probes in 32-bit processes on amd64. MFC after: 1 month --- lib/libproc/Makefile | 2 +- lib/libproc/_libproc.h | 6 ++- lib/libproc/libproc.h | 4 ++ lib/libproc/proc_create.c | 127 +++++++++++++++++++++++++++++++--------------- lib/libproc/proc_rtld.c | 2 +- lib/libproc/proc_util.c | 10 ++++ 6 files changed, 108 insertions(+), 43 deletions(-) (limited to 'lib/libproc') diff --git a/lib/libproc/Makefile b/lib/libproc/Makefile index 0372377d8b64..9744557e680d 100644 --- a/lib/libproc/Makefile +++ b/lib/libproc/Makefile @@ -24,7 +24,7 @@ LIBADD+= cxxrt LIBADD+= supcplusplus .endif -LIBADD+= elf rtld_db util +LIBADD+= elf procstat rtld_db util .if ${MK_CDDL} != "no" LIBADD+= ctf diff --git a/lib/libproc/_libproc.h b/lib/libproc/_libproc.h index 0ab3251e55b8..29951932a151 100644 --- a/lib/libproc/_libproc.h +++ b/lib/libproc/_libproc.h @@ -33,18 +33,22 @@ #include "libproc.h" +struct procstat; + struct proc_handle { pid_t pid; /* Process ID. */ int flags; /* Process flags. */ int status; /* Process status (PS_*). */ int wstat; /* Process wait status. */ + int model; /* Process data model. */ rd_agent_t *rdap; /* librtld_db agent */ rd_loadobj_t *rdobjs; /* Array of loaded objects. */ size_t rdobjsz; /* Array size. */ size_t nobjs; /* Num. objects currently loaded. */ rd_loadobj_t *rdexec; /* rdobj for program executable. */ struct lwpstatus lwps; /* Process status. */ - char execname[MAXPATHLEN]; /* Path to program executable. */ + struct procstat *procstat; /* libprocstat handle. */ + char execpath[MAXPATHLEN]; /* Path to program executable. */ }; #ifdef DEBUG diff --git a/lib/libproc/libproc.h b/lib/libproc/libproc.h index 5d81c2bf4505..5445d47abef6 100644 --- a/lib/libproc/libproc.h +++ b/lib/libproc/libproc.h @@ -113,6 +113,9 @@ typedef struct lwpstatus { #define FLTBPT -1 } lwpstatus_t; +#define PR_MODEL_ILP32 1 +#define PR_MODEL_LP64 2 + /* Function prototype definitions. */ __BEGIN_DECLS @@ -136,6 +139,7 @@ int proc_name2sym(struct proc_handle *, const char *, const char *, struct ctf_file *proc_name2ctf(struct proc_handle *, const char *); int proc_setflags(struct proc_handle *, int); int proc_state(struct proc_handle *); +int proc_getmodel(struct proc_handle *); pid_t proc_getpid(struct proc_handle *); int proc_wstatus(struct proc_handle *); int proc_getwstat(struct proc_handle *); diff --git a/lib/libproc/proc_create.c b/lib/libproc/proc_create.c index 4a925809badf..ad975b4c9979 100644 --- a/lib/libproc/proc_create.c +++ b/lib/libproc/proc_create.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -38,57 +39,103 @@ #include #include +#include +#include + #include "_libproc.h" -static int proc_init(pid_t, int, int, struct proc_handle *); +static int getelfclass(int); +static int proc_init(pid_t, int, int, struct proc_handle **); + +static int +getelfclass(int fd) +{ + GElf_Ehdr ehdr; + Elf *e; + int class; + + class = ELFCLASSNONE; + + if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) + goto out; + if (gelf_getehdr(e, &ehdr) == NULL) + goto out; + class = ehdr.e_ident[EI_CLASS]; +out: + (void)elf_end(e); + return (class); +} static int -proc_init(pid_t pid, int flags, int status, struct proc_handle *phdl) +proc_init(pid_t pid, int flags, int status, struct proc_handle **pphdl) { - int mib[4], error; - size_t len; + struct kinfo_proc *kp; + struct proc_handle *phdl; + int error, class, count, fd; + + *pphdl = NULL; + if ((phdl = malloc(sizeof(*phdl))) == NULL) + return (ENOMEM); memset(phdl, 0, sizeof(*phdl)); phdl->pid = pid; phdl->flags = flags; phdl->status = status; + phdl->procstat = procstat_open_sysctl(); + if (phdl->procstat == NULL) + return (ENOMEM); - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PATHNAME; - mib[3] = pid; - len = sizeof(phdl->execname); - if (sysctl(mib, 4, phdl->execname, &len, NULL, 0) != 0) { - error = errno; - DPRINTF("ERROR: cannot get pathname for child process %d", pid); + /* Obtain a path to the executable. */ + if ((kp = procstat_getprocs(phdl->procstat, KERN_PROC_PID, pid, + &count)) == NULL) + return (ENOMEM); + error = procstat_getpathname(phdl->procstat, kp, phdl->execpath, + sizeof(phdl->execpath)); + procstat_freeprocs(phdl->procstat, kp); + if (error != 0) return (error); + + /* Use it to determine the data model for the process. */ + if ((fd = open(phdl->execpath, O_RDONLY)) < 0) { + error = errno; + goto out; } - if (len == 0) - phdl->execname[0] = '\0'; + class = getelfclass(fd); + switch (class) { + case ELFCLASS64: + phdl->model = PR_MODEL_LP64; + break; + case ELFCLASS32: + phdl->model = PR_MODEL_ILP32; + break; + case ELFCLASSNONE: + default: + error = EINVAL; + break; + } + (void)close(fd); - return (0); +out: + *pphdl = phdl; + return (error); } int proc_attach(pid_t pid, int flags, struct proc_handle **pphdl) { struct proc_handle *phdl; - int error = 0; - int status; + int error, status; if (pid == 0 || pid == getpid()) return (EINVAL); + if (elf_version(EV_CURRENT) == EV_NONE) + return (ENOENT); /* * Allocate memory for the process handle, a structure containing * all things related to the process. */ - if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) - return (ENOMEM); - - elf_version(EV_CURRENT); - - error = proc_init(pid, flags, PS_RUN, phdl); + error = proc_init(pid, flags, PS_RUN, &phdl); if (error != 0) goto out; @@ -106,16 +153,17 @@ proc_attach(pid_t pid, int flags, struct proc_handle **pphdl) } /* Check for an unexpected status. */ - if (WIFSTOPPED(status) == 0) + if (!WIFSTOPPED(status)) DPRINTFX("ERROR: child process %d status 0x%x", pid, status); else phdl->status = PS_STOP; out: - if (error) + if (error && phdl != NULL) { proc_free(phdl); - else - *pphdl = phdl; + phdl = NULL; + } + *pphdl = phdl; return (error); } @@ -128,14 +176,8 @@ proc_create(const char *file, char * const *argv, proc_child_func *pcf, int status; pid_t pid; - /* - * Allocate memory for the process handle, a structure containing - * all things related to the process. - */ - if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) - return (ENOMEM); - - elf_version(EV_CURRENT); + if (elf_version(EV_CURRENT) == EV_NONE) + return (ENOENT); /* Fork a new process. */ if ((pid = vfork()) == -1) @@ -153,9 +195,10 @@ proc_create(const char *file, char * const *argv, proc_child_func *pcf, /* Couldn't execute the file. */ _exit(2); + /* NOTREACHED */ } else { /* The parent owns the process handle. */ - error = proc_init(pid, 0, PS_IDLE, phdl); + error = proc_init(pid, 0, PS_IDLE, &phdl); if (error != 0) goto bad; @@ -167,7 +210,7 @@ proc_create(const char *file, char * const *argv, proc_child_func *pcf, } /* Check for an unexpected status. */ - if (WIFSTOPPED(status) == 0) { + if (!WIFSTOPPED(status)) { error = errno; DPRINTFX("ERROR: child process %d status 0x%x", pid, status); goto bad; @@ -175,15 +218,19 @@ proc_create(const char *file, char * const *argv, proc_child_func *pcf, phdl->status = PS_STOP; } bad: - if (error) + if (error && phdl != NULL) { proc_free(phdl); - else - *pphdl = phdl; + phdl = NULL; + } + *pphdl = phdl; return (error); } void proc_free(struct proc_handle *phdl) { + + if (phdl->procstat != NULL) + procstat_close(phdl->procstat); free(phdl); } diff --git a/lib/libproc/proc_rtld.c b/lib/libproc/proc_rtld.c index 8dff3b726615..6c34a8a21bb3 100644 --- a/lib/libproc/proc_rtld.c +++ b/lib/libproc/proc_rtld.c @@ -49,7 +49,7 @@ map_iter(const rd_loadobj_t *lop, void *arg) if (phdl->rdobjs == NULL) return (-1); } - if (strcmp(lop->rdl_path, phdl->execname) == 0 && + if (strcmp(lop->rdl_path, phdl->execpath) == 0 && (lop->rdl_prot & RD_RDL_X) != 0) phdl->rdexec = &phdl->rdobjs[phdl->nobjs]; memcpy(&phdl->rdobjs[phdl->nobjs++], lop, sizeof(*lop)); diff --git a/lib/libproc/proc_util.c b/lib/libproc/proc_util.c index 4d9aa20b3de6..1e14c4fd3837 100644 --- a/lib/libproc/proc_util.c +++ b/lib/libproc/proc_util.c @@ -139,6 +139,16 @@ proc_getpid(struct proc_handle *phdl) return (phdl->pid); } +int +proc_getmodel(struct proc_handle *phdl) +{ + + if (phdl == NULL) + return (-1); + + return (phdl->model); +} + int proc_wstatus(struct proc_handle *phdl) { -- cgit v1.2.3