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