| Juan Cespedes | d44c6b8 | 1998-09-25 14:48:42 +0200 | [diff] [blame] | 1 | #if HAVE_CONFIG_H |
| 2 | #include "config.h" |
| 3 | #endif |
| 4 | |
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 5 | #include <stdlib.h> |
| 6 | #include <assert.h> |
| 7 | |
| Juan Cespedes | f1bfe20 | 2002-03-27 00:22:23 +0100 | [diff] [blame] | 8 | #ifdef __powerpc__ |
| 9 | #include <sys/ptrace.h> |
| 10 | #endif |
| 11 | |
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame^] | 12 | #include "ltrace.h" |
| 13 | #include "options.h" |
| 14 | #include "debug.h" |
| 15 | #include "dict.h" |
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 16 | |
| 17 | /*****************************************************************************/ |
| 18 | |
| Juan Cespedes | 8cc1b9d | 2002-03-01 19:54:23 +0100 | [diff] [blame] | 19 | struct breakpoint * |
| 20 | address2bpstruct(struct process * proc, void * addr) { |
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame^] | 21 | return dict_find_entry(proc->breakpoints, addr); |
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 22 | } |
| 23 | |
| Juan Cespedes | 8cc1b9d | 2002-03-01 19:54:23 +0100 | [diff] [blame] | 24 | void |
| 25 | insert_breakpoint(struct process * proc, void * addr) { |
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 26 | struct breakpoint * sbp; |
| 27 | |
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame^] | 28 | if (!proc->breakpoints) { |
| 29 | proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int); |
| 30 | /* atexit(brk_dict_clear); */ /* why bother to do this on exit? */ |
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 31 | } |
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame^] | 32 | sbp = dict_find_entry(proc->breakpoints, addr); |
| 33 | if (!sbp) { |
| 34 | sbp = malloc(sizeof(struct breakpoint)); |
| 35 | if (!sbp) { |
| 36 | return; /* TODO FIXME XXX: error_mem */ |
| 37 | } |
| 38 | dict_enter(proc->breakpoints, addr, sbp); |
| 39 | sbp->addr = addr; |
| 40 | sbp->enabled = 0; |
| 41 | } |
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 42 | sbp->enabled++; |
| 43 | if (sbp->enabled==1 && proc->pid) enable_breakpoint(proc->pid, sbp); |
| 44 | } |
| 45 | |
| Juan Cespedes | 8cc1b9d | 2002-03-01 19:54:23 +0100 | [diff] [blame] | 46 | void |
| 47 | delete_breakpoint(struct process * proc, void * addr) { |
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame^] | 48 | struct breakpoint * sbp = dict_find_entry(proc->breakpoints, addr); |
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 49 | assert(sbp); /* FIXME: remove after debugging has been done. */ |
| 50 | /* This should only happen on out-of-memory conditions. */ |
| 51 | if (sbp == NULL) return; |
| 52 | |
| 53 | sbp->enabled--; |
| 54 | if (sbp->enabled == 0) disable_breakpoint(proc->pid, sbp); |
| 55 | assert(sbp->enabled >= 0); |
| 56 | } |
| 57 | |
| Juan Cespedes | 8cc1b9d | 2002-03-01 19:54:23 +0100 | [diff] [blame] | 58 | static void |
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame^] | 59 | enable_bp_cb(void * addr, void * sbp, void * proc) { |
| 60 | if (((struct breakpoint *)sbp)->enabled) { |
| 61 | enable_breakpoint(((struct process *)proc)->pid, sbp); |
| 62 | } |
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 63 | } |
| 64 | |
| Juan Cespedes | 8cc1b9d | 2002-03-01 19:54:23 +0100 | [diff] [blame] | 65 | void |
| 66 | enable_all_breakpoints(struct process * proc) { |
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 67 | if (proc->breakpoints_enabled <= 0) { |
| Juan Cespedes | f1bfe20 | 2002-03-27 00:22:23 +0100 | [diff] [blame] | 68 | #ifdef __powerpc__ |
| 69 | unsigned long a; |
| 70 | |
| 71 | /* |
| 72 | * PPC HACK! (XXX FIXME TODO) |
| 73 | * If the dynamic linker hasn't populated the PLT then |
| 74 | * dont enable the breakpoints |
| 75 | */ |
| Juan Cespedes | de5a7eb | 2002-03-31 20:53:52 +0200 | [diff] [blame] | 76 | if (opt_L) { |
| 77 | a = ptrace(PTRACE_PEEKTEXT, proc->pid, proc->list_of_symbols->enter_addr, 0); |
| 78 | if (a == 0x0) |
| 79 | return; |
| 80 | } |
| Juan Cespedes | f1bfe20 | 2002-03-27 00:22:23 +0100 | [diff] [blame] | 81 | #endif |
| 82 | |
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame^] | 83 | debug(1, "Enabling breakpoints for pid %u...", proc->pid); |
| 84 | dict_apply_to_all(proc->breakpoints, enable_bp_cb, proc); |
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 85 | } |
| 86 | proc->breakpoints_enabled = 1; |
| 87 | } |
| 88 | |
| Juan Cespedes | 8cc1b9d | 2002-03-01 19:54:23 +0100 | [diff] [blame] | 89 | static void |
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame^] | 90 | disable_bp_cb(void * addr, void * sbp, void * proc) { |
| 91 | if (((struct breakpoint *)sbp)->enabled) { |
| 92 | disable_breakpoint(((struct process *)proc)->pid, sbp); |
| 93 | } |
| Juan Cespedes | 5b3ffdf | 2001-07-02 00:52:45 +0200 | [diff] [blame] | 94 | } |
| 95 | |
| Juan Cespedes | 8cc1b9d | 2002-03-01 19:54:23 +0100 | [diff] [blame] | 96 | void |
| 97 | disable_all_breakpoints(struct process * proc) { |
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 98 | if (proc->breakpoints_enabled) { |
| Juan Cespedes | cac15c3 | 2003-01-31 18:58:58 +0100 | [diff] [blame^] | 99 | debug(1, "Disabling breakpoints for pid %u...", proc->pid); |
| 100 | dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); |
| Juan Cespedes | 5e01f65 | 1998-03-08 22:31:44 +0100 | [diff] [blame] | 101 | } |
| 102 | proc->breakpoints_enabled = 0; |
| 103 | } |