db_break.c revision 1.2.4.1 1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
25 */
26 /*
27 * $Id: db_break.c,v 1.2.4.1 1993/11/14 22:48:28 mycroft Exp $
28 *
29 * HISTORY
30 * $Log: db_break.c,v $
31 * Revision 1.2.4.1 1993/11/14 22:48:28 mycroft
32 * Canonicalize all #includes.
33 *
34 * Revision 1.2 1993/05/20 03:39:08 cgd
35 * add explicit rcs id
36 *
37 * Revision 1.1.1.1 1993/03/21 09:46:26 cgd
38 * initial import of 386bsd-0.1 sources
39 *
40 * Revision 1.1 1992/03/25 21:44:57 pace
41 * Initial revision
42 *
43 * Revision 2.7 91/02/05 17:06:00 mrt
44 * Changed to new Mach copyright
45 * [91/01/31 16:17:01 mrt]
46 *
47 * Revision 2.6 91/01/08 15:09:03 rpd
48 * Added db_map_equal, db_map_current, db_map_addr.
49 * [90/11/10 rpd]
50 *
51 * Revision 2.5 90/11/05 14:26:32 rpd
52 * Initialize db_breakpoints_inserted to TRUE.
53 * [90/11/04 rpd]
54 *
55 * Revision 2.4 90/10/25 14:43:33 rwd
56 * Added map field to breakpoints.
57 * Added map argument to db_set_breakpoint, db_delete_breakpoint,
58 * db_find_breakpoint. Added db_find_breakpoint_here.
59 * [90/10/18 rpd]
60 *
61 * Revision 2.3 90/09/28 16:57:07 jsb
62 * Fixed db_breakpoint_free.
63 * [90/09/18 rpd]
64 *
65 * Revision 2.2 90/08/27 21:49:53 dbg
66 * Reflected changes in db_printsym()'s calling seq.
67 * [90/08/20 af]
68 * Clear breakpoints only if inserted.
69 * Reduce lint.
70 * [90/08/07 dbg]
71 * Created.
72 * [90/07/25 dbg]
73 *
74 */
75 /*
76 * Author: David B. Golub, Carnegie Mellon University
77 * Date: 7/90
78 */
79 /*
80 * Breakpoints.
81 */
82 #include <sys/param.h>
83 #include <sys/proc.h>
84 #include <machine/db_machdep.h> /* type definitions */
85
86 #include <ddb/db_lex.h>
87 #include <ddb/db_break.h>
88 #include <ddb/db_access.h>
89 #include <ddb/db_sym.h>
90 #include <ddb/db_break.h>
91
92 extern boolean_t db_map_equal();
93 extern boolean_t db_map_current();
94 extern vm_map_t db_map_addr();
95
96 #define NBREAKPOINTS 100
97 struct db_breakpoint db_break_table[NBREAKPOINTS];
98 db_breakpoint_t db_next_free_breakpoint = &db_break_table[0];
99 db_breakpoint_t db_free_breakpoints = 0;
100 db_breakpoint_t db_breakpoint_list = 0;
101
102 db_breakpoint_t
103 db_breakpoint_alloc()
104 {
105 register db_breakpoint_t bkpt;
106
107 if ((bkpt = db_free_breakpoints) != 0) {
108 db_free_breakpoints = bkpt->link;
109 return (bkpt);
110 }
111 if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
112 db_printf("All breakpoints used.\n");
113 return (0);
114 }
115 bkpt = db_next_free_breakpoint;
116 db_next_free_breakpoint++;
117
118 return (bkpt);
119 }
120
121 void
122 db_breakpoint_free(bkpt)
123 register db_breakpoint_t bkpt;
124 {
125 bkpt->link = db_free_breakpoints;
126 db_free_breakpoints = bkpt;
127 }
128
129 void
130 db_set_breakpoint(map, addr, count)
131 vm_map_t map;
132 db_addr_t addr;
133 int count;
134 {
135 register db_breakpoint_t bkpt;
136
137 if (db_find_breakpoint(map, addr)) {
138 db_printf("Already set.\n");
139 return;
140 }
141
142 bkpt = db_breakpoint_alloc();
143 if (bkpt == 0) {
144 db_printf("Too many breakpoints.\n");
145 return;
146 }
147
148 bkpt->map = map;
149 bkpt->address = addr;
150 bkpt->flags = 0;
151 bkpt->init_count = count;
152 bkpt->count = count;
153
154 bkpt->link = db_breakpoint_list;
155 db_breakpoint_list = bkpt;
156 }
157
158 void
159 db_delete_breakpoint(map, addr)
160 vm_map_t map;
161 db_addr_t addr;
162 {
163 register db_breakpoint_t bkpt;
164 register db_breakpoint_t *prev;
165
166 for (prev = &db_breakpoint_list;
167 (bkpt = *prev) != 0;
168 prev = &bkpt->link) {
169 if (db_map_equal(bkpt->map, map) &&
170 (bkpt->address == addr)) {
171 *prev = bkpt->link;
172 break;
173 }
174 }
175 if (bkpt == 0) {
176 db_printf("Not set.\n");
177 return;
178 }
179
180 db_breakpoint_free(bkpt);
181 }
182
183 db_breakpoint_t
184 db_find_breakpoint(map, addr)
185 vm_map_t map;
186 db_addr_t addr;
187 {
188 register db_breakpoint_t bkpt;
189
190 for (bkpt = db_breakpoint_list;
191 bkpt != 0;
192 bkpt = bkpt->link)
193 {
194 if (db_map_equal(bkpt->map, map) &&
195 (bkpt->address == addr))
196 return (bkpt);
197 }
198 return (0);
199 }
200
201 db_breakpoint_t
202 db_find_breakpoint_here(addr)
203 db_addr_t addr;
204 {
205 return db_find_breakpoint(db_map_addr(addr), addr);
206 }
207
208 boolean_t db_breakpoints_inserted = TRUE;
209
210 void
211 db_set_breakpoints()
212 {
213 register db_breakpoint_t bkpt;
214
215 if (!db_breakpoints_inserted) {
216
217 for (bkpt = db_breakpoint_list;
218 bkpt != 0;
219 bkpt = bkpt->link)
220 if (db_map_current(bkpt->map)) {
221 bkpt->bkpt_inst = db_get_value(bkpt->address,
222 BKPT_SIZE,
223 FALSE);
224 db_put_value(bkpt->address,
225 BKPT_SIZE,
226 BKPT_SET(bkpt->bkpt_inst));
227 }
228 db_breakpoints_inserted = TRUE;
229 }
230 }
231
232 void
233 db_clear_breakpoints()
234 {
235 register db_breakpoint_t bkpt;
236
237 if (db_breakpoints_inserted) {
238
239 for (bkpt = db_breakpoint_list;
240 bkpt != 0;
241 bkpt = bkpt->link)
242 if (db_map_current(bkpt->map)) {
243 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
244 }
245 db_breakpoints_inserted = FALSE;
246 }
247 }
248
249 /*
250 * Set a temporary breakpoint.
251 * The instruction is changed immediately,
252 * so the breakpoint does not have to be on the breakpoint list.
253 */
254 db_breakpoint_t
255 db_set_temp_breakpoint(addr)
256 db_addr_t addr;
257 {
258 register db_breakpoint_t bkpt;
259
260 bkpt = db_breakpoint_alloc();
261 if (bkpt == 0) {
262 db_printf("Too many breakpoints.\n");
263 return 0;
264 }
265
266 bkpt->map = NULL;
267 bkpt->address = addr;
268 bkpt->flags = BKPT_TEMP;
269 bkpt->init_count = 1;
270 bkpt->count = 1;
271
272 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
273 db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
274 return bkpt;
275 }
276
277 void
278 db_delete_temp_breakpoint(bkpt)
279 db_breakpoint_t bkpt;
280 {
281 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
282 db_breakpoint_free(bkpt);
283 }
284
285 /*
286 * List breakpoints.
287 */
288 void
289 db_list_breakpoints()
290 {
291 register db_breakpoint_t bkpt;
292
293 if (db_breakpoint_list == 0) {
294 db_printf("No breakpoints set\n");
295 return;
296 }
297
298 db_printf(" Map Count Address\n");
299 for (bkpt = db_breakpoint_list;
300 bkpt != 0;
301 bkpt = bkpt->link)
302 {
303 db_printf("%s%8x %5d ",
304 db_map_current(bkpt->map) ? "*" : " ",
305 bkpt->map, bkpt->init_count);
306 db_printsym(bkpt->address, DB_STGY_PROC);
307 db_printf("\n");
308 }
309 }
310
311 /* Delete breakpoint */
312 /*ARGSUSED*/
313 void
314 db_delete_cmd(addr, have_addr, count, modif)
315 db_expr_t addr;
316 int have_addr;
317 db_expr_t count;
318 char * modif;
319 {
320 db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
321 }
322
323 /* Set breakpoint with skip count */
324 /*ARGSUSED*/
325 void
326 db_breakpoint_cmd(addr, have_addr, count, modif)
327 db_expr_t addr;
328 int have_addr;
329 db_expr_t count;
330 char * modif;
331 {
332 if (count == -1)
333 count = 1;
334
335 db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
336 }
337
338 /* list breakpoints */
339 void
340 db_listbreak_cmd()
341 {
342 db_list_breakpoints();
343 }
344
345 #include <vm/vm_kern.h>
346
347 /*
348 * We want ddb to be usable before most of the kernel has been
349 * initialized. In particular, current_thread() or kernel_map
350 * (or both) may be null.
351 */
352
353 boolean_t
354 db_map_equal(map1, map2)
355 vm_map_t map1, map2;
356 {
357 return ((map1 == map2) ||
358 ((map1 == NULL) && (map2 == kernel_map)) ||
359 ((map1 == kernel_map) && (map2 == NULL)));
360 }
361
362 boolean_t
363 db_map_current(map)
364 vm_map_t map;
365 {
366 #if 0
367 thread_t thread;
368
369 return ((map == NULL) ||
370 (map == kernel_map) ||
371 (((thread = current_thread()) != NULL) &&
372 (map == thread->task->map)));
373 #else
374 return (1);
375 #endif
376 }
377
378 vm_map_t
379 db_map_addr(addr)
380 vm_offset_t addr;
381 {
382 #if 0
383 thread_t thread;
384
385 /*
386 * We want to return kernel_map for all
387 * non-user addresses, even when debugging
388 * kernel tasks with their own maps.
389 */
390
391 if ((VM_MIN_ADDRESS <= addr) &&
392 (addr < VM_MAX_ADDRESS) &&
393 ((thread = current_thread()) != NULL))
394 return thread->task->map;
395 else
396 #endif
397 return kernel_map;
398 }
399