aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--breakpoint.h94
-rw-r--r--breakpoints.c15
-rw-r--r--common.h28
-rw-r--r--handle_event.c4
-rw-r--r--proc.c1
-rw-r--r--sysdeps/linux-gnu/breakpoint.c1
-rw-r--r--sysdeps/linux-gnu/events.c1
-rw-r--r--sysdeps/linux-gnu/proc.c1
-rw-r--r--sysdeps/linux-gnu/trace.c1
10 files changed, 125 insertions, 30 deletions
diff --git a/ChangeLog b/ChangeLog
index 6107a12..dffc370 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);
diff --git a/common.h b/common.h
index b6e10f2..c6c7317 100644
--- a/common.h
+++ b/common.h
@@ -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);
diff --git a/proc.c b/proc.c
index ded0c95..ec6bd3a 100644
--- a/proc.c
+++ b/proc.c
@@ -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. */