FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_break.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,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 "AS IS"
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@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 Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: db_break.c,v $
29 * Revision 2.18 93/11/17 16:20:04 dbg
30 * Added ANSI function prototypes.
31 * [93/10/08 dbg]
32 *
33 * Revision 2.17 93/05/17 10:26:24 rvb
34 * Type casts, etc to quiet gcc 2.3.3 warnings
35 *
36 * Revision 2.16 93/01/14 17:24:29 danner
37 * 64bit cleanup.
38 * [92/11/30 af]
39 *
40 * Revision 2.15 92/08/03 17:30:33 jfriedl
41 * removed silly prototypes
42 * [92/08/02 jfriedl]
43 *
44 * Revision 2.14 92/05/21 17:06:24 jfriedl
45 * Removed unused variable from db_delete_cmd().
46 * Added declaration for arg 'count' of db_add_thread_breakpoint().
47 * [92/05/18 jfriedl]
48 *
49 * Revision 2.13 92/05/04 11:23:49 danner
50 * Fixed b/tu to b/Tu work if the specified address is valid in the
51 * target address space but not the current user space. Explicit
52 * user space breakpoints (b/u, b/Tu, etc) will no longer get
53 * inserted into the kernel if the specified address is invalid.
54 * [92/04/18 danner]
55 *
56 * Revision 2.12 92/02/19 16:46:24 elf
57 * Removed one of the many user-unfriendlinesses.
58 * [92/02/10 17:48:25 af]
59 *
60 * Revision 2.11 91/11/12 11:50:24 rvb
61 * Fixed db_delete_cmd so that just "d" works in user space.
62 * [91/10/31 rpd]
63 * Fixed db_delete_thread_breakpoint for zero task_thd.
64 * [91/10/30 rpd]
65 *
66 * Revision 2.10 91/10/09 15:57:41 af
67 * Supported thread-oriented break points.
68 * [91/08/29 tak]
69 *
70 * Revision 2.9 91/07/09 23:15:39 danner
71 * Conditionalized db_map_addr to work right on the luna. Used a
72 * ifdef luna88k. This is evil, and needs to be fixed.
73 * [91/07/08 danner]
74 *
75 * Revision 2.2 91/04/10 22:54:50 mbj
76 * Grabbed 3.0 copyright/disclaimer since ddb comes from 3.0.
77 * [91/04/09 rvb]
78 *
79 * Revision 2.7 91/02/05 17:06:00 mrt
80 * Changed to new Mach copyright
81 * [91/01/31 16:17:01 mrt]
82 *
83 * Revision 2.6 91/01/08 15:09:03 rpd
84 * Added db_map_equal, db_map_current, db_map_addr.
85 * [90/11/10 rpd]
86 *
87 * Revision 2.5 90/11/05 14:26:32 rpd
88 * Initialize db_breakpoints_inserted to TRUE.
89 * [90/11/04 rpd]
90 *
91 * Revision 2.4 90/10/25 14:43:33 rwd
92 * Added map field to breakpoints.
93 * Added map argument to db_set_breakpoint, db_delete_breakpoint,
94 * db_find_breakpoint. Added db_find_breakpoint_here.
95 * [90/10/18 rpd]
96 *
97 * Revision 2.3 90/09/28 16:57:07 jsb
98 * Fixed db_breakpoint_free.
99 * [90/09/18 rpd]
100 *
101 * Revision 2.2 90/08/27 21:49:53 dbg
102 * Reflected changes in db_printsym()'s calling seq.
103 * [90/08/20 af]
104 * Clear breakpoints only if inserted.
105 * Reduce lint.
106 * [90/08/07 dbg]
107 * Created.
108 * [90/07/25 dbg]
109 *
110 */
111 /*
112 * Author: David B. Golub, Carnegie Mellon University
113 * Date: 7/90
114 */
115
116 /*
117 * Breakpoints.
118 */
119 #include <mach/boolean.h>
120 #include <machine/db_machdep.h>
121 #include <ddb/db_lex.h>
122 #include <ddb/db_break.h>
123 #include <ddb/db_access.h>
124 #include <ddb/db_sym.h>
125 #include <ddb/db_variables.h>
126 #include <ddb/db_command.h>
127 #include <ddb/db_task_thread.h>
128 #include <ddb/db_output.h>
129
130 #define NBREAKPOINTS 100
131 #define NTHREAD_LIST (NBREAKPOINTS*3)
132
133 struct db_breakpoint db_break_table[NBREAKPOINTS];
134 db_breakpoint_t db_next_free_breakpoint = &db_break_table[0];
135 db_breakpoint_t db_free_breakpoints = 0;
136 db_breakpoint_t db_breakpoint_list = 0;
137
138 static struct db_thread_breakpoint db_thread_break_list[NTHREAD_LIST];
139 static db_thread_breakpoint_t db_free_thread_break_list = 0;
140 static boolean_t db_thread_break_init = FALSE;
141 static int db_breakpoint_number = 0;
142
143 db_breakpoint_t
144 db_breakpoint_alloc(void)
145 {
146 register db_breakpoint_t bkpt;
147
148 if ((bkpt = db_free_breakpoints) != 0) {
149 db_free_breakpoints = bkpt->link;
150 return bkpt;
151 }
152 if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
153 db_printf("All breakpoints used.\n");
154 return 0;
155 }
156 bkpt = db_next_free_breakpoint;
157 db_next_free_breakpoint++;
158
159 return bkpt;
160 }
161
162 void
163 db_breakpoint_free(
164 register db_breakpoint_t bkpt)
165 {
166 bkpt->link = db_free_breakpoints;
167 db_free_breakpoints = bkpt;
168 }
169
170 static boolean_t
171 db_add_thread_breakpoint(
172 register db_breakpoint_t bkpt,
173 vm_offset_t task_thd,
174 int count,
175 boolean_t task_bpt)
176 {
177 register db_thread_breakpoint_t tp;
178
179 if (db_thread_break_init == FALSE) {
180 for (tp = db_thread_break_list;
181 tp < &db_thread_break_list[NTHREAD_LIST-1]; tp++)
182 tp->tb_next = tp+1;
183 tp->tb_next = 0;
184 db_free_thread_break_list = db_thread_break_list;
185 db_thread_break_init = TRUE;
186 }
187 if (db_free_thread_break_list == 0)
188 return FALSE;
189 tp = db_free_thread_break_list;
190 db_free_thread_break_list = tp->tb_next;
191 tp->tb_is_task = task_bpt;
192 tp->tb_task_thd = task_thd;
193 tp->tb_count = count;
194 tp->tb_init_count = count;
195 tp->tb_cond = 0;
196 tp->tb_number = ++db_breakpoint_number;
197 tp->tb_next = bkpt->threads;
198 bkpt->threads = tp;
199 return TRUE;
200 }
201
202 static int
203 db_delete_thread_breakpoint(
204 register db_breakpoint_t bkpt,
205 vm_offset_t task_thd)
206 {
207 register db_thread_breakpoint_t tp;
208 register db_thread_breakpoint_t *tpp;
209 void db_cond_free();
210
211 if (task_thd == 0) {
212 /* delete all the thread-breakpoints */
213
214 for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
215 db_cond_free(tp);
216
217 *tpp = db_free_thread_break_list;
218 db_free_thread_break_list = bkpt->threads;
219 bkpt->threads = 0;
220 return TRUE;
221 } else {
222 /* delete the specified thread-breakpoint */
223
224 for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
225 if (tp->tb_task_thd == task_thd) {
226 db_cond_free(tp);
227 *tpp = tp->tb_next;
228 tp->tb_next = db_free_thread_break_list;
229 db_free_thread_break_list = tp;
230 return TRUE;
231 }
232
233 return FALSE; /* not found */
234 }
235 }
236
237 static db_thread_breakpoint_t
238 db_find_thread_breakpoint(
239 db_breakpoint_t bkpt,
240 thread_t thread)
241 {
242 register db_thread_breakpoint_t tp;
243 register task_t task = (thread == THREAD_NULL)? TASK_NULL: thread->task;
244
245 for (tp = bkpt->threads; tp; tp = tp->tb_next) {
246 if (tp->tb_is_task) {
247 if (tp->tb_task_thd == (vm_offset_t)task)
248 break;
249 continue;
250 }
251 if (tp->tb_task_thd == (vm_offset_t)thread || tp->tb_task_thd == 0)
252 break;
253 }
254 return tp;
255 }
256
257 db_thread_breakpoint_t
258 db_find_thread_breakpoint_here(
259 task_t task,
260 db_addr_t addr)
261 {
262 db_breakpoint_t bkpt;
263
264 bkpt = db_find_breakpoint(task, addr);
265 if (bkpt == 0)
266 return 0;
267 return db_find_thread_breakpoint(bkpt, current_thread());
268 }
269
270 db_thread_breakpoint_t
271 db_find_breakpoint_number(
272 int num,
273 db_breakpoint_t *bkptp)
274 {
275 register db_thread_breakpoint_t tp;
276 register db_breakpoint_t bkpt;
277
278 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
279 for (tp = bkpt->threads; tp; tp = tp->tb_next) {
280 if (tp->tb_number == num) {
281 if (bkptp)
282 *bkptp = bkpt;
283 return tp;
284 }
285 }
286 }
287 return 0;
288 }
289
290 static void
291 db_force_delete_breakpoint(
292 db_breakpoint_t bkpt,
293 vm_offset_t task_thd,
294 boolean_t is_task)
295 {
296 db_printf("deleted a stale breakpoint at ");
297 if (bkpt->task == TASK_NULL || db_lookup_task(bkpt->task) >= 0)
298 db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
299 else
300 db_printf("%#X", bkpt->address);
301 if (bkpt->task)
302 db_printf(" in task %X", bkpt->task);
303 if (task_thd)
304 db_printf(" for %s %X", (is_task)? "task": "thread", task_thd);
305 db_printf("\n");
306 (void) db_delete_thread_breakpoint(bkpt, task_thd);
307 }
308
309 void
310 db_check_breakpoint_valid(void)
311 {
312 register db_thread_breakpoint_t tbp, tbp_next;
313 register db_breakpoint_t bkpt, *bkptp;
314
315 bkptp = &db_breakpoint_list;
316 for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
317 if (bkpt->task != TASK_NULL) {
318 if (db_lookup_task(bkpt->task) < 0) {
319 db_force_delete_breakpoint(bkpt, 0, FALSE);
320 *bkptp = bkpt->link;
321 db_breakpoint_free(bkpt);
322 continue;
323 }
324 } else {
325 for (tbp = bkpt->threads; tbp; tbp = tbp_next) {
326 tbp_next = tbp->tb_next;
327 if (tbp->tb_task_thd == 0)
328 continue;
329 if ((tbp->tb_is_task &&
330 db_lookup_task((task_t)(tbp->tb_task_thd)) < 0) ||
331 (!tbp->tb_is_task &&
332 db_lookup_thread((thread_t)(tbp->tb_task_thd)) < 0)) {
333 db_force_delete_breakpoint(bkpt,
334 tbp->tb_task_thd, tbp->tb_is_task);
335 }
336 }
337 if (bkpt->threads == 0) {
338 db_put_task_value(bkpt->address, BKPT_SIZE,
339 bkpt->bkpt_inst, bkpt->task);
340 *bkptp = bkpt->link;
341 db_breakpoint_free(bkpt);
342 continue;
343 }
344 }
345 bkptp = &bkpt->link;
346 }
347 }
348
349 void
350 db_set_breakpoint(
351 task_t task,
352 db_addr_t addr,
353 int count,
354 thread_t thread,
355 boolean_t task_bpt)
356 {
357 register db_breakpoint_t bkpt;
358 db_breakpoint_t alloc_bkpt = 0;
359 vm_offset_t task_thd;
360
361 bkpt = db_find_breakpoint(task, addr);
362 if (bkpt) {
363 if (thread == THREAD_NULL
364 || db_find_thread_breakpoint(bkpt, thread)) {
365 db_printf("Already set.\n");
366 return;
367 }
368 } else {
369 if (!DB_CHECK_ACCESS(addr, BKPT_SIZE, task)) {
370 db_printf("Cannot set break point at %X\n", addr);
371 return;
372 }
373 alloc_bkpt = bkpt = db_breakpoint_alloc();
374 if (bkpt == 0) {
375 db_printf("Too many breakpoints.\n");
376 return;
377 }
378 bkpt->task = task;
379 bkpt->flags = (task && thread == THREAD_NULL)?
380 (BKPT_USR_GLOBAL|BKPT_1ST_SET): 0;
381 bkpt->address = addr;
382 bkpt->threads = 0;
383 }
384 if (db_breakpoint_list == 0)
385 db_breakpoint_number = 0;
386 task_thd = (task_bpt)? (vm_offset_t)(thread->task): (vm_offset_t)thread;
387 if (!db_add_thread_breakpoint(bkpt, task_thd, count, task_bpt)) {
388 if (alloc_bkpt)
389 db_breakpoint_free(alloc_bkpt);
390 db_printf("Too many thread_breakpoints.\n");
391 } else {
392 db_printf("set breakpoint #%d\n", db_breakpoint_number);
393 if (alloc_bkpt) {
394 bkpt->link = db_breakpoint_list;
395 db_breakpoint_list = bkpt;
396 }
397 }
398 }
399
400 void
401 db_delete_breakpoint(
402 task_t task,
403 db_addr_t addr,
404 vm_offset_t task_thd)
405 {
406 register db_breakpoint_t bkpt;
407 register db_breakpoint_t *prev;
408
409 for (prev = &db_breakpoint_list; (bkpt = *prev) != 0;
410 prev = &bkpt->link) {
411 if ((bkpt->task == task
412 || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
413 && bkpt->address == addr)
414 break;
415 }
416 if (bkpt && (bkpt->flags & BKPT_SET_IN_MEM)) {
417 db_printf("cannot delete it now.\n");
418 return;
419 }
420 if (bkpt == 0
421 || !db_delete_thread_breakpoint(bkpt, task_thd)) {
422 db_printf("Not set.\n");
423 return;
424 }
425 if (bkpt->threads == 0) {
426 *prev = bkpt->link;
427 db_breakpoint_free(bkpt);
428 }
429 }
430
431 db_breakpoint_t
432 db_find_breakpoint(
433 task_t task,
434 db_addr_t addr)
435 {
436 register db_breakpoint_t bkpt;
437
438 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
439 if ((bkpt->task == task
440 || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
441 && bkpt->address == addr)
442 return bkpt;
443 }
444 return 0;
445 }
446
447 boolean_t
448 db_find_breakpoint_here(
449 task_t task,
450 db_addr_t addr)
451 {
452 register db_breakpoint_t bkpt;
453
454 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
455 if ((bkpt->task == task
456 || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
457 && bkpt->address == addr)
458 return TRUE;
459 if ((bkpt->flags & BKPT_USR_GLOBAL) == 0 &&
460 DB_PHYS_EQ(task, (vm_offset_t)addr,
461 bkpt->task, (vm_offset_t)bkpt->address))
462 return TRUE;
463 }
464 return FALSE;
465 }
466
467 boolean_t db_breakpoints_inserted = TRUE;
468
469 void
470 db_set_breakpoints(void)
471 {
472 register db_breakpoint_t bkpt;
473 register task_t task;
474 db_expr_t inst;
475 task_t cur_task;
476
477 cur_task = (current_thread())? current_thread()->task: TASK_NULL;
478 if (!db_breakpoints_inserted) {
479 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
480 if (bkpt->flags & BKPT_SET_IN_MEM)
481 continue;
482 task = bkpt->task;
483 if (bkpt->flags & BKPT_USR_GLOBAL) {
484 if ((bkpt->flags & BKPT_1ST_SET) == 0) {
485 if (cur_task == TASK_NULL)
486 continue;
487 task = cur_task;
488 } else
489 bkpt->flags &= ~BKPT_1ST_SET;
490 }
491 if (DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
492 inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE,
493 task);
494 if (inst == BKPT_SET(inst))
495 continue;
496 bkpt->bkpt_inst = inst;
497 db_put_task_value(bkpt->address,
498 BKPT_SIZE,
499 BKPT_SET(bkpt->bkpt_inst), task);
500 bkpt->flags |= BKPT_SET_IN_MEM;
501 } else {
502 db_printf("Warning: cannot set breakpoint at %X ",
503 bkpt->address);
504 if (task)
505 db_printf("in task %X\n", task);
506 else
507 db_printf("in kernel space\n");
508 }
509 }
510 db_breakpoints_inserted = TRUE;
511 }
512 }
513
514 void
515 db_clear_breakpoints(void)
516 {
517 register db_breakpoint_t bkpt, *bkptp;
518 register task_t task;
519 task_t cur_task;
520 db_expr_t inst;
521
522 cur_task = (current_thread())? current_thread()->task: TASK_NULL;
523 if (db_breakpoints_inserted) {
524 bkptp = &db_breakpoint_list;
525 for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
526 task = bkpt->task;
527 if (bkpt->flags & BKPT_USR_GLOBAL) {
528 if (cur_task == TASK_NULL) {
529 bkptp = &bkpt->link;
530 continue;
531 }
532 task = cur_task;
533 }
534 if ((bkpt->flags & BKPT_SET_IN_MEM)
535 && DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
536 inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE,
537 task);
538 if (inst != BKPT_SET(inst)) {
539 if (bkpt->flags & BKPT_USR_GLOBAL) {
540 bkptp = &bkpt->link;
541 continue;
542 }
543 db_force_delete_breakpoint(bkpt, 0, FALSE);
544 *bkptp = bkpt->link;
545 db_breakpoint_free(bkpt);
546 continue;
547 }
548 db_put_task_value(bkpt->address, BKPT_SIZE,
549 bkpt->bkpt_inst, task);
550 bkpt->flags &= ~BKPT_SET_IN_MEM;
551 }
552 bkptp = &bkpt->link;
553 }
554 db_breakpoints_inserted = FALSE;
555 }
556 }
557
558 /*
559 * Set a temporary breakpoint.
560 * The instruction is changed immediately,
561 * so the breakpoint does not have to be on the breakpoint list.
562 */
563 db_breakpoint_t
564 db_set_temp_breakpoint(
565 task_t task,
566 db_addr_t addr)
567 {
568 register db_breakpoint_t bkpt;
569
570 bkpt = db_breakpoint_alloc();
571 if (bkpt == 0) {
572 db_printf("Too many breakpoints.\n");
573 return 0;
574 }
575 bkpt->task = task;
576 bkpt->address = addr;
577 bkpt->flags = BKPT_TEMP;
578 bkpt->threads = 0;
579 if (!db_add_thread_breakpoint(bkpt, 0, 1, FALSE)) {
580 if (bkpt)
581 db_breakpoint_free(bkpt);
582 db_printf("Too many thread_breakpoints.\n");
583 return 0;
584 }
585 bkpt->bkpt_inst = db_get_task_value(bkpt->address, BKPT_SIZE,
586 FALSE, task);
587 db_put_task_value(bkpt->address, BKPT_SIZE,
588 BKPT_SET(bkpt->bkpt_inst), task);
589 return bkpt;
590 }
591
592 void
593 db_delete_temp_breakpoint(
594 task_t task,
595 db_breakpoint_t bkpt)
596 {
597 db_put_task_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst, task);
598 (void) db_delete_thread_breakpoint(bkpt, 0);
599 db_breakpoint_free(bkpt);
600 }
601
602 /*
603 * List breakpoints.
604 */
605 void
606 db_list_breakpoints(void)
607 {
608 register db_breakpoint_t bkpt;
609
610 if (db_breakpoint_list == 0) {
611 db_printf("No breakpoints set\n");
612 return;
613 }
614
615 db_printf(" No Space Thread Cnt Address(Cond)\n");
616 for (bkpt = db_breakpoint_list;
617 bkpt != 0;
618 bkpt = bkpt->link)
619 {
620 register db_thread_breakpoint_t tp;
621 int task_id;
622 int thread_id;
623
624 if (bkpt->threads) {
625 for (tp = bkpt->threads; tp; tp = tp->tb_next) {
626 db_printf("%3d ", tp->tb_number);
627 if (bkpt->flags & BKPT_USR_GLOBAL)
628 db_printf("user ");
629 else if (bkpt->task == TASK_NULL)
630 db_printf("kernel ");
631 else if ((task_id = db_lookup_task(bkpt->task)) < 0)
632 db_printf("%0*X ", 2*sizeof(vm_offset_t), bkpt->task);
633 else
634 db_printf("task%-3d ", task_id);
635 if (tp->tb_task_thd == 0) {
636 db_printf("all ");
637 } else {
638 if (tp->tb_is_task) {
639 task_id = db_lookup_task((task_t)(tp->tb_task_thd));
640 if (task_id < 0)
641 db_printf("%0*X ", 2*sizeof(vm_offset_t),
642 tp->tb_task_thd);
643 else
644 db_printf("task%03d ", task_id);
645 } else {
646 thread_t thd = (thread_t)(tp->tb_task_thd);
647 task_id = db_lookup_task(thd->task);
648 thread_id = db_lookup_task_thread(thd->task, thd);
649 if (task_id < 0 || thread_id < 0)
650 db_printf("%0*X ", 2*sizeof(vm_offset_t),
651 tp->tb_task_thd);
652 else
653 db_printf("task%03d.%-3d ", task_id, thread_id);
654 }
655 }
656 db_printf("%3d ", tp->tb_init_count);
657 db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
658 if (tp->tb_cond > 0) {
659 db_printf("(");
660 db_cond_print(tp);
661 db_printf(")");
662 }
663 db_printf("\n");
664 }
665 } else {
666 if (bkpt->task == TASK_NULL)
667 db_printf(" ? kernel ");
668 else
669 db_printf("%*X ", 2*sizeof(vm_offset_t), bkpt->task);
670 db_printf("(?) ");
671 db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
672 db_printf("\n");
673 }
674 }
675 }
676
677 /* Delete breakpoint */
678 /*ARGSUSED*/
679 void
680 db_delete_cmd()
681 {
682 register n;
683 thread_t thread;
684 vm_offset_t task_thd;
685 boolean_t user_global = FALSE;
686 boolean_t task_bpt = FALSE;
687 boolean_t user_space = FALSE;
688 boolean_t thd_bpt = FALSE;
689 db_expr_t addr;
690 int t;
691
692 t = db_read_token();
693 if (t == tSLASH) {
694 t = db_read_token();
695 if (t != tIDENT) {
696 db_printf("Bad modifier \"%s\"\n", db_tok_string);
697 db_error(0);
698 }
699 user_global = db_option(db_tok_string, 'U');
700 user_space = (user_global)? TRUE: db_option(db_tok_string, 'u');
701 task_bpt = db_option(db_tok_string, 'T');
702 thd_bpt = db_option(db_tok_string, 't');
703 if (task_bpt && user_global)
704 db_error("Cannot specify both 'T' and 'U' option\n");
705 t = db_read_token();
706 }
707 if (t == tHASH) {
708 db_thread_breakpoint_t tbp;
709 db_breakpoint_t bkpt;
710
711 if (db_read_token() != tNUMBER) {
712 db_printf("Bad break point number #%s\n", db_tok_string);
713 db_error(0);
714 }
715 if ((tbp = db_find_breakpoint_number(db_tok_number, &bkpt)) == 0) {
716 db_printf("No such break point #%d\n", db_tok_number);
717 db_error(0);
718 }
719 db_delete_breakpoint(bkpt->task, bkpt->address, tbp->tb_task_thd);
720 return;
721 }
722 db_unread_token(t);
723 if (!db_expression(&addr)) {
724 /*
725 * We attempt to pick up the user_space indication from db_dot,
726 * so that a plain "d" always works.
727 */
728 addr = (db_expr_t)db_dot;
729 if (!user_space && !DB_VALID_ADDRESS((vm_offset_t)addr, FALSE))
730 user_space = TRUE;
731 }
732 if (!DB_VALID_ADDRESS((vm_offset_t) addr, user_space)) {
733 db_printf("Address %#X is not in %s space\n", addr,
734 (user_space)? "user": "kernel");
735 db_error(0);
736 }
737 if (thd_bpt || task_bpt) {
738 for (n = 0; db_get_next_thread(&thread, n); n++) {
739 if (thread == THREAD_NULL)
740 db_error("No active thread\n");
741 if (task_bpt) {
742 if (thread->task == TASK_NULL)
743 db_error("No task\n");
744 task_thd = (vm_offset_t) (thread->task);
745 } else
746 task_thd = (user_global)? 0: (vm_offset_t) thread;
747 db_delete_breakpoint(db_target_space(thread, user_space),
748 (db_addr_t)addr, task_thd);
749 }
750 } else {
751 db_delete_breakpoint(db_target_space(THREAD_NULL, user_space),
752 (db_addr_t)addr, 0);
753 }
754 }
755
756 /* Set breakpoint with skip count */
757 /*ARGSUSED*/
758 void
759 db_breakpoint_cmd(
760 db_expr_t addr,
761 boolean_t have_addr,
762 db_expr_t count,
763 char * modif)
764 {
765 register int n;
766 thread_t thread;
767 boolean_t user_global = db_option(modif, 'U');
768 boolean_t task_bpt = db_option(modif, 'T');
769 boolean_t user_space;
770
771 if (count == -1)
772 count = 1;
773
774 if (!task_bpt && db_option(modif,'t'))
775 task_bpt = TRUE;
776
777 if (task_bpt && user_global)
778 db_error("Cannot specify both 'T' and 'U'\n");
779 user_space = (user_global)? TRUE: db_option(modif, 'u');
780 if (user_space && db_access_level < DB_ACCESS_CURRENT)
781 db_error("User space break point is not supported\n");
782 if (!task_bpt && !DB_VALID_ADDRESS((vm_offset_t)addr, user_space)) {
783 /* if the user has explicitly specified user space,
784 do not insert a breakpoint into the kernel */
785 if (user_space)
786 db_error("Invalid user space address\n");
787 user_space = TRUE;
788 db_printf("%#X is in user space\n", addr);
789 }
790 if (db_option(modif, 't') || task_bpt) {
791 for (n = 0; db_get_next_thread(&thread, n); n++) {
792 if (thread == THREAD_NULL)
793 db_error("No active thread\n");
794 if (task_bpt && thread->task == TASK_NULL)
795 db_error("No task\n");
796 if (db_access_level <= DB_ACCESS_CURRENT && user_space
797 && thread->task != db_current_task())
798 db_error("Cannot set break point in inactive user space\n");
799 db_set_breakpoint(db_target_space(thread, user_space),
800 (db_addr_t)addr, count,
801 (user_global)? THREAD_NULL: thread,
802 task_bpt);
803 }
804 } else {
805 db_set_breakpoint(db_target_space(THREAD_NULL, user_space),
806 (db_addr_t)addr,
807 count, THREAD_NULL, FALSE);
808 }
809 }
810
811 /* list breakpoints */
812 /*ARGSUSED*/
813 void
814 db_listbreak_cmd()
815 {
816 db_list_breakpoints();
817 }
Cache object: 4a6c822a9ceda147ec394f8a35759560
|