breakpoints.c revision a413e5b8880de643a83ad124d078091c0956fe1d
1#if HAVE_CONFIG_H 2#include "config.h" 3#endif 4 5#include <stdlib.h> 6#include <string.h> 7#include <assert.h> 8 9#ifdef __powerpc__ 10#include <sys/ptrace.h> 11#endif 12 13#include "ltrace.h" 14#include "options.h" 15#include "debug.h" 16#include "dict.h" 17#include "elf.h" 18 19/*****************************************************************************/ 20 21struct breakpoint *address2bpstruct(struct process *proc, void *addr) 22{ 23 return dict_find_entry(proc->breakpoints, addr); 24} 25 26void 27insert_breakpoint(struct process *proc, void *addr, 28 struct library_symbol *libsym) 29{ 30 struct breakpoint *sbp; 31 debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr); 32 33 if (!addr) 34 return; 35 36 if (libsym) 37 libsym->needs_init = 0; 38 39 sbp = dict_find_entry(proc->breakpoints, addr); 40 if (!sbp) { 41 sbp = calloc(1, sizeof(struct breakpoint)); 42 if (!sbp) { 43 return; /* TODO FIXME XXX: error_mem */ 44 } 45 dict_enter(proc->breakpoints, addr, sbp); 46 sbp->addr = addr; 47 sbp->libsym = libsym; 48 if (libsym) 49 libsym->brkpnt = sbp; 50 } 51 sbp->enabled++; 52 if (sbp->enabled == 1 && proc->pid) 53 enable_breakpoint(proc->pid, sbp); 54} 55 56void delete_breakpoint(struct process *proc, void *addr) 57{ 58 struct breakpoint *sbp = dict_find_entry(proc->breakpoints, addr); 59 assert(sbp); /* FIXME: remove after debugging has been done. */ 60 /* This should only happen on out-of-memory conditions. */ 61 if (sbp == NULL) 62 return; 63 64 sbp->enabled--; 65 if (sbp->enabled == 0) 66 disable_breakpoint(proc->pid, sbp); 67 assert(sbp->enabled >= 0); 68} 69 70static void enable_bp_cb(void *addr, void *sbp, void *proc) 71{ 72 if (((struct breakpoint *)sbp)->enabled) { 73 enable_breakpoint(((struct process *)proc)->pid, sbp); 74 } 75} 76 77void enable_all_breakpoints(struct process *proc) 78{ 79 if (proc->breakpoints_enabled <= 0) { 80#ifdef __powerpc__ 81 unsigned long a; 82 83 /* 84 * PPC HACK! (XXX FIXME TODO) 85 * If the dynamic linker hasn't populated the PLT then 86 * dont enable the breakpoints 87 */ 88 if (opt_L) { 89 a = ptrace(PTRACE_PEEKTEXT, proc->pid, 90 sym2addr(proc, proc->list_of_symbols), 91 0); 92 if (a == 0x0) 93 return; 94 } 95#endif 96 97 debug(1, "Enabling breakpoints for pid %u...", proc->pid); 98 if (proc->breakpoints) { 99 dict_apply_to_all(proc->breakpoints, enable_bp_cb, 100 proc); 101 } 102#ifdef __mips__ 103 { 104 // I'm sure there is a nicer way to do this. We need to 105 // insert breakpoints _after_ the child has been started. 106 struct library_symbol *sym; 107 struct library_symbol *new_sym; 108 sym=proc->list_of_symbols; 109 while(sym){ 110 void *addr= sym2addr(proc,sym); 111 if(!addr){ 112 sym=sym->next; 113 continue; 114 } 115 if(dict_find_entry(proc->breakpoints,addr)){ 116 sym=sym->next; 117 continue; 118 } 119 debug(2,"inserting bp %p %s",addr,sym->name); 120 new_sym=malloc(sizeof(*new_sym)); 121 memcpy(new_sym,sym,sizeof(*new_sym)); 122 new_sym->next=proc->list_of_symbols; 123 proc->list_of_symbols=new_sym; 124 new_sym->brkpnt=0; 125 insert_breakpoint(proc, addr, new_sym); 126 sym=sym->next; 127 } 128 } 129#endif 130 } 131 proc->breakpoints_enabled = 1; 132} 133 134static void disable_bp_cb(void *addr, void *sbp, void *proc) 135{ 136 if (((struct breakpoint *)sbp)->enabled) { 137 disable_breakpoint(((struct process *)proc)->pid, sbp); 138 } 139} 140 141void disable_all_breakpoints(struct process *proc) 142{ 143 if (proc->breakpoints_enabled) { 144 debug(1, "Disabling breakpoints for pid %u...", proc->pid); 145 dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); 146 } 147 proc->breakpoints_enabled = 0; 148} 149 150static void free_bp_cb(void *addr, void *sbp, void *data) 151{ 152 assert(sbp); 153 free(sbp); 154} 155 156void breakpoints_init(struct process *proc) 157{ 158 struct library_symbol *sym; 159 160 if (proc->breakpoints) { /* let's remove that struct */ 161 dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL); 162 dict_clear(proc->breakpoints); 163 proc->breakpoints = NULL; 164 } 165 proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int); 166 167 if (opt_L && proc->filename) { 168 proc->list_of_symbols = read_elf(proc); 169 if (opt_e) { 170 struct library_symbol **tmp1 = &(proc->list_of_symbols); 171 while (*tmp1) { 172 struct opt_e_t *tmp2 = opt_e; 173 int keep = !opt_e_enable; 174 175 while (tmp2) { 176 if (!strcmp((*tmp1)->name, tmp2->name)) { 177 keep = opt_e_enable; 178 } 179 tmp2 = tmp2->next; 180 } 181 if (!keep) { 182 *tmp1 = (*tmp1)->next; 183 } else { 184 tmp1 = &((*tmp1)->next); 185 } 186 } 187 } 188 } else { 189 proc->list_of_symbols = NULL; 190 } 191 for (sym = proc->list_of_symbols; sym; sym = sym->next) { 192 /* proc->pid==0 delays enabling. */ 193 insert_breakpoint(proc, sym2addr(proc, sym), sym); 194 } 195 proc->callstack_depth = 0; 196 proc->breakpoints_enabled = -1; 197} 198 199void reinitialize_breakpoints(struct process *proc) 200{ 201 struct library_symbol *sym = proc->list_of_symbols; 202 203 while (sym) { 204 if (sym->needs_init) { 205 insert_breakpoint(proc, sym2addr(proc, sym), 206 sym); 207 if (sym->needs_init && !sym->is_weak) { 208 fprintf(stderr, 209 "could not re-initialize breakpoint for \"%s\" in file \"%s\"\n", 210 sym->name, proc->filename); 211 exit(1); 212 } 213 } 214 sym = sym->next; 215 } 216} 217