diff options
-rw-r--r-- | breakpoints.c | 21 | ||||
-rw-r--r-- | debug.c | 7 | ||||
-rw-r--r-- | debug.h | 28 | ||||
-rw-r--r-- | demangle.c | 3 | ||||
-rw-r--r-- | dict.c | 25 | ||||
-rw-r--r-- | elf.c | 7 | ||||
-rw-r--r-- | ltrace.1 | 21 | ||||
-rw-r--r-- | options.c | 14 | ||||
-rw-r--r-- | process_event.c | 46 | ||||
-rw-r--r-- | sysdeps/linux-gnu/breakpoint.c | 22 | ||||
-rw-r--r-- | sysdeps/linux-gnu/events.c | 22 | ||||
-rw-r--r-- | sysdeps/linux-gnu/trace.c | 10 |
12 files changed, 177 insertions, 49 deletions
diff --git a/breakpoints.c b/breakpoints.c index 968d1f1..7112d49 100644 --- a/breakpoints.c +++ b/breakpoints.c @@ -20,6 +20,7 @@ Breakpoint * address2bpstruct(Process *proc, void *addr) { + debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr); return dict_find_entry(proc->breakpoints, addr); } @@ -27,6 +28,8 @@ void insert_breakpoint(Process *proc, void *addr, struct library_symbol *libsym) { Breakpoint *sbp; + + debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)", proc->pid, addr, libsym ? libsym->name : "NULL"); debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr); if (!addr) @@ -56,7 +59,11 @@ insert_breakpoint(Process *proc, void *addr, void delete_breakpoint(Process *proc, void *addr) { - Breakpoint *sbp = dict_find_entry(proc->breakpoints, addr); + Breakpoint *sbp; + + debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); + + sbp = dict_find_entry(proc->breakpoints, addr); assert(sbp); /* FIXME: remove after debugging has been done. */ /* This should only happen on out-of-memory conditions. */ if (sbp == NULL) @@ -70,6 +77,7 @@ delete_breakpoint(Process *proc, void *addr) { static void enable_bp_cb(void *addr, void *sbp, void *proc) { + debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid); if (((Breakpoint *)sbp)->enabled) { enable_breakpoint(((Process *)proc)->pid, sbp); } @@ -77,6 +85,7 @@ enable_bp_cb(void *addr, void *sbp, void *proc) { void enable_all_breakpoints(Process *proc) { + debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid); if (proc->breakpoints_enabled <= 0) { #ifdef __powerpc__ unsigned long a; @@ -133,6 +142,7 @@ enable_all_breakpoints(Process *proc) { static void disable_bp_cb(void *addr, void *sbp, void *proc) { + debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid); if (((Breakpoint *)sbp)->enabled) { disable_breakpoint(((Process *)proc)->pid, sbp); } @@ -140,6 +150,7 @@ disable_bp_cb(void *addr, void *sbp, void *proc) { void disable_all_breakpoints(Process *proc) { + debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid); if (proc->breakpoints_enabled) { debug(1, "Disabling breakpoints for pid %u...", proc->pid); dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); @@ -149,6 +160,7 @@ disable_all_breakpoints(Process *proc) { static void free_bp_cb(void *addr, void *sbp, void *data) { + debug(DEBUG_FUNCTION, "free_bp_cb(sbp=%p)", sbp); assert(sbp); free(sbp); } @@ -157,6 +169,7 @@ void breakpoints_init(Process *proc) { struct library_symbol *sym; + debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); if (proc->breakpoints) { /* let's remove that struct */ dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL); dict_clear(proc->breakpoints); @@ -198,7 +211,11 @@ breakpoints_init(Process *proc) { void reinitialize_breakpoints(Process *proc) { - struct library_symbol *sym = proc->list_of_symbols; + struct library_symbol *sym; + + debug(DEBUG_FUNCTION, "reinitialize_breakpoints(pid=%d)", proc->pid); + + sym = proc->list_of_symbols; while (sym) { if (sym->needs_init) { @@ -6,19 +6,18 @@ #include "output.h" void -debug_(int level, const char *file, int line, const char *func, - const char *fmt, ...) { +debug_(int level, const char *file, int line, const char *fmt, ...) { char buf[1024]; va_list args; - if (options.debug < level) { + if (!(options.debug & level)) { return; } va_start(args, fmt); vsnprintf(buf, 1024, fmt, args); va_end(args); - output_line(NULL, "DEBUG: %s:%d: %s(): %s", file, line, func, buf); + output_line(NULL, "DEBUG: %s:%d: %s", file, line, buf); } // The following section provides a way to print things, like hex dumps, @@ -1,23 +1,17 @@ #include <features.h> -void debug_(int level, const char *file, int line, const char *func, - const char *fmt, ...) __attribute__((format(printf,5,6))); +/* debug levels: + */ +enum { + DEBUG_EVENT = 0x10, + DEBUG_PROCESS = 0x20, + DEBUG_FUNCTION = 0x40 +}; + +void debug_(int level, const char *file, int line, + const char *fmt, ...) __attribute__((format(printf,4,5))); int xinfdump(long, void *, int); -# define debug(level, expr...) debug_(level, __FILE__, __LINE__, DEBUG_FUNCTION, expr) +# define debug(level, expr...) debug_(level, __FILE__, __LINE__, expr) -/* Version 2.4 and later of GCC define a magical variable `__PRETTY_FUNCTION__' - which contains the name of the function currently being defined. - This is broken in G++ before version 2.6. - C9x has a similar variable called __func__, but prefer the GCC one since - it demangles C++ function names. */ -# if __GNUC_PREREQ (2, 4) -# define DEBUG_FUNCTION __PRETTY_FUNCTION__ -# else -# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L -# define DEBUG_FUNCTION __func__ -# else -# define DEBUG_FUNCTION "???" -# endif -# endif @@ -9,6 +9,7 @@ #include "options.h" #include "output.h" #include "demangle.h" +#include "debug.h" #include "dict.h" @@ -26,6 +27,8 @@ my_demangle(const char *function_name) { int status = 0; #endif + debug(DEBUG_FUNCTION, "my_demangle(name=%s)", function_name); + if (!d) d = dict_init(dict_key2hash_string, dict_key_cmp_string); @@ -36,6 +36,8 @@ dict_init(unsigned int (*key2hash) (void *), struct dict *d; int i; + debug(DEBUG_FUNCTION, "dict_init()"); + d = malloc(sizeof(struct dict)); if (!d) { perror("malloc()"); @@ -54,6 +56,7 @@ dict_clear(struct dict *d) { int i; struct dict_entry *entry, *nextentry; + debug(DEBUG_FUNCTION, "dict_clear()"); assert(d); for (i = 0; i < DICTTABLESIZE; i++) { for (entry = d->buckets[i]; entry != NULL; entry = nextentry) { @@ -68,8 +71,13 @@ dict_clear(struct dict *d) { int dict_enter(struct dict *d, void *key, void *value) { struct dict_entry *entry, *newentry; - unsigned int hash = d->key2hash(key); - unsigned int bucketpos = hash % DICTTABLESIZE; + unsigned int hash; + unsigned int bucketpos; + + debug(DEBUG_FUNCTION, "dict_enter()"); + + hash = d->key2hash(key); + bucketpos = hash % DICTTABLESIZE; assert(d); newentry = malloc(sizeof(struct dict_entry)); @@ -98,10 +106,15 @@ dict_enter(struct dict *d, void *key, void *value) { void * dict_find_entry(struct dict *d, void *key) { - unsigned int hash = d->key2hash(key); - unsigned int bucketpos = hash % DICTTABLESIZE; + unsigned int hash; + unsigned int bucketpos; struct dict_entry *entry; + debug(DEBUG_FUNCTION, "dict_find_entry()"); + + hash = d->key2hash(key); + bucketpos = hash % DICTTABLESIZE; + assert(d); for (entry = d->buckets[bucketpos]; entry; entry = entry->next) { if (hash != entry->hash) { @@ -119,6 +132,8 @@ dict_apply_to_all(struct dict *d, void (*func) (void *key, void *value, void *data), void *data) { int i; + debug(DEBUG_FUNCTION, "dict_apply_to_all()"); + if (!d) { return; } @@ -171,6 +186,8 @@ dict_clone(struct dict *old, void * (*key_clone)(void*), void * (*value_clone)(v struct dict *d; int i; + debug(DEBUG_FUNCTION, "dict_clone()"); + d = malloc(sizeof(struct dict)); if (!d) { perror("malloc()"); @@ -35,6 +35,7 @@ do_init_elf(struct ltelf *lte, const char *filename) { GElf_Addr relplt_addr = 0; size_t relplt_size = 0; + debug(DEBUG_FUNCTION, "do_init_elf(filename=%s)", filename); debug(1, "Reading ELF from %s...", filename); memset(lte, 0, sizeof(*lte)); @@ -320,6 +321,7 @@ do_init_elf(struct ltelf *lte, const char *filename) { static void do_close_elf(struct ltelf *lte) { + debug(DEBUG_FUNCTION, "do_close_elf()"); if (lte->lte_flags & LTE_HASH_MALLOCED) free((char *)lte->hash); elf_end(lte->elf); @@ -331,6 +333,9 @@ add_library_symbol(GElf_Addr addr, const char *name, struct library_symbol **library_symbolspp, enum toplt type_of_plt, int is_weak) { struct library_symbol *s; + + debug(DEBUG_FUNCTION, "add_library_symbol()"); + s = malloc(sizeof(struct library_symbol) + strlen(name) + 1); if (s == NULL) error(EXIT_FAILURE, errno, "add_library_symbol failed"); @@ -460,6 +465,8 @@ read_elf(Process *proc) { struct library_symbol **lib_tail = NULL; int exit_out = 0; + debug(DEBUG_FUNCTION, "read_elf(file=%s)", proc->filename); + elf_version(EV_CURRENT); do_init_elf(lte, proc->filename); @@ -6,7 +6,7 @@ ltrace \- A library call tracer .SH SYNOPSIS .B ltrace -.I "[-CdfhiLrStttV] [-a column] [-A maxelts] [-e expr] [-l filename] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-X extern] [-x extern] ... [--align=column] [--debug] [--demangle] [--help] [--indent=nr] [--library=filename] [--output=filename] [--version] [command [arg ...]]" +.I "[-CfhiLrStttV] [-a column] [-A maxelts] [-d level] [-e expr] [-l filename] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-X extern] [-x extern] ... [--align=column] [--debug=level] [--demangle] [--help] [--indent=nr] [--library=filename] [--output=filename] [--version] [command [arg ...]]" .SH DESCRIPTION .B ltrace @@ -36,11 +36,20 @@ Decode (demangle) low-level symbol names into user-level names. Besides removing any initial underscore prefix used by the system, this makes C++ function names readable. .TP -.I \-d, \-\-debug -Increase the debugging level. -Use more (ie. -.I \-dd -) for greater debugging information. +.I \-d, \-\-debug level +Show debugging output of +.B ltrace +itself. +.I level +must be a sum of some of the following numbers: +.RS +.TP +.B 0x10 +DEBUG_EVENT. Shows every event received by a traced program +.TP +.B 0x20 +DEBUG_PROCESS. Shows every action carried out in a traced program +.RE .TP .I \-e expr A qualifying expression which modifies which events to trace. @@ -93,9 +93,9 @@ usage(void) { # endif # endif # if HAVE_GETOPT_LONG - " -d, --debug print debugging info.\n" + " -d, --debug=LEVEL print debugging info.\n" # else - " -d print debugging info.\n" + " -d LEVEL print debugging info.\n" # endif " -e expr modify which events to trace.\n" " -f trace children (fork() and clone()).\n" @@ -226,18 +226,18 @@ process_options(int argc, char **argv) { {"version", 0, 0, 'V'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "+cdfhiLrStTV" + c = getopt_long(argc, argv, "+cfhiLrStTV" # ifdef USE_DEMANGLE "C" # endif - "a:A:e:F:l:n:o:p:s:u:x:X:", long_options, + "a:A:d:e:F:l:n:o:p:s:u:x:X:", long_options, &option_index); #else - c = getopt(argc, argv, "+cdfhiLrStTV" + c = getopt(argc, argv, "+cfhiLrStTV" # ifdef USE_DEMANGLE "C" # endif - "a:A:e:F:l:n:o:p:s:u:x:X:"); + "a:A:d:e:F:l:n:o:p:s:u:x:X:"); #endif if (c == -1) { break; @@ -258,7 +258,7 @@ process_options(int argc, char **argv) { break; #endif case 'd': - options.debug++; + options.debug = strtoul(optarg,NULL,0); break; case 'e': { diff --git a/process_event.c b/process_event.c index d15d8f7..94ecaac 100644 --- a/process_event.c +++ b/process_event.c @@ -40,11 +40,13 @@ static void callstack_pop(Process *proc); /* TODO */ void * address_clone(void * addr) { + debug(DEBUG_FUNCTION, "address_clone(%p)", addr); return addr; } void * breakpoint_clone(void * bp) { Breakpoint * b; + debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp); b = malloc(sizeof(Breakpoint)); if (!b) { perror("malloc()"); @@ -63,7 +65,11 @@ static Pending_New * pending_news = NULL; static int pending_new(pid_t pid) { - Pending_New * p = pending_news; + Pending_New * p; + + debug(DEBUG_FUNCTION, "pending_new(%d)", pid); + + p = pending_news; while (p) { if (p->pid == pid) { return 1; @@ -75,7 +81,11 @@ pending_new(pid_t pid) { static void pending_new_insert(pid_t pid) { - Pending_New * p = malloc(sizeof(Pending_New)); + Pending_New * p; + + debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid); + + p = malloc(sizeof(Pending_New)); if (!p) { perror("malloc()"); exit(1); @@ -89,6 +99,8 @@ static void pending_new_remove(pid_t pid) { Pending_New *p, *pred; + debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid); + p = pending_news; if (p->pid == pid) { pending_news = p->next; @@ -109,6 +121,8 @@ static void process_clone(Event * event) { Process *p; + debug(DEBUG_FUNCTION, "process_clone(pid=%d)", event->proc->pid); + p = malloc(sizeof(Process)); if (!p) { perror("malloc()"); @@ -136,7 +150,11 @@ process_clone(Event * event) { static void process_new(Event * event) { - Process * proc = pid2proc(event->e_un.newpid); + Process * proc; + + debug(DEBUG_FUNCTION, "process_new(pid=%d)", event->e_un.newpid); + + proc = pid2proc(event->e_un.newpid); if (!proc) { pending_new_insert(event->e_un.newpid); } else { @@ -163,6 +181,8 @@ shortsignal(Process *proc, int signum) { sizeof signalent1 / sizeof signalent1[0] }; + debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum); + if (proc->personality > sizeof signalents / sizeof signalents[0]) abort(); if (signum < 0 || signum >= nsignals[proc->personality]) { @@ -186,6 +206,8 @@ sysname(Process *proc, int sysnum) { sizeof syscalent1 / sizeof syscalent1[0] }; + debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum); + if (proc->personality > sizeof syscalents / sizeof syscalents[0]) abort(); if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) { @@ -206,6 +228,8 @@ arch_sysname(Process *proc, int sysnum) { }; int nsyscals = sizeof arch_syscalent / sizeof arch_syscalent[0]; + debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum); + if (sysnum < 0 || sysnum >= nsyscals) { sprintf(result, "ARCH_%d", sysnum); return result; @@ -218,6 +242,7 @@ arch_sysname(Process *proc, int sysnum) { void process_event(Event *event) { + debug(DEBUG_FUNCTION, "process_event(pid=%d, type=%d)", event->proc ? event->proc->pid : -1, event->type); switch (event->type) { case EVENT_NONE: debug(1, "event: none"); @@ -286,6 +311,7 @@ process_event(Event *event) { static void process_signal(Event *event) { + debug(DEBUG_FUNCTION, "process_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum); if (exiting && event->e_un.signum == SIGSTOP) { pid_t pid = event->proc->pid; disable_all_breakpoints(event->proc); @@ -301,6 +327,7 @@ process_signal(Event *event) { static void process_exit(Event *event) { + debug(DEBUG_FUNCTION, "process_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val); output_line(event->proc, "+++ exited (status %d) +++", event->e_un.ret_val); remove_proc(event->proc); @@ -308,6 +335,7 @@ process_exit(Event *event) { static void process_exit_signal(Event *event) { + debug(DEBUG_FUNCTION, "process_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum); output_line(event->proc, "+++ killed by %s +++", shortsignal(event->proc, event->e_un.signum)); remove_proc(event->proc); @@ -317,7 +345,7 @@ static void remove_proc(Process *proc) { Process *tmp, *tmp2; - debug(1, "Removing pid %u\n", proc->pid); + debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid); if (list_of_processes == proc) { tmp = list_of_processes; @@ -339,6 +367,7 @@ remove_proc(Process *proc) { static void process_syscall(Event *event) { + debug(DEBUG_FUNCTION, "process_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); if (options.syscalls) { output_left(LT_TOF_SYSCALL, event->proc, sysname(event->proc, event->e_un.sysnum)); @@ -352,12 +381,14 @@ process_syscall(Event *event) { static void process_exec(Event * event) { + debug(DEBUG_FUNCTION, "process_exec(pid=%d)", event->proc->pid); output_line(event->proc, "--- exec() ---"); abort(); } static void process_arch_syscall(Event *event) { + debug(DEBUG_FUNCTION, "process_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); if (options.syscalls) { output_left(LT_TOF_SYSCALL, event->proc, arch_sysname(event->proc, event->e_un.sysnum)); @@ -378,6 +409,7 @@ calc_time_spent(Process *proc) { struct timeval diff; struct callstack_element *elem; + debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid); elem = &proc->callstack[proc->callstack_depth - 1]; gettimeofday(&tv, &tz); @@ -394,6 +426,7 @@ calc_time_spent(Process *proc) { static void process_sysret(Event *event) { + debug(DEBUG_FUNCTION, "process_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); if (opt_T || options.summary) { calc_time_spent(event->proc); } @@ -407,6 +440,7 @@ process_sysret(Event *event) { static void process_arch_sysret(Event *event) { + debug(DEBUG_FUNCTION, "process_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); if (opt_T || options.summary) { calc_time_spent(event->proc); } @@ -423,6 +457,7 @@ process_breakpoint(Event *event) { int i, j; Breakpoint *sbp; + debug(DEBUG_FUNCTION, "process_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr); debug(2, "event: breakpoint (%p)", event->e_un.brk_addr); #ifdef __powerpc__ @@ -552,6 +587,7 @@ static void callstack_push_syscall(Process *proc, int sysnum) { struct callstack_element *elem; + debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum); /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ if (proc->callstack_depth == MAX_CALLDEPTH - 1) { fprintf(stderr, "Error: call nesting too deep!\n"); @@ -574,6 +610,7 @@ static void callstack_push_symfunc(Process *proc, struct library_symbol *sym) { struct callstack_element *elem; + debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name); /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ if (proc->callstack_depth == MAX_CALLDEPTH - 1) { fprintf(stderr, "Error: call nesting too deep!\n"); @@ -601,6 +638,7 @@ callstack_pop(Process *proc) { struct callstack_element *elem; assert(proc->callstack_depth > 0); + debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid); elem = &proc->callstack[proc->callstack_depth - 1]; if (!elem->is_syscall && elem->return_addr) { delete_breakpoint(proc, elem->return_addr); diff --git a/sysdeps/linux-gnu/breakpoint.c b/sysdeps/linux-gnu/breakpoint.c index 5a56bd3..64b70e4 100644 --- a/sysdeps/linux-gnu/breakpoint.c +++ b/sysdeps/linux-gnu/breakpoint.c @@ -15,6 +15,11 @@ static unsigned char break_insn[] = BREAKPOINT_VALUE; extern void arch_enable_breakpoint(pid_t, Breakpoint *); void enable_breakpoint(pid_t pid, Breakpoint *sbp) { + if (sbp->libsym) { + debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); + } else { + debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); + } arch_enable_breakpoint(pid, sbp); } #else @@ -22,7 +27,11 @@ void enable_breakpoint(pid_t pid, Breakpoint *sbp) { unsigned int i, j; - debug(1, "enable_breakpoint(%d,%p)", pid, sbp->addr); + if (sbp->libsym) { + debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); + } else { + debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); + } for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) { long a = @@ -45,6 +54,11 @@ enable_breakpoint(pid_t pid, Breakpoint *sbp) { extern void arch_disable_breakpoint(pid_t, const Breakpoint *sbp); void disable_breakpoint(pid_t pid, const Breakpoint *sbp) { + if (sbp->libsym) { + debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); + } else { + debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); + } arch_disable_breakpoint(pid, sbp); } #else @@ -52,7 +66,11 @@ void disable_breakpoint(pid_t pid, const Breakpoint *sbp) { unsigned int i, j; - debug(2, "disable_breakpoint(%d,%p)", pid, sbp->addr); + if (sbp->libsym) { + debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); + } else { + debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); + } for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) { long a = diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c index dfb8284..6dedcc9 100644 --- a/sysdeps/linux-gnu/events.c +++ b/sysdeps/linux-gnu/events.c @@ -25,17 +25,18 @@ next_event(void) { int tmp; int stop_signal; + debug(DEBUG_FUNCTION, "next_event()"); if (!list_of_processes) { - debug(1, "No more children"); + debug(DEBUG_EVENT, "event: No more traced programs: exiting"); exit(0); } pid = wait(&status); if (pid == -1) { if (errno == ECHILD) { - debug(1, "No more children"); + debug(DEBUG_EVENT, "event: No more traced programs: exiting"); exit(0); } else if (errno == EINTR) { - debug(1, "wait received EINTR ?"); + debug(DEBUG_EVENT, "event: none (wait received EINTR?)"); event.type = EVENT_NONE; return &event; } @@ -45,6 +46,7 @@ next_event(void) { event.proc = pid2proc(pid); if (!event.proc) { event.type = EVENT_NEW; + debug(DEBUG_EVENT, "event: NEW: pid=%d", pid); return &event; } get_arch_dep(event.proc); @@ -55,6 +57,7 @@ next_event(void) { event.type = EVENT_NONE; trace_set_options(event.proc, event.proc->pid); continue_process(event.proc->pid); + debug(DEBUG_EVENT, "event: NONE: pid=%d (enabling breakpoints)", pid); return &event; } if (opt_i) { @@ -65,22 +68,27 @@ next_event(void) { case 1: event.type = EVENT_SYSCALL; event.e_un.sysnum = tmp; + debug(DEBUG_EVENT, "event: SYSCALL: pid=%d, sysnum=%d", pid, tmp); return &event; case 2: event.type = EVENT_SYSRET; event.e_un.sysnum = tmp; + debug(DEBUG_EVENT, "event: SYSRET: pid=%d, sysnum=%d", pid, tmp); return &event; case 3: event.type = EVENT_ARCH_SYSCALL; event.e_un.sysnum = tmp; + debug(DEBUG_EVENT, "event: ARCH_SYSCALL: pid=%d, sysnum=%d", pid, tmp); return &event; case 4: event.type = EVENT_ARCH_SYSRET; event.e_un.sysnum = tmp; + debug(DEBUG_EVENT, "event: ARCH_SYSRET: pid=%d, sysnum=%d", pid, tmp); return &event; case -1: event.type = EVENT_NONE; continue_process(event.proc->pid); + debug(DEBUG_EVENT, "event: NONE: pid=%d (syscall_p returned -1)", pid); return &event; } if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) { @@ -88,24 +96,29 @@ next_event(void) { ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data); event.type = EVENT_CLONE; event.e_un.newpid = data; + debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", pid, (int)data); return &event; } if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) { event.type = EVENT_EXEC; + debug(DEBUG_EVENT, "event: EXEC: pid=%d", pid); return &event; } if (WIFEXITED(status)) { event.type = EVENT_EXIT; event.e_un.ret_val = WEXITSTATUS(status); + debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val); return &event; } if (WIFSIGNALED(status)) { event.type = EVENT_EXIT_SIGNAL; event.e_un.signum = WTERMSIG(status); + debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum); return &event; } if (!WIFSTOPPED(status)) { event.type = EVENT_NONE; + debug(DEBUG_EVENT, "event: NONE: pid=%d (wait error?)", pid); return &event; } @@ -133,6 +146,7 @@ next_event(void) { && stop_signal != SIGTRAP) { event.type = EVENT_SIGNAL; event.e_un.signum = stop_signal; + debug(DEBUG_EVENT, "event: SIGNAL: pid=%d, signum=%d", pid, stop_signal); return &event; } @@ -151,6 +165,7 @@ next_event(void) { breakpoints_init(event.proc); event.proc->pid = saved_pid; continue_process(event.proc->pid); + debug(DEBUG_EVENT, "event: NONE: pid=%d (was_exec; placed breakpoints)", pid); return &event; } @@ -161,5 +176,6 @@ next_event(void) { } event.e_un.brk_addr = event.proc->instruction_pointer - DECR_PC_AFTER_BREAK; + debug(DEBUG_EVENT, "event: BREAKPOINT: pid=%d, addr=%p", pid, event.e_un.brk_addr); return &event; } diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c index cbda70b..65d561f 100644 --- a/sysdeps/linux-gnu/trace.c +++ b/sysdeps/linux-gnu/trace.c @@ -161,6 +161,7 @@ was_exec(Process *proc, int status) { void trace_me(void) { + debug(DEBUG_PROCESS, "trace_me: pid=%d\n", getpid()); if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { perror("PTRACE_TRACEME"); exit(1); @@ -169,6 +170,7 @@ trace_me(void) { int trace_pid(pid_t pid) { + debug(DEBUG_PROCESS, "trace_pid: pid=%d\n", pid); if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) { return -1; } @@ -190,6 +192,8 @@ trace_set_options(Process *proc, pid_t pid) { if (proc->tracesysgood & 0x80) return; + debug(DEBUG_PROCESS, "trace_set_options: pid=%d\n", pid); + long options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC; @@ -203,6 +207,7 @@ trace_set_options(Process *proc, pid_t pid) { void untrace_pid(pid_t pid) { + debug(DEBUG_PROCESS, "untrace_pid: pid=%d\n", pid); ptrace(PTRACE_DETACH, pid, 1, 0); } @@ -210,6 +215,8 @@ void continue_after_signal(pid_t pid, int signum) { Process *proc; + debug(DEBUG_PROCESS, "continue_after_signal: pid=%d, signum=%d", pid, signum); + proc = pid2proc(pid); if (proc && proc->breakpoint_being_enabled) { #if defined __sparc__ || defined __ia64___ @@ -226,6 +233,8 @@ void continue_process(pid_t pid) { /* We always trace syscalls to control fork(), clone(), execve()... */ + debug(DEBUG_PROCESS, "continue_process: pid=%d", pid); + ptrace(PTRACE_SYSCALL, pid, 0, 0); } @@ -237,6 +246,7 @@ continue_enabling_breakpoint(pid_t pid, Breakpoint *sbp) { void continue_after_breakpoint(Process *proc, Breakpoint *sbp) { + debug(DEBUG_PROCESS, "continue_after_breakpoint: pid=%d, addr=%p", proc->pid, sbp->addr); if (sbp->enabled) disable_breakpoint(proc->pid, sbp); set_instruction_pointer(proc, sbp->addr); |