breakpoints.c revision 81c65272697a63d81e6baece69bef6ba8f55932e
1#include "config.h" 2 3#include <stdlib.h> 4#include <string.h> 5#include <assert.h> 6#include <error.h> 7#include <errno.h> 8 9#ifdef __powerpc__ 10#include <sys/ptrace.h> 11#endif 12 13#include "breakpoint.h" 14#include "common.h" 15#include "proc.h" 16#include "library.h" 17 18void 19breakpoint_on_hit(struct breakpoint *bp, struct Process *proc) 20{ 21 assert(bp != NULL); 22 if (bp->cbs != NULL && bp->cbs->on_hit != NULL) 23 (bp->cbs->on_hit) (bp, proc); 24} 25 26void 27breakpoint_on_destroy(struct breakpoint *bp) 28{ 29 assert(bp != NULL); 30 if (bp->cbs != NULL && bp->cbs->on_destroy != NULL) 31 (bp->cbs->on_destroy) (bp); 32} 33 34/*****************************************************************************/ 35 36struct breakpoint * 37address2bpstruct(Process *proc, void *addr) 38{ 39 assert(proc != NULL); 40 assert(proc->breakpoints != NULL); 41 assert(proc->leader == proc); 42 debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr); 43 return dict_find_entry(proc->breakpoints, addr); 44} 45 46#ifdef ARCH_HAVE_BREAKPOINT_DATA 47int arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp); 48#else 49int 50arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp) 51{ 52 return 0; 53} 54#endif 55 56int 57breakpoint_init(struct breakpoint *bp, struct Process *proc, 58 target_address_t addr, struct library_symbol *libsym, 59 struct bp_callbacks *cbs) 60{ 61 bp->cbs = cbs; 62 bp->addr = addr; 63 memset(bp->orig_value, 0, sizeof(bp->orig_value)); 64 bp->enabled = 0; 65 bp->libsym = libsym; 66 return arch_breakpoint_init(proc, bp); 67} 68 69struct breakpoint * 70insert_breakpoint(Process *proc, void *addr, 71 struct library_symbol *libsym, int enable) 72{ 73 Process * leader = proc->leader; 74 75 /* Only the group leader should be getting the breakpoints and 76 * thus have ->breakpoint initialized. */ 77 assert(leader != NULL); 78 assert(leader->breakpoints != NULL); 79 80 debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)", proc->pid, addr, libsym ? libsym->name : "NULL"); 81 debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr); 82 83 if (addr == 0) { 84 /* XXX we need a better way to deal with this. For 85 * now, just abuse errno to carry the error 86 * information. */ 87 errno = EINVAL; 88 return NULL; 89 } 90 91 if (libsym) 92 libsym->needs_init = 0; 93 94 struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr); 95 if (sbp == NULL) { 96 sbp = malloc(sizeof(*sbp)); 97 if (sbp == NULL 98 || breakpoint_init(sbp, proc, addr, libsym, NULL) < 0 99 || dict_enter(leader->breakpoints, addr, sbp) < 0) { 100 free(sbp); 101 return NULL; 102 } 103 } 104 105 sbp->enabled++; 106 if (sbp->enabled == 1 && enable) { 107 assert(proc->pid != 0); 108 enable_breakpoint(proc, sbp); 109 } 110 111 return sbp; 112} 113 114void 115delete_breakpoint(Process *proc, void *addr) 116{ 117 struct breakpoint *sbp; 118 119 debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); 120 121 Process * leader = proc->leader; 122 assert(leader != NULL); 123 124 sbp = dict_find_entry(leader->breakpoints, addr); 125 assert(sbp); /* FIXME: remove after debugging has been done. */ 126 /* This should only happen on out-of-memory conditions. */ 127 if (sbp == NULL) 128 return; 129 130 sbp->enabled--; 131 if (sbp->enabled == 0) 132 disable_breakpoint(proc, sbp); 133 assert(sbp->enabled >= 0); 134} 135 136static void 137enable_bp_cb(void *addr, void *sbp, void *proc) 138{ 139 debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid); 140 if (((struct breakpoint *)sbp)->enabled) 141 enable_breakpoint(proc, sbp); 142} 143 144void 145enable_all_breakpoints(Process *proc) 146{ 147 debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid); 148 149 debug(1, "Enabling breakpoints for pid %u...", proc->pid); 150 if (proc->breakpoints) { 151 dict_apply_to_all(proc->breakpoints, enable_bp_cb, 152 proc); 153 } 154#ifdef __mips__ 155 { 156 /* 157 * I'm sure there is a nicer way to do this. We need to 158 * insert breakpoints _after_ the child has been started. 159 */ 160 struct library_symbol *sym; 161 struct library_symbol *new_sym; 162 sym=proc->list_of_symbols; 163 while(sym){ 164 void *addr= sym2addr(proc,sym); 165 if(!addr){ 166 sym=sym->next; 167 continue; 168 } 169 if(dict_find_entry(proc->breakpoints,addr)){ 170 sym=sym->next; 171 continue; 172 } 173 debug(2,"inserting bp %p %s",addr,sym->name); 174 new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1); 175 memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1); 176 new_sym->next=proc->list_of_symbols; 177 proc->list_of_symbols=new_sym; 178 insert_breakpoint(proc, addr, new_sym); 179 sym=sym->next; 180 } 181 } 182#endif 183} 184 185static void 186disable_bp_cb(void *addr, void *sbp, void *proc) 187{ 188 debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid); 189 if (((struct breakpoint *)sbp)->enabled) 190 disable_breakpoint(proc, sbp); 191} 192 193void 194disable_all_breakpoints(Process *proc) { 195 debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid); 196 assert(proc->leader == proc); 197 dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); 198} 199 200static enum callback_status 201reinitialize_breakpoints(struct Process *proc, struct library *library, 202 void *data) 203{ 204 debug(DEBUG_FUNCTION, "reinitialize_breakpoints_in(pid=%d, %s)", 205 proc->pid, library->name); 206 207 struct library_symbol *sym; 208 for (sym = library->symbols; sym != NULL; sym = sym->next) 209 if (sym->needs_init) { 210 target_address_t addr = sym2addr(proc, sym); 211 if (insert_breakpoint(proc, addr, sym, 1) == NULL 212 || (sym->needs_init && !sym->is_weak)) 213 fprintf(stderr, 214 "could not re-initialize breakpoint " 215 "for \"%s\" in file \"%s\"\n", 216 sym->name, proc->filename); 217 } 218 219 return CBS_CONT; 220} 221 222static void 223entry_callback_hit(struct breakpoint *bp, struct Process *proc) 224{ 225 fprintf(stderr, "entry_callback_hit\n"); 226 if (proc == NULL || proc->leader == NULL) 227 return; 228 delete_breakpoint(proc, bp->addr); // xxx 229 230 linkmap_init(proc); 231 proc_each_library(proc->leader, NULL, reinitialize_breakpoints, NULL); 232} 233 234int 235breakpoints_init(Process *proc, int enable) 236{ 237 fprintf(stderr, "breakpoints_init %d enable=%d\n", proc->pid, enable); 238 debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); 239 240 /* XXX breakpoint dictionary should be initialized 241 * outside. Here we just put in breakpoints. */ 242 assert(proc->breakpoints != NULL); 243 244 /* Only the thread group leader should hold the breakpoints. */ 245 assert(proc->leader == proc); 246 247 if (options.libcalls && proc->filename) { 248 struct library *lib = ltelf_read_main_binary(proc, proc->filename); 249 switch (lib != NULL) { 250 fail: 251 proc_remove_library(proc, lib); 252 library_destroy(lib); 253 case 0: 254 return -1; 255 } 256 proc_add_library(proc, lib); 257 fprintf(stderr, "note: symbols in %s were not filtered.\n", 258 lib->name); 259 260 struct breakpoint *entry_bp 261 = insert_breakpoint(proc, lib->entry, NULL, 1); 262 if (entry_bp == NULL) { 263 error(0, errno, "couldn't insert entry breakpoint"); 264 goto fail; 265 } 266 267 fprintf(stderr, "setting entry_callbacks by hand, fix it\n"); 268 static struct bp_callbacks entry_callbacks = { 269 .on_hit = entry_callback_hit, 270 }; 271 entry_bp->cbs = &entry_callbacks; 272 } 273 274 proc->callstack_depth = 0; 275 return 0; 276} 277