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