db_break.c revision 1.14 1 /* $NetBSD: db_break.c,v 1.14 2000/06/26 14:21:09 mrg Exp $ */
2
3 /*
4 * Mach Operating System
5 * Copyright (c) 1991,1990 Carnegie Mellon University
6 * All Rights Reserved.
7 *
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
13 *
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 *
18 * Carnegie Mellon requests users of this software to return to
19 *
20 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
24 *
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
27 *
28 * Author: David B. Golub, Carnegie Mellon University
29 * Date: 7/90
30 */
31
32 /*
33 * Breakpoints.
34 */
35 #include <sys/param.h>
36 #include <sys/proc.h>
37
38 #include <machine/db_machdep.h> /* type definitions */
39
40 #include <ddb/db_lex.h>
41 #include <ddb/db_access.h>
42 #include <ddb/db_sym.h>
43 #include <ddb/db_break.h>
44 #include <ddb/db_output.h>
45
46 #define NBREAKPOINTS 100
47 struct db_breakpoint db_break_table[NBREAKPOINTS];
48 db_breakpoint_t db_next_free_breakpoint = &db_break_table[0];
49 db_breakpoint_t db_free_breakpoints = 0;
50 db_breakpoint_t db_breakpoint_list = 0;
51
52 db_breakpoint_t
53 db_breakpoint_alloc()
54 {
55 db_breakpoint_t bkpt;
56
57 if ((bkpt = db_free_breakpoints) != 0) {
58 db_free_breakpoints = bkpt->link;
59 return (bkpt);
60 }
61 if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
62 db_printf("All breakpoints used.\n");
63 return (0);
64 }
65 bkpt = db_next_free_breakpoint;
66 db_next_free_breakpoint++;
67
68 return (bkpt);
69 }
70
71 void
72 db_breakpoint_free(bkpt)
73 db_breakpoint_t bkpt;
74 {
75 bkpt->link = db_free_breakpoints;
76 db_free_breakpoints = bkpt;
77 }
78
79 void
80 db_set_breakpoint(map, addr, count)
81 vm_map_t map;
82 db_addr_t addr;
83 int count;
84 {
85 db_breakpoint_t bkpt;
86
87 if (db_find_breakpoint(map, addr)) {
88 db_printf("Already set.\n");
89 return;
90 }
91
92 bkpt = db_breakpoint_alloc();
93 if (bkpt == 0) {
94 db_printf("Too many breakpoints.\n");
95 return;
96 }
97
98 bkpt->map = map;
99 bkpt->address = addr;
100 bkpt->flags = 0;
101 bkpt->init_count = count;
102 bkpt->count = count;
103
104 bkpt->link = db_breakpoint_list;
105 db_breakpoint_list = bkpt;
106 }
107
108 void
109 db_delete_breakpoint(map, addr)
110 vm_map_t map;
111 db_addr_t addr;
112 {
113 db_breakpoint_t bkpt;
114 db_breakpoint_t *prev;
115
116 for (prev = &db_breakpoint_list;
117 (bkpt = *prev) != 0;
118 prev = &bkpt->link) {
119 if (db_map_equal(bkpt->map, map) &&
120 (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(map, addr)
135 vm_map_t map;
136 db_addr_t addr;
137 {
138 db_breakpoint_t bkpt;
139
140 for (bkpt = db_breakpoint_list;
141 bkpt != 0;
142 bkpt = bkpt->link)
143 {
144 if (db_map_equal(bkpt->map, map) &&
145 (bkpt->address == addr))
146 return (bkpt);
147 }
148 return (0);
149 }
150
151 db_breakpoint_t
152 db_find_breakpoint_here(addr)
153 db_addr_t addr;
154 {
155 return db_find_breakpoint(db_map_addr(addr), addr);
156 }
157
158 boolean_t db_breakpoints_inserted = TRUE;
159
160 void
161 db_set_breakpoints()
162 {
163 db_breakpoint_t bkpt;
164
165 if (!db_breakpoints_inserted) {
166
167 for (bkpt = db_breakpoint_list;
168 bkpt != 0;
169 bkpt = bkpt->link)
170 if (db_map_current(bkpt->map)) {
171 bkpt->bkpt_inst = db_get_value(bkpt->address,
172 BKPT_SIZE,
173 FALSE);
174 db_put_value(bkpt->address,
175 BKPT_SIZE,
176 BKPT_SET(bkpt->bkpt_inst));
177 }
178 db_breakpoints_inserted = TRUE;
179 }
180 }
181
182 void
183 db_clear_breakpoints()
184 {
185 db_breakpoint_t bkpt;
186
187 if (db_breakpoints_inserted) {
188
189 for (bkpt = db_breakpoint_list;
190 bkpt != 0;
191 bkpt = bkpt->link)
192 if (db_map_current(bkpt->map)) {
193 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
194 }
195 db_breakpoints_inserted = FALSE;
196 }
197 }
198
199 /*
200 * List breakpoints.
201 */
202 void
203 db_list_breakpoints()
204 {
205 db_breakpoint_t bkpt;
206
207 if (db_breakpoint_list == 0) {
208 db_printf("No breakpoints set\n");
209 return;
210 }
211
212 db_printf(" Map Count Address\n");
213 for (bkpt = db_breakpoint_list;
214 bkpt != 0;
215 bkpt = bkpt->link)
216 {
217 db_printf("%s%p %5d ",
218 db_map_current(bkpt->map) ? "*" : " ",
219 bkpt->map, bkpt->init_count);
220 db_printsym(bkpt->address, DB_STGY_PROC, db_printf);
221 db_printf("\n");
222 }
223 }
224
225 /* Delete breakpoint */
226 /*ARGSUSED*/
227 void
228 db_delete_cmd(addr, have_addr, count, modif)
229 db_expr_t addr;
230 int have_addr;
231 db_expr_t count;
232 char * modif;
233 {
234 db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
235 }
236
237 /* Set breakpoint with skip count */
238 /*ARGSUSED*/
239 void
240 db_breakpoint_cmd(addr, have_addr, count, modif)
241 db_expr_t addr;
242 int have_addr;
243 db_expr_t count;
244 char * modif;
245 {
246 if (count == -1)
247 count = 1;
248
249 db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
250 }
251
252 /* list breakpoints */
253 /*ARGSUSED*/
254 void
255 db_listbreak_cmd(addr, have_addr, count, modif)
256 db_expr_t addr;
257 int have_addr;
258 db_expr_t count;
259 char * modif;
260 {
261 db_list_breakpoints();
262 }
263
264 #include <uvm/uvm_extern.h>
265
266 /*
267 * We want ddb to be usable before most of the kernel has been
268 * initialized. In particular, current_thread() or kernel_map
269 * (or both) may be null.
270 */
271
272 boolean_t
273 db_map_equal(map1, map2)
274 vm_map_t map1, map2;
275 {
276 return ((map1 == map2) ||
277 ((map1 == NULL) && (map2 == kernel_map)) ||
278 ((map1 == kernel_map) && (map2 == NULL)));
279 }
280
281 boolean_t
282 db_map_current(map)
283 vm_map_t map;
284 {
285 #if 0
286 thread_t thread;
287
288 return ((map == NULL) ||
289 (map == kernel_map) ||
290 (((thread = current_thread()) != NULL) &&
291 (map == thread->task->map)));
292 #else
293 return (1);
294 #endif
295 }
296
297 vm_map_t
298 db_map_addr(addr)
299 vaddr_t addr;
300 {
301 #if 0
302 thread_t thread;
303
304 /*
305 * We want to return kernel_map for all
306 * non-user addresses, even when debugging
307 * kernel tasks with their own maps.
308 */
309
310 if ((VM_MIN_ADDRESS <= addr) &&
311 (addr < VM_MAX_ADDRESS) &&
312 ((thread = current_thread()) != NULL))
313 return thread->task->map;
314 else
315 #endif
316 return kernel_map;
317 }
318