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