|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 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: * HISTORY ! 27: * ! 28: * Revision 1.1.1.1 1998/09/22 21:05:47 wsanchez ! 29: * Import of Mac OS X kernel (~semeria) ! 30: * ! 31: * Revision 1.2 1998/04/29 17:35:26 mburg ! 32: * MK7.3 merger ! 33: * ! 34: * Revision 1.2.47.1 1998/02/03 09:23:57 gdt ! 35: * Merge up to MK7.3 ! 36: * [1998/02/03 09:10:14 gdt] ! 37: * ! 38: * Revision 1.2.45.1 1997/03/27 18:46:16 barbou ! 39: * ri-osc CR1557: re-enable thread-specific breakpoints. ! 40: * [1995/09/20 15:23:46 bolinger] ! 41: * [97/02/25 barbou] ! 42: * ! 43: * Revision 1.2.21.6 1996/01/09 19:15:21 devrcs ! 44: * Changed declarations of 'register foo' to 'register int foo' ! 45: * Fixed printfs which print addresses. ! 46: * [1995/12/01 21:41:51 jfraser] ! 47: * ! 48: * Merged '64-bit safe' changes from DEC alpha port. ! 49: * [1995/11/21 18:02:40 jfraser] ! 50: * ! 51: * Revision 1.2.21.5 1995/04/07 18:52:54 barbou ! 52: * Allow breakpoints on non-resident pages. The breakpoint will ! 53: * actually be set when the page is paged in. ! 54: * [93/09/23 barbou] ! 55: * [95/03/08 barbou] ! 56: * ! 57: * Revision 1.2.21.4 1995/02/23 21:43:19 alanl ! 58: * Merged with DIPC2_SHARED. ! 59: * [1995/01/04 20:15:04 alanl] ! 60: * ! 61: * Revision 1.2.28.1 1994/11/04 09:52:15 dwm ! 62: * mk6 CR668 - 1.3b26 merge ! 63: * * Revision 1.2.4.5 1994/05/06 18:38:52 tmt ! 64: * Merged osc1.3dec/shared with osc1.3b19 ! 65: * Moved struct db_breakpoint from here to db_break.h. ! 66: * Merge Alpha changes into osc1.312b source code. ! 67: * 64bit cleanup. ! 68: * * End1.3merge ! 69: * [1994/11/04 08:49:10 dwm] ! 70: * ! 71: * Revision 1.2.21.2 1994/09/23 01:17:57 ezf ! 72: * change marker to not FREE ! 73: * [1994/09/22 21:09:19 ezf] ! 74: * ! 75: * Revision 1.2.21.1 1994/06/11 21:11:24 bolinger ! 76: * Merge up to NMK17.2. ! 77: * [1994/06/11 20:01:06 bolinger] ! 78: * ! 79: * Revision 1.2.25.2 1994/10/28 18:56:21 rwd ! 80: * Delint. ! 81: * [94/10/28 rwd] ! 82: * ! 83: * Revision 1.2.25.1 1994/08/04 01:42:15 mmp ! 84: * 23-Jun-94 Stan Smith ([email protected]) ! 85: * Let d * delete all breakpoints. ! 86: * [1994/06/28 13:54:00 sjs] ! 87: * ! 88: * Revision 1.2.19.2 1994/04/11 09:34:22 bernadat ! 89: * Moved db_breakpoint struct declaration to db_break.h ! 90: * [94/03/16 bernadat] ! 91: * ! 92: * Revision 1.2.19.1 1994/02/08 10:57:22 bernadat ! 93: * When setting a breakpoint, force user_space if breakpoint is ! 94: * outside kernel_space (like in the case of an emulator). ! 95: * [93/09/27 paire] ! 96: * ! 97: * Changed silly decimal display to hex (to match input conventions). ! 98: * Change from NORMA_MK14.6 [93/01/09 sjs] ! 99: * [93/07/16 bernadat] ! 100: * [94/02/07 bernadat] ! 101: * ! 102: * Revision 1.2.4.3 1993/07/27 18:26:48 elliston ! 103: * Add ANSI prototypes. CR #9523. ! 104: * [1993/07/27 18:10:54 elliston] ! 105: * ! 106: * Revision 1.2.4.2 1993/06/09 02:19:39 gm ! 107: * Added to OSF/1 R1.3 from NMK15.0. ! 108: * [1993/06/02 20:55:42 jeffc] ! 109: * ! 110: * Revision 1.2 1993/04/19 16:01:31 devrcs ! 111: * Changes from MK78: ! 112: * Removed unused variable from db_delete_cmd(). ! 113: * Added declaration for arg 'count' of db_add_thread_breakpoint(). ! 114: * [92/05/18 jfriedl] ! 115: * Fixed b/tu to b/Tu work if the specified address is valid in the ! 116: * target address space but not the current user space. Explicit ! 117: * user space breakpoints (b/u, b/Tu, etc) will no longer get ! 118: * inserted into the kernel if the specified address is invalid. ! 119: * [92/04/18 danner] ! 120: * [92/12/18 bruel] ! 121: * ! 122: * Revision 1.1 1992/09/30 02:00:52 robert ! 123: * Initial revision ! 124: * ! 125: * $EndLog$ ! 126: */ ! 127: /* CMU_HIST */ ! 128: /* ! 129: * Revision 2.11.3.1 92/03/03 16:13:20 jeffreyh ! 130: * Pick up changes from TRUNK ! 131: * [92/02/26 10:58:37 jeffreyh] ! 132: * ! 133: * Revision 2.12 92/02/19 16:46:24 elf ! 134: * Removed one of the many user-unfriendlinesses. ! 135: * [92/02/10 17:48:25 af] ! 136: * ! 137: * Revision 2.11 91/11/12 11:50:24 rvb ! 138: * Fixed db_delete_cmd so that just "d" works in user space. ! 139: * [91/10/31 rpd] ! 140: * Fixed db_delete_thread_breakpoint for zero task_thd. ! 141: * [91/10/30 rpd] ! 142: * ! 143: * Revision 2.10 91/10/09 15:57:41 af ! 144: * Supported thread-oriented break points. ! 145: * [91/08/29 tak] ! 146: * ! 147: * Revision 2.9 91/07/09 23:15:39 danner ! 148: * Conditionalized db_map_addr to work right on the luna. Used a ! 149: * ifdef luna88k. This is evil, and needs to be fixed. ! 150: * [91/07/08 danner] ! 151: * ! 152: * Revision 2.2 91/04/10 22:54:50 mbj ! 153: * Grabbed 3.0 copyright/disclaimer since ddb comes from 3.0. ! 154: * [91/04/09 rvb] ! 155: * ! 156: * Revision 2.7 91/02/05 17:06:00 mrt ! 157: * Changed to new Mach copyright ! 158: * [91/01/31 16:17:01 mrt] ! 159: * ! 160: * Revision 2.6 91/01/08 15:09:03 rpd ! 161: * Added db_map_equal, db_map_current, db_map_addr. ! 162: * [90/11/10 rpd] ! 163: * ! 164: * Revision 2.5 90/11/05 14:26:32 rpd ! 165: * Initialize db_breakpoints_inserted to TRUE. ! 166: * [90/11/04 rpd] ! 167: * ! 168: * Revision 2.4 90/10/25 14:43:33 rwd ! 169: * Added map field to breakpoints. ! 170: * Added map argument to db_set_breakpoint, db_delete_breakpoint, ! 171: * db_find_breakpoint. Added db_find_breakpoint_here. ! 172: * [90/10/18 rpd] ! 173: * ! 174: * Revision 2.3 90/09/28 16:57:07 jsb ! 175: * Fixed db_breakpoint_free. ! 176: * [90/09/18 rpd] ! 177: * ! 178: * Revision 2.2 90/08/27 21:49:53 dbg ! 179: * Reflected changes in db_printsym()'s calling seq. ! 180: * [90/08/20 af] ! 181: * Clear breakpoints only if inserted. ! 182: * Reduce lint. ! 183: * [90/08/07 dbg] ! 184: * Created. ! 185: * [90/07/25 dbg] ! 186: * ! 187: */ ! 188: /* CMU_ENDHIST */ ! 189: /* ! 190: * Mach Operating System ! 191: * Copyright (c) 1991,1990 Carnegie Mellon University ! 192: * All Rights Reserved. ! 193: * ! 194: * Permission to use, copy, modify and distribute this software and its ! 195: * documentation is hereby granted, provided that both the copyright ! 196: * notice and this permission notice appear in all copies of the ! 197: * software, derivative works or modified versions, and any portions ! 198: * thereof, and that both notices appear in supporting documentation. ! 199: * ! 200: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 201: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 202: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 203: * ! 204: * Carnegie Mellon requests users of this software to return to ! 205: * ! 206: * Software Distribution Coordinator or [email protected] ! 207: * School of Computer Science ! 208: * Carnegie Mellon University ! 209: * Pittsburgh PA 15213-3890 ! 210: * ! 211: * any improvements or extensions that they make and grant Carnegie Mellon ! 212: * the rights to redistribute these changes. ! 213: */ ! 214: /* ! 215: */ ! 216: /* ! 217: * Author: David B. Golub, Carnegie Mellon University ! 218: * Date: 7/90 ! 219: */ ! 220: ! 221: /* ! 222: * Breakpoints. ! 223: */ ! 224: #include <mach/boolean.h> ! 225: #include <machine/db_machdep.h> ! 226: #include <ddb/db_lex.h> ! 227: #include <ddb/db_break.h> ! 228: #include <ddb/db_access.h> ! 229: #include <ddb/db_sym.h> ! 230: #include <ddb/db_variables.h> ! 231: #include <ddb/db_command.h> ! 232: #include <ddb/db_cond.h> ! 233: #include <ddb/db_expr.h> ! 234: #include <ddb/db_output.h> /* For db_printf() */ ! 235: #include <ddb/db_task_thread.h> ! 236: ! 237: ! 238: #define NBREAKPOINTS 100 ! 239: #define NTHREAD_LIST (NBREAKPOINTS*3) ! 240: ! 241: struct db_breakpoint db_break_table[NBREAKPOINTS]; ! 242: db_breakpoint_t db_next_free_breakpoint = &db_break_table[0]; ! 243: db_breakpoint_t db_free_breakpoints = 0; ! 244: db_breakpoint_t db_breakpoint_list = 0; ! 245: ! 246: static struct db_thread_breakpoint db_thread_break_list[NTHREAD_LIST]; ! 247: static db_thread_breakpoint_t db_free_thread_break_list = 0; ! 248: static boolean_t db_thread_break_init = FALSE; ! 249: static int db_breakpoint_number = 0; ! 250: ! 251: /* Prototypes for functions local to this file. XXX -- should be static! ! 252: */ ! 253: static int db_add_thread_breakpoint( ! 254: register db_breakpoint_t bkpt, ! 255: vm_offset_t task_thd, ! 256: int count, ! 257: boolean_t task_bpt); ! 258: ! 259: static int db_delete_thread_breakpoint( ! 260: register db_breakpoint_t bkpt, ! 261: vm_offset_t task_thd); ! 262: ! 263: static db_thread_breakpoint_t db_find_thread_breakpoint( ! 264: db_breakpoint_t bkpt, ! 265: thread_act_t thr_act); ! 266: ! 267: static void db_force_delete_breakpoint( ! 268: db_breakpoint_t bkpt, ! 269: vm_offset_t task_thd, ! 270: boolean_t is_task); ! 271: ! 272: db_breakpoint_t db_breakpoint_alloc(void); ! 273: ! 274: void db_breakpoint_free(register db_breakpoint_t bkpt); ! 275: ! 276: void db_delete_breakpoint( ! 277: task_t task, ! 278: db_addr_t addr, ! 279: vm_offset_t task_thd); ! 280: ! 281: void ! 282: db_delete_all_breakpoints( ! 283: task_t task); ! 284: ! 285: void db_list_breakpoints(void); ! 286: ! 287: ! 288: ! 289: db_breakpoint_t ! 290: db_breakpoint_alloc(void) ! 291: { ! 292: register db_breakpoint_t bkpt; ! 293: ! 294: if ((bkpt = db_free_breakpoints) != 0) { ! 295: db_free_breakpoints = bkpt->link; ! 296: return (bkpt); ! 297: } ! 298: if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) { ! 299: db_printf("All breakpoints used.\n"); ! 300: return (0); ! 301: } ! 302: bkpt = db_next_free_breakpoint; ! 303: db_next_free_breakpoint++; ! 304: ! 305: return (bkpt); ! 306: } ! 307: ! 308: void ! 309: db_breakpoint_free(register db_breakpoint_t bkpt) ! 310: { ! 311: bkpt->link = db_free_breakpoints; ! 312: db_free_breakpoints = bkpt; ! 313: } ! 314: ! 315: static int ! 316: db_add_thread_breakpoint( ! 317: register db_breakpoint_t bkpt, ! 318: vm_offset_t task_thd, ! 319: int count, ! 320: boolean_t task_bpt) ! 321: { ! 322: register db_thread_breakpoint_t tp; ! 323: ! 324: if (db_thread_break_init == FALSE) { ! 325: for (tp = db_thread_break_list; ! 326: tp < &db_thread_break_list[NTHREAD_LIST-1]; tp++) ! 327: tp->tb_next = tp+1; ! 328: tp->tb_next = 0; ! 329: db_free_thread_break_list = db_thread_break_list; ! 330: db_thread_break_init = TRUE; ! 331: } ! 332: if (db_free_thread_break_list == 0) ! 333: return (-1); ! 334: tp = db_free_thread_break_list; ! 335: db_free_thread_break_list = tp->tb_next; ! 336: tp->tb_is_task = task_bpt; ! 337: tp->tb_task_thd = task_thd; ! 338: tp->tb_count = count; ! 339: tp->tb_init_count = count; ! 340: tp->tb_cond = 0; ! 341: tp->tb_number = ++db_breakpoint_number; ! 342: tp->tb_next = bkpt->threads; ! 343: bkpt->threads = tp; ! 344: return(0); ! 345: } ! 346: ! 347: static int ! 348: db_delete_thread_breakpoint( ! 349: register db_breakpoint_t bkpt, ! 350: vm_offset_t task_thd) ! 351: { ! 352: register db_thread_breakpoint_t tp; ! 353: register db_thread_breakpoint_t *tpp; ! 354: ! 355: if (task_thd == 0) { ! 356: /* delete all the thread-breakpoints */ ! 357: ! 358: for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next) ! 359: db_cond_free(tp); ! 360: ! 361: *tpp = db_free_thread_break_list; ! 362: db_free_thread_break_list = bkpt->threads; ! 363: bkpt->threads = 0; ! 364: return 0; ! 365: } else { ! 366: /* delete the specified thread-breakpoint */ ! 367: ! 368: for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next) ! 369: if (tp->tb_task_thd == task_thd) { ! 370: db_cond_free(tp); ! 371: *tpp = tp->tb_next; ! 372: tp->tb_next = db_free_thread_break_list; ! 373: db_free_thread_break_list = tp; ! 374: return 0; ! 375: } ! 376: ! 377: return -1; /* not found */ ! 378: } ! 379: } ! 380: ! 381: static db_thread_breakpoint_t ! 382: db_find_thread_breakpoint( ! 383: db_breakpoint_t bkpt, ! 384: thread_act_t thr_act) ! 385: { ! 386: register db_thread_breakpoint_t tp; ! 387: register task_t task = ! 388: (thr_act == THR_ACT_NULL || thr_act->kernel_loaded) ! 389: ? TASK_NULL : thr_act->task; ! 390: ! 391: for (tp = bkpt->threads; tp; tp = tp->tb_next) { ! 392: if (tp->tb_is_task) { ! 393: if (tp->tb_task_thd == (vm_offset_t)task) ! 394: break; ! 395: continue; ! 396: } ! 397: if (tp->tb_task_thd == (vm_offset_t)thr_act || tp->tb_task_thd == 0) ! 398: break; ! 399: } ! 400: return(tp); ! 401: } ! 402: ! 403: db_thread_breakpoint_t ! 404: db_find_thread_breakpoint_here( ! 405: task_t task, ! 406: db_addr_t addr) ! 407: { ! 408: db_breakpoint_t bkpt; ! 409: ! 410: bkpt = db_find_breakpoint(task, (db_addr_t)addr); ! 411: if (bkpt == 0) ! 412: return(0); ! 413: return(db_find_thread_breakpoint(bkpt, current_act())); ! 414: } ! 415: ! 416: db_thread_breakpoint_t ! 417: db_find_breakpoint_number( ! 418: int num, ! 419: db_breakpoint_t *bkptp) ! 420: { ! 421: register db_thread_breakpoint_t tp; ! 422: register db_breakpoint_t bkpt; ! 423: ! 424: for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { ! 425: for (tp = bkpt->threads; tp; tp = tp->tb_next) { ! 426: if (tp->tb_number == num) { ! 427: if (bkptp) ! 428: *bkptp = bkpt; ! 429: return(tp); ! 430: } ! 431: } ! 432: } ! 433: return(0); ! 434: } ! 435: ! 436: static void ! 437: db_force_delete_breakpoint( ! 438: db_breakpoint_t bkpt, ! 439: vm_offset_t task_thd, ! 440: boolean_t is_task) ! 441: { ! 442: db_printf("deleted a stale breakpoint at "); ! 443: if (bkpt->task == TASK_NULL || db_lookup_task(bkpt->task) >= 0) ! 444: db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task); ! 445: else ! 446: db_printf("%#X", bkpt->address); ! 447: if (bkpt->task) ! 448: db_printf(" in task %X", bkpt->task); ! 449: if (task_thd) ! 450: db_printf(" for %s %X", (is_task)? "task": "thr_act", task_thd); ! 451: db_printf("\n"); ! 452: db_delete_thread_breakpoint(bkpt, task_thd); ! 453: } ! 454: ! 455: void ! 456: db_check_breakpoint_valid(void) ! 457: { ! 458: register db_thread_breakpoint_t tbp, tbp_next; ! 459: register db_breakpoint_t bkpt, *bkptp; ! 460: ! 461: bkptp = &db_breakpoint_list; ! 462: for (bkpt = *bkptp; bkpt; bkpt = *bkptp) { ! 463: if (bkpt->task != TASK_NULL) { ! 464: if (db_lookup_task(bkpt->task) < 0) { ! 465: db_force_delete_breakpoint(bkpt, 0, FALSE); ! 466: *bkptp = bkpt->link; ! 467: db_breakpoint_free(bkpt); ! 468: continue; ! 469: } ! 470: } else { ! 471: for (tbp = bkpt->threads; tbp; tbp = tbp_next) { ! 472: tbp_next = tbp->tb_next; ! 473: if (tbp->tb_task_thd == 0) ! 474: continue; ! 475: if ((tbp->tb_is_task && ! 476: db_lookup_task((task_t)(tbp->tb_task_thd)) < 0) || ! 477: (!tbp->tb_is_task && ! 478: db_lookup_act((thread_act_t)(tbp->tb_task_thd)) < 0)) { ! 479: db_force_delete_breakpoint(bkpt, ! 480: tbp->tb_task_thd, tbp->tb_is_task); ! 481: } ! 482: } ! 483: if (bkpt->threads == 0) { ! 484: db_put_task_value(bkpt->address, BKPT_SIZE, ! 485: bkpt->bkpt_inst, bkpt->task); ! 486: *bkptp = bkpt->link; ! 487: db_breakpoint_free(bkpt); ! 488: continue; ! 489: } ! 490: } ! 491: bkptp = &bkpt->link; ! 492: } ! 493: } ! 494: ! 495: void ! 496: db_set_breakpoint( ! 497: task_t task, ! 498: db_addr_t addr, ! 499: int count, ! 500: thread_act_t thr_act, ! 501: boolean_t task_bpt) ! 502: { ! 503: register db_breakpoint_t bkpt; ! 504: db_breakpoint_t alloc_bkpt = 0; ! 505: vm_offset_t task_thd; ! 506: ! 507: bkpt = db_find_breakpoint(task, addr); ! 508: if (bkpt) { ! 509: if (thr_act == THR_ACT_NULL ! 510: || db_find_thread_breakpoint(bkpt, thr_act)) { ! 511: db_printf("Already set.\n"); ! 512: return; ! 513: } ! 514: } else { ! 515: if (!DB_CHECK_ACCESS(addr, BKPT_SIZE, task)) { ! 516: if (task) { ! 517: db_printf("Warning: non-resident page for breakpoint at %lX", ! 518: addr); ! 519: db_printf(" in task %lX.\n", task); ! 520: } else { ! 521: db_printf("Cannot set breakpoint at %lX in kernel space.\n", ! 522: addr); ! 523: return; ! 524: } ! 525: } ! 526: alloc_bkpt = bkpt = db_breakpoint_alloc(); ! 527: if (bkpt == 0) { ! 528: db_printf("Too many breakpoints.\n"); ! 529: return; ! 530: } ! 531: bkpt->task = task; ! 532: bkpt->flags = (task && thr_act == THR_ACT_NULL)? ! 533: (BKPT_USR_GLOBAL|BKPT_1ST_SET): 0; ! 534: bkpt->address = addr; ! 535: bkpt->threads = 0; ! 536: } ! 537: if (db_breakpoint_list == 0) ! 538: db_breakpoint_number = 0; ! 539: task_thd = (task_bpt) ? (vm_offset_t)(thr_act->task) ! 540: : (vm_offset_t)thr_act; ! 541: if (db_add_thread_breakpoint(bkpt, task_thd, count, task_bpt) < 0) { ! 542: if (alloc_bkpt) ! 543: db_breakpoint_free(alloc_bkpt); ! 544: db_printf("Too many thread_breakpoints.\n"); ! 545: } else { ! 546: db_printf("set breakpoint #%x\n", db_breakpoint_number); ! 547: if (alloc_bkpt) { ! 548: bkpt->link = db_breakpoint_list; ! 549: db_breakpoint_list = bkpt; ! 550: } ! 551: } ! 552: } ! 553: ! 554: void ! 555: db_delete_breakpoint( ! 556: task_t task, ! 557: db_addr_t addr, ! 558: vm_offset_t task_thd) ! 559: { ! 560: register db_breakpoint_t bkpt; ! 561: register db_breakpoint_t *prev; ! 562: ! 563: for (prev = &db_breakpoint_list; (bkpt = *prev) != 0; ! 564: prev = &bkpt->link) { ! 565: if ((bkpt->task == task ! 566: || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL))) ! 567: && bkpt->address == addr) ! 568: break; ! 569: } ! 570: if (bkpt && (bkpt->flags & BKPT_SET_IN_MEM)) { ! 571: db_printf("cannot delete it now.\n"); ! 572: return; ! 573: } ! 574: if (bkpt == 0 ! 575: || db_delete_thread_breakpoint(bkpt, task_thd) < 0) { ! 576: db_printf("Not set.\n"); ! 577: return; ! 578: } ! 579: if (bkpt->threads == 0) { ! 580: *prev = bkpt->link; ! 581: db_breakpoint_free(bkpt); ! 582: } ! 583: } ! 584: ! 585: db_breakpoint_t ! 586: db_find_breakpoint( ! 587: task_t task, ! 588: db_addr_t addr) ! 589: { ! 590: register db_breakpoint_t bkpt; ! 591: ! 592: for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { ! 593: if ((bkpt->task == task ! 594: || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL))) ! 595: && bkpt->address == addr) ! 596: return (bkpt); ! 597: } ! 598: return (0); ! 599: } ! 600: ! 601: boolean_t ! 602: db_find_breakpoint_here( ! 603: task_t task, ! 604: db_addr_t addr) ! 605: { ! 606: register db_breakpoint_t bkpt; ! 607: ! 608: for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { ! 609: if ((bkpt->task == task ! 610: || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL))) ! 611: && bkpt->address == addr) ! 612: return(TRUE); ! 613: if ((bkpt->flags & BKPT_USR_GLOBAL) == 0 && ! 614: DB_PHYS_EQ(task, addr, bkpt->task, bkpt->address)) ! 615: return (TRUE); ! 616: } ! 617: return(FALSE); ! 618: } ! 619: ! 620: boolean_t db_breakpoints_inserted = TRUE; ! 621: ! 622: void ! 623: db_set_breakpoints(void) ! 624: { ! 625: register db_breakpoint_t bkpt; ! 626: register task_t task; ! 627: db_expr_t inst; ! 628: thread_act_t cur_act = current_act(); ! 629: task_t cur_task = ! 630: (cur_act && !cur_act->kernel_loaded) ? ! 631: cur_act->task : TASK_NULL; ! 632: boolean_t inserted = TRUE; ! 633: ! 634: if (!db_breakpoints_inserted) { ! 635: for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) { ! 636: if (bkpt->flags & BKPT_SET_IN_MEM) ! 637: continue; ! 638: task = bkpt->task; ! 639: if (bkpt->flags & BKPT_USR_GLOBAL) { ! 640: if ((bkpt->flags & BKPT_1ST_SET) == 0) { ! 641: if (cur_task == TASK_NULL) ! 642: continue; ! 643: task = cur_task; ! 644: } else ! 645: bkpt->flags &= ~BKPT_1ST_SET; ! 646: } ! 647: if (DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) { ! 648: inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE, ! 649: task); ! 650: if (inst == BKPT_SET(inst)) ! 651: continue; ! 652: bkpt->bkpt_inst = inst; ! 653: db_put_task_value(bkpt->address, ! 654: BKPT_SIZE, ! 655: BKPT_SET(bkpt->bkpt_inst), task); ! 656: bkpt->flags |= BKPT_SET_IN_MEM; ! 657: } else { ! 658: inserted = FALSE; ! 659: } ! 660: } ! 661: db_breakpoints_inserted = inserted; ! 662: } ! 663: } ! 664: ! 665: void ! 666: db_clear_breakpoints(void) ! 667: { ! 668: register db_breakpoint_t bkpt, *bkptp; ! 669: register task_t task; ! 670: db_expr_t inst; ! 671: thread_act_t cur_act = current_act(); ! 672: task_t cur_task = (cur_act && !cur_act->kernel_loaded) ? ! 673: cur_act->task: TASK_NULL; ! 674: ! 675: if (db_breakpoints_inserted) { ! 676: bkptp = &db_breakpoint_list; ! 677: for (bkpt = *bkptp; bkpt; bkpt = *bkptp) { ! 678: task = bkpt->task; ! 679: if (bkpt->flags & BKPT_USR_GLOBAL) { ! 680: if (cur_task == TASK_NULL) { ! 681: bkptp = &bkpt->link; ! 682: continue; ! 683: } ! 684: task = cur_task; ! 685: } ! 686: if ((bkpt->flags & BKPT_SET_IN_MEM) ! 687: && DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) { ! 688: inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE, ! 689: task); ! 690: if (inst != BKPT_SET(inst)) { ! 691: if (bkpt->flags & BKPT_USR_GLOBAL) { ! 692: bkptp = &bkpt->link; ! 693: continue; ! 694: } ! 695: db_force_delete_breakpoint(bkpt, 0, FALSE); ! 696: *bkptp = bkpt->link; ! 697: db_breakpoint_free(bkpt); ! 698: continue; ! 699: } ! 700: db_put_task_value(bkpt->address, BKPT_SIZE, ! 701: bkpt->bkpt_inst, task); ! 702: bkpt->flags &= ~BKPT_SET_IN_MEM; ! 703: } ! 704: bkptp = &bkpt->link; ! 705: } ! 706: db_breakpoints_inserted = FALSE; ! 707: } ! 708: } ! 709: ! 710: /* ! 711: * Set a temporary breakpoint. ! 712: * The instruction is changed immediately, ! 713: * so the breakpoint does not have to be on the breakpoint list. ! 714: */ ! 715: db_breakpoint_t ! 716: db_set_temp_breakpoint( ! 717: task_t task, ! 718: db_addr_t addr) ! 719: { ! 720: register db_breakpoint_t bkpt; ! 721: ! 722: bkpt = db_breakpoint_alloc(); ! 723: if (bkpt == 0) { ! 724: db_printf("Too many breakpoints.\n"); ! 725: return 0; ! 726: } ! 727: bkpt->task = task; ! 728: bkpt->address = addr; ! 729: bkpt->flags = BKPT_TEMP; ! 730: bkpt->threads = 0; ! 731: if (db_add_thread_breakpoint(bkpt, 0, 1, FALSE) < 0) { ! 732: if (bkpt) ! 733: db_breakpoint_free(bkpt); ! 734: db_printf("Too many thread_breakpoints.\n"); ! 735: return 0; ! 736: } ! 737: bkpt->bkpt_inst = db_get_task_value(bkpt->address, BKPT_SIZE, ! 738: FALSE, task); ! 739: db_put_task_value(bkpt->address, BKPT_SIZE, ! 740: BKPT_SET(bkpt->bkpt_inst), task); ! 741: return bkpt; ! 742: } ! 743: ! 744: void ! 745: db_delete_temp_breakpoint( ! 746: task_t task, ! 747: db_breakpoint_t bkpt) ! 748: { ! 749: db_put_task_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst, task); ! 750: db_delete_thread_breakpoint(bkpt, 0); ! 751: db_breakpoint_free(bkpt); ! 752: } ! 753: ! 754: /* ! 755: * List breakpoints. ! 756: */ ! 757: void ! 758: db_list_breakpoints(void) ! 759: { ! 760: register db_breakpoint_t bkpt; ! 761: ! 762: if (db_breakpoint_list == 0) { ! 763: db_printf("No breakpoints set\n"); ! 764: return; ! 765: } ! 766: ! 767: db_printf(" No Space Task.Act Cnt Address(Cond)\n"); ! 768: for (bkpt = db_breakpoint_list; ! 769: bkpt != 0; ! 770: bkpt = bkpt->link) ! 771: { ! 772: register db_thread_breakpoint_t tp; ! 773: int task_id; ! 774: int act_id; ! 775: ! 776: if (bkpt->threads) { ! 777: for (tp = bkpt->threads; tp; tp = tp->tb_next) { ! 778: db_printf("%3d ", tp->tb_number); ! 779: if (bkpt->flags & BKPT_USR_GLOBAL) ! 780: db_printf("user "); ! 781: else if (bkpt->task == TASK_NULL) ! 782: db_printf("kernel "); ! 783: else if ((task_id = db_lookup_task(bkpt->task)) < 0) ! 784: db_printf("%0*X ", 2*sizeof(vm_offset_t), bkpt->task); ! 785: else ! 786: db_printf("task%-3d ", task_id); ! 787: if (tp->tb_task_thd == 0) { ! 788: db_printf("all "); ! 789: } else { ! 790: if (tp->tb_is_task) { ! 791: task_id = db_lookup_task((task_t)(tp->tb_task_thd)); ! 792: if (task_id < 0) ! 793: db_printf("%0*X ", 2*sizeof(vm_offset_t), ! 794: tp->tb_task_thd); ! 795: else ! 796: db_printf("task%03d ", task_id); ! 797: } else { ! 798: thread_act_t thd = (thread_act_t)(tp->tb_task_thd); ! 799: task_id = db_lookup_task(thd->task); ! 800: act_id = db_lookup_task_act(thd->task, thd); ! 801: if (task_id < 0 || act_id < 0) ! 802: db_printf("%0*X ", 2*sizeof(vm_offset_t), ! 803: tp->tb_task_thd); ! 804: else ! 805: db_printf("task%03d.%-3d ", task_id, act_id); ! 806: } ! 807: } ! 808: db_printf("%3d ", tp->tb_init_count); ! 809: db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task); ! 810: if (tp->tb_cond > 0) { ! 811: db_printf("("); ! 812: db_cond_print(tp); ! 813: db_printf(")"); ! 814: } ! 815: db_printf("\n"); ! 816: } ! 817: } else { ! 818: if (bkpt->task == TASK_NULL) ! 819: db_printf(" ? kernel "); ! 820: else ! 821: db_printf("%*X ", 2*sizeof(vm_offset_t), bkpt->task); ! 822: db_printf("(?) "); ! 823: db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task); ! 824: db_printf("\n"); ! 825: } ! 826: } ! 827: } ! 828: ! 829: void ! 830: db_delete_all_breakpoints( ! 831: task_t task) ! 832: { ! 833: register db_breakpoint_t bkpt; ! 834: ! 835: bkpt = db_breakpoint_list; ! 836: while ( bkpt != 0 ) { ! 837: if (bkpt->task == task || ! 838: (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL))) { ! 839: db_delete_breakpoint(task, bkpt->address, 0); ! 840: bkpt = db_breakpoint_list; ! 841: } ! 842: else ! 843: bkpt = bkpt->link; ! 844: ! 845: } ! 846: } ! 847: ! 848: /* Delete breakpoint */ ! 849: void ! 850: db_delete_cmd(void) ! 851: { ! 852: register int n; ! 853: thread_act_t thr_act; ! 854: vm_offset_t task_thd; ! 855: boolean_t user_global = FALSE; ! 856: boolean_t task_bpt = FALSE; ! 857: boolean_t user_space = FALSE; ! 858: boolean_t thd_bpt = FALSE; ! 859: db_expr_t addr; ! 860: int t; ! 861: ! 862: t = db_read_token(); ! 863: if (t == tSLASH) { ! 864: t = db_read_token(); ! 865: if (t != tIDENT) { ! 866: db_printf("Bad modifier \"%s\"\n", db_tok_string); ! 867: db_error(0); ! 868: } ! 869: user_global = db_option(db_tok_string, 'U'); ! 870: user_space = (user_global)? TRUE: db_option(db_tok_string, 'u'); ! 871: task_bpt = db_option(db_tok_string, 'T'); ! 872: thd_bpt = db_option(db_tok_string, 't'); ! 873: if (task_bpt && user_global) ! 874: db_error("Cannot specify both 'T' and 'U' option\n"); ! 875: t = db_read_token(); ! 876: } ! 877: ! 878: if ( t == tSTAR ) { ! 879: db_printf("Delete ALL breakpoints\n"); ! 880: db_delete_all_breakpoints( (task_t)task_bpt ); ! 881: return; ! 882: } ! 883: ! 884: if (t == tHASH) { ! 885: db_thread_breakpoint_t tbp; ! 886: db_breakpoint_t bkpt; ! 887: ! 888: if (db_read_token() != tNUMBER) { ! 889: db_printf("Bad break point number #%s\n", db_tok_string); ! 890: db_error(0); ! 891: } ! 892: if ((tbp = db_find_breakpoint_number(db_tok_number, &bkpt)) == 0) { ! 893: db_printf("No such break point #%d\n", db_tok_number); ! 894: db_error(0); ! 895: } ! 896: db_delete_breakpoint(bkpt->task, bkpt->address, tbp->tb_task_thd); ! 897: return; ! 898: } ! 899: db_unread_token(t); ! 900: if (!db_expression(&addr)) { ! 901: /* ! 902: * We attempt to pick up the user_space indication from db_dot, ! 903: * so that a plain "d" always works. ! 904: */ ! 905: addr = (db_expr_t)db_dot; ! 906: if (!user_space && !DB_VALID_ADDRESS(addr, FALSE)) ! 907: user_space = TRUE; ! 908: } ! 909: if (!DB_VALID_ADDRESS(addr, user_space)) { ! 910: db_printf("Address %#X is not in %s space\n", addr, ! 911: (user_space)? "user": "kernel"); ! 912: db_error(0); ! 913: } ! 914: if (thd_bpt || task_bpt) { ! 915: for (n = 0; db_get_next_act(&thr_act, n); n++) { ! 916: if (thr_act == THR_ACT_NULL) ! 917: db_error("No active thr_act\n"); ! 918: if (task_bpt) { ! 919: if (thr_act->task == TASK_NULL) ! 920: db_error("No task\n"); ! 921: task_thd = (vm_offset_t) (thr_act->task); ! 922: } else ! 923: task_thd = (user_global)? 0: (vm_offset_t) thr_act; ! 924: db_delete_breakpoint(db_target_space(thr_act, user_space), ! 925: (db_addr_t)addr, task_thd); ! 926: } ! 927: } else { ! 928: db_delete_breakpoint(db_target_space(THR_ACT_NULL, user_space), ! 929: (db_addr_t)addr, 0); ! 930: } ! 931: } ! 932: ! 933: /* Set breakpoint with skip count */ ! 934: #include <mach/machine/vm_param.h> ! 935: ! 936: void ! 937: db_breakpoint_cmd( ! 938: db_expr_t addr, ! 939: int have_addr, ! 940: db_expr_t count, ! 941: char * modif) ! 942: { ! 943: register int n; ! 944: thread_act_t thr_act; ! 945: boolean_t user_global = db_option(modif, 'U'); ! 946: boolean_t task_bpt = db_option(modif, 'T'); ! 947: boolean_t user_space; ! 948: ! 949: if (count == -1) ! 950: count = 1; ! 951: #if 0 /* CHECKME */ ! 952: if (!task_bpt && db_option(modif,'t')) ! 953: task_bpt = TRUE; ! 954: #endif ! 955: ! 956: if (task_bpt && user_global) ! 957: db_error("Cannot specify both 'T' and 'U'\n"); ! 958: user_space = (user_global)? TRUE: db_option(modif, 'u'); ! 959: if (user_space && db_access_level < DB_ACCESS_CURRENT) ! 960: db_error("User space break point is not supported\n"); ! 961: if ((!task_bpt || !user_space) && ! 962: !DB_VALID_ADDRESS(addr, user_space)) { ! 963: /* if the user has explicitly specified user space, ! 964: do not insert a breakpoint into the kernel */ ! 965: if (user_space) ! 966: db_error("Invalid user space address\n"); ! 967: user_space = TRUE; ! 968: db_printf("%#X is in user space\n", addr); ! 969: db_printf("kernel is from %#X to %#x\n", VM_MIN_KERNEL_ADDRESS, VM_MAX_KERNEL_ADDRESS); ! 970: } ! 971: if (db_option(modif, 't') || task_bpt) { ! 972: for (n = 0; db_get_next_act(&thr_act, n); n++) { ! 973: if (thr_act == THR_ACT_NULL) ! 974: db_error("No active thr_act\n"); ! 975: if (task_bpt && thr_act->task == TASK_NULL) ! 976: db_error("No task\n"); ! 977: if (db_access_level <= DB_ACCESS_CURRENT && user_space ! 978: && thr_act->task != db_current_space()) ! 979: db_error("Cannot set break point in inactive user space\n"); ! 980: db_set_breakpoint(db_target_space(thr_act, user_space), ! 981: (db_addr_t)addr, count, ! 982: (user_global)? THR_ACT_NULL: thr_act, ! 983: task_bpt); ! 984: } ! 985: } else { ! 986: db_set_breakpoint(db_target_space(THR_ACT_NULL, user_space), ! 987: (db_addr_t)addr, ! 988: count, THR_ACT_NULL, FALSE); ! 989: } ! 990: } ! 991: ! 992: /* list breakpoints */ ! 993: void ! 994: db_listbreak_cmd(void) ! 995: { ! 996: db_list_breakpoints(); ! 997: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.