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