xref: /openbsd-src/sys/ddb/db_break.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: db_break.c,v 1.15 2014/07/08 13:02:57 deraadt Exp $	*/
2 /*	$NetBSD: db_break.c,v 1.7 1996/03/30 22:30:03 christos Exp $	*/
3 
4 /*
5  * Mach Operating System
6  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7  * All Rights Reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie Mellon
27  * the rights to redistribute these changes.
28  *
29  *	Author: David B. Golub, Carnegie Mellon University
30  *	Date:	7/90
31  */
32 
33 /*
34  * Breakpoints.
35  */
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/proc.h>
39 
40 #include <machine/db_machdep.h>		/* type definitions */
41 
42 #include <ddb/db_lex.h>
43 #include <ddb/db_access.h>
44 #include <ddb/db_sym.h>
45 #include <ddb/db_break.h>
46 #include <ddb/db_output.h>
47 
48 #define	NBREAKPOINTS	100
49 struct db_breakpoint	db_break_table[NBREAKPOINTS];
50 db_breakpoint_t		db_next_free_breakpoint = &db_break_table[0];
51 db_breakpoint_t		db_free_breakpoints = 0;
52 db_breakpoint_t		db_breakpoint_list = 0;
53 
54 db_breakpoint_t
55 db_breakpoint_alloc(void)
56 {
57 	db_breakpoint_t	bkpt;
58 
59 	if ((bkpt = db_free_breakpoints) != 0) {
60 	    db_free_breakpoints = bkpt->link;
61 	    return (bkpt);
62 	}
63 	if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
64 	    db_printf("All breakpoints used.\n");
65 	    return (0);
66 	}
67 	bkpt = db_next_free_breakpoint;
68 	db_next_free_breakpoint++;
69 
70 	return (bkpt);
71 }
72 
73 void
74 db_breakpoint_free(db_breakpoint_t bkpt)
75 {
76 	bkpt->link = db_free_breakpoints;
77 	db_free_breakpoints = bkpt;
78 }
79 
80 void
81 db_set_breakpoint(db_addr_t addr, int count)
82 {
83 	db_breakpoint_t	bkpt;
84 
85 	if (db_find_breakpoint(addr)) {
86 		db_printf("Already set.\n");
87 		return;
88 	}
89 
90 #ifdef DB_VALID_BREAKPOINT
91 	if (!DB_VALID_BREAKPOINT(addr)) {
92 		db_printf("Not a valid address for a breakpoint.\n");
93 		return;
94 	}
95 #endif
96 
97 	bkpt = db_breakpoint_alloc();
98 	if (bkpt == 0) {
99 		db_printf("Too many breakpoints.\n");
100 		return;
101 	}
102 
103 	bkpt->address = addr;
104 	bkpt->flags = 0;
105 	bkpt->init_count = count;
106 	bkpt->count = count;
107 
108 	bkpt->link = db_breakpoint_list;
109 	db_breakpoint_list = bkpt;
110 }
111 
112 void
113 db_delete_breakpoint(db_addr_t addr)
114 {
115 	db_breakpoint_t	bkpt;
116 	db_breakpoint_t	*prev;
117 
118 	for (prev = &db_breakpoint_list; (bkpt = *prev) != 0;
119 	    prev = &bkpt->link) {
120 		if (bkpt->address == addr) {
121 			*prev = bkpt->link;
122 			break;
123 		}
124 	}
125 	if (bkpt == 0) {
126 		db_printf("Not set.\n");
127 		return;
128 	}
129 
130 	db_breakpoint_free(bkpt);
131 }
132 
133 db_breakpoint_t
134 db_find_breakpoint(db_addr_t addr)
135 {
136 	db_breakpoint_t	bkpt;
137 
138 	for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link)
139 		if (bkpt->address == addr)
140 			return (bkpt);
141 
142 	return (0);
143 }
144 
145 boolean_t	db_breakpoints_inserted = TRUE;
146 
147 void
148 db_set_breakpoints(void)
149 {
150 	db_breakpoint_t	bkpt;
151 
152 	if (!db_breakpoints_inserted) {
153 		for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
154 			bkpt->bkpt_inst =
155 			    db_get_value(bkpt->address, BKPT_SIZE, FALSE);
156 			db_put_value(bkpt->address, BKPT_SIZE,
157 			    BKPT_SET(bkpt->bkpt_inst));
158 		}
159 		db_breakpoints_inserted = TRUE;
160 	}
161 }
162 
163 void
164 db_clear_breakpoints(void)
165 {
166 	db_breakpoint_t	bkpt;
167 
168 	if (db_breakpoints_inserted) {
169 		for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link)
170 			db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
171 		db_breakpoints_inserted = FALSE;
172 	}
173 }
174 
175 /*
176  * Set a temporary breakpoint.
177  * The instruction is changed immediately,
178  * so the breakpoint does not have to be on the breakpoint list.
179  */
180 db_breakpoint_t
181 db_set_temp_breakpoint(db_addr_t addr)
182 {
183 	db_breakpoint_t	bkpt;
184 
185 #ifdef DB_VALID_BREAKPOINT
186 	if (!DB_VALID_BREAKPOINT(addr)) {
187 		db_printf("Not a valid address for a breakpoint.\n");
188 		return (0);
189 	}
190 #endif
191 
192 	bkpt = db_breakpoint_alloc();
193 	if (bkpt == 0) {
194 	    db_printf("Too many breakpoints.\n");
195 	    return (0);
196 	}
197 
198 	bkpt->address = addr;
199 	bkpt->flags = BKPT_TEMP;
200 	bkpt->init_count = 1;
201 	bkpt->count = 1;
202 
203 	bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
204 	db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
205 	return bkpt;
206 }
207 
208 void
209 db_delete_temp_breakpoint(db_breakpoint_t bkpt)
210 {
211 	db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
212 	db_breakpoint_free(bkpt);
213 }
214 
215 /*
216  * List breakpoints.
217  */
218 void
219 db_list_breakpoints(void)
220 {
221 	db_breakpoint_t	bkpt;
222 
223 	if (db_breakpoint_list == NULL) {
224 		db_printf("No breakpoints set\n");
225 		return;
226 	}
227 
228 	db_printf(" Count    Address\n");
229 	for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
230 		db_printf(" %5d    ", bkpt->init_count);
231 		db_printsym(bkpt->address, DB_STGY_PROC, db_printf);
232 		db_printf("\n");
233 	}
234 }
235 
236 /* Delete breakpoint */
237 /*ARGSUSED*/
238 void
239 db_delete_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
240 {
241 	db_delete_breakpoint((db_addr_t)addr);
242 }
243 
244 /* Set breakpoint with skip count */
245 /*ARGSUSED*/
246 void
247 db_breakpoint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
248 {
249 	if (count == -1)
250 		count = 1;
251 
252 	db_set_breakpoint((db_addr_t)addr, count);
253 }
254 
255 /* list breakpoints */
256 /*ARGSUSED*/
257 void
258 db_listbreak_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
259 {
260 	db_list_breakpoints();
261 }
262