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