diff options
author | rpaulo <rpaulo@FreeBSD.org> | 2010-07-31 16:10:20 +0000 |
---|---|---|
committer | rpaulo <rpaulo@FreeBSD.org> | 2010-07-31 16:10:20 +0000 |
commit | a049970caad5cf461ceb13d4b2fcd914b2af24f1 (patch) | |
tree | 30c1af86897f11bb9ea43da0c92ec31dbecd1c50 /lib/libproc/proc_util.c | |
parent | f5ec1d3118207f2f24806692cce1f78fff6d53d3 (diff) | |
download | FreeBSD-src-a049970caad5cf461ceb13d4b2fcd914b2af24f1.zip FreeBSD-src-a049970caad5cf461ceb13d4b2fcd914b2af24f1.tar.gz |
New version of libproc. Changes are:
* breakpoint setup support
* register query
* symbol to address mapping and vice-versa
* more misc utility functions based on their Solaris counterpart
Also, I've written some test cases.
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'lib/libproc/proc_util.c')
-rw-r--r-- | lib/libproc/proc_util.c | 139 |
1 files changed, 113 insertions, 26 deletions
diff --git a/lib/libproc/proc_util.c b/lib/libproc/proc_util.c index 0e7020e..9a53977 100644 --- a/lib/libproc/proc_util.c +++ b/lib/libproc/proc_util.c @@ -1,6 +1,10 @@ /*- + * Copyright (c) 2010 The FreeBSD Foundation * Copyright (c) 2008 John Birrell (jb@freebsd.org) * All rights reserved. + * + * Portions of this software were developed by Rui Paulo under sponsorship + * from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,16 +30,21 @@ * $FreeBSD$ */ -#include "_libproc.h" -#include <errno.h> -#include <unistd.h> +#include <sys/types.h> #include <sys/ptrace.h> #include <sys/wait.h> +#include <err.h> +#include <errno.h> +#include <unistd.h> #include <stdio.h> +#include <signal.h> +#include <string.h> +#include "_libproc.h" int proc_clearflags(struct proc_handle *phdl, int mask) { + if (phdl == NULL) return (EINVAL); @@ -44,14 +53,18 @@ proc_clearflags(struct proc_handle *phdl, int mask) return (0); } +/* + * NB: we return -1 as the Solaris libproc Psetrun() function. + */ int proc_continue(struct proc_handle *phdl) { + if (phdl == NULL) - return (EINVAL); + return (-1); if (ptrace(PT_CONTINUE, phdl->pid, (caddr_t)(uintptr_t) 1, 0) != 0) - return (errno); + return (-1); phdl->status = PS_RUN; @@ -59,13 +72,25 @@ proc_continue(struct proc_handle *phdl) } int -proc_detach(struct proc_handle *phdl) +proc_detach(struct proc_handle *phdl, int reason) { + int status; + if (phdl == NULL) return (EINVAL); - - if (ptrace(PT_DETACH, phdl->pid, 0, 0) != 0) - return (errno); + if (reason == PRELEASE_KILL) { + kill(phdl->pid, SIGKILL); + return (0); + } + if (ptrace(PT_DETACH, phdl->pid, 0, 0) != 0 && errno == ESRCH) + return (0); + if (errno == EBUSY) { + kill(phdl->pid, SIGSTOP); + waitpid(phdl->pid, &status, WUNTRACED); + ptrace(PT_DETACH, phdl->pid, 0, 0); + kill(phdl->pid, SIGCONT); + return (0); + } return (0); } @@ -73,6 +98,7 @@ proc_detach(struct proc_handle *phdl) int proc_getflags(struct proc_handle *phdl) { + if (phdl == NULL) return (-1); @@ -82,6 +108,7 @@ proc_getflags(struct proc_handle *phdl) int proc_setflags(struct proc_handle *phdl, int mask) { + if (phdl == NULL) return (EINVAL); @@ -93,41 +120,101 @@ proc_setflags(struct proc_handle *phdl, int mask) int proc_state(struct proc_handle *phdl) { + if (phdl == NULL) return (-1); return (phdl->status); } -int -proc_wait(struct proc_handle *phdl) +pid_t +proc_getpid(struct proc_handle *phdl) { - int status = 0; - struct kevent kev; if (phdl == NULL) - return (EINVAL); + return (-1); - if (kevent(phdl->kq, NULL, 0, &kev, 1, NULL) <= 0) - return (0); + return (phdl->pid); +} - switch (kev.filter) { - /* Child has exited */ - case EVFILT_PROC: /* target has exited */ +int +proc_wstatus(struct proc_handle *phdl) +{ + int status; + + if (phdl == NULL) + return (-1); + if (waitpid(phdl->pid, &status, WUNTRACED) < 0) + return (-1); + if (WIFSTOPPED(status)) + phdl->status = PS_STOP; + if (WIFEXITED(status) || WIFSIGNALED(status)) phdl->status = PS_UNDEAD; - break; - default: - break; - } + phdl->wstat = status; return (status); } -pid_t -proc_getpid(struct proc_handle *phdl) +int +proc_getwstat(struct proc_handle *phdl) { + if (phdl == NULL) return (-1); - return (phdl->pid); + return (phdl->wstat); +} + +char * +proc_signame(int sig, char *name, size_t namesz) +{ + + strlcpy(name, strsignal(sig), namesz); + + return (name); +} + +int +proc_read(struct proc_handle *phdl, char *buf, size_t size, size_t addr) +{ + struct ptrace_io_desc piod; + + if (phdl == NULL) + return (-1); + piod.piod_op = PIOD_READ_D; + piod.piod_len = size; + piod.piod_addr = (void *)buf; + piod.piod_offs = (void *)addr; + + if (ptrace(PT_IO, phdl->pid, (caddr_t)&piod, 0) < 0) + return (-1); + return (piod.piod_len); +} + +const lwpstatus_t * +proc_getlwpstatus(struct proc_handle *phdl) +{ + struct ptrace_lwpinfo lwpinfo; + lwpstatus_t *psp = &phdl->lwps; + siginfo_t *siginfo; + + if (phdl == NULL) + return (NULL); + if (ptrace(PT_LWPINFO, phdl->pid, (caddr_t)&lwpinfo,sizeof(lwpinfo)) < 0) + return (NULL); + siginfo = &lwpinfo.pl_siginfo; + if (lwpinfo.pl_event == PL_EVENT_SIGNAL && + (lwpinfo.pl_flags & PL_FLAG_SI) && + siginfo->si_signo == SIGTRAP && + (siginfo->si_code == TRAP_BRKPT || + siginfo->si_code == TRAP_TRACE)) { + psp->pr_why = PR_FAULTED; + psp->pr_what = FLTBPT; + } else if (lwpinfo.pl_flags & PL_FLAG_SCE) { + psp->pr_why = PR_SYSENTRY; + } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { + psp->pr_why = PR_SYSEXIT; + } + + return (psp); } |