blob: d9ea6e928a1c183da507168ee2be7392b6e317e5 [file] [log] [blame]
Juan Cespedesd44c6b81998-09-25 14:48:42 +02001#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +02005#include <stdlib.h>
Juan Cespedes7186e2a2003-01-31 19:56:34 +01006#include <string.h>
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +02007#include <assert.h>
8
Juan Cespedesf1bfe202002-03-27 00:22:23 +01009#ifdef __powerpc__
10#include <sys/ptrace.h>
11#endif
12
Juan Cespedescac15c32003-01-31 18:58:58 +010013#include "ltrace.h"
14#include "options.h"
15#include "debug.h"
16#include "dict.h"
Juan Cespedes7186e2a2003-01-31 19:56:34 +010017#include "elf.h"
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020018
19/*****************************************************************************/
20
Ian Wienand9a2ad352006-02-20 22:44:45 +010021struct breakpoint *
22address2bpstruct(struct process * proc, void * addr) {
Juan Cespedescac15c32003-01-31 18:58:58 +010023 return dict_find_entry(proc->breakpoints, addr);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020024}
25
Ian Wienand9a2ad352006-02-20 22:44:45 +010026void
27insert_breakpoint(struct process * proc, void * addr, struct library_symbol * libsym) {
28 struct breakpoint * sbp;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020029
Juan Cespedescac15c32003-01-31 18:58:58 +010030 if (!proc->breakpoints) {
Ian Wienand9a2ad352006-02-20 22:44:45 +010031 proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int);
32 /* atexit(brk_dict_clear); */ /* why bother to do this on exit? */
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020033 }
Ian Wienand9a2ad352006-02-20 22:44:45 +010034
35 if (!addr)
36 return;
37
38 if (libsym)
39 libsym->needs_init = 0;
40
Juan Cespedescac15c32003-01-31 18:58:58 +010041 sbp = dict_find_entry(proc->breakpoints, addr);
42 if (!sbp) {
Ian Wienand9a2ad352006-02-20 22:44:45 +010043 sbp = calloc(1, sizeof(struct breakpoint));
Juan Cespedescac15c32003-01-31 18:58:58 +010044 if (!sbp) {
Ian Wienand9a2ad352006-02-20 22:44:45 +010045 return; /* TODO FIXME XXX: error_mem */
Juan Cespedescac15c32003-01-31 18:58:58 +010046 }
47 dict_enter(proc->breakpoints, addr, sbp);
48 sbp->addr = addr;
Ian Wienand9a2ad352006-02-20 22:44:45 +010049 sbp->libsym = libsym;
50 if (libsym)
51 libsym->brkpnt = sbp;
Juan Cespedescac15c32003-01-31 18:58:58 +010052 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020053 sbp->enabled++;
Ian Wienand9a2ad352006-02-20 22:44:45 +010054 if (sbp->enabled==1 && proc->pid) enable_breakpoint(proc->pid, sbp);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020055}
56
Ian Wienand9a2ad352006-02-20 22:44:45 +010057void
58delete_breakpoint(struct process * proc, void * addr) {
59 struct breakpoint * sbp = dict_find_entry(proc->breakpoints, addr);
60 assert(sbp); /* FIXME: remove after debugging has been done. */
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020061 /* This should only happen on out-of-memory conditions. */
Ian Wienand9a2ad352006-02-20 22:44:45 +010062 if (sbp == NULL) return;
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020063
64 sbp->enabled--;
Ian Wienand9a2ad352006-02-20 22:44:45 +010065 if (sbp->enabled == 0) disable_breakpoint(proc->pid, sbp);
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020066 assert(sbp->enabled >= 0);
67}
68
Ian Wienand9a2ad352006-02-20 22:44:45 +010069static void
70enable_bp_cb(void * addr, void * sbp, void * proc) {
Juan Cespedescac15c32003-01-31 18:58:58 +010071 if (((struct breakpoint *)sbp)->enabled) {
72 enable_breakpoint(((struct process *)proc)->pid, sbp);
73 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +020074}
75
Ian Wienand9a2ad352006-02-20 22:44:45 +010076void
77enable_all_breakpoints(struct process * proc) {
Juan Cespedes5e01f651998-03-08 22:31:44 +010078 if (proc->breakpoints_enabled <= 0) {
Juan Cespedesf1bfe202002-03-27 00:22:23 +010079#ifdef __powerpc__
80 unsigned long a;
81
82 /*
83 * PPC HACK! (XXX FIXME TODO)
84 * If the dynamic linker hasn't populated the PLT then
85 * dont enable the breakpoints
86 */
Juan Cespedesde5a7eb2002-03-31 20:53:52 +020087 if (opt_L) {
Ian Wienand9a2ad352006-02-20 22:44:45 +010088 a = ptrace(PTRACE_PEEKTEXT, proc->pid, plt2addr(proc, proc->list_of_symbols->enter_addr), 0);
Juan Cespedesde5a7eb2002-03-31 20:53:52 +020089 if (a == 0x0)
90 return;
91 }
Juan Cespedesf1bfe202002-03-27 00:22:23 +010092#endif
93
Juan Cespedescac15c32003-01-31 18:58:58 +010094 debug(1, "Enabling breakpoints for pid %u...", proc->pid);
Juan Cespedesa0ccf392003-02-01 19:02:37 +010095 if (proc->breakpoints) {
Ian Wienand9a2ad352006-02-20 22:44:45 +010096 dict_apply_to_all(proc->breakpoints, enable_bp_cb, proc);
Juan Cespedesa0ccf392003-02-01 19:02:37 +010097 }
Juan Cespedes5e01f651998-03-08 22:31:44 +010098 }
99 proc->breakpoints_enabled = 1;
100}
101
Ian Wienand9a2ad352006-02-20 22:44:45 +0100102static void
103disable_bp_cb(void * addr, void * sbp, void * proc) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100104 if (((struct breakpoint *)sbp)->enabled) {
105 disable_breakpoint(((struct process *)proc)->pid, sbp);
106 }
Juan Cespedes5b3ffdf2001-07-02 00:52:45 +0200107}
108
Ian Wienand9a2ad352006-02-20 22:44:45 +0100109void
110disable_all_breakpoints(struct process * proc) {
Juan Cespedes5e01f651998-03-08 22:31:44 +0100111 if (proc->breakpoints_enabled) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100112 debug(1, "Disabling breakpoints for pid %u...", proc->pid);
113 dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
Juan Cespedes5e01f651998-03-08 22:31:44 +0100114 }
115 proc->breakpoints_enabled = 0;
116}
Juan Cespedes7186e2a2003-01-31 19:56:34 +0100117
Ian Wienand9a2ad352006-02-20 22:44:45 +0100118static void
119free_bp_cb(void * addr, void * sbp, void * data) {
Juan Cespedes7186e2a2003-01-31 19:56:34 +0100120 assert(sbp);
121 free(sbp);
122}
123
Ian Wienand9a2ad352006-02-20 22:44:45 +0100124void
125breakpoints_init(struct process * proc) {
126 struct library_symbol * sym;
Juan Cespedes7186e2a2003-01-31 19:56:34 +0100127
Ian Wienand9a2ad352006-02-20 22:44:45 +0100128 if (proc->breakpoints) { /* let's remove that struct */
Juan Cespedes7186e2a2003-01-31 19:56:34 +0100129 /* TODO FIXME XXX: free() all "struct breakpoint"s */
130 dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL);
131 dict_clear(proc->breakpoints);
132 proc->breakpoints = NULL;
133 }
134
135 if (opt_L && proc->filename) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100136 proc->list_of_symbols = read_elf(proc);
Juan Cespedes7186e2a2003-01-31 19:56:34 +0100137 if (opt_e) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100138 struct library_symbol ** tmp1 = &(proc->list_of_symbols);
139 while(*tmp1) {
140 struct opt_e_t * tmp2 = opt_e;
Juan Cespedes7186e2a2003-01-31 19:56:34 +0100141 int keep = !opt_e_enable;
142
Ian Wienand9a2ad352006-02-20 22:44:45 +0100143 while(tmp2) {
Juan Cespedes7186e2a2003-01-31 19:56:34 +0100144 if (!strcmp((*tmp1)->name, tmp2->name)) {
145 keep = opt_e_enable;
146 }
147 tmp2 = tmp2->next;
148 }
149 if (!keep) {
150 *tmp1 = (*tmp1)->next;
151 } else {
152 tmp1 = &((*tmp1)->next);
153 }
154 }
155 }
156 } else {
157 proc->list_of_symbols = NULL;
158 }
159 sym = proc->list_of_symbols;
160 while (sym) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100161 /* proc->pid==0 delays enabling. */
162 if (sym->static_plt2addr) {
163 insert_breakpoint(proc, sym->enter_addr, sym);
164 } else {
165 insert_breakpoint(proc, plt2addr(proc, sym->enter_addr), sym); /* proc->pid==0 delays enabling. */
166 }
Juan Cespedes7186e2a2003-01-31 19:56:34 +0100167 sym = sym->next;
168 }
169 proc->callstack_depth = 0;
170 proc->breakpoints_enabled = -1;
171}
Ian Wienand9a2ad352006-02-20 22:44:45 +0100172
173void
174reinitialize_breakpoints (struct process * proc) {
175 struct library_symbol * sym = proc->list_of_symbols;
176
177 while (sym) {
178 if (sym->needs_init) {
179 insert_breakpoint(proc, plt2addr(proc, sym->enter_addr), sym);
180 if (sym->needs_init && !sym->is_weak) {
181 fprintf(stderr, "could not re-initialize breakpoint for \"%s\" in file \"%s\"\n", sym->name, proc->filename);
182 exit(1);
183 }
184 }
185 sym = sym->next;
186 }
187}
188