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