]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_break.c
xnu-1228.5.18.tar.gz
[apple/xnu.git] / osfmk / ddb / db_break.c
1 /*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 */
33 /*
34 * Author: David B. Golub, Carnegie Mellon University
35 * Date: 7/90
36 */
37
38 /*
39 * Breakpoints.
40 */
41 #include <mach/boolean.h>
42 #include <machine/db_machdep.h>
43 #include <ddb/db_lex.h>
44 #include <ddb/db_break.h>
45 #include <ddb/db_access.h>
46 #include <ddb/db_sym.h>
47 #include <ddb/db_variables.h>
48 #include <ddb/db_command.h>
49 #include <ddb/db_cond.h>
50 #include <ddb/db_expr.h>
51 #include <ddb/db_output.h> /* For db_printf() */
52 #include <ddb/db_task_thread.h>
53 #include <kern/thread.h>
54
55 #define NBREAKPOINTS 100
56 #define NTHREAD_LIST (NBREAKPOINTS*3)
57
58 struct db_breakpoint db_break_table[NBREAKPOINTS];
59 db_breakpoint_t db_next_free_breakpoint = &db_break_table[0];
60 db_breakpoint_t db_free_breakpoints = 0;
61 db_breakpoint_t db_breakpoint_list = 0;
62
63 static struct db_thread_breakpoint db_thread_break_list[NTHREAD_LIST];
64 static db_thread_breakpoint_t db_free_thread_break_list = 0;
65 static boolean_t db_thread_break_init = FALSE;
66 static int db_breakpoint_number = 0;
67
68 /* Prototypes for functions local to this file. XXX -- should be static!
69 */
70 static int db_add_thread_breakpoint(
71 register db_breakpoint_t bkpt,
72 vm_offset_t task_thd,
73 int count,
74 boolean_t task_bpt);
75
76 static int db_delete_thread_breakpoint(
77 register db_breakpoint_t bkpt,
78 vm_offset_t task_thd);
79
80 static db_thread_breakpoint_t db_find_thread_breakpoint(
81 db_breakpoint_t bkpt,
82 thread_t thr_act);
83
84 static void db_force_delete_breakpoint(
85 db_breakpoint_t bkpt,
86 vm_offset_t task_thd,
87 boolean_t is_task);
88
89 db_breakpoint_t db_breakpoint_alloc(void);
90
91 void db_breakpoint_free(register db_breakpoint_t bkpt);
92
93 void db_delete_breakpoint(
94 task_t task,
95 db_addr_t addr,
96 vm_offset_t task_thd);
97
98 void
99 db_delete_all_breakpoints(
100 task_t task);
101
102 void db_list_breakpoints(void);
103
104
105
106 db_breakpoint_t
107 db_breakpoint_alloc(void)
108 {
109 register db_breakpoint_t bkpt;
110
111 if ((bkpt = db_free_breakpoints) != 0) {
112 db_free_breakpoints = bkpt->link;
113 return (bkpt);
114 }
115 if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
116 db_printf("All breakpoints used.\n");
117 return (0);
118 }
119 bkpt = db_next_free_breakpoint;
120 db_next_free_breakpoint++;
121
122 return (bkpt);
123 }
124
125 void
126 db_breakpoint_free(register db_breakpoint_t bkpt)
127 {
128 bkpt->link = db_free_breakpoints;
129 db_free_breakpoints = bkpt;
130 }
131
132 static int
133 db_add_thread_breakpoint(
134 register db_breakpoint_t bkpt,
135 vm_offset_t task_thd,
136 int count,
137 boolean_t task_bpt)
138 {
139 register db_thread_breakpoint_t tp;
140
141 if (db_thread_break_init == FALSE) {
142 for (tp = db_thread_break_list;
143 tp < &db_thread_break_list[NTHREAD_LIST-1]; tp++)
144 tp->tb_next = tp+1;
145 tp->tb_next = 0;
146 db_free_thread_break_list = db_thread_break_list;
147 db_thread_break_init = TRUE;
148 }
149 if (db_free_thread_break_list == 0)
150 return (-1);
151 tp = db_free_thread_break_list;
152 db_free_thread_break_list = tp->tb_next;
153 tp->tb_is_task = task_bpt;
154 tp->tb_task_thd = task_thd;
155 tp->tb_count = count;
156 tp->tb_init_count = count;
157 tp->tb_cond = 0;
158 tp->tb_number = ++db_breakpoint_number;
159 tp->tb_next = bkpt->threads;
160 bkpt->threads = tp;
161 return(0);
162 }
163
164 static int
165 db_delete_thread_breakpoint(
166 register db_breakpoint_t bkpt,
167 vm_offset_t task_thd)
168 {
169 register db_thread_breakpoint_t tp;
170 register db_thread_breakpoint_t *tpp;
171
172 if (task_thd == 0) {
173 /* delete all the thread-breakpoints */
174
175 for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
176 db_cond_free(tp);
177
178 *tpp = db_free_thread_break_list;
179 db_free_thread_break_list = bkpt->threads;
180 bkpt->threads = 0;
181 return 0;
182 } else {
183 /* delete the specified thread-breakpoint */
184
185 for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
186 if (tp->tb_task_thd == task_thd) {
187 db_cond_free(tp);
188 *tpp = tp->tb_next;
189 tp->tb_next = db_free_thread_break_list;
190 db_free_thread_break_list = tp;
191 return 0;
192 }
193
194 return -1; /* not found */
195 }
196 }
197
198 static db_thread_breakpoint_t
199 db_find_thread_breakpoint(
200 db_breakpoint_t bkpt,
201 thread_t thr_act)
202 {
203 register db_thread_breakpoint_t tp;
204 register task_t task =
205 (thr_act == THREAD_NULL)
206 ? TASK_NULL : thr_act->task;
207
208 for (tp = bkpt->threads; tp; tp = tp->tb_next) {
209 if (tp->tb_is_task) {
210 if (tp->tb_task_thd == (vm_offset_t)task)
211 break;
212 continue;
213 }
214 if (tp->tb_task_thd == (vm_offset_t)thr_act || tp->tb_task_thd == 0)
215 break;
216 }
217 return(tp);
218 }
219
220 db_thread_breakpoint_t
221 db_find_thread_breakpoint_here(
222 task_t task,
223 db_addr_t addr)
224 {
225 db_breakpoint_t bkpt;
226
227 bkpt = db_find_breakpoint(task, (db_addr_t)addr);
228 if (bkpt == 0)
229 return(0);
230 return(db_find_thread_breakpoint(bkpt, current_thread()));
231 }
232
233 db_thread_breakpoint_t
234 db_find_breakpoint_number(
235 int num,
236 db_breakpoint_t *bkptp)
237 {
238 register db_thread_breakpoint_t tp;
239 register db_breakpoint_t bkpt;
240
241 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
242 for (tp = bkpt->threads; tp; tp = tp->tb_next) {
243 if (tp->tb_number == num) {
244 if (bkptp)
245 *bkptp = bkpt;
246 return(tp);
247 }
248 }
249 }
250 return(0);
251 }
252
253 static void
254 db_force_delete_breakpoint(
255 db_breakpoint_t bkpt,
256 vm_offset_t task_thd,
257 boolean_t is_task)
258 {
259 db_printf("deleted a stale breakpoint at ");
260 if (bkpt->task == TASK_NULL || db_lookup_task(bkpt->task) >= 0)
261 db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
262 else
263 db_printf("%#X", bkpt->address);
264 if (bkpt->task)
265 db_printf(" in task %X", bkpt->task);
266 if (task_thd)
267 db_printf(" for %s %X", (is_task)? "task": "thr_act", task_thd);
268 db_printf("\n");
269 db_delete_thread_breakpoint(bkpt, task_thd);
270 }
271
272 void
273 db_check_breakpoint_valid(void)
274 {
275 register db_thread_breakpoint_t tbp, tbp_next;
276 register db_breakpoint_t bkpt, *bkptp;
277
278 bkptp = &db_breakpoint_list;
279 for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
280 if (bkpt->task != TASK_NULL) {
281 if (db_lookup_task(bkpt->task) < 0) {
282 db_force_delete_breakpoint(bkpt, 0, FALSE);
283 *bkptp = bkpt->link;
284 db_breakpoint_free(bkpt);
285 continue;
286 }
287 } else {
288 for (tbp = bkpt->threads; tbp; tbp = tbp_next) {
289 tbp_next = tbp->tb_next;
290 if (tbp->tb_task_thd == 0)
291 continue;
292 if ((tbp->tb_is_task &&
293 db_lookup_task((task_t)(tbp->tb_task_thd)) < 0) ||
294 (!tbp->tb_is_task &&
295 db_lookup_act((thread_t)(tbp->tb_task_thd)) < 0)) {
296 db_force_delete_breakpoint(bkpt,
297 tbp->tb_task_thd, tbp->tb_is_task);
298 }
299 }
300 if (bkpt->threads == 0) {
301 db_put_task_value(bkpt->address, BKPT_SIZE,
302 bkpt->bkpt_inst, bkpt->task);
303 *bkptp = bkpt->link;
304 db_breakpoint_free(bkpt);
305 continue;
306 }
307 }
308 bkptp = &bkpt->link;
309 }
310 }
311
312 void
313 db_set_breakpoint(
314 task_t task,
315 db_addr_t addr,
316 int count,
317 thread_t thr_act,
318 boolean_t task_bpt)
319 {
320 register db_breakpoint_t bkpt;
321 db_breakpoint_t alloc_bkpt = 0;
322 vm_offset_t task_thd;
323
324 bkpt = db_find_breakpoint(task, addr);
325 if (bkpt) {
326 if (thr_act == THREAD_NULL
327 || db_find_thread_breakpoint(bkpt, thr_act)) {
328 db_printf("Already set.\n");
329 return;
330 }
331 } else {
332 if (!DB_CHECK_ACCESS(addr, BKPT_SIZE, task)) {
333 if (task) {
334 db_printf("Warning: non-resident page for breakpoint at %llX",
335 (unsigned long long)addr);
336 db_printf(" in task %lX.\n", task);
337 } else {
338 db_printf("Cannot set breakpoint at %llX in kernel space.\n",
339 (unsigned long long)addr);
340 return;
341 }
342 }
343 alloc_bkpt = bkpt = db_breakpoint_alloc();
344 if (bkpt == 0) {
345 db_printf("Too many breakpoints.\n");
346 return;
347 }
348 bkpt->task = task;
349 bkpt->flags = (task && thr_act == THREAD_NULL)?
350 (BKPT_USR_GLOBAL|BKPT_1ST_SET): 0;
351 bkpt->address = addr;
352 bkpt->threads = 0;
353 }
354 if (db_breakpoint_list == 0)
355 db_breakpoint_number = 0;
356 task_thd = (task_bpt) ? (vm_offset_t)(thr_act->task)
357 : (vm_offset_t)thr_act;
358 if (db_add_thread_breakpoint(bkpt, task_thd, count, task_bpt) < 0) {
359 if (alloc_bkpt)
360 db_breakpoint_free(alloc_bkpt);
361 db_printf("Too many thread_breakpoints.\n");
362 } else {
363 db_printf("set breakpoint #%x\n", db_breakpoint_number);
364 if (alloc_bkpt) {
365 bkpt->link = db_breakpoint_list;
366 db_breakpoint_list = bkpt;
367 }
368 }
369 }
370
371 void
372 db_delete_breakpoint(
373 task_t task,
374 db_addr_t addr,
375 vm_offset_t task_thd)
376 {
377 register db_breakpoint_t bkpt;
378 register db_breakpoint_t *prev;
379
380 for (prev = &db_breakpoint_list; (bkpt = *prev) != 0;
381 prev = &bkpt->link) {
382 if ((bkpt->task == task
383 || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
384 && bkpt->address == addr)
385 break;
386 }
387 if (bkpt && (bkpt->flags & BKPT_SET_IN_MEM)) {
388 db_printf("cannot delete it now.\n");
389 return;
390 }
391 if (bkpt == 0
392 || db_delete_thread_breakpoint(bkpt, task_thd) < 0) {
393 db_printf("Not set.\n");
394 return;
395 }
396 if (bkpt->threads == 0) {
397 *prev = bkpt->link;
398 db_breakpoint_free(bkpt);
399 }
400 }
401
402 db_breakpoint_t
403 db_find_breakpoint(
404 task_t task,
405 db_addr_t addr)
406 {
407 register db_breakpoint_t bkpt;
408
409 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
410 if ((bkpt->task == task
411 || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
412 && bkpt->address == addr)
413 return (bkpt);
414 }
415 return (0);
416 }
417
418 boolean_t
419 db_find_breakpoint_here(
420 task_t task,
421 db_addr_t addr)
422 {
423 register db_breakpoint_t bkpt;
424
425 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
426 if ((bkpt->task == task
427 || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
428 && bkpt->address == addr)
429 return(TRUE);
430 if ((bkpt->flags & BKPT_USR_GLOBAL) == 0 &&
431 DB_PHYS_EQ(task, addr, bkpt->task, bkpt->address))
432 return (TRUE);
433 }
434 return(FALSE);
435 }
436
437 boolean_t db_breakpoints_inserted = TRUE;
438
439 void
440 db_set_breakpoints(void)
441 {
442 register db_breakpoint_t bkpt;
443 register task_t task;
444 db_expr_t inst;
445 thread_t cur_act = current_thread();
446 task_t cur_task =
447 (cur_act) ?
448 cur_act->task : TASK_NULL;
449 boolean_t inserted = TRUE;
450
451 if (!db_breakpoints_inserted) {
452 for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
453 if (bkpt->flags & BKPT_SET_IN_MEM)
454 continue;
455 task = bkpt->task;
456 if (bkpt->flags & BKPT_USR_GLOBAL) {
457 if ((bkpt->flags & BKPT_1ST_SET) == 0) {
458 if (cur_task == TASK_NULL)
459 continue;
460 task = cur_task;
461 } else
462 bkpt->flags &= ~BKPT_1ST_SET;
463 }
464 if (DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
465 inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE,
466 task);
467 if (inst == BKPT_SET(inst))
468 continue;
469 bkpt->bkpt_inst = inst;
470 db_put_task_value(bkpt->address,
471 BKPT_SIZE,
472 BKPT_SET(bkpt->bkpt_inst), task);
473 bkpt->flags |= BKPT_SET_IN_MEM;
474 } else {
475 inserted = FALSE;
476 }
477 }
478 db_breakpoints_inserted = inserted;
479 }
480 }
481
482 void
483 db_clear_breakpoints(void)
484 {
485 register db_breakpoint_t bkpt, *bkptp;
486 register task_t task;
487 db_expr_t inst;
488 thread_t cur_act = current_thread();
489 task_t cur_task = (cur_act) ?
490 cur_act->task: TASK_NULL;
491
492 if (db_breakpoints_inserted) {
493 bkptp = &db_breakpoint_list;
494 for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
495 task = bkpt->task;
496 if (bkpt->flags & BKPT_USR_GLOBAL) {
497 if (cur_task == TASK_NULL) {
498 bkptp = &bkpt->link;
499 continue;
500 }
501 task = cur_task;
502 }
503 if ((bkpt->flags & BKPT_SET_IN_MEM)
504 && DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
505 inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE,
506 task);
507 if (inst != BKPT_SET(inst)) {
508 if (bkpt->flags & BKPT_USR_GLOBAL) {
509 bkptp = &bkpt->link;
510 continue;
511 }
512 db_force_delete_breakpoint(bkpt, 0, FALSE);
513 *bkptp = bkpt->link;
514 db_breakpoint_free(bkpt);
515 continue;
516 }
517 db_put_task_value(bkpt->address, BKPT_SIZE,
518 bkpt->bkpt_inst, task);
519 bkpt->flags &= ~BKPT_SET_IN_MEM;
520 }
521 bkptp = &bkpt->link;
522 }
523 db_breakpoints_inserted = FALSE;
524 }
525 }
526
527 /*
528 * Set a temporary breakpoint.
529 * The instruction is changed immediately,
530 * so the breakpoint does not have to be on the breakpoint list.
531 */
532 db_breakpoint_t
533 db_set_temp_breakpoint(
534 task_t task,
535 db_addr_t addr)
536 {
537 register db_breakpoint_t bkpt;
538
539 bkpt = db_breakpoint_alloc();
540 if (bkpt == 0) {
541 db_printf("Too many breakpoints.\n");
542 return 0;
543 }
544 bkpt->task = task;
545 bkpt->address = addr;
546 bkpt->flags = BKPT_TEMP;
547 bkpt->threads = 0;
548 if (db_add_thread_breakpoint(bkpt, 0, 1, FALSE) < 0) {
549 if (bkpt)
550 db_breakpoint_free(bkpt);
551 db_printf("Too many thread_breakpoints.\n");
552 return 0;
553 }
554 bkpt->bkpt_inst = db_get_task_value(bkpt->address, BKPT_SIZE,
555 FALSE, task);
556 db_put_task_value(bkpt->address, BKPT_SIZE,
557 BKPT_SET(bkpt->bkpt_inst), task);
558 return bkpt;
559 }
560
561 void
562 db_delete_temp_breakpoint(
563 task_t task,
564 db_breakpoint_t bkpt)
565 {
566 db_put_task_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst, task);
567 db_delete_thread_breakpoint(bkpt, 0);
568 db_breakpoint_free(bkpt);
569 }
570
571 /*
572 * List breakpoints.
573 */
574 void
575 db_list_breakpoints(void)
576 {
577 register db_breakpoint_t bkpt;
578
579 if (db_breakpoint_list == 0) {
580 db_printf("No breakpoints set\n");
581 return;
582 }
583
584 db_printf(" No Space Task.Act Cnt Address(Cond)\n");
585 for (bkpt = db_breakpoint_list;
586 bkpt != 0;
587 bkpt = bkpt->link)
588 {
589 register db_thread_breakpoint_t tp;
590 int task_id;
591 int act_id;
592
593 if (bkpt->threads) {
594 for (tp = bkpt->threads; tp; tp = tp->tb_next) {
595 db_printf("%3d ", tp->tb_number);
596 if (bkpt->flags & BKPT_USR_GLOBAL)
597 db_printf("user ");
598 else if (bkpt->task == TASK_NULL)
599 db_printf("kernel ");
600 else if ((task_id = db_lookup_task(bkpt->task)) < 0)
601 db_printf("%0*X ", 2*sizeof(vm_offset_t), bkpt->task);
602 else
603 db_printf("task%-3d ", task_id);
604 if (tp->tb_task_thd == 0) {
605 db_printf("all ");
606 } else {
607 if (tp->tb_is_task) {
608 task_id = db_lookup_task((task_t)(tp->tb_task_thd));
609 if (task_id < 0)
610 db_printf("%0*X ", 2*sizeof(vm_offset_t),
611 tp->tb_task_thd);
612 else
613 db_printf("task%03d ", task_id);
614 } else {
615 thread_t thd = (thread_t)(tp->tb_task_thd);
616 task_id = db_lookup_task(thd->task);
617 act_id = db_lookup_task_act(thd->task, thd);
618 if (task_id < 0 || act_id < 0)
619 db_printf("%0*X ", 2*sizeof(vm_offset_t),
620 tp->tb_task_thd);
621 else
622 db_printf("task%03d.%-3d ", task_id, act_id);
623 }
624 }
625 db_printf("%3d ", tp->tb_init_count);
626 db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
627 if (tp->tb_cond > 0) {
628 db_printf("(");
629 db_cond_print(tp);
630 db_printf(")");
631 }
632 db_printf("\n");
633 }
634 } else {
635 if (bkpt->task == TASK_NULL)
636 db_printf(" ? kernel ");
637 else
638 db_printf("%*X ", 2*sizeof(vm_offset_t), bkpt->task);
639 db_printf("(?) ");
640 db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
641 db_printf("\n");
642 }
643 }
644 }
645
646 void
647 db_delete_all_breakpoints(
648 task_t task)
649 {
650 register db_breakpoint_t bkpt;
651
652 bkpt = db_breakpoint_list;
653 while ( bkpt != 0 ) {
654 if (bkpt->task == task ||
655 (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL))) {
656 db_delete_breakpoint(task, bkpt->address, 0);
657 bkpt = db_breakpoint_list;
658 }
659 else
660 bkpt = bkpt->link;
661
662 }
663 }
664
665 /* Delete breakpoint */
666 void
667 db_delete_cmd(void)
668 {
669 register int n;
670 thread_t thr_act;
671 vm_offset_t task_thd;
672 boolean_t user_global = FALSE;
673 boolean_t task_bpt = FALSE;
674 boolean_t user_space = FALSE;
675 boolean_t thd_bpt = FALSE;
676 db_expr_t addr;
677 int t;
678
679 t = db_read_token();
680 if (t == tSLASH) {
681 t = db_read_token();
682 if (t != tIDENT) {
683 db_printf("Bad modifier \"%s\"\n", db_tok_string);
684 db_error(0);
685 }
686 user_global = db_option(db_tok_string, 'U');
687 user_space = (user_global)? TRUE: db_option(db_tok_string, 'u');
688 task_bpt = db_option(db_tok_string, 'T');
689 thd_bpt = db_option(db_tok_string, 't');
690 if (task_bpt && user_global)
691 db_error("Cannot specify both 'T' and 'U' option\n");
692 t = db_read_token();
693 }
694
695 if ( t == tSTAR ) {
696 db_printf("Delete ALL breakpoints\n");
697 db_delete_all_breakpoints( (task_t)task_bpt );
698 return;
699 }
700
701 if (t == tHASH) {
702 db_thread_breakpoint_t tbp;
703 db_breakpoint_t bkpt = 0;
704
705 if (db_read_token() != tNUMBER) {
706 db_printf("Bad break point number #%s\n", db_tok_string);
707 db_error(0);
708 }
709 if ((tbp = db_find_breakpoint_number(db_tok_number, &bkpt)) == 0) {
710 db_printf("No such break point #%d\n", db_tok_number);
711 db_error(0);
712 }
713 db_delete_breakpoint(bkpt->task, bkpt->address, tbp->tb_task_thd);
714 return;
715 }
716 db_unread_token(t);
717 if (!db_expression(&addr)) {
718 /*
719 * We attempt to pick up the user_space indication from db_dot,
720 * so that a plain "d" always works.
721 */
722 addr = (db_expr_t)db_dot;
723 if (!user_space && !DB_VALID_ADDRESS(addr, FALSE))
724 user_space = TRUE;
725 }
726 if (!DB_VALID_ADDRESS(addr, user_space)) {
727 db_printf("Address %#llX is not in %s space\n", (unsigned long long)addr,
728 (user_space)? "user": "kernel");
729 db_error(0);
730 }
731 if (thd_bpt || task_bpt) {
732 for (n = 0; db_get_next_act(&thr_act, n); n++) {
733 if (thr_act == THREAD_NULL)
734 db_error("No active thr_act\n");
735 if (task_bpt) {
736 if (thr_act->task == TASK_NULL)
737 db_error("No task\n");
738 task_thd = (vm_offset_t) (thr_act->task);
739 } else
740 task_thd = (user_global)? 0: (vm_offset_t) thr_act;
741 db_delete_breakpoint(db_target_space(thr_act, user_space),
742 (db_addr_t)addr, task_thd);
743 }
744 } else {
745 db_delete_breakpoint(db_target_space(THREAD_NULL, user_space),
746 (db_addr_t)addr, 0);
747 }
748 }
749
750 /* Set breakpoint with skip count */
751 #include <mach/machine/vm_param.h>
752
753 void
754 db_breakpoint_cmd(db_expr_t addr, __unused boolean_t have_addr, db_expr_t count,
755 char *modif)
756 {
757 register int n;
758 thread_t thr_act;
759 boolean_t user_global = db_option(modif, 'U');
760 boolean_t task_bpt = db_option(modif, 'T');
761 boolean_t user_space;
762
763 if (count == (uint64_t)-1)
764 count = 1;
765 #if 0 /* CHECKME */
766 if (!task_bpt && db_option(modif,'t'))
767 task_bpt = TRUE;
768 #endif
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 || !user_space) &&
776 !DB_VALID_ADDRESS(addr, user_space)) {
777 /* if the user has explicitly specified user space,
778 do not insert a breakpoint into the kernel */
779 if (user_space)
780 db_error("Invalid user space address\n");
781 user_space = TRUE;
782 db_printf("%#llX is in user space\n", (unsigned long long)addr);
783 #ifdef ppc
784 db_printf("kernel is from %#X to %#x\n", VM_MIN_KERNEL_ADDRESS, vm_last_addr);
785 #else
786 db_printf("kernel is from %#X to %#x\n", VM_MIN_KERNEL_ADDRESS, VM_MAX_KERNEL_ADDRESS);
787 #endif
788 }
789 if (db_option(modif, 't') || task_bpt) {
790 for (n = 0; db_get_next_act(&thr_act, n); n++) {
791 if (thr_act == THREAD_NULL)
792 db_error("No active thr_act\n");
793 if (task_bpt && thr_act->task == TASK_NULL)
794 db_error("No task\n");
795 if (db_access_level <= DB_ACCESS_CURRENT && user_space
796 && thr_act->task != db_current_space())
797 db_error("Cannot set break point in inactive user space\n");
798 db_set_breakpoint(db_target_space(thr_act, user_space),
799 (db_addr_t)addr, count,
800 (user_global)? THREAD_NULL: thr_act,
801 task_bpt);
802 }
803 } else {
804 db_set_breakpoint(db_target_space(THREAD_NULL, user_space),
805 (db_addr_t)addr,
806 count, THREAD_NULL, FALSE);
807 }
808 }
809
810 /* list breakpoints */
811 void
812 db_listbreak_cmd(__unused db_expr_t addr, __unused boolean_t have_addr,
813 __unused db_expr_t count, __unused char *modif)
814 {
815 db_list_breakpoints();
816 }