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