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