aboutsummaryrefslogtreecommitdiff
path: root/breakpoint.h
blob: c36f673eeccd625684f287494e9b57508d2ce431 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 * This file is part of ltrace.
 * Copyright (C) 2012,2013,2014 Petr Machata, Red Hat Inc.
 * Copyright (C) 2009 Juan Cespedes
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#ifndef BREAKPOINT_H
#define BREAKPOINT_H

/* XXX This is currently a very weak abstraction.  We would like to
 * much expand this to allow things like breakpoints on SDT probes and
 * such.
 *
 * In particular, we would like to add a tracepoint abstraction.
 * Tracepoint is a traceable feature--e.g. an exact address, a DWARF
 * symbol, an ELF symbol, a PLT entry, or an SDT probe.  Tracepoints
 * are named and the user can configure which of them he wants to
 * enable.  Realized tracepoints enable breakpoints, which are a
 * low-level realization of high-level tracepoint.
 *
 * Service breakpoints like the handling of dlopen would be a
 * low-level breakpoint, likely without tracepoint attached.
 *
 * So that's for sometimes.
 */

#include "sysdep.h"
#include "library.h"
#include "forward.h"

struct bp_callbacks {
	void (*on_hit)(struct breakpoint *bp, struct process *proc);
	void (*on_continue)(struct breakpoint *bp, struct process *proc);
	void (*on_install)(struct breakpoint *bp, struct process *proc);
	void (*on_retract)(struct breakpoint *bp, struct process *proc);

	/* Create a new breakpoint that should handle return from the
	 * function.  BP is the breakpoint that was just hit and for
	 * which we wish to find the corresponding return breakpoint.
	 * This returns 0 on success (in which case *RET will have
	 * been initialized to desired breakpoint object, or NULL if
	 * none is necessary) or a negative value on failure.  */
	int (*get_return_bp)(struct breakpoint **ret,
			     struct breakpoint *bp, struct process *proc);
};

struct breakpoint {
	struct bp_callbacks *cbs;
	struct library_symbol *libsym;
	void *addr;
	unsigned char orig_value[BREAKPOINT_LENGTH];
	int enabled;
	struct arch_breakpoint_data arch;
	struct os_breakpoint_data os;
};

/* Call ON_HIT handler of BP, if any is set.  */
void breakpoint_on_hit(struct breakpoint *bp, struct process *proc);

/* Call ON_CONTINUE handler of BP.  If none is set, call
 * continue_after_breakpoint.  */
void breakpoint_on_continue(struct breakpoint *bp, struct process *proc);

/* Call ON_RETRACT handler of BP, if any is set.  This should be
 * called before the breakpoints are destroyed.  The reason for a
 * separate interface is that breakpoint_destroy has to be callable
 * without PROC.  ON_DISABLE might be useful as well, but that would
 * be called every time we disable the breakpoint, which is too often
 * (a breakpoint has to be disabled every time that we need to execute
 * the instruction underneath it).  */
void breakpoint_on_retract(struct breakpoint *bp, struct process *proc);

/* Call ON_INSTALL handler of BP, if any is set.  This should be
 * called after the breakpoint is enabled for the first time, not
 * every time it's enabled (such as after stepping over a site of a
 * temporarily disabled breakpoint).  */
void breakpoint_on_install(struct breakpoint *bp, struct process *proc);

/* Call GET_RETURN_BP handler of BP, if any is set.  If none is set,
 * call CREATE_DEFAULT_RETURN_BP to obtain one.  */
int breakpoint_get_return_bp(struct breakpoint **ret,
			     struct breakpoint *bp, struct process *proc);

/* Initialize a breakpoint structure.  That doesn't actually realize
 * the breakpoint.  The breakpoint is initially assumed to be
 * disabled.  orig_value has to be set separately.  CBS may be
 * NULL.  */
int breakpoint_init(struct breakpoint *bp, struct process *proc,
		    arch_addr_t addr, struct library_symbol *libsym);

/* Make a clone of breakpoint BP into the area of memory pointed to by
 * RETP.  Symbols of cloned breakpoint are looked up in NEW_PROC.
 * Returns 0 on success or a negative value on failure.  */
int breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
		     struct breakpoint *bp);

/* Set callbacks.  If CBS is non-NULL, then BP->cbs shall be NULL.  */
void breakpoint_set_callbacks(struct breakpoint *bp, struct bp_callbacks *cbs);

/* Destroy a breakpoint structure.   */
void breakpoint_destroy(struct breakpoint *bp);

/* Call enable_breakpoint the first time it's called.  Returns 0 on
 * success and a negative value on failure.  */
int breakpoint_turn_on(struct breakpoint *bp, struct process *proc);

/* Call disable_breakpoint when turned off the same number of times
 * that it was turned on.  Returns 0 on success and a negative value
 * on failure.  */
int breakpoint_turn_off(struct breakpoint *bp, struct process *proc);

/* Allocate and initialize a default return breakpoint.  Returns NULL
 * on failure.  */
struct breakpoint *create_default_return_bp(struct process *proc);

/* This allocates and initializes new breakpoint at ADDR, then calls
 * INSERT_BREAKPOINT.  Returns the new breakpoint or NULL if there are
 * errors.  */
struct breakpoint *insert_breakpoint_at(struct process *proc, arch_addr_t addr,
					struct library_symbol *libsym);

/* Check if there is a breakpoint on this address already.  If yes,
 * return that breakpoint instead (BP was not added).  If no, try to
 * PROC_ADD_BREAKPOINT and BREAKPOINT_TURN_ON.  If it all works,
 * return BP.  Otherwise return NULL.  */
struct breakpoint *insert_breakpoint(struct process *proc,
				     struct breakpoint *bp);

/* Name of a symbol associated with BP.  May be NULL.  */
const char *breakpoint_name(const struct breakpoint *bp);

/* A library that this breakpoint comes from.  May be NULL.  */
struct library *breakpoint_library(const struct breakpoint *bp);

/* Again, this seems to be several interfaces rolled into one:
 *  - breakpoint_disable
 *  - proc_remove_breakpoint
 *  - breakpoint_destroy
 * XXX */
void delete_breakpoint_at(struct process *proc, void *addr);
int delete_breakpoint(struct process *proc, struct breakpoint *bp);

/* XXX some of the following belongs to proc.h/proc.c.  */
struct breakpoint *address2bpstruct(struct process *proc, void *addr);
void disable_all_breakpoints(struct process *proc);
int breakpoints_init(struct process *proc);

#endif /* BREAKPOINT_H */