diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | breakpoint.h | 94 | ||||
-rw-r--r-- | breakpoints.c | 15 | ||||
-rw-r--r-- | common.h | 28 | ||||
-rw-r--r-- | handle_event.c | 4 | ||||
-rw-r--r-- | proc.c | 1 | ||||
-rw-r--r-- | sysdeps/linux-gnu/breakpoint.c | 1 | ||||
-rw-r--r-- | sysdeps/linux-gnu/events.c | 1 | ||||
-rw-r--r-- | sysdeps/linux-gnu/proc.c | 1 | ||||
-rw-r--r-- | sysdeps/linux-gnu/trace.c | 1 |
10 files changed, 125 insertions, 30 deletions
@@ -7,6 +7,15 @@ 2012-02-07 Petr Machata <pmachata@redhat.com> + * breakpoint.h: New header file. + * common.h (struct breakpoint): Move to breakpoint.h. + (address2bpstruct, breakpoints_init, insert_breakpoint) + (delete_breakpoint, enable_all_breakpoints, enable_breakpoint) + (disable_breakpoint, reinitialize_breakpoints): Likewise. + (insert_breakpoint): Now returns the created breakpoint. + +2012-02-07 Petr Machata <pmachata@redhat.com> + * common.h (wait_for_proc): New interface. * sysdeps/linux-gnu/trace.c: Implement it. * execute_program.c: Call it. diff --git a/breakpoint.h b/breakpoint.h new file mode 100644 index 0000000..1b7ca84 --- /dev/null +++ b/breakpoint.h @@ -0,0 +1,94 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef BREAKPOINT_H +#define BREAKPOINT_H + +/* XXX This is currently a very weak abstraction. We would like to + * much expand this to allow things like breakpoints on SDT probes and + * such. + * + * In particular, we would like to add a tracepoint abstraction. + * Tracepoint is a traceable feature--e.g. an exact address, a DWARF + * symbol, an ELF symbol, a PLT entry, or an SDT probe. Tracepoints + * are named and the user can configure which of them he wants to + * enable. Realized tracepoints enable breakpoints, which are a + * low-level realization of high-level tracepoint. + * + * Tracepoints are provided by the main binary as well as by any + * opened libraries: every time an ELF file is mapped into the address + * space, a new set of tracepoints is extracted, and filtered + * according to user settings. Those tracepoints that are left are + * then realized, and the tracing starts. + * + * A scheme like this would take care of gradually introducing + * breakpoints when the library is mapped, and therefore ready, and + * would avoid certain hacks. For example on PPC64, we don't actually + * add breakpoints to PLT. Instead, we read the PLT (which contains + * addresses, not code), to figure out where to put the breakpoints. + * In prelinked code, that address is non-zero, and points to an + * address that's not yet mapped. ptrace then fails when we try to + * add the breakpoint. + * + * Ideally, return breakpoints would be just a special kind of + * tracepoint that has attached some magic. Or a feature of a + * tracepoint. Service breakpoints like the handling of dlopen would + * be a low-level breakpoint, likely without tracepoint attached. + * + * So that's for sometimes. + */ + +#include "arch.h" + +struct Process; + +typedef struct breakpoint Breakpoint; +struct breakpoint { + void *addr; + unsigned char orig_value[BREAKPOINT_LENGTH]; + int enabled; + struct library_symbol *libsym; +#ifdef __arm__ + int thumb_mode; +#endif +}; + +/* This is actually three functions rolled in one: + * - breakpoint_init + * - proc_insert_breakpoint + * - breakpoint_enable + * XXX I think it should be broken up somehow. */ +struct breakpoint *insert_breakpoint(struct Process *proc, void *addr, + struct library_symbol *libsym, int enable); + +/* */ +void delete_breakpoint(struct Process *proc, void *addr); + +/* XXX some of the following belongs to proc.h/proc.c. */ +struct breakpoint *address2bpstruct(struct Process *proc, void *addr); +void enable_all_breakpoints(struct Process *proc); +void disable_all_breakpoints(struct Process *proc); +int breakpoints_init(struct Process *proc, int enable); + +void reinitialize_breakpoints(struct Process *proc); + + +#endif /* BREAKPOINT_H */ diff --git a/breakpoints.c b/breakpoints.c index ec84e6e..6e2f490 100644 --- a/breakpoints.c +++ b/breakpoints.c @@ -8,11 +8,12 @@ #include <sys/ptrace.h> #endif +#include "breakpoint.h" #include "common.h" /*****************************************************************************/ -Breakpoint * +struct breakpoint * address2bpstruct(Process *proc, void *addr) { assert(proc != NULL); @@ -22,11 +23,11 @@ address2bpstruct(Process *proc, void *addr) return dict_find_entry(proc->breakpoints, addr); } -void +struct breakpoint * insert_breakpoint(Process *proc, void *addr, struct library_symbol *libsym, int enable) { - Breakpoint *sbp; + struct breakpoint *sbp; Process * leader = proc->leader; @@ -45,7 +46,7 @@ insert_breakpoint(Process *proc, void *addr, debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr); if (!addr) - return; + return NULL; if (libsym) libsym->needs_init = 0; @@ -54,7 +55,7 @@ insert_breakpoint(Process *proc, void *addr, if (sbp == NULL) { sbp = calloc(1, sizeof(*sbp)); if (sbp == NULL) { - return; /* TODO FIXME XXX: error_mem */ + return NULL; /* TODO FIXME XXX: error_mem */ } dict_enter(leader->breakpoints, addr, sbp); sbp->addr = addr; @@ -69,12 +70,14 @@ insert_breakpoint(Process *proc, void *addr, assert(proc->pid != 0); enable_breakpoint(proc, sbp); } + + return sbp; } void delete_breakpoint(Process *proc, void *addr) { - Breakpoint *sbp; + struct breakpoint *sbp; debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); @@ -26,17 +26,6 @@ extern char * command; extern int exiting; /* =1 if we have to exit ASAP */ -typedef struct Breakpoint Breakpoint; -struct Breakpoint { - void * addr; - unsigned char orig_value[BREAKPOINT_LENGTH]; - int enabled; - struct library_symbol * libsym; -#ifdef __arm__ - int thumb_mode; -#endif -}; - enum arg_type { ARGTYPE_UNKNOWN = -1, ARGTYPE_VOID, @@ -187,7 +176,7 @@ struct Process { pid_t pid; /* Dictionary of breakpoints (which is a mapping - * address->Breakpoint). This is NULL for non-leader + * address->breakpoint). This is NULL for non-leader * processes. */ Dict * breakpoints; @@ -296,14 +285,7 @@ extern void destroy_event_handler(Process * proc); extern pid_t execute_program(const char * command, char ** argv); extern int display_arg(enum tof type, Process * proc, int arg_num, arg_type_info * info); -extern Breakpoint * address2bpstruct(Process * proc, void * addr); -extern int breakpoints_init(Process * proc, int enable); -extern void insert_breakpoint(Process * proc, void * addr, - struct library_symbol * libsym, int enable); -extern void delete_breakpoint(Process * proc, void * addr); -extern void enable_all_breakpoints(Process * proc); extern void disable_all_breakpoints(Process * proc); -extern void reinitialize_breakpoints(Process *); extern Process * open_program(char * filename, pid_t pid, int init_breakpoints); extern void open_pid(pid_t pid); @@ -322,6 +304,8 @@ extern struct library_symbol * clone_library_symbol(struct library_symbol * s); extern void destroy_library_symbol(struct library_symbol * s); extern void destroy_library_symbol_chain(struct library_symbol * chain); +struct breakpoint; + /* Arch-dependent stuff: */ extern char * pid2name(pid_t pid); extern pid_t process_leader(pid_t pid); @@ -339,13 +323,13 @@ extern void set_instruction_pointer(Process * proc, void * addr); extern void * get_stack_pointer(Process * proc); extern void * get_return_addr(Process * proc, void * stack_pointer); extern void set_return_addr(Process * proc, void * addr); -extern void enable_breakpoint(Process * proc, Breakpoint * sbp); -extern void disable_breakpoint(Process * proc, Breakpoint * sbp); +extern void enable_breakpoint(Process * proc, struct breakpoint *sbp); +extern void disable_breakpoint(Process * proc, struct breakpoint *sbp); extern int syscall_p(Process * proc, int status, int * sysnum); extern void continue_process(pid_t pid); extern void continue_after_signal(pid_t pid, int signum); extern void continue_after_syscall(Process *proc, int sysnum, int ret_p); -extern void continue_after_breakpoint(Process * proc, Breakpoint * sbp); +extern void continue_after_breakpoint(Process * proc, struct breakpoint *sbp); extern void continue_after_vfork(Process * proc); extern long gimme_arg(enum tof type, Process * proc, int arg_num, arg_type_info * info); extern void save_register_args(enum tof type, Process * proc); diff --git a/handle_event.c b/handle_event.c index 8c3c7ce..63ed536 100644 --- a/handle_event.c +++ b/handle_event.c @@ -14,6 +14,7 @@ #endif #include "common.h" +#include "breakpoint.h" static void handle_signal(Event *event); static void handle_exit(Event *event); @@ -158,10 +159,9 @@ address_clone(void * addr, void * data) static void * breakpoint_clone(void *bp, void *data) { - Breakpoint * b; Dict *map = data; debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp); - b = malloc(sizeof(Breakpoint)); + struct breakpoint *b = malloc(sizeof(*b)); if (!b) { perror("malloc()"); exit(1); @@ -14,6 +14,7 @@ #include <error.h> #include "common.h" +#include "breakpoint.h" Process * open_program(char *filename, pid_t pid, int enable) { diff --git a/sysdeps/linux-gnu/breakpoint.c b/sysdeps/linux-gnu/breakpoint.c index 5a49e9d..bbfa481 100644 --- a/sysdeps/linux-gnu/breakpoint.c +++ b/sysdeps/linux-gnu/breakpoint.c @@ -5,6 +5,7 @@ #include "common.h" #include "arch.h" +#include "breakpoint.h" #ifdef ARCH_HAVE_ENABLE_BREAKPOINT extern void arch_enable_breakpoint(pid_t, Breakpoint *); diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c index b6c12ef..79f6817 100644 --- a/sysdeps/linux-gnu/events.c +++ b/sysdeps/linux-gnu/events.c @@ -12,6 +12,7 @@ #include <unistd.h> #include "common.h" +#include "breakpoint.h" static Event event; diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c index a99593c..d8d381a 100644 --- a/sysdeps/linux-gnu/proc.c +++ b/sysdeps/linux-gnu/proc.c @@ -17,6 +17,7 @@ #include <sys/syscall.h> #include <error.h> +#include "breakpoint.h" /* /proc/pid doesn't exist just after the fork, and sometimes `ltrace' * couldn't open it to find the executable. So it may be necessary to diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c index d962048..0751a35 100644 --- a/sysdeps/linux-gnu/trace.c +++ b/sysdeps/linux-gnu/trace.c @@ -16,6 +16,7 @@ #include "ptrace.h" #include "common.h" +#include "breakpoint.h" /* If the system headers did not provide the constants, hard-code the normal values. */ |