breakpoints.c revision 5bfb061c4c7cfac6e1882a586cf36c849d95fcea
1#if HAVE_CONFIG_H 2#include "config.h" 3#endif 4 5#include "ltrace.h" 6#include "options.h" 7#include "output.h" 8 9#include <stdlib.h> 10#include <assert.h> 11 12#ifdef __powerpc__ 13#include <sys/ptrace.h> 14#endif 15 16/*****************************************************************************/ 17 18/* 19 Dictionary code done by Morten Eriksen <mortene@sim.no>. 20 21 FIXME: should we merge with dictionary code in demangle.c? 19990704 mortene. 22*/ 23 24struct dict_entry { 25 struct process * proc; 26 struct breakpoint brk; /* addr field of struct is the hash key. */ 27 struct dict_entry * next; 28}; 29 30#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */ 31static struct dict_entry * dict_buckets[DICTTABLESIZE]; 32static int dict_initialized = 0; 33 34static void dict_init(void); 35static void dict_clear(void); 36static struct breakpoint * dict_enter(struct process * proc, void * brkaddr); 37struct breakpoint * dict_find_entry(struct process * proc, void * brkaddr); 38static void dict_apply_to_all(void (* func)(struct process *, struct breakpoint *, void * data), void * data); 39 40 41static void 42dict_init(void) { 43 int i; 44 /* FIXME: is this necessary? Check with ANSI C spec. 19990702 mortene. */ 45 for (i = 0; i < DICTTABLESIZE; i++) dict_buckets[i] = NULL; 46 dict_initialized = 1; 47} 48 49static void 50dict_clear(void) { 51 int i; 52 struct dict_entry * entry, * nextentry; 53 54 for (i = 0; i < DICTTABLESIZE; i++) { 55 for (entry = dict_buckets[i]; entry != NULL; entry = nextentry) { 56 nextentry = entry->next; 57 free(entry); 58 } 59 dict_buckets[i] = NULL; 60 } 61} 62 63static struct breakpoint * 64dict_enter(struct process * proc, void * brkaddr) { 65 struct dict_entry * entry, * newentry; 66 unsigned int bucketpos = ((unsigned long int)brkaddr) % DICTTABLESIZE; 67 68 newentry = malloc(sizeof(struct dict_entry)); 69 if (!newentry) { 70 perror("malloc"); 71 return NULL; 72 } 73 74 newentry->proc = proc; 75 newentry->brk.addr = brkaddr; 76 newentry->brk.enabled = 0; 77 newentry->next = NULL; 78 79 entry = dict_buckets[bucketpos]; 80 while (entry && entry->next) entry = entry->next; 81 82 if (entry) entry->next = newentry; 83 else dict_buckets[bucketpos] = newentry; 84 85 if (opt_d > 2) 86 output_line(0, "new brk dict entry at %p\n", brkaddr); 87 88 return &(newentry->brk); 89} 90 91struct breakpoint * 92dict_find_entry(struct process * proc, void * brkaddr) { 93 unsigned int bucketpos = ((unsigned long int)brkaddr) % DICTTABLESIZE; 94 struct dict_entry * entry = dict_buckets[bucketpos]; 95 while (entry) { 96 if ((entry->brk.addr == brkaddr) && (entry->proc == proc)) break; 97 entry = entry->next; 98 } 99 return entry ? &(entry->brk) : NULL; 100} 101 102static void 103dict_apply_to_all(void (* func)(struct process *, struct breakpoint *, void * data), void * data) { 104 int i; 105 106 for (i = 0; i < DICTTABLESIZE; i++) { 107 struct dict_entry * entry = dict_buckets[i]; 108 while (entry) { 109 func(entry->proc, &(entry->brk), data); 110 entry = entry->next; 111 } 112 } 113} 114 115#undef DICTTABLESIZE 116 117/*****************************************************************************/ 118 119struct breakpoint * 120address2bpstruct(struct process * proc, void * addr) { 121 return dict_find_entry(proc, addr); 122} 123 124void 125insert_breakpoint(struct process * proc, void * addr) { 126 struct breakpoint * sbp; 127 128 if (!dict_initialized) { 129 dict_init(); 130 atexit(dict_clear); 131 } 132 133 sbp = dict_find_entry(proc, addr); 134 if (!sbp) sbp = dict_enter(proc, addr); 135 if (!sbp) return; 136 137 sbp->enabled++; 138 if (sbp->enabled==1 && proc->pid) enable_breakpoint(proc->pid, sbp); 139} 140 141void 142delete_breakpoint(struct process * proc, void * addr) { 143 struct breakpoint * sbp = dict_find_entry(proc, addr); 144 assert(sbp); /* FIXME: remove after debugging has been done. */ 145 /* This should only happen on out-of-memory conditions. */ 146 if (sbp == NULL) return; 147 148 sbp->enabled--; 149 if (sbp->enabled == 0) disable_breakpoint(proc->pid, sbp); 150 assert(sbp->enabled >= 0); 151} 152 153static void 154enable_bp_cb(struct process * proc, struct breakpoint * sbp, void * data) { 155 struct process * myproc = (struct process *)data; 156 if (myproc == proc && sbp->enabled) enable_breakpoint(proc->pid, sbp); 157} 158 159void 160enable_all_breakpoints(struct process * proc) { 161 if (proc->breakpoints_enabled <= 0) { 162#ifdef __powerpc__ 163 unsigned long a; 164 165 /* 166 * PPC HACK! (XXX FIXME TODO) 167 * If the dynamic linker hasn't populated the PLT then 168 * dont enable the breakpoints 169 */ 170 a = ptrace(PTRACE_PEEKTEXT, proc->pid, proc->list_of_symbols->enter_addr, 0); 171 if (a == 0x0) 172 return; 173#endif 174 175 if (opt_d>0) { 176 output_line(0, "Enabling breakpoints for pid %u...", proc->pid); 177 } 178 dict_apply_to_all(enable_bp_cb, proc); 179 } 180 proc->breakpoints_enabled = 1; 181} 182 183static void 184disable_bp_cb(struct process * proc, struct breakpoint * sbp, void * data) { 185 struct process * myproc = (struct process *)data; 186 if (myproc == proc && sbp->enabled) disable_breakpoint(proc->pid, sbp); 187} 188 189void 190disable_all_breakpoints(struct process * proc) { 191 if (proc->breakpoints_enabled) { 192 if (opt_d>0) { 193 output_line(0, "Disabling breakpoints for pid %u...", proc->pid); 194 } 195 dict_apply_to_all(disable_bp_cb, proc); 196 } 197 proc->breakpoints_enabled = 0; 198} 199