1 /*- 2 * Mach Operating System 3 * Copyright (c) 1991,1990 Carnegie Mellon University 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify and distribute this software and its 7 * documentation is hereby granted, provided that both the copyright 8 * notice and this permission notice appear in all copies of the 9 * software, derivative works or modified versions, and any portions 10 * thereof, and that both notices appear in supporting documentation. 11 * 12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15 * 16 * Carnegie Mellon requests users of this software to return to 17 * 18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19 * School of Computer Science 20 * Carnegie Mellon University 21 * Pittsburgh PA 15213-3890 22 * 23 * any improvements or extensions that they make and grant Carnegie the 24 * rights to redistribute these changes. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kdb.h> 33 #include <sys/proc.h> 34 #include <sys/stack.h> 35 #include <sys/sysent.h> 36 37 #include <machine/cpu.h> 38 #include <machine/md_var.h> 39 #include <machine/pcb.h> 40 #include <machine/reg.h> 41 42 #include <vm/vm.h> 43 #include <vm/vm_param.h> 44 #include <vm/pmap.h> 45 46 #include <ddb/ddb.h> 47 #include <ddb/db_access.h> 48 #include <ddb/db_sym.h> 49 #include <ddb/db_variables.h> 50 51 static db_varfcn_t db_dr0; 52 static db_varfcn_t db_dr1; 53 static db_varfcn_t db_dr2; 54 static db_varfcn_t db_dr3; 55 static db_varfcn_t db_dr4; 56 static db_varfcn_t db_dr5; 57 static db_varfcn_t db_dr6; 58 static db_varfcn_t db_dr7; 59 static db_varfcn_t db_esp; 60 static db_varfcn_t db_frame; 61 static db_varfcn_t db_ss; 62 63 /* 64 * Machine register set. 65 */ 66 #define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) 67 struct db_variable db_regs[] = { 68 { "cs", DB_OFFSET(tf_cs), db_frame }, 69 { "ds", DB_OFFSET(tf_ds), db_frame }, 70 { "es", DB_OFFSET(tf_es), db_frame }, 71 { "fs", DB_OFFSET(tf_fs), db_frame }, 72 { "ss", NULL, db_ss }, 73 { "eax", DB_OFFSET(tf_eax), db_frame }, 74 { "ecx", DB_OFFSET(tf_ecx), db_frame }, 75 { "edx", DB_OFFSET(tf_edx), db_frame }, 76 { "ebx", DB_OFFSET(tf_ebx), db_frame }, 77 { "esp", NULL, db_esp }, 78 { "ebp", DB_OFFSET(tf_ebp), db_frame }, 79 { "esi", DB_OFFSET(tf_esi), db_frame }, 80 { "edi", DB_OFFSET(tf_edi), db_frame }, 81 { "eip", DB_OFFSET(tf_eip), db_frame }, 82 { "efl", DB_OFFSET(tf_eflags), db_frame }, 83 #define DB_N_SHOW_REGS 15 /* Don't show registers after here. */ 84 { "dr0", NULL, db_dr0 }, 85 { "dr1", NULL, db_dr1 }, 86 { "dr2", NULL, db_dr2 }, 87 { "dr3", NULL, db_dr3 }, 88 { "dr4", NULL, db_dr4 }, 89 { "dr5", NULL, db_dr5 }, 90 { "dr6", NULL, db_dr6 }, 91 { "dr7", NULL, db_dr7 }, 92 }; 93 struct db_variable *db_eregs = db_regs + DB_N_SHOW_REGS; 94 95 #define DB_DRX_FUNC(reg) \ 96 static int \ 97 db_ ## reg (vp, valuep, op) \ 98 struct db_variable *vp; \ 99 db_expr_t * valuep; \ 100 int op; \ 101 { \ 102 if (op == DB_VAR_GET) \ 103 *valuep = r ## reg (); \ 104 else \ 105 load_ ## reg (*valuep); \ 106 return (1); \ 107 } 108 109 DB_DRX_FUNC(dr0) 110 DB_DRX_FUNC(dr1) 111 DB_DRX_FUNC(dr2) 112 DB_DRX_FUNC(dr3) 113 DB_DRX_FUNC(dr4) 114 DB_DRX_FUNC(dr5) 115 DB_DRX_FUNC(dr6) 116 DB_DRX_FUNC(dr7) 117 118 static __inline int 119 get_esp(struct trapframe *tf) 120 { 121 return ((ISPL(tf->tf_cs)) ? tf->tf_esp : 122 (db_expr_t)tf + (uintptr_t)DB_OFFSET(tf_esp)); 123 } 124 125 static int 126 db_frame(struct db_variable *vp, db_expr_t *valuep, int op) 127 { 128 int *reg; 129 130 if (kdb_frame == NULL) 131 return (0); 132 133 reg = (int *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep); 134 if (op == DB_VAR_GET) 135 *valuep = *reg; 136 else 137 *reg = *valuep; 138 return (1); 139 } 140 141 static int 142 db_esp(struct db_variable *vp, db_expr_t *valuep, int op) 143 { 144 145 if (kdb_frame == NULL) 146 return (0); 147 148 if (op == DB_VAR_GET) 149 *valuep = get_esp(kdb_frame); 150 else if (ISPL(kdb_frame->tf_cs)) 151 kdb_frame->tf_esp = *valuep; 152 return (1); 153 } 154 155 static int 156 db_ss(struct db_variable *vp, db_expr_t *valuep, int op) 157 { 158 159 if (kdb_frame == NULL) 160 return (0); 161 162 if (op == DB_VAR_GET) 163 *valuep = (ISPL(kdb_frame->tf_cs)) ? kdb_frame->tf_ss : rss(); 164 else if (ISPL(kdb_frame->tf_cs)) 165 kdb_frame->tf_ss = *valuep; 166 return (1); 167 } 168 169 /* 170 * Stack trace. 171 */ 172 #define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK && \ 173 ((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS) 174 175 struct i386_frame { 176 struct i386_frame *f_frame; 177 int f_retaddr; 178 int f_arg0; 179 }; 180 181 #define NORMAL 0 182 #define TRAP 1 183 #define INTERRUPT 2 184 #define SYSCALL 3 185 #define DOUBLE_FAULT 4 186 #define TRAP_INTERRUPT 5 187 188 static void db_nextframe(struct i386_frame **, db_addr_t *, struct thread *); 189 static int db_numargs(struct i386_frame *); 190 static void db_print_stack_entry(const char *, int, char **, int *, db_addr_t); 191 static void decode_syscall(int, struct thread *); 192 193 static const char * watchtype_str(int type); 194 int i386_set_watch(int watchnum, unsigned int watchaddr, int size, int access, 195 struct dbreg *d); 196 int i386_clr_watch(int watchnum, struct dbreg *d); 197 198 /* 199 * Figure out how many arguments were passed into the frame at "fp". 200 */ 201 static int 202 db_numargs(fp) 203 struct i386_frame *fp; 204 { 205 char *argp; 206 int inst; 207 int args; 208 209 argp = (char *)db_get_value((int)&fp->f_retaddr, 4, FALSE); 210 /* 211 * XXX etext is wrong for LKMs. We should attempt to interpret 212 * the instruction at the return address in all cases. This 213 * may require better fault handling. 214 */ 215 if (argp < btext || argp >= etext) { 216 args = -1; 217 } else { 218 retry: 219 inst = db_get_value((int)argp, 4, FALSE); 220 if ((inst & 0xff) == 0x59) /* popl %ecx */ 221 args = 1; 222 else if ((inst & 0xffff) == 0xc483) /* addl $Ibs, %esp */ 223 args = ((inst >> 16) & 0xff) / 4; 224 else if ((inst & 0xf8ff) == 0xc089) { /* movl %eax, %Reg */ 225 argp += 2; 226 goto retry; 227 } else 228 args = -1; 229 } 230 return (args); 231 } 232 233 static void 234 db_print_stack_entry(name, narg, argnp, argp, callpc) 235 const char *name; 236 int narg; 237 char **argnp; 238 int *argp; 239 db_addr_t callpc; 240 { 241 int n = narg >= 0 ? narg : 5; 242 243 db_printf("%s(", name); 244 while (n) { 245 if (argnp) 246 db_printf("%s=", *argnp++); 247 db_printf("%r", db_get_value((int)argp, 4, FALSE)); 248 argp++; 249 if (--n != 0) 250 db_printf(","); 251 } 252 if (narg < 0) 253 db_printf(",..."); 254 db_printf(") at "); 255 db_printsym(callpc, DB_STGY_PROC); 256 db_printf("\n"); 257 } 258 259 static void 260 decode_syscall(int number, struct thread *td) 261 { 262 struct proc *p; 263 c_db_sym_t sym; 264 db_expr_t diff; 265 sy_call_t *f; 266 const char *symname; 267 268 db_printf(" (%d", number); 269 p = (td != NULL) ? td->td_proc : NULL; 270 if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) { 271 f = p->p_sysent->sv_table[number].sy_call; 272 sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff); 273 if (sym != DB_SYM_NULL && diff == 0) { 274 db_symbol_values(sym, &symname, NULL); 275 db_printf(", %s, %s", p->p_sysent->sv_name, symname); 276 } 277 } 278 db_printf(")"); 279 } 280 281 /* 282 * Figure out the next frame up in the call stack. 283 */ 284 static void 285 db_nextframe(struct i386_frame **fp, db_addr_t *ip, struct thread *td) 286 { 287 struct trapframe *tf; 288 int frame_type; 289 int eip, esp, ebp; 290 db_expr_t offset; 291 c_db_sym_t sym; 292 const char *name; 293 294 eip = db_get_value((int) &(*fp)->f_retaddr, 4, FALSE); 295 ebp = db_get_value((int) &(*fp)->f_frame, 4, FALSE); 296 297 /* 298 * Figure out frame type. We look at the address just before 299 * the saved instruction pointer as the saved EIP is after the 300 * call function, and if the function being called is marked as 301 * dead (such as panic() at the end of dblfault_handler()), then 302 * the instruction at the saved EIP will be part of a different 303 * function (syscall() in this example) rather than the one that 304 * actually made the call. 305 */ 306 frame_type = NORMAL; 307 sym = db_search_symbol(eip - 1, DB_STGY_ANY, &offset); 308 db_symbol_values(sym, &name, NULL); 309 if (name != NULL) { 310 if (strcmp(name, "calltrap") == 0 || 311 strcmp(name, "fork_trampoline") == 0) 312 frame_type = TRAP; 313 else if (strncmp(name, "Xatpic_intr", 11) == 0 || 314 strncmp(name, "Xapic_isr", 9) == 0) 315 frame_type = INTERRUPT; 316 else if (strcmp(name, "Xlcall_syscall") == 0 || 317 strcmp(name, "Xint0x80_syscall") == 0) 318 frame_type = SYSCALL; 319 else if (strcmp(name, "dblfault_handler") == 0) 320 frame_type = DOUBLE_FAULT; 321 /* XXX: These are interrupts with trap frames. */ 322 else if (strcmp(name, "Xtimerint") == 0 || 323 strcmp(name, "Xcpustop") == 0 || 324 strcmp(name, "Xrendezvous") == 0 || 325 strcmp(name, "Xipi_intr_bitmap_handler") == 0 || 326 strcmp(name, "Xlazypmap") == 0) 327 frame_type = TRAP_INTERRUPT; 328 } 329 330 /* 331 * Normal frames need no special processing. 332 */ 333 if (frame_type == NORMAL) { 334 *ip = (db_addr_t) eip; 335 *fp = (struct i386_frame *) ebp; 336 return; 337 } 338 339 db_print_stack_entry(name, 0, 0, 0, eip); 340 341 /* 342 * For a double fault, we have to snag the values from the 343 * previous TSS since a double fault uses a task gate to 344 * switch to a known good state. 345 */ 346 if (frame_type == DOUBLE_FAULT) { 347 esp = PCPU_GET(common_tss.tss_esp); 348 eip = PCPU_GET(common_tss.tss_eip); 349 ebp = PCPU_GET(common_tss.tss_ebp); 350 db_printf( 351 "--- trap 0x17, eip = %#r, esp = %#r, ebp = %#r ---\n", 352 eip, esp, ebp); 353 *ip = (db_addr_t) eip; 354 *fp = (struct i386_frame *) ebp; 355 return; 356 } 357 358 /* 359 * Point to base of trapframe which is just above the 360 * current frame. 361 */ 362 if (frame_type == INTERRUPT) 363 tf = (struct trapframe *)((int)*fp + 16); 364 else 365 tf = (struct trapframe *)((int)*fp + 12); 366 367 if (INKERNEL((int) tf)) { 368 esp = get_esp(tf); 369 eip = tf->tf_eip; 370 ebp = tf->tf_ebp; 371 switch (frame_type) { 372 case TRAP: 373 db_printf("--- trap %#r", tf->tf_trapno); 374 break; 375 case SYSCALL: 376 db_printf("--- syscall"); 377 decode_syscall(tf->tf_eax, td); 378 break; 379 case TRAP_INTERRUPT: 380 case INTERRUPT: 381 db_printf("--- interrupt"); 382 break; 383 default: 384 panic("The moon has moved again."); 385 } 386 db_printf(", eip = %#r, esp = %#r, ebp = %#r ---\n", eip, 387 esp, ebp); 388 } 389 390 *ip = (db_addr_t) eip; 391 *fp = (struct i386_frame *) ebp; 392 } 393 394 static int 395 db_backtrace(struct thread *td, struct trapframe *tf, struct i386_frame *frame, 396 db_addr_t pc, int count) 397 { 398 struct i386_frame *actframe; 399 #define MAXNARG 16 400 char *argnames[MAXNARG], **argnp = NULL; 401 const char *name; 402 int *argp; 403 db_expr_t offset; 404 c_db_sym_t sym; 405 int instr, narg; 406 boolean_t first; 407 408 /* 409 * If an indirect call via an invalid pointer caused a trap, 410 * %pc contains the invalid address while the return address 411 * of the unlucky caller has been saved by CPU on the stack 412 * just before the trap frame. In this case, try to recover 413 * the caller's address so that the first frame is assigned 414 * to the right spot in the right function, for that is where 415 * the failure actually happened. 416 * 417 * This trick depends on the fault address stashed in tf_err 418 * by trap_fatal() before entering KDB. 419 */ 420 if (kdb_frame && pc == kdb_frame->tf_err) { 421 /* 422 * Find where the trap frame actually ends. 423 * It won't contain tf_esp or tf_ss unless crossing rings. 424 */ 425 if (ISPL(kdb_frame->tf_cs)) 426 instr = (int)(kdb_frame + 1); 427 else 428 instr = (int)&kdb_frame->tf_esp; 429 pc = db_get_value(instr, 4, FALSE); 430 } 431 432 if (count == -1) 433 count = 1024; 434 435 first = TRUE; 436 while (count-- && !db_pager_quit) { 437 sym = db_search_symbol(pc, DB_STGY_ANY, &offset); 438 db_symbol_values(sym, &name, NULL); 439 440 /* 441 * Attempt to determine a (possibly fake) frame that gives 442 * the caller's pc. It may differ from `frame' if the 443 * current function never sets up a standard frame or hasn't 444 * set one up yet or has just discarded one. The last two 445 * cases can be guessed fairly reliably for code generated 446 * by gcc. The first case is too much trouble to handle in 447 * general because the amount of junk on the stack depends 448 * on the pc (the special handling of "calltrap", etc. in 449 * db_nextframe() works because the `next' pc is special). 450 */ 451 actframe = frame; 452 if (first) { 453 if (tf != NULL) { 454 instr = db_get_value(pc, 4, FALSE); 455 if ((instr & 0xffffff) == 0x00e58955) { 456 /* pushl %ebp; movl %esp, %ebp */ 457 actframe = (void *)(get_esp(tf) - 4); 458 } else if ((instr & 0xffff) == 0x0000e589) { 459 /* movl %esp, %ebp */ 460 actframe = (void *)get_esp(tf); 461 if (tf->tf_ebp == 0) { 462 /* Fake frame better. */ 463 frame = actframe; 464 } 465 } else if ((instr & 0xff) == 0x000000c3) { 466 /* ret */ 467 actframe = (void *)(get_esp(tf) - 4); 468 } else if (offset == 0) { 469 /* Probably an assembler symbol. */ 470 actframe = (void *)(get_esp(tf) - 4); 471 } 472 } else if (strcmp(name, "fork_trampoline") == 0) { 473 /* 474 * Don't try to walk back on a stack for a 475 * process that hasn't actually been run yet. 476 */ 477 db_print_stack_entry(name, 0, 0, 0, pc); 478 break; 479 } 480 first = FALSE; 481 } 482 483 argp = &actframe->f_arg0; 484 narg = MAXNARG; 485 if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) { 486 argnp = argnames; 487 } else { 488 narg = db_numargs(frame); 489 } 490 491 db_print_stack_entry(name, narg, argnp, argp, pc); 492 493 if (actframe != frame) { 494 /* `frame' belongs to caller. */ 495 pc = (db_addr_t) 496 db_get_value((int)&actframe->f_retaddr, 4, FALSE); 497 continue; 498 } 499 500 db_nextframe(&frame, &pc, td); 501 502 if (INKERNEL((int)pc) && !INKERNEL((int) frame)) { 503 sym = db_search_symbol(pc, DB_STGY_ANY, &offset); 504 db_symbol_values(sym, &name, NULL); 505 db_print_stack_entry(name, 0, 0, 0, pc); 506 break; 507 } 508 if (!INKERNEL((int) frame)) { 509 break; 510 } 511 } 512 513 return (0); 514 } 515 516 void 517 db_trace_self(void) 518 { 519 struct i386_frame *frame; 520 db_addr_t callpc; 521 register_t ebp; 522 523 __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); 524 frame = (struct i386_frame *)ebp; 525 callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE); 526 frame = frame->f_frame; 527 db_backtrace(curthread, NULL, frame, callpc, -1); 528 } 529 530 int 531 db_trace_thread(struct thread *thr, int count) 532 { 533 struct pcb *ctx; 534 535 ctx = kdb_thr_ctx(thr); 536 return (db_backtrace(thr, NULL, (struct i386_frame *)ctx->pcb_ebp, 537 ctx->pcb_eip, count)); 538 } 539 540 void 541 stack_save(struct stack *st) 542 { 543 struct i386_frame *frame; 544 vm_offset_t callpc; 545 register_t ebp; 546 547 stack_zero(st); 548 __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); 549 frame = (struct i386_frame *)ebp; 550 while (1) { 551 if (!INKERNEL(frame)) 552 break; 553 callpc = frame->f_retaddr; 554 if (!INKERNEL(callpc)) 555 break; 556 if (stack_put(st, callpc) == -1) 557 break; 558 if (frame->f_frame <= frame || 559 (vm_offset_t)frame->f_frame >= 560 (vm_offset_t)ebp + KSTACK_PAGES * PAGE_SIZE) 561 break; 562 frame = frame->f_frame; 563 } 564 } 565 566 int 567 i386_set_watch(watchnum, watchaddr, size, access, d) 568 int watchnum; 569 unsigned int watchaddr; 570 int size; 571 int access; 572 struct dbreg *d; 573 { 574 int i, len; 575 576 if (watchnum == -1) { 577 for (i = 0; i < 4; i++) 578 if (!DBREG_DR7_ENABLED(d->dr[7], i)) 579 break; 580 if (i < 4) 581 watchnum = i; 582 else 583 return (-1); 584 } 585 586 switch (access) { 587 case DBREG_DR7_EXEC: 588 size = 1; /* size must be 1 for an execution breakpoint */ 589 /* fall through */ 590 case DBREG_DR7_WRONLY: 591 case DBREG_DR7_RDWR: 592 break; 593 default: 594 return (-1); 595 } 596 597 /* 598 * we can watch a 1, 2, or 4 byte sized location 599 */ 600 switch (size) { 601 case 1: 602 len = DBREG_DR7_LEN_1; 603 break; 604 case 2: 605 len = DBREG_DR7_LEN_2; 606 break; 607 case 4: 608 len = DBREG_DR7_LEN_4; 609 break; 610 default: 611 return (-1); 612 } 613 614 /* clear the bits we are about to affect */ 615 d->dr[7] &= ~DBREG_DR7_MASK(watchnum); 616 617 /* set drN register to the address, N=watchnum */ 618 DBREG_DRX(d, watchnum) = watchaddr; 619 620 /* enable the watchpoint */ 621 d->dr[7] |= DBREG_DR7_SET(watchnum, len, access, 622 DBREG_DR7_GLOBAL_ENABLE); 623 624 return (watchnum); 625 } 626 627 628 int 629 i386_clr_watch(watchnum, d) 630 int watchnum; 631 struct dbreg *d; 632 { 633 634 if (watchnum < 0 || watchnum >= 4) 635 return (-1); 636 637 d->dr[7] &= ~DBREG_DR7_MASK(watchnum); 638 DBREG_DRX(d, watchnum) = 0; 639 640 return (0); 641 } 642 643 644 int 645 db_md_set_watchpoint(addr, size) 646 db_expr_t addr; 647 db_expr_t size; 648 { 649 struct dbreg d; 650 int avail, i, wsize; 651 652 fill_dbregs(NULL, &d); 653 654 avail = 0; 655 for(i = 0; i < 4; i++) { 656 if (!DBREG_DR7_ENABLED(d.dr[7], i)) 657 avail++; 658 } 659 660 if (avail * 4 < size) 661 return (-1); 662 663 for (i = 0; i < 4 && (size > 0); i++) { 664 if (!DBREG_DR7_ENABLED(d.dr[7], i)) { 665 if (size > 2) 666 wsize = 4; 667 else 668 wsize = size; 669 i386_set_watch(i, addr, wsize, 670 DBREG_DR7_WRONLY, &d); 671 addr += wsize; 672 size -= wsize; 673 } 674 } 675 676 set_dbregs(NULL, &d); 677 678 return(0); 679 } 680 681 682 int 683 db_md_clr_watchpoint(addr, size) 684 db_expr_t addr; 685 db_expr_t size; 686 { 687 struct dbreg d; 688 int i; 689 690 fill_dbregs(NULL, &d); 691 692 for(i = 0; i < 4; i++) { 693 if (DBREG_DR7_ENABLED(d.dr[7], i)) { 694 if ((DBREG_DRX((&d), i) >= addr) && 695 (DBREG_DRX((&d), i) < addr+size)) 696 i386_clr_watch(i, &d); 697 698 } 699 } 700 701 set_dbregs(NULL, &d); 702 703 return(0); 704 } 705 706 707 static const char * 708 watchtype_str(type) 709 int type; 710 { 711 switch (type) { 712 case DBREG_DR7_EXEC : return "execute"; break; 713 case DBREG_DR7_RDWR : return "read/write"; break; 714 case DBREG_DR7_WRONLY : return "write"; break; 715 default : return "invalid"; break; 716 } 717 } 718 719 720 void 721 db_md_list_watchpoints() 722 { 723 struct dbreg d; 724 int i, len, type; 725 726 fill_dbregs(NULL, &d); 727 728 db_printf("\nhardware watchpoints:\n"); 729 db_printf(" watch status type len address\n"); 730 db_printf(" ----- -------- ---------- --- ----------\n"); 731 for (i = 0; i < 4; i++) { 732 if (DBREG_DR7_ENABLED(d.dr[7], i)) { 733 type = DBREG_DR7_ACCESS(d.dr[7], i); 734 len = DBREG_DR7_LEN(d.dr[7], i); 735 db_printf(" %-5d %-8s %10s %3d ", 736 i, "enabled", watchtype_str(type), len + 1); 737 db_printsym((db_addr_t)DBREG_DRX((&d), i), DB_STGY_ANY); 738 db_printf("\n"); 739 } else { 740 db_printf(" %-5d disabled\n", i); 741 } 742 } 743 744 db_printf("\ndebug register values:\n"); 745 for (i = 0; i < 8; i++) { 746 db_printf(" dr%d 0x%08x\n", i, DBREG_DRX((&d), i)); 747 } 748 db_printf("\n"); 749 } 750 751 752