breakpoints.c revision 9294d82f67e20f5f2b61f317ad04f5cb717c7d27
1#include "config.h" 2 3#include <stdlib.h> 4#include <string.h> 5#include <assert.h> 6 7#ifdef __powerpc__ 8#include <sys/ptrace.h> 9#endif 10 11#include "breakpoint.h" 12#include "common.h" 13 14/*****************************************************************************/ 15 16struct breakpoint * 17address2bpstruct(Process *proc, void *addr) 18{ 19 assert(proc != NULL); 20 assert(proc->breakpoints != NULL); 21 assert(proc->leader == proc); 22 debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr); 23 return dict_find_entry(proc->breakpoints, addr); 24} 25 26struct breakpoint * 27insert_breakpoint(Process *proc, void *addr, 28 struct library_symbol *libsym, int enable) 29{ 30 struct breakpoint *sbp; 31 32 Process * leader = proc->leader; 33 34 /* Only the group leader should be getting the breakpoints and 35 * thus have ->breakpoint initialized. */ 36 assert(leader != NULL); 37 assert(leader->breakpoints != NULL); 38 39#ifdef __arm__ 40 int thumb_mode = (int)addr & 1; 41 if (thumb_mode) 42 addr = (void *)((int)addr & ~1); 43#endif 44 45 debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)", proc->pid, addr, libsym ? libsym->name : "NULL"); 46 debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr); 47 48 if (!addr) 49 return NULL; 50 51 if (libsym) 52 libsym->needs_init = 0; 53 54 sbp = dict_find_entry(leader->breakpoints, addr); 55 if (sbp == NULL) { 56 sbp = calloc(1, sizeof(*sbp)); 57 if (sbp == NULL) { 58 return NULL; /* TODO FIXME XXX: error_mem */ 59 } 60 dict_enter(leader->breakpoints, addr, sbp); 61 sbp->addr = addr; 62 sbp->libsym = libsym; 63 } 64#ifdef __arm__ 65 sbp->thumb_mode = thumb_mode | proc->thumb_mode; 66 proc->thumb_mode = 0; 67#endif 68 sbp->enabled++; 69 if (sbp->enabled == 1 && enable) { 70 assert(proc->pid != 0); 71 enable_breakpoint(proc, sbp); 72 } 73 74 return sbp; 75} 76 77void 78delete_breakpoint(Process *proc, void *addr) 79{ 80 struct breakpoint *sbp; 81 82 debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); 83 84 Process * leader = proc->leader; 85 assert(leader != NULL); 86 87 sbp = dict_find_entry(leader->breakpoints, addr); 88 assert(sbp); /* FIXME: remove after debugging has been done. */ 89 /* This should only happen on out-of-memory conditions. */ 90 if (sbp == NULL) 91 return; 92 93 sbp->enabled--; 94 if (sbp->enabled == 0) 95 disable_breakpoint(proc, sbp); 96 assert(sbp->enabled >= 0); 97} 98 99static void 100enable_bp_cb(void *addr, void *sbp, void *proc) 101{ 102 debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid); 103 if (((Breakpoint *)sbp)->enabled) { 104 enable_breakpoint(proc, sbp); 105 } 106} 107 108void 109enable_all_breakpoints(Process *proc) { 110 debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid); 111 if (proc->breakpoints_enabled <= 0) { 112#ifdef __powerpc__ 113 unsigned long a; 114 115 /* 116 * PPC HACK! (XXX FIXME TODO) 117 * If the dynamic linker hasn't populated the PLT then 118 * dont enable the breakpoints 119 */ 120 if (options.libcalls) { 121 a = ptrace(PTRACE_PEEKTEXT, proc->pid, 122 sym2addr(proc, proc->list_of_symbols), 123 0); 124 if (a == 0x0) 125 return; 126 } 127#endif 128 129 debug(1, "Enabling breakpoints for pid %u...", proc->pid); 130 if (proc->breakpoints) { 131 dict_apply_to_all(proc->breakpoints, enable_bp_cb, 132 proc); 133 } 134#ifdef __mips__ 135 { 136 /* 137 * I'm sure there is a nicer way to do this. We need to 138 * insert breakpoints _after_ the child has been started. 139 */ 140 struct library_symbol *sym; 141 struct library_symbol *new_sym; 142 sym=proc->list_of_symbols; 143 while(sym){ 144 void *addr= sym2addr(proc,sym); 145 if(!addr){ 146 sym=sym->next; 147 continue; 148 } 149 if(dict_find_entry(proc->breakpoints,addr)){ 150 sym=sym->next; 151 continue; 152 } 153 debug(2,"inserting bp %p %s",addr,sym->name); 154 new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1); 155 memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1); 156 new_sym->next=proc->list_of_symbols; 157 proc->list_of_symbols=new_sym; 158 insert_breakpoint(proc, addr, new_sym); 159 sym=sym->next; 160 } 161 } 162#endif 163 } 164 proc->breakpoints_enabled = 1; 165} 166 167static void 168disable_bp_cb(void *addr, void *sbp, void *proc) 169{ 170 debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid); 171 if (((Breakpoint *)sbp)->enabled) { 172 disable_breakpoint(proc, sbp); 173 } 174} 175 176void 177disable_all_breakpoints(Process *proc) { 178 debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid); 179 assert(proc->leader == proc); 180 if (proc->breakpoints_enabled) { 181 debug(1, "Disabling breakpoints for pid %u...", proc->pid); 182 dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); 183 } 184 proc->breakpoints_enabled = 0; 185} 186 187static void 188free_bp_cb(void *addr, void *sbp, void *data) { 189 debug(DEBUG_FUNCTION, "free_bp_cb(sbp=%p)", sbp); 190 assert(sbp); 191 free(sbp); 192} 193 194int 195breakpoints_init(Process *proc, int enable) 196{ 197 struct library_symbol *sym; 198 199 debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); 200 if (proc->breakpoints) { /* let's remove that struct */ 201 dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL); 202 dict_clear(proc->breakpoints); 203 proc->breakpoints = NULL; 204 } 205 206 /* Only the thread group leader should hold the breakpoints. 207 * (N.B. PID may be set to 0 temporarily when called by 208 * handle_exec). */ 209 assert(proc->leader == proc); 210 211 proc->breakpoints = dict_init(dict_key2hash_int, 212 dict_key_cmp_int); 213 214 destroy_library_symbol_chain(proc->list_of_symbols); 215 proc->list_of_symbols = NULL; 216 217 if (options.libcalls && proc->filename) { 218 proc->list_of_symbols = read_elf(proc); 219 if (proc->list_of_symbols == NULL) { 220 /* XXX leak breakpoints */ 221 return -1; 222 } 223 224 if (opt_e) { 225 struct library_symbol **tmp1 = &proc->list_of_symbols; 226 while (*tmp1) { 227 struct opt_e_t *tmp2 = opt_e; 228 int keep = !opt_e_enable; 229 230 while (tmp2) { 231 if (!strcmp((*tmp1)->name, 232 tmp2->name)) { 233 keep = opt_e_enable; 234 } 235 tmp2 = tmp2->next; 236 } 237 if (!keep) { 238 *tmp1 = (*tmp1)->next; 239 } else { 240 tmp1 = &((*tmp1)->next); 241 } 242 } 243 } 244 } 245 246 for (sym = proc->list_of_symbols; sym; sym = sym->next) 247 insert_breakpoint(proc, sym2addr(proc, sym), sym, enable); 248 249 proc->callstack_depth = 0; 250 proc->breakpoints_enabled = -1; 251 return 0; 252} 253 254void 255reinitialize_breakpoints(Process *proc) { 256 struct library_symbol *sym; 257 258 debug(DEBUG_FUNCTION, "reinitialize_breakpoints(pid=%d)", proc->pid); 259 260 sym = proc->list_of_symbols; 261 262 while (sym) { 263 if (sym->needs_init) { 264 insert_breakpoint(proc, sym2addr(proc, sym), sym, 1); 265 if (sym->needs_init && !sym->is_weak) { 266 fprintf(stderr, 267 "could not re-initialize breakpoint for \"%s\" in file \"%s\"\n", 268 sym->name, proc->filename); 269 exit(1); 270 } 271 } 272 sym = sym->next; 273 } 274} 275