breakpoints.c revision 642626096a694c6af279d25d2b1b2fba5b10ddfb
1#include "config.h"
2
3#include <stdlib.h>
4#include <string.h>
5#include <assert.h>
6#include <errno.h>
7
8#ifdef __powerpc__
9#include <sys/ptrace.h>
10#endif
11
12#include "breakpoint.h"
13#include "proc.h"
14#include "library.h"
15#include "backend.h"
16
17#ifndef ARCH_HAVE_TRANSLATE_ADDRESS
18int
19arch_translate_address_dyn(struct Process *proc,
20		       target_address_t addr, target_address_t *ret)
21{
22	*ret = addr;
23	return 0;
24}
25
26struct ltelf;
27int
28arch_translate_address(struct ltelf *lte,
29		       target_address_t addr, target_address_t *ret)
30{
31	*ret = addr;
32	return 0;
33}
34#endif
35
36void
37breakpoint_on_hit(struct breakpoint *bp, struct Process *proc)
38{
39	assert(bp != NULL);
40	if (bp->cbs != NULL && bp->cbs->on_hit != NULL)
41		(bp->cbs->on_hit)(bp, proc);
42}
43
44void
45breakpoint_on_continue(struct breakpoint *bp, struct Process *proc)
46{
47	assert(bp != NULL);
48	if (bp->cbs != NULL && bp->cbs->on_continue != NULL)
49		(bp->cbs->on_continue)(bp, proc);
50	else
51		continue_after_breakpoint(proc, bp);
52}
53
54void
55breakpoint_on_retract(struct breakpoint *bp, struct Process *proc)
56{
57	assert(bp != NULL);
58	if (bp->cbs != NULL && bp->cbs->on_retract != NULL)
59		(bp->cbs->on_retract)(bp, proc);
60}
61
62/*****************************************************************************/
63
64struct breakpoint *
65address2bpstruct(Process *proc, void *addr)
66{
67	assert(proc != NULL);
68	assert(proc->breakpoints != NULL);
69	assert(proc->leader == proc);
70	debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr);
71	return dict_find_entry(proc->breakpoints, addr);
72}
73
74#ifndef ARCH_HAVE_BREAKPOINT_DATA
75int
76arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp)
77{
78	return 0;
79}
80
81void
82arch_breakpoint_destroy(struct breakpoint *sbp)
83{
84}
85
86int
87arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp)
88{
89	return 0;
90}
91#endif
92
93static void
94breakpoint_init_base(struct breakpoint *bp, struct Process *proc,
95		     target_address_t addr, struct library_symbol *libsym)
96{
97	bp->cbs = NULL;
98	bp->addr = addr;
99	memset(bp->orig_value, 0, sizeof(bp->orig_value));
100	bp->enabled = 0;
101	bp->libsym = libsym;
102}
103
104/* On second thought, I don't think we need PROC.  All the translation
105 * (arch_translate_address in particular) should be doable using
106 * static lookups of various sections in the ELF file.  We shouldn't
107 * need process for anything.  */
108int
109breakpoint_init(struct breakpoint *bp, struct Process *proc,
110		target_address_t addr, struct library_symbol *libsym)
111{
112	breakpoint_init_base(bp, proc, addr, libsym);
113	return arch_breakpoint_init(proc, bp);
114}
115
116void
117breakpoint_set_callbacks(struct breakpoint *bp, struct bp_callbacks *cbs)
118{
119	if (bp->cbs != NULL)
120		assert(bp->cbs == NULL);
121	bp->cbs = cbs;
122}
123
124void
125breakpoint_destroy(struct breakpoint *bp)
126{
127	if (bp == NULL)
128		return;
129	arch_breakpoint_destroy(bp);
130}
131
132struct find_symbol_data {
133	struct library_symbol *old_libsym;
134	struct library_symbol *found_libsym;
135};
136
137static enum callback_status
138find_sym_in_lib(struct Process *proc, struct library *lib, void *u)
139{
140	struct find_symbol_data *fs = u;
141	fs->found_libsym
142		= library_each_symbol(lib, NULL, library_symbol_equal_cb,
143				      fs->old_libsym);
144	return fs->found_libsym != NULL ? CBS_STOP : CBS_CONT;
145}
146
147int
148breakpoint_clone(struct breakpoint *retp, struct Process *new_proc,
149		 struct breakpoint *bp, struct Process *old_proc)
150{
151	/* Find library and symbol that this breakpoint was linked to.  */
152	struct library_symbol *libsym = bp->libsym;
153	struct library *lib = NULL;
154	if (libsym != NULL) {
155		struct find_symbol_data f_data = {
156			.old_libsym = libsym,
157		};
158		lib = proc_each_library(old_proc, NULL,
159					find_sym_in_lib, &f_data);
160		assert(lib != NULL);
161		libsym = f_data.found_libsym;
162	}
163
164	/* LIB and LIBSYM now hold the new library and symbol that
165	 * correspond to the original breakpoint.  Now we can do the
166	 * clone itself.  */
167	breakpoint_init_base(retp, new_proc, bp->addr, libsym);
168	memcpy(retp->orig_value, bp->orig_value, sizeof(bp->orig_value));
169	retp->enabled = bp->enabled;
170	if (arch_breakpoint_clone(retp, bp) < 0)
171		return -1;
172	breakpoint_set_callbacks(retp, bp->cbs);
173	return 0;
174}
175
176int
177breakpoint_turn_on(struct breakpoint *bp, struct Process *proc)
178{
179	bp->enabled++;
180	if (bp->enabled == 1) {
181		assert(proc->pid != 0);
182		enable_breakpoint(proc, bp);
183	}
184	return 0;
185}
186
187int
188breakpoint_turn_off(struct breakpoint *bp, struct Process *proc)
189{
190	bp->enabled--;
191	if (bp->enabled == 0)
192		disable_breakpoint(proc, bp);
193	assert(bp->enabled >= 0);
194	return 0;
195}
196
197struct breakpoint *
198insert_breakpoint(struct Process *proc, void *addr,
199		  struct library_symbol *libsym)
200{
201	Process *leader = proc->leader;
202
203	/* Only the group leader should be getting the breakpoints and
204	 * thus have ->breakpoint initialized.  */
205	assert(leader != NULL);
206	assert(leader->breakpoints != NULL);
207
208	debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)",
209	      proc->pid, addr, libsym ? libsym->name : "NULL");
210
211	assert(addr != 0);
212
213	/* XXX what we need to do instead is have a list of
214	 * breakpoints that are enabled at this address.  The
215	 * following works if every breakpoint is the same and there's
216	 * no extra data, but that doesn't hold anymore.  For now it
217	 * will suffice, about the only realistic case where we need
218	 * to have more than one breakpoint per address is return from
219	 * a recursive library call.  */
220	struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr);
221	if (sbp == NULL) {
222		sbp = malloc(sizeof(*sbp));
223		if (sbp == NULL
224		    || breakpoint_init(sbp, proc, addr, libsym) < 0) {
225			free(sbp);
226			return NULL;
227		}
228		if (proc_add_breakpoint(leader, sbp) < 0) {
229		fail:
230			breakpoint_destroy(sbp);
231			free(sbp);
232			return NULL;
233		}
234	}
235
236	if (breakpoint_turn_on(sbp, proc) < 0) {
237		proc_remove_breakpoint(leader, sbp);
238		goto fail;
239	}
240
241	return sbp;
242}
243
244void
245delete_breakpoint(Process *proc, void *addr)
246{
247	debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr);
248
249	Process * leader = proc->leader;
250	assert(leader != NULL);
251
252	struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr);
253	assert(sbp != NULL);
254	/* This should only happen on out-of-memory conditions. */
255	if (sbp == NULL)
256		return;
257
258	if (breakpoint_turn_off(sbp, proc) < 0) {
259		fprintf(stderr, "Couldn't turn off the breakpoint %s@%p\n",
260			breakpoint_name(sbp), sbp->addr);
261		return;
262	}
263	if (sbp->enabled == 0) {
264		proc_remove_breakpoint(leader, sbp);
265		breakpoint_destroy(sbp);
266		free(sbp);
267	}
268}
269
270const char *
271breakpoint_name(const struct breakpoint *bp)
272{
273	assert(bp != NULL);
274	return bp->libsym != NULL ? bp->libsym->name : NULL;
275}
276
277struct library *
278breakpoint_library(const struct breakpoint *bp)
279{
280	assert(bp != NULL);
281	return bp->libsym != NULL ? bp->libsym->lib : NULL;
282}
283
284static void
285enable_bp_cb(void *addr, void *sbp, void *proc)
286{
287	debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid);
288	if (((struct breakpoint *)sbp)->enabled)
289		enable_breakpoint(proc, sbp);
290}
291
292void
293enable_all_breakpoints(Process *proc)
294{
295	debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid);
296
297	debug(1, "Enabling breakpoints for pid %u...", proc->pid);
298	if (proc->breakpoints) {
299		dict_apply_to_all(proc->breakpoints, enable_bp_cb,
300				  proc);
301	}
302#ifdef __mips__
303	{
304		/*
305		 * I'm sure there is a nicer way to do this. We need to
306		 * insert breakpoints _after_ the child has been started.
307		 */
308		struct library_symbol *sym;
309		struct library_symbol *new_sym;
310		sym=proc->list_of_symbols;
311		while(sym){
312			void *addr= sym2addr(proc,sym);
313			if(!addr){
314				sym=sym->next;
315				continue;
316			}
317			if(dict_find_entry(proc->breakpoints,addr)){
318				sym=sym->next;
319				continue;
320			}
321			debug(2,"inserting bp %p %s",addr,sym->name);
322			new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
323			memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
324			new_sym->next=proc->list_of_symbols;
325			proc->list_of_symbols=new_sym;
326			insert_breakpoint(proc, addr, new_sym);
327			sym=sym->next;
328		}
329	}
330#endif
331}
332
333static void
334disable_bp_cb(void *addr, void *sbp, void *proc)
335{
336	debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid);
337	if (((struct breakpoint *)sbp)->enabled)
338		disable_breakpoint(proc, sbp);
339}
340
341void
342disable_all_breakpoints(Process *proc) {
343	debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid);
344	assert(proc->leader == proc);
345	dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
346}
347
348/* XXX This is not currently properly supported.  On clone, this is
349 * just sliced.  Hopefully at the point that clone is done, this
350 * breakpoint is not necessary anymore.  If this use case ends up
351 * being important, we need to add a clone and destroy callbacks to
352 * breakpoints, and we should also probably drop arch_breakpoint_data
353 * so that we don't end up with two different customization mechanisms
354 * for one structure.  */
355struct entry_breakpoint {
356	struct breakpoint super;
357	target_address_t dyn_addr;
358};
359
360static void
361entry_breakpoint_on_hit(struct breakpoint *a, struct Process *proc)
362{
363	struct entry_breakpoint *bp = (void *)a;
364	if (proc == NULL || proc->leader == NULL)
365		return;
366	target_address_t dyn_addr = bp->dyn_addr;
367	delete_breakpoint(proc, bp->super.addr);
368	linkmap_init(proc, dyn_addr);
369	arch_dynlink_done(proc);
370}
371
372int
373entry_breakpoint_init(struct Process *proc,
374		      struct entry_breakpoint *bp, target_address_t addr,
375		      struct library *lib)
376{
377	int err;
378	if ((err = breakpoint_init(&bp->super, proc, addr, NULL)) < 0)
379		return err;
380
381	static struct bp_callbacks entry_callbacks = {
382		.on_hit = entry_breakpoint_on_hit,
383	};
384	bp->super.cbs = &entry_callbacks;
385	bp->dyn_addr = lib->dyn_addr;
386	return 0;
387}
388
389int
390breakpoints_init(Process *proc)
391{
392	debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid);
393
394	/* XXX breakpoint dictionary should be initialized
395	 * outside.  Here we just put in breakpoints.  */
396	assert(proc->breakpoints != NULL);
397
398	/* Only the thread group leader should hold the breakpoints.  */
399	assert(proc->leader == proc);
400
401	/* N.B. the following used to be conditional on this, and
402	 * maybe it still needs to be.  */
403	assert(proc->filename != NULL);
404
405	struct library *lib = ltelf_read_main_binary(proc, proc->filename);
406	struct entry_breakpoint *entry_bp = NULL;
407	int bp_state = 0;
408	int result = -1;
409	switch (lib != NULL) {
410	fail:
411		switch (bp_state) {
412		case 2:
413			proc_remove_library(proc, lib);
414			proc_remove_breakpoint(proc, &entry_bp->super);
415		case 1:
416			breakpoint_destroy(&entry_bp->super);
417		}
418		library_destroy(lib);
419		free(entry_bp);
420	case 0:
421		return result;
422	}
423
424	entry_bp = malloc(sizeof(*entry_bp));
425	if (entry_bp == NULL
426	    || (entry_breakpoint_init(proc, entry_bp,
427				      lib->entry, lib)) < 0) {
428		fprintf(stderr,
429			"Couldn't initialize entry breakpoint for PID %d.\n"
430			"Some tracing events may be missed.\n", proc->pid);
431		free(entry_bp);
432
433	} else {
434		++bp_state;
435
436		if ((result = proc_add_breakpoint(proc, &entry_bp->super)) < 0)
437			goto fail;
438		++bp_state;
439
440		if ((result = breakpoint_turn_on(&entry_bp->super, proc)) < 0)
441			goto fail;
442	}
443	proc_add_library(proc, lib);
444
445	proc->callstack_depth = 0;
446	return 0;
447}
448