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