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 58struct db_breakpoint db_break_table[NBREAKPOINTS]; 59db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; 60db_breakpoint_t db_free_breakpoints = 0; 61db_breakpoint_t db_breakpoint_list = 0; 62 63static struct db_thread_breakpoint db_thread_break_list[NTHREAD_LIST]; 64static db_thread_breakpoint_t db_free_thread_break_list = 0; 65static boolean_t db_thread_break_init = FALSE; 66static int db_breakpoint_number = 0; 67 68/* Prototypes for functions local to this file. XXX -- should be static! 69 */ 70static 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 76static int db_delete_thread_breakpoint( 77 register db_breakpoint_t bkpt, 78 vm_offset_t task_thd); 79 80static db_thread_breakpoint_t db_find_thread_breakpoint( 81 db_breakpoint_t bkpt, 82 thread_t thr_act); 83 84static void db_force_delete_breakpoint( 85 db_breakpoint_t bkpt, 86 vm_offset_t task_thd, 87 boolean_t is_task); 88 89db_breakpoint_t db_breakpoint_alloc(void); 90 91void db_breakpoint_free(register db_breakpoint_t bkpt); 92 93void db_delete_breakpoint( 94 task_t task, 95 db_addr_t addr, 96 vm_offset_t task_thd); 97 98void 99db_delete_all_breakpoints( 100 task_t task); 101 102void db_list_breakpoints(void); 103 104 105 106db_breakpoint_t 107db_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 125void 126db_breakpoint_free(register db_breakpoint_t bkpt) 127{ 128 bkpt->link = db_free_breakpoints; 129 db_free_breakpoints = bkpt; 130} 131 132static int 133db_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 164static int 165db_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 198static db_thread_breakpoint_t 199db_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 220db_thread_breakpoint_t 221db_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 233db_thread_breakpoint_t 234db_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 253static void 254db_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 272void 273db_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 312void 313db_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 371void 372db_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 402db_breakpoint_t 403db_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 418boolean_t 419db_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 437boolean_t db_breakpoints_inserted = TRUE; 438 439void 440db_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 482void 483db_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 */ 532db_breakpoint_t 533db_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 561void 562db_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 */ 574void 575db_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 646void 647db_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 */ 666void 667db_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 753void 754db_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 */ 811void 812db_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} 817