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