xref: /openbsd-src/sys/ddb/db_break.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: db_break.c,v 1.14 2010/11/27 19:59:11 miod 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/proc.h>
38 
39 #include <uvm/uvm_extern.h>
40 
41 #include <machine/db_machdep.h>		/* type definitions */
42 
43 #include <ddb/db_lex.h>
44 #include <ddb/db_access.h>
45 #include <ddb/db_sym.h>
46 #include <ddb/db_break.h>
47 #include <ddb/db_output.h>
48 
49 #define	NBREAKPOINTS	100
50 struct db_breakpoint	db_break_table[NBREAKPOINTS];
51 db_breakpoint_t		db_next_free_breakpoint = &db_break_table[0];
52 db_breakpoint_t		db_free_breakpoints = 0;
53 db_breakpoint_t		db_breakpoint_list = 0;
54 
55 db_breakpoint_t
56 db_breakpoint_alloc(void)
57 {
58 	db_breakpoint_t	bkpt;
59 
60 	if ((bkpt = db_free_breakpoints) != 0) {
61 	    db_free_breakpoints = bkpt->link;
62 	    return (bkpt);
63 	}
64 	if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
65 	    db_printf("All breakpoints used.\n");
66 	    return (0);
67 	}
68 	bkpt = db_next_free_breakpoint;
69 	db_next_free_breakpoint++;
70 
71 	return (bkpt);
72 }
73 
74 void
75 db_breakpoint_free(db_breakpoint_t bkpt)
76 {
77 	bkpt->link = db_free_breakpoints;
78 	db_free_breakpoints = bkpt;
79 }
80 
81 void
82 db_set_breakpoint(db_addr_t addr, int count)
83 {
84 	db_breakpoint_t	bkpt;
85 
86 	if (db_find_breakpoint(addr)) {
87 		db_printf("Already set.\n");
88 		return;
89 	}
90 
91 #ifdef DB_VALID_BREAKPOINT
92 	if (!DB_VALID_BREAKPOINT(addr)) {
93 		db_printf("Not a valid address for a breakpoint.\n");
94 		return;
95 	}
96 #endif
97 
98 	bkpt = db_breakpoint_alloc();
99 	if (bkpt == 0) {
100 		db_printf("Too many breakpoints.\n");
101 		return;
102 	}
103 
104 	bkpt->address = addr;
105 	bkpt->flags = 0;
106 	bkpt->init_count = count;
107 	bkpt->count = count;
108 
109 	bkpt->link = db_breakpoint_list;
110 	db_breakpoint_list = bkpt;
111 }
112 
113 void
114 db_delete_breakpoint(db_addr_t addr)
115 {
116 	db_breakpoint_t	bkpt;
117 	db_breakpoint_t	*prev;
118 
119 	for (prev = &db_breakpoint_list; (bkpt = *prev) != 0;
120 	    prev = &bkpt->link) {
121 		if (bkpt->address == addr) {
122 			*prev = bkpt->link;
123 			break;
124 		}
125 	}
126 	if (bkpt == 0) {
127 		db_printf("Not set.\n");
128 		return;
129 	}
130 
131 	db_breakpoint_free(bkpt);
132 }
133 
134 db_breakpoint_t
135 db_find_breakpoint(db_addr_t addr)
136 {
137 	db_breakpoint_t	bkpt;
138 
139 	for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link)
140 		if (bkpt->address == addr)
141 			return (bkpt);
142 
143 	return (0);
144 }
145 
146 boolean_t	db_breakpoints_inserted = TRUE;
147 
148 void
149 db_set_breakpoints(void)
150 {
151 	db_breakpoint_t	bkpt;
152 
153 	if (!db_breakpoints_inserted) {
154 		for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
155 			bkpt->bkpt_inst =
156 			    db_get_value(bkpt->address, BKPT_SIZE, FALSE);
157 			db_put_value(bkpt->address, BKPT_SIZE,
158 			    BKPT_SET(bkpt->bkpt_inst));
159 		}
160 		db_breakpoints_inserted = TRUE;
161 	}
162 }
163 
164 void
165 db_clear_breakpoints(void)
166 {
167 	db_breakpoint_t	bkpt;
168 
169 	if (db_breakpoints_inserted) {
170 		for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link)
171 			db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
172 		db_breakpoints_inserted = FALSE;
173 	}
174 }
175 
176 /*
177  * Set a temporary breakpoint.
178  * The instruction is changed immediately,
179  * so the breakpoint does not have to be on the breakpoint list.
180  */
181 db_breakpoint_t
182 db_set_temp_breakpoint(db_addr_t addr)
183 {
184 	db_breakpoint_t	bkpt;
185 
186 #ifdef DB_VALID_BREAKPOINT
187 	if (!DB_VALID_BREAKPOINT(addr)) {
188 		db_printf("Not a valid address for a breakpoint.\n");
189 		return (0);
190 	}
191 #endif
192 
193 	bkpt = db_breakpoint_alloc();
194 	if (bkpt == 0) {
195 	    db_printf("Too many breakpoints.\n");
196 	    return (0);
197 	}
198 
199 	bkpt->address = addr;
200 	bkpt->flags = BKPT_TEMP;
201 	bkpt->init_count = 1;
202 	bkpt->count = 1;
203 
204 	bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
205 	db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
206 	return bkpt;
207 }
208 
209 void
210 db_delete_temp_breakpoint(db_breakpoint_t bkpt)
211 {
212 	db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
213 	db_breakpoint_free(bkpt);
214 }
215 
216 /*
217  * List breakpoints.
218  */
219 void
220 db_list_breakpoints(void)
221 {
222 	db_breakpoint_t	bkpt;
223 
224 	if (db_breakpoint_list == NULL) {
225 		db_printf("No breakpoints set\n");
226 		return;
227 	}
228 
229 	db_printf(" Count    Address\n");
230 	for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
231 		db_printf(" %5d    ", bkpt->init_count);
232 		db_printsym(bkpt->address, DB_STGY_PROC, db_printf);
233 		db_printf("\n");
234 	}
235 }
236 
237 /* Delete breakpoint */
238 /*ARGSUSED*/
239 void
240 db_delete_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
241 {
242 	db_delete_breakpoint((db_addr_t)addr);
243 }
244 
245 /* Set breakpoint with skip count */
246 /*ARGSUSED*/
247 void
248 db_breakpoint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
249 {
250 	if (count == -1)
251 		count = 1;
252 
253 	db_set_breakpoint((db_addr_t)addr, count);
254 }
255 
256 /* list breakpoints */
257 /*ARGSUSED*/
258 void
259 db_listbreak_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
260 {
261 	db_list_breakpoints();
262 }
263