Changeset View
Standalone View
usr.bin/truss/setup.c
Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "truss.h" | #include "truss.h" | ||||
#include "syscall.h" | #include "syscall.h" | ||||
#include "extern.h" | #include "extern.h" | ||||
SET_DECLARE(procabi, struct procabi); | SET_DECLARE(procabi, struct procabi); | ||||
static sig_atomic_t detaching; | static sig_atomic_t detaching, alarm_tripped; | ||||
jhb: Can probably merge these two declarations to declare both on a single line. | |||||
static void enter_syscall(struct trussinfo *, struct threadinfo *, | static void enter_syscall(struct trussinfo *, struct threadinfo *, | ||||
struct ptrace_lwpinfo *); | struct ptrace_lwpinfo *); | ||||
static void new_proc(struct trussinfo *, pid_t, lwpid_t); | static void new_proc(struct trussinfo *, pid_t, lwpid_t); | ||||
/* | /* | ||||
* setup_and_wait() is called to start a process. All it really does | * setup_and_wait() is called to start a process. All it really does | ||||
* is fork(), enable tracing in the child, and then exec the given | * is fork(), enable tracing in the child, and then exec the given | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | detach_proc(pid_t pid) | ||||
if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) | if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) | ||||
err(1, "Can not detach the process"); | err(1, "Can not detach the process"); | ||||
kill(pid, SIGCONT); | kill(pid, SIGCONT); | ||||
} | } | ||||
/* | /* | ||||
* A signal handler so we can break out of wait after a timeout. | |||||
*/ | |||||
static void | |||||
trap_alarm(int signo __unused) | |||||
Done Inline ActionsI would still add the underscore as most other functions in this file use an underscore between words. jhb: I would still add the underscore as most other functions in this file use an underscore between… | |||||
Not Done Inline ActionsHeh. I didn't even notice the underscore in your suggestion. I just saw the spelling change. dnelson_1901_yahoo.com: Heh. I didn't even notice the underscore in your suggestion. I just saw the spelling change. | |||||
{ | |||||
alarm_tripped = 1; | |||||
Done Inline ActionsMore reliable would be to have a global 'sig_atomic_t alarm_tripped' that this set to 1 and checking that in the loop below so that you really know that SIGALRM fired vs some other signal. Also, I think you can just spell out 'trap_alarm' jhb: More reliable would be to have a global 'sig_atomic_t alarm_tripped' that this set to 1 and… | |||||
} | |||||
static bool | |||||
set_alarm(struct trussinfo *info) | |||||
{ | |||||
struct procinfo *p; | |||||
struct threadinfo *t; | |||||
LIST_FOREACH(p, &info->proclist, entries) { | |||||
LIST_FOREACH(t, &p->threadlist, entries) { | |||||
Done Inline ActionsBlank line after the 'struct procinfo *p' line. jhb: Blank line after the 'struct procinfo *p' line. | |||||
if (t->in_syscall) { | |||||
Done Inline ActionsThe prevailing style is to declare all the locals in one block at the start of the function, especially for a small function such as this. jhb: The prevailing style is to declare all the locals in one block at the start of the function… | |||||
alarm(info->timeout); | |||||
alarm_tripped = 0; | |||||
return (true); | |||||
} | |||||
Not Done Inline ActionsA curious affect of this will be that it will print out incorrect times once the syscall actually completes. I would perhaps explicitly save the old value of 't->after' and restore it after calling print_syscall(). jhb: A curious affect of this will be that it will print out incorrect times once the syscall… | |||||
Not Done Inline ActionsEverywhere else, 't->after' is updated before use, so I think computing an "interim" value before the syscall completes should be safe. dnelson_1901_yahoo.com: Everywhere else, 't->after' is updated before use, so I think computing an "interim" value… | |||||
Not Done Inline ActionsAh, ok. jhb: Ah, ok. | |||||
} | |||||
} | |||||
return (false); | |||||
} | |||||
/* | |||||
* Prints names and arguments of any threads currently in a syscall. | |||||
*/ | |||||
static void | |||||
print_sleeping_threads(struct trussinfo *info) | |||||
{ | |||||
struct procinfo *p; | |||||
struct threadinfo *t; | |||||
LIST_FOREACH(p, &info->proclist, entries) { | |||||
LIST_FOREACH(t, &p->threadlist, entries) { | |||||
if (t->in_syscall) { | |||||
info->curthread = t; | |||||
if (info->flags & (RELATIVETIMESTAMPS | | |||||
ABSOLUTETIMESTAMPS)) | |||||
clock_gettime(CLOCK_REALTIME, | |||||
&t->after); | |||||
print_syscall(info); | |||||
fprintf(info->outfile, " <in progress>\n"); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
/* | |||||
* Determine the ABI. This is called after every exec, and when | * Determine the ABI. This is called after every exec, and when | ||||
* a process is first monitored. | * a process is first monitored. | ||||
*/ | */ | ||||
static struct procabi * | static struct procabi * | ||||
find_abi(pid_t pid) | find_abi(pid_t pid) | ||||
{ | { | ||||
struct procabi **pabi; | struct procabi **pabi; | ||||
size_t len; | size_t len; | ||||
▲ Show 20 Lines • Show All 322 Lines • ▼ Show 20 Lines | if (sc->args[i].type & OUT) { | ||||
} else { | } else { | ||||
temp = print_arg(&sc->args[i], | temp = print_arg(&sc->args[i], | ||||
t->cs.args, retval, info); | t->cs.args, retval, info); | ||||
} | } | ||||
t->cs.s_args[i] = temp; | t->cs.s_args[i] = temp; | ||||
} | } | ||||
} | } | ||||
t->in_syscall = 0; | |||||
print_syscall_ret(info, errorp, retval); | print_syscall_ret(info, errorp, retval); | ||||
free_syscall(t); | free_syscall(t); | ||||
/* | /* | ||||
* If the process executed a new image, check the ABI. If the | * If the process executed a new image, check the ABI. If the | ||||
* new ABI isn't supported, stop tracing this process. | * new ABI isn't supported, stop tracing this process. | ||||
*/ | */ | ||||
if (pl->pl_flags & PL_FLAG_EXEC) { | if (pl->pl_flags & PL_FLAG_EXEC) { | ||||
▲ Show 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | |||||
* asked to stop. | * asked to stop. | ||||
*/ | */ | ||||
void | void | ||||
eventloop(struct trussinfo *info) | eventloop(struct trussinfo *info) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
siginfo_t si; | siginfo_t si; | ||||
int pending_signal; | int pending_signal; | ||||
bool alarm_set = false; | |||||
signal(SIGALRM, trap_alarm); | |||||
siginterrupt(SIGALRM, 1); | |||||
while (!LIST_EMPTY(&info->proclist)) { | while (!LIST_EMPTY(&info->proclist)) { | ||||
if (detaching) { | if (detaching) { | ||||
detach_all_procs(info); | detach_all_procs(info); | ||||
return; | return; | ||||
} | } | ||||
if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) { | if (info->timeout) | ||||
if (errno == EINTR) | alarm_set = set_alarm(info); | ||||
while (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) { | |||||
if (errno == EINTR) { | |||||
if (detaching) | |||||
break; | |||||
if (info->timeout && alarm_tripped) { | |||||
/* | |||||
* The timer interrupted us, so we | |||||
* must be waiting on slow syscalls. | |||||
* Print their names and continue | |||||
* waiting, this time forever. | |||||
*/ | |||||
print_sleeping_threads(info); | |||||
fflush(info->outfile); | |||||
alarm(0); | |||||
alarm_set = false; | |||||
} | |||||
Done Inline ActionsI would stop once you find a single thread in a syscall. It might be simplest to actually do this in a helper function: static bool set_alarm(struct trussing *info) { struct procinfo *p; struct threadinfo *t; LIST_FOREACH(p, &info->proclist, entries) { LIST_FOREACH(t, &p->threadlist, entries) { if (t->in_syscall) { alarm(2); return (true); } } } return (false); } I would then use it like so; alarm_set = set_alarm(info); while (waitid(....) == -1) { if (errno == EINTR) { ... if (alarm_triggered) { print_sleeping_threads(info); alarm(0); alarm_set = false; } ... } if (alarm_set) alarm(0); jhb: I would stop once you find a single thread in a syscall. It might be simplest to actually do… | |||||
continue; | continue; | ||||
} | |||||
err(1, "Unexpected error from waitid"); | err(1, "Unexpected error from waitid"); | ||||
} | } | ||||
if (detaching) | |||||
continue; | |||||
if (alarm_set) | |||||
alarm(0); | |||||
assert(si.si_signo == SIGCHLD); | assert(si.si_signo == SIGCHLD); | ||||
switch (si.si_code) { | switch (si.si_code) { | ||||
case CLD_EXITED: | case CLD_EXITED: | ||||
case CLD_KILLED: | case CLD_KILLED: | ||||
case CLD_DUMPED: | case CLD_DUMPED: | ||||
find_exit_thread(info, si.si_pid); | find_exit_thread(info, si.si_pid); | ||||
▲ Show 20 Lines • Show All 57 Lines • Show Last 20 Lines |
Can probably merge these two declarations to declare both on a single line.