summaryrefslogtreecommitdiffstats
path: root/usr.bin/truss/setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/truss/setup.c')
-rw-r--r--usr.bin/truss/setup.c220
1 files changed, 117 insertions, 103 deletions
diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c
index a6f8864..698d9f7 100644
--- a/usr.bin/truss/setup.c
+++ b/usr.bin/truss/setup.c
@@ -38,11 +38,12 @@ __FBSDID("$FreeBSD$");
*/
#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/pioctl.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
#include <sys/wait.h>
#include <err.h>
+#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
@@ -51,10 +52,12 @@ __FBSDID("$FreeBSD$");
#include <time.h>
#include <unistd.h>
+#include <machine/reg.h>
+
#include "truss.h"
#include "extern.h"
-static int evflags = 0;
+static int child_pid;
/*
* setup_and_wait() is called to start a process. All it really does
@@ -66,75 +69,28 @@ static int evflags = 0;
int
setup_and_wait(char *command[])
{
- struct procfs_status pfs;
- char buf[32];
- int fd;
int pid;
- int flags;
- int loop;
+ int waitval;
- pid = fork();
+ pid = vfork();
if (pid == -1) {
err(1, "fork failed");
}
if (pid == 0) { /* Child */
- int mask = S_EXEC | S_EXIT;
- fd = open("/proc/curproc/mem", O_WRONLY);
- if (fd == -1)
- err(2, "cannot open /proc/curproc/mem");
- fcntl(fd, F_SETFD, 1);
- if (ioctl(fd, PIOCBIS, mask) == -1)
- err(3, "PIOCBIS");
- flags = PF_LINGER;
- /*
- * The PF_LINGER flag tells procfs not to wake up the
- * process on last close; normally, this is the behaviour
- * we want.
- */
- if (ioctl(fd, PIOCSFL, flags) == -1)
- warn("cannot set PF_LINGER");
+ ptrace(PT_TRACE_ME, 0, 0, 0);
+ setpgid (0, 0);
execvp(command[0], command);
- mask = ~0;
- ioctl(fd, PIOCBIC, ~0);
- err(4, "execvp %s", command[0]);
+ err(1, "execvp %s", command[0]);
}
+
/* Only in the parent here */
-
- if (waitpid(pid, NULL, WNOHANG) != 0) {
- /*
- * Process exited before it got to us -- meaning the exec failed
- * miserably -- so we just quietly exit.
- */
- exit(1);
+ if (waitpid(pid, &waitval, 0) < -1) {
+ err(1, "unexpect stop in waitpid");
+ return 0;
}
- sprintf(buf, "/proc/%d/mem", pid);
-
- /* Try 6 times to trace our child, waiting 1/2 second each time */
- for (loop=6 ;; loop--) {
- if (loop != 6)
- usleep(500000);
- if ((fd = open(buf, O_RDWR)) == -1) {
- if (loop > 0)
- continue;
- else
- err(5, "cannot open1 %s", buf);
- }
- if (ioctl(fd, PIOCWAIT, &pfs) == -1) {
- if (loop >= 0)
- continue;
- else
- err(6, "PIOCWAIT");
- }
- if (pfs.why == S_EXIT) {
- warnx("process exited before exec'ing");
- ioctl(fd, PIOCCONT, 0);
- wait(0);
- exit(7);
- } else
- break;
- }
- close(fd);
+ child_pid = pid;
+
return (pid);
}
@@ -145,45 +101,24 @@ setup_and_wait(char *command[])
*/
int
-start_tracing(int pid, int failisfatal, int eventflags, int flags)
+start_tracing(int pid)
{
- int fd;
- char buf[32];
- struct procfs_status tmp;
-
- sprintf(buf, "/proc/%d/mem", pid);
- /* usleep(500000); */
-
- fd = open(buf, O_RDWR);
- if (fd == -1) {
- /*
- * The process may have run away before we could start -- this
- * happens with SUGID programs. So we need to see if it still
- * exists before we complain bitterly.
- */
- if (!failisfatal && kill(pid, 0) == -1)
- return (-1);
- err(8, "cannot open2 %s", buf);
- }
-
- if (ioctl(fd, PIOCSTATUS, &tmp) == -1) {
- err(10, "cannot get procfs status struct");
- }
- evflags = tmp.events;
-
- if (ioctl(fd, PIOCBIS, eventflags) == -1)
- err(9, "cannot set procfs event bit mask");
-
- /*
- * This clears the PF_LINGER set above in setup_and_wait();
- * if truss happens to die before this, then the process
- * needs to be woken up via procctl.
- */
-
- if (ioctl(fd, PIOCSFL, flags) == -1)
- warn("cannot clear PF_LINGER");
-
- return (fd);
+ int waitval;
+ int ret;
+ int retry = 10;
+
+ do {
+ ret = ptrace(PT_ATTACH, pid, NULL, 0);
+ usleep(200);
+ } while(ret && retry-- > 0);
+ if (ret)
+ err(1, "can not attach to target process");
+
+ child_pid = pid;
+ if (waitpid(pid, &waitval, 0) < -1)
+ err(1, "Unexpect stop in waitpid");
+
+ return (0);
}
/*
@@ -193,10 +128,89 @@ start_tracing(int pid, int failisfatal, int eventflags, int flags)
* process.
*/
void
-restore_proc(int signo __unused) {
+restore_proc(int signo __unused)
+{
+ int waitval;
- ioctl(Procfd, PIOCBIC, ~0);
- if (evflags)
- ioctl(Procfd, PIOCBIS, evflags);
+ /* stop the child so that we can detach */
+ kill(child_pid, SIGSTOP);
+ if (waitpid(child_pid, &waitval, 0) < -1)
+ err(1, "Unexpected stop in waitpid");
+
+ if (ptrace(PT_DETACH, child_pid, (caddr_t)1, 0) < 0)
+ err(1, "Can not detach the process");
+
+ kill(child_pid, SIGCONT);
exit(0);
}
+
+/*
+ * Change curthread member based on lwpid.
+ * If it is a new thread, create a threadinfo structure
+ */
+static void
+find_thread(struct trussinfo *info, lwpid_t lwpid)
+{
+ info->curthread = NULL;
+ struct threadinfo *np;
+ SLIST_FOREACH(np, &info->threadlist, entries) {
+ if (np->tid == lwpid) {
+ info->curthread = np;
+ return;
+ }
+ }
+
+ np = (struct threadinfo *)malloc(sizeof(struct threadinfo));
+ if (np == NULL)
+ errx(1, "malloc() failed");
+ np->tid = lwpid;
+ np->in_fork = 0;
+ np->in_syscall = 0;
+ SLIST_INSERT_HEAD(&info->threadlist, np, entries);
+ info->curthread = np;
+}
+
+/*
+ * Start the traced process and wait until it stoped.
+ * Fill trussinfo structure.
+ * When this even returns, the traced process is in stop state.
+ */
+void
+waitevent(struct trussinfo *info)
+{
+ int waitval;
+ static int pending_signal = 0;
+
+ ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal);
+ pending_signal = 0;
+
+ if (waitpid(info->pid, &waitval, 0) < -1) {
+ err(1, "Unexpected stop in waitpid");
+ }
+
+ if (WIFCONTINUED(waitval)) {
+ info->pr_why = S_NONE;
+ return;
+ }
+ if (WIFEXITED(waitval)) {
+ info->pr_why = S_EXIT;
+ info->pr_data = WEXITSTATUS(waitval);
+ return;
+ }
+ if (WIFSTOPPED(waitval) || (WIFSIGNALED(waitval))) {
+ struct ptrace_lwpinfo lwpinfo;
+ ptrace(PT_LWPINFO, info->pid, (caddr_t)&lwpinfo, sizeof(lwpinfo));
+ find_thread(info, lwpinfo.pl_lwpid);
+ switch(WSTOPSIG(waitval)) {
+ case SIGTRAP:
+ info->pr_why = info->curthread->in_syscall?S_SCX:S_SCE;
+ info->curthread->in_syscall = 1 - info->curthread->in_syscall;
+ break;
+ default:
+ info->pr_why = S_SIG;
+ info->pr_data = WSTOPSIG(waitval);
+ pending_signal = info->pr_data;
+ break;
+ }
+ }
+}
OpenPOWER on IntegriCloud