db_break.c revision 1.6 1 /* $NetBSD: db_break.c,v 1.6 1996/02/05 01:56:50 christos 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
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 register 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 register 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 register 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 register db_breakpoint_t bkpt;
114 register 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 register 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 register 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 register 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 * Set a temporary breakpoint.
201 * The instruction is changed immediately,
202 * so the breakpoint does not have to be on the breakpoint list.
203 */
204 db_breakpoint_t
205 db_set_temp_breakpoint(addr)
206 db_addr_t addr;
207 {
208 register db_breakpoint_t bkpt;
209
210 bkpt = db_breakpoint_alloc();
211 if (bkpt == 0) {
212 db_printf("Too many breakpoints.\n");
213 return 0;
214 }
215
216 bkpt->map = NULL;
217 bkpt->address = addr;
218 bkpt->flags = BKPT_TEMP;
219 bkpt->init_count = 1;
220 bkpt->count = 1;
221
222 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
223 db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
224 return bkpt;
225 }
226
227 void
228 db_delete_temp_breakpoint(bkpt)
229 db_breakpoint_t bkpt;
230 {
231 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
232 db_breakpoint_free(bkpt);
233 }
234
235 /*
236 * List breakpoints.
237 */
238 void
239 db_list_breakpoints()
240 {
241 register db_breakpoint_t bkpt;
242
243 if (db_breakpoint_list == 0) {
244 db_printf("No breakpoints set\n");
245 return;
246 }
247
248 db_printf(" Map Count Address\n");
249 for (bkpt = db_breakpoint_list;
250 bkpt != 0;
251 bkpt = bkpt->link)
252 {
253 db_printf("%s%8x %5d ",
254 db_map_current(bkpt->map) ? "*" : " ",
255 bkpt->map, bkpt->init_count);
256 db_printsym(bkpt->address, DB_STGY_PROC);
257 db_printf("\n");
258 }
259 }
260
261 /* Delete breakpoint */
262 /*ARGSUSED*/
263 void
264 db_delete_cmd(addr, have_addr, count, modif)
265 db_expr_t addr;
266 int have_addr;
267 db_expr_t count;
268 char * modif;
269 {
270 db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
271 }
272
273 /* Set breakpoint with skip count */
274 /*ARGSUSED*/
275 void
276 db_breakpoint_cmd(addr, have_addr, count, modif)
277 db_expr_t addr;
278 int have_addr;
279 db_expr_t count;
280 char * modif;
281 {
282 if (count == -1)
283 count = 1;
284
285 db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
286 }
287
288 /* list breakpoints */
289 /*ARGSUSED*/
290 void
291 db_listbreak_cmd(addr, have_addr, count, modif)
292 db_expr_t addr;
293 int have_addr;
294 db_expr_t count;
295 char * modif;
296 {
297 db_list_breakpoints();
298 }
299
300 #include <vm/vm_kern.h>
301
302 /*
303 * We want ddb to be usable before most of the kernel has been
304 * initialized. In particular, current_thread() or kernel_map
305 * (or both) may be null.
306 */
307
308 boolean_t
309 db_map_equal(map1, map2)
310 vm_map_t map1, map2;
311 {
312 return ((map1 == map2) ||
313 ((map1 == NULL) && (map2 == kernel_map)) ||
314 ((map1 == kernel_map) && (map2 == NULL)));
315 }
316
317 boolean_t
318 db_map_current(map)
319 vm_map_t map;
320 {
321 #if 0
322 thread_t thread;
323
324 return ((map == NULL) ||
325 (map == kernel_map) ||
326 (((thread = current_thread()) != NULL) &&
327 (map == thread->task->map)));
328 #else
329 return (1);
330 #endif
331 }
332
333 vm_map_t
334 db_map_addr(addr)
335 vm_offset_t addr;
336 {
337 #if 0
338 thread_t thread;
339
340 /*
341 * We want to return kernel_map for all
342 * non-user addresses, even when debugging
343 * kernel tasks with their own maps.
344 */
345
346 if ((VM_MIN_ADDRESS <= addr) &&
347 (addr < VM_MAX_ADDRESS) &&
348 ((thread = current_thread()) != NULL))
349 return thread->task->map;
350 else
351 #endif
352 return kernel_map;
353 }
354