breakpoints.c revision b931085e37224dd2932fb637eaba5da29c4c5eb7
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 struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr); 92 if (sbp == NULL) { 93 sbp = malloc(sizeof(*sbp)); 94 if (sbp == NULL 95 || breakpoint_init(sbp, proc, addr, libsym, NULL) < 0 96 || dict_enter(leader->breakpoints, addr, sbp) < 0) { 97 free(sbp); 98 return NULL; 99 } 100 } 101 102 sbp->enabled++; 103 if (sbp->enabled == 1 && enable) { 104 assert(proc->pid != 0); 105 enable_breakpoint(proc, sbp); 106 } 107 108 return sbp; 109} 110 111void 112delete_breakpoint(Process *proc, void *addr) 113{ 114 struct breakpoint *sbp; 115 116 debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); 117 118 Process * leader = proc->leader; 119 assert(leader != NULL); 120 121 sbp = dict_find_entry(leader->breakpoints, addr); 122 assert(sbp); /* FIXME: remove after debugging has been done. */ 123 /* This should only happen on out-of-memory conditions. */ 124 if (sbp == NULL) 125 return; 126 127 sbp->enabled--; 128 if (sbp->enabled == 0) 129 disable_breakpoint(proc, sbp); 130 assert(sbp->enabled >= 0); 131} 132 133static void 134enable_bp_cb(void *addr, void *sbp, void *proc) 135{ 136 debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid); 137 if (((struct breakpoint *)sbp)->enabled) 138 enable_breakpoint(proc, sbp); 139} 140 141void 142enable_all_breakpoints(Process *proc) 143{ 144 debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid); 145 146 debug(1, "Enabling breakpoints for pid %u...", proc->pid); 147 if (proc->breakpoints) { 148 dict_apply_to_all(proc->breakpoints, enable_bp_cb, 149 proc); 150 } 151#ifdef __mips__ 152 { 153 /* 154 * I'm sure there is a nicer way to do this. We need to 155 * insert breakpoints _after_ the child has been started. 156 */ 157 struct library_symbol *sym; 158 struct library_symbol *new_sym; 159 sym=proc->list_of_symbols; 160 while(sym){ 161 void *addr= sym2addr(proc,sym); 162 if(!addr){ 163 sym=sym->next; 164 continue; 165 } 166 if(dict_find_entry(proc->breakpoints,addr)){ 167 sym=sym->next; 168 continue; 169 } 170 debug(2,"inserting bp %p %s",addr,sym->name); 171 new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1); 172 memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1); 173 new_sym->next=proc->list_of_symbols; 174 proc->list_of_symbols=new_sym; 175 insert_breakpoint(proc, addr, new_sym); 176 sym=sym->next; 177 } 178 } 179#endif 180} 181 182static void 183disable_bp_cb(void *addr, void *sbp, void *proc) 184{ 185 debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid); 186 if (((struct breakpoint *)sbp)->enabled) 187 disable_breakpoint(proc, sbp); 188} 189 190void 191disable_all_breakpoints(Process *proc) { 192 debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid); 193 assert(proc->leader == proc); 194 dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); 195} 196 197static void 198entry_callback_hit(struct breakpoint *bp, struct Process *proc) 199{ 200 fprintf(stderr, "entry_callback_hit\n"); 201 if (proc == NULL || proc->leader == NULL) 202 return; 203 delete_breakpoint(proc, bp->addr); // xxx 204 enable_all_breakpoints(proc); 205 206 linkmap_init(proc); 207} 208 209int 210breakpoints_init(Process *proc, int enable) 211{ 212 fprintf(stderr, "breakpoints_init %d enable=%d\n", proc->pid, enable); 213 debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); 214 215 /* XXX breakpoint dictionary should be initialized 216 * outside. Here we just put in breakpoints. */ 217 assert(proc->breakpoints != NULL); 218 219 /* Only the thread group leader should hold the breakpoints. */ 220 assert(proc->leader == proc); 221 222 if (options.libcalls && proc->filename) { 223 struct library *lib = ltelf_read_main_binary(proc, proc->filename); 224 switch (lib != NULL) { 225 fail: 226 proc_remove_library(proc, lib); 227 library_destroy(lib); 228 case 0: 229 return -1; 230 } 231 proc_add_library(proc, lib); 232 fprintf(stderr, "note: symbols in %s were not filtered.\n", 233 lib->name); 234 235 struct breakpoint *entry_bp 236 = insert_breakpoint(proc, lib->entry, NULL, 1); 237 if (entry_bp == NULL) { 238 error(0, errno, "couldn't insert entry breakpoint"); 239 goto fail; 240 } 241 242 fprintf(stderr, "setting entry_callbacks by hand, fix it\n"); 243 static struct bp_callbacks entry_callbacks = { 244 .on_hit = entry_callback_hit, 245 }; 246 entry_bp->cbs = &entry_callbacks; 247 } 248 249 proc->callstack_depth = 0; 250 return 0; 251} 252