1 /* 2 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 10 #include <arch/debug.h> 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 15 #include <cpu.h> 16 #include <debug.h> 17 #include <elf.h> 18 #include <kernel.h> 19 #include <kimage.h> 20 #include <thread.h> 21 #include <vm.h> 22 #include <vm_types.h> 23 24 #include <arch_cpu.h> 25 26 27 struct stack_frame { 28 struct stack_frame *previous; 29 addr_t return_address; 30 }; 31 32 #define NUM_PREVIOUS_LOCATIONS 32 33 34 35 static bool 36 already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 ebp) 37 { 38 int32 last = *_last; 39 int32 num = *_num; 40 int32 i; 41 42 for (i = 0; i < num; i++) { 43 if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) % NUM_PREVIOUS_LOCATIONS] == ebp) 44 return true; 45 } 46 47 *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS; 48 visited[last] = ebp; 49 50 if (num < NUM_PREVIOUS_LOCATIONS) 51 *_num = num + 1; 52 53 return false; 54 } 55 56 57 static status_t 58 get_next_frame(addr_t ebp, addr_t *_next, addr_t *_eip) 59 { 60 // set fault handler, so that we can safely access user stacks 61 addr_t oldFaultHandler = thread_get_current_thread()->fault_handler; 62 thread_get_current_thread()->fault_handler = (addr_t)&&error; 63 // Fake goto to trick the compiler not to optimize the code at the label 64 // away. 65 if (ebp == 0) 66 goto error; 67 68 *_eip = ((struct stack_frame *)ebp)->return_address; 69 *_next = (addr_t)((struct stack_frame *)ebp)->previous; 70 71 thread_get_current_thread()->fault_handler = oldFaultHandler; 72 return B_OK; 73 74 error: 75 thread_get_current_thread()->fault_handler = oldFaultHandler; 76 return B_BAD_ADDRESS; 77 } 78 79 80 static status_t 81 lookup_symbol(struct thread* thread, addr_t address, addr_t *_baseAddress, 82 const char **_symbolName, const char **_imageName, bool *_exactMatch) 83 { 84 status_t status = B_ENTRY_NOT_FOUND; 85 86 if (IS_KERNEL_ADDRESS(address)) { 87 // a kernel symbol 88 status = elf_debug_lookup_symbol_address(address, _baseAddress, 89 _symbolName, _imageName, _exactMatch); 90 } else if (thread != NULL && thread->team != NULL) { 91 // try a lookup using the userland runtime loader structures 92 status = elf_debug_lookup_user_symbol_address(thread->team, address, 93 _baseAddress, _symbolName, _imageName, _exactMatch); 94 95 if (status != B_OK) { 96 // try to locate the image in the images loaded into user space 97 status = image_debug_lookup_user_symbol_address(thread->team, 98 address, _baseAddress, _symbolName, _imageName, _exactMatch); 99 } 100 } 101 102 if (status == B_OK) { 103 *_symbolName = debug_demangle(*_symbolName); 104 } 105 106 return status; 107 } 108 109 110 static void 111 print_stack_frame(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp, 112 int32 callIndex) 113 { 114 const char *symbol, *image; 115 addr_t baseAddress; 116 bool exactMatch; 117 status_t status; 118 addr_t diff; 119 120 diff = nextEbp - ebp; 121 122 // kernel space/user space switch 123 if (diff & 0x80000000) 124 diff = 0; 125 126 status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image, 127 &exactMatch); 128 129 kprintf("%2ld %08lx (+%4ld) %08lx", callIndex, ebp, diff, eip); 130 131 if (status == B_OK) { 132 if (symbol != NULL) { 133 kprintf(" <%s>:%s + 0x%04lx%s\n", image, symbol, 134 eip - baseAddress, exactMatch ? "" : " (nearest)"); 135 } else { 136 kprintf(" <%s@%p>:unknown + 0x%04lx\n", image, 137 (void *)baseAddress, eip - baseAddress); 138 } 139 } else { 140 vm_area *area = NULL; 141 if (thread->team->address_space != NULL) 142 area = vm_area_lookup(thread->team->address_space, eip); 143 if (area != NULL) { 144 kprintf(" %ld:%s@%p + %#lx\n", area->id, area->name, (void *)area->base, 145 eip - area->base); 146 } else 147 kprintf("\n"); 148 } 149 } 150 151 152 static void 153 print_iframe(struct iframe *frame) 154 { 155 bool isUser = IFRAME_IS_USER(frame); 156 kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame, 157 isUser ? (uint32*)(frame + 1) : &frame->user_esp); 158 159 kprintf(" eax 0x%-9lx ebx 0x%-9lx ecx 0x%-9lx edx 0x%lx\n", 160 frame->eax, frame->ebx, frame->ecx, frame->edx); 161 kprintf(" esi 0x%-9lx edi 0x%-9lx ebp 0x%-9lx esp 0x%lx\n", 162 frame->esi, frame->edi, frame->ebp, frame->esp); 163 kprintf(" eip 0x%-9lx eflags 0x%-9lx", frame->eip, frame->flags); 164 if (isUser) { 165 // from user space 166 kprintf("user esp 0x%lx", frame->user_esp); 167 } 168 kprintf("\n"); 169 kprintf(" vector: 0x%lx, error code: 0x%lx\n", frame->vector, 170 frame->error_code); 171 } 172 173 174 static void 175 setup_for_thread(char *arg, struct thread **_thread, uint32 *_ebp, 176 uint32 *_oldPageDirectory) 177 { 178 struct thread *thread = NULL; 179 180 if (arg != NULL) { 181 thread_id id = strtoul(arg, NULL, 0); 182 thread = thread_get_thread_struct_locked(id); 183 if (thread == NULL) { 184 kprintf("could not find thread %ld\n", id); 185 return; 186 } 187 188 if (id != thread_get_current_thread_id()) { 189 // switch to the page directory of the new thread to be 190 // able to follow the stack trace into userland 191 addr_t newPageDirectory = (addr_t)x86_next_page_directory( 192 thread_get_current_thread(), thread); 193 194 if (newPageDirectory != 0) { 195 read_cr3(*_oldPageDirectory); 196 write_cr3(newPageDirectory); 197 } 198 199 // read %ebp from the thread's stack stored by a pushad 200 *_ebp = thread->arch_info.current_stack.esp[2]; 201 } else 202 thread = NULL; 203 } 204 205 if (thread == NULL) { 206 // if we don't have a thread yet, we want the current one 207 // (ebp has been set by the caller for this case already) 208 thread = thread_get_current_thread(); 209 } 210 211 *_thread = thread; 212 } 213 214 static bool 215 is_double_fault_stack_address(int32 cpu, addr_t address) 216 { 217 size_t size; 218 addr_t bottom = (addr_t)x86_get_double_fault_stack(cpu, &size); 219 return address >= bottom && address < bottom + size; 220 } 221 222 223 static bool 224 is_kernel_stack_address(struct thread* thread, addr_t address) 225 { 226 // We don't have a thread pointer in the early boot process, but then we are 227 // on the kernel stack for sure. 228 if (thread == NULL) 229 return IS_KERNEL_ADDRESS(address); 230 231 return address >= thread->kernel_stack_base 232 && address < thread->kernel_stack_top 233 || thread->cpu != NULL 234 && is_double_fault_stack_address(thread->cpu->cpu_num, address); 235 } 236 237 238 static bool 239 is_iframe(struct thread* thread, addr_t frame) 240 { 241 if (!is_kernel_stack_address(thread, frame)) 242 return false; 243 244 addr_t previousFrame = *(addr_t*)frame; 245 return ((previousFrame & ~IFRAME_TYPE_MASK) == 0 && previousFrame != 0); 246 } 247 248 249 static struct iframe * 250 find_previous_iframe(struct thread *thread, addr_t frame) 251 { 252 // iterate backwards through the stack frames, until we hit an iframe 253 while (is_kernel_stack_address(thread, frame)) { 254 if (is_iframe(thread, frame)) 255 return (struct iframe*)frame; 256 257 frame = *(addr_t*)frame; 258 } 259 260 return NULL; 261 } 262 263 264 static struct iframe* 265 get_previous_iframe(struct thread* thread, struct iframe* frame) 266 { 267 if (frame == NULL) 268 return NULL; 269 270 return find_previous_iframe(thread, frame->ebp); 271 } 272 273 274 static struct iframe* 275 get_current_iframe(struct thread* thread) 276 { 277 if (thread == thread_get_current_thread()) 278 return i386_get_current_iframe(); 279 280 addr_t ebp = thread->arch_info.current_stack.esp[2]; 281 // NOTE: This doesn't work, if the thread is running (on another CPU). 282 return find_previous_iframe(thread, ebp); 283 } 284 285 286 uint32* 287 find_debug_variable(const char* variableName, bool& settable) 288 { 289 struct iframe* frame = get_current_iframe(debug_get_debugged_thread()); 290 if (frame == NULL) 291 return NULL; 292 293 settable = false; 294 295 if (strcmp(variableName, "gs") == 0) { 296 return &frame->gs; 297 } else if (strcmp(variableName, "fs") == 0) { 298 return &frame->fs; 299 } else if (strcmp(variableName, "es") == 0) { 300 return &frame->es; 301 } else if (strcmp(variableName, "ds") == 0) { 302 return &frame->ds; 303 } else if (strcmp(variableName, "cs") == 0) { 304 return &frame->cs; 305 } else if (strcmp(variableName, "edi") == 0) { 306 settable = true; 307 return &frame->edi; 308 } else if (strcmp(variableName, "esi") == 0) { 309 settable = true; 310 return &frame->esi; 311 } else if (strcmp(variableName, "ebp") == 0) { 312 settable = true; 313 return &frame->ebp; 314 } else if (strcmp(variableName, "esp") == 0) { 315 settable = true; 316 return &frame->esp; 317 } else if (strcmp(variableName, "ebx") == 0) { 318 settable = true; 319 return &frame->ebx; 320 } else if (strcmp(variableName, "edx") == 0) { 321 settable = true; 322 return &frame->edx; 323 } else if (strcmp(variableName, "ecx") == 0) { 324 settable = true; 325 return &frame->ecx; 326 } else if (strcmp(variableName, "eax") == 0) { 327 settable = true; 328 return &frame->eax; 329 } else if (strcmp(variableName, "orig_eax") == 0) { 330 settable = true; 331 return &frame->orig_eax; 332 } else if (strcmp(variableName, "orig_edx") == 0) { 333 settable = true; 334 return &frame->orig_edx; 335 } else if (strcmp(variableName, "eip") == 0) { 336 settable = true; 337 return &frame->eip; 338 } else if (strcmp(variableName, "eflags") == 0) { 339 settable = true; 340 return &frame->flags; 341 } 342 343 if (IFRAME_IS_USER(frame)) { 344 if (strcmp(variableName, "user_esp") == 0) { 345 settable = true; 346 return &frame->user_esp; 347 } else if (strcmp(variableName, "user_ss") == 0) { 348 return &frame->user_ss; 349 } 350 } 351 352 return NULL; 353 } 354 355 356 static int 357 stack_trace(int argc, char **argv) 358 { 359 static const char* usage = "usage: %s [ <thread id> ]\n" 360 "Prints a stack trace for the current, respectively the specified\n" 361 "thread.\n" 362 " <thread id> - The ID of the thread for which to print the stack\n" 363 " trace.\n"; 364 if (argc > 2 || argc == 2 && strcmp(argv[1], "--help") == 0) { 365 kprintf(usage, argv[0]); 366 return 0; 367 } 368 369 uint32 previousLocations[NUM_PREVIOUS_LOCATIONS]; 370 struct thread *thread = NULL; 371 addr_t oldPageDirectory = 0; 372 uint32 ebp = x86_read_ebp(); 373 int32 num = 0, last = 0; 374 375 setup_for_thread(argc == 2 ? argv[1] : NULL, &thread, &ebp, 376 &oldPageDirectory); 377 378 if (thread != NULL) { 379 kprintf("stack trace for thread %ld \"%s\"\n", thread->id, 380 thread->name); 381 382 kprintf(" kernel stack: %p to %p\n", 383 (void *)thread->kernel_stack_base, 384 (void *)(thread->kernel_stack_top)); 385 if (thread->user_stack_base != 0) { 386 kprintf(" user stack: %p to %p\n", 387 (void *)thread->user_stack_base, 388 (void *)(thread->user_stack_base + thread->user_stack_size)); 389 } 390 } 391 392 kprintf("frame caller <image>:function + offset\n"); 393 394 bool onKernelStack = true; 395 396 for (int32 callIndex = 0;; callIndex++) { 397 onKernelStack = onKernelStack 398 && is_kernel_stack_address(thread, ebp); 399 400 if (onKernelStack && is_iframe(thread, ebp)) { 401 struct iframe *frame = (struct iframe *)ebp; 402 403 print_iframe(frame); 404 print_stack_frame(thread, frame->eip, ebp, frame->ebp, callIndex); 405 406 ebp = frame->ebp; 407 } else { 408 addr_t eip, nextEbp; 409 410 if (get_next_frame(ebp, &nextEbp, &eip) != B_OK) { 411 kprintf("%08lx -- read fault\n", ebp); 412 break; 413 } 414 415 if (eip == 0 || ebp == 0) 416 break; 417 418 print_stack_frame(thread, eip, ebp, nextEbp, callIndex); 419 ebp = nextEbp; 420 } 421 422 if (already_visited(previousLocations, &last, &num, ebp)) { 423 kprintf("circular stack frame: %p!\n", (void *)ebp); 424 break; 425 } 426 if (ebp == 0) 427 break; 428 } 429 430 if (oldPageDirectory != 0) { 431 // switch back to the previous page directory to no cause any troubles 432 write_cr3(oldPageDirectory); 433 } 434 435 return 0; 436 } 437 438 439 static void 440 print_call(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp, 441 int32 argCount) 442 { 443 const char *symbol, *image; 444 addr_t baseAddress; 445 bool exactMatch; 446 status_t status; 447 448 status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image, 449 &exactMatch); 450 451 kprintf("%08lx %08lx", ebp, eip); 452 453 if (status == B_OK) { 454 if (symbol != NULL) { 455 kprintf(" <%s>:%s%s", image, symbol, 456 exactMatch ? "" : " (nearest)"); 457 } else { 458 kprintf(" <%s@%p>:unknown + 0x%04lx", image, 459 (void *)baseAddress, eip - baseAddress); 460 } 461 } else { 462 vm_area *area = NULL; 463 if (thread->team->address_space != NULL) 464 area = vm_area_lookup(thread->team->address_space, eip); 465 if (area != NULL) { 466 kprintf(" %ld:%s@%p + %#lx", area->id, area->name, 467 (void *)area->base, eip - area->base); 468 } 469 } 470 471 int32 *arg = (int32 *)(nextEbp + 8); 472 kprintf("("); 473 474 for (int32 i = 0; i < argCount; i++) { 475 if (i > 0) 476 kprintf(", "); 477 kprintf("%#lx", *arg); 478 if (*arg > -0x10000 && *arg < 0x10000) 479 kprintf(" (%ld)", *arg); 480 481 char name[8]; 482 snprintf(name, sizeof(name), "_arg%ld", i + 1); 483 set_debug_variable(name, *(uint32 *)arg); 484 485 arg++; 486 } 487 488 kprintf(")\n"); 489 490 set_debug_variable("_frame", nextEbp); 491 } 492 493 494 static int 495 show_call(int argc, char **argv) 496 { 497 static const char* usage 498 = "usage: %s [ <thread id> ] <call index> [ -<arg count> ]\n" 499 "Prints a function call with parameters of the current, respectively\n" 500 "the specified thread.\n" 501 " <thread id> - The ID of the thread for which to print the call.\n" 502 " <call index> - The index of the call in the stack trace.\n" 503 " <arg count> - The number of call arguments to print.\n"; 504 if (argc == 2 && strcmp(argv[1], "--help") == 0) { 505 kprintf(usage, argv[0]); 506 return 0; 507 } 508 509 struct thread *thread = NULL; 510 addr_t oldPageDirectory = 0; 511 addr_t ebp = x86_read_ebp(); 512 int32 argCount = 0; 513 514 if (argc >= 2 && argv[argc - 1][0] == '-') { 515 argCount = strtoul(argv[argc - 1] + 1, NULL, 0); 516 if (argCount < 0 || argCount > 16) { 517 kprintf("Invalid argument count \"%ld\".\n", argCount); 518 return 0; 519 } 520 argc--; 521 } 522 523 if (argc < 2 || argc > 3) { 524 kprintf(usage, argv[0]); 525 return 0; 526 } 527 528 setup_for_thread(argc == 3 ? argv[1] : NULL, &thread, &ebp, 529 &oldPageDirectory); 530 531 int32 callIndex = strtoul(argv[argc == 3 ? 2 : 1], NULL, 0); 532 533 if (thread != NULL) 534 kprintf("thread %ld, %s\n", thread->id, thread->name); 535 536 bool onKernelStack = true; 537 538 for (int32 index = 0; index <= callIndex; index++) { 539 onKernelStack = onKernelStack 540 && is_kernel_stack_address(thread, ebp); 541 542 if (onKernelStack && is_iframe(thread, ebp)) { 543 struct iframe *frame = (struct iframe *)ebp; 544 545 if (index == callIndex) 546 print_call(thread, frame->eip, ebp, frame->ebp, argCount); 547 548 ebp = frame->ebp; 549 } else { 550 addr_t eip, nextEbp; 551 552 if (get_next_frame(ebp, &nextEbp, &eip) != B_OK) { 553 kprintf("%08lx -- read fault\n", ebp); 554 break; 555 } 556 557 if (eip == 0 || ebp == 0) 558 break; 559 560 if (index == callIndex) 561 print_call(thread, eip, ebp, nextEbp, argCount); 562 563 ebp = nextEbp; 564 } 565 566 if (ebp == 0) 567 break; 568 } 569 570 if (oldPageDirectory != 0) { 571 // switch back to the previous page directory to not cause any troubles 572 write_cr3(oldPageDirectory); 573 } 574 575 return 0; 576 } 577 578 579 static int 580 dump_iframes(int argc, char **argv) 581 { 582 static const char* usage = "usage: %s [ <thread id> ]\n" 583 "Prints the iframe stack for the current, respectively the specified\n" 584 "thread.\n" 585 " <thread id> - The ID of the thread for which to print the iframe\n" 586 " stack.\n"; 587 if (argc == 2 && strcmp(argv[1], "--help") == 0) { 588 kprintf(usage, argv[0]); 589 return 0; 590 } 591 592 struct thread *thread = NULL; 593 594 if (argc < 2) { 595 thread = thread_get_current_thread(); 596 } else if (argc == 2) { 597 thread_id id = strtoul(argv[1], NULL, 0); 598 thread = thread_get_thread_struct_locked(id); 599 if (thread == NULL) { 600 kprintf("could not find thread %ld\n", id); 601 return 0; 602 } 603 } else if (argc > 2) { 604 kprintf(usage, argv[0]); 605 return 0; 606 } 607 608 if (thread != NULL) 609 kprintf("iframes for thread %ld \"%s\"\n", thread->id, thread->name); 610 611 struct iframe* frame = find_previous_iframe(thread, x86_read_ebp()); 612 while (frame != NULL) { 613 print_iframe(frame); 614 frame = get_previous_iframe(thread, frame); 615 } 616 617 return 0; 618 } 619 620 621 static bool 622 is_calling(struct thread *thread, addr_t eip, const char *pattern, 623 addr_t start, addr_t end) 624 { 625 if (pattern == NULL) 626 return eip >= start && eip < end; 627 628 const char *symbol; 629 if (lookup_symbol(thread, eip, NULL, &symbol, NULL, NULL) != B_OK) 630 return false; 631 632 return strstr(symbol, pattern); 633 } 634 635 636 static int 637 cmd_in_context(int argc, char** argv) 638 { 639 if (argc != 2) { 640 print_debugger_command_usage(argv[0]); 641 return 0; 642 } 643 644 // get the thread ID 645 const char* commandLine = argv[1]; 646 char threadIDString[16]; 647 if (parse_next_debug_command_argument(&commandLine, threadIDString, 648 sizeof(threadIDString)) != B_OK) { 649 kprintf("Failed to parse thread ID.\n"); 650 return 0; 651 } 652 653 if (commandLine == NULL) { 654 print_debugger_command_usage(argv[0]); 655 return 0; 656 } 657 658 uint64 threadID; 659 if (!evaluate_debug_expression(threadIDString, &threadID, false)) 660 return 0; 661 662 // get the thread 663 struct thread* thread = thread_get_thread_struct_locked(threadID); 664 if (thread == NULL) { 665 kprintf("Could not find thread with ID \"%s\".\n", threadIDString); 666 return 0; 667 } 668 669 // switch the page directory, if necessary 670 addr_t oldPageDirectory = 0; 671 if (thread != thread_get_current_thread()) { 672 addr_t newPageDirectory = (addr_t)x86_next_page_directory( 673 thread_get_current_thread(), thread); 674 675 if (newPageDirectory != 0) { 676 read_cr3(oldPageDirectory); 677 write_cr3(newPageDirectory); 678 } 679 } 680 681 struct thread* previousThread = debug_set_debugged_thread(thread); 682 683 // execute the command 684 evaluate_debug_command(commandLine); 685 686 debug_set_debugged_thread(previousThread); 687 688 // reset the page directory 689 if (oldPageDirectory) 690 write_cr3(oldPageDirectory); 691 692 return 0; 693 } 694 695 696 // #pragma mark - 697 698 699 bool 700 arch_debug_contains_call(struct thread *thread, const char *symbol, 701 addr_t start, addr_t end) 702 { 703 addr_t ebp; 704 if (thread == thread_get_current_thread()) 705 ebp = x86_read_ebp(); 706 else 707 ebp = thread->arch_info.current_stack.esp[2]; 708 709 for (;;) { 710 if (!is_kernel_stack_address(thread, ebp)) 711 break; 712 713 if (is_iframe(thread, ebp)) { 714 struct iframe *frame = (struct iframe *)ebp; 715 716 if (is_calling(thread, frame->eip, symbol, start, end)) 717 return true; 718 719 ebp = frame->ebp; 720 } else { 721 addr_t eip, nextEbp; 722 723 if (get_next_frame(ebp, &nextEbp, &eip) != B_OK 724 || eip == 0 || ebp == 0) 725 break; 726 727 if (is_calling(thread, eip, symbol, start, end)) 728 return true; 729 730 ebp = nextEbp; 731 } 732 733 if (ebp == 0) 734 break; 735 } 736 737 return false; 738 } 739 740 741 void * 742 arch_debug_get_caller(void) 743 { 744 struct stack_frame *frame = (struct stack_frame *)x86_read_ebp(); 745 return (void *)frame->previous->return_address; 746 } 747 748 749 int32 750 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, 751 int32 skipFrames, bool userOnly) 752 { 753 // always skip our own frame 754 skipFrames++; 755 756 struct thread* thread = thread_get_current_thread(); 757 int32 count = 0; 758 addr_t ebp = x86_read_ebp(); 759 bool onKernelStack = true; 760 761 while (ebp != 0 && count < maxCount) { 762 onKernelStack = onKernelStack 763 && is_kernel_stack_address(thread, ebp); 764 765 addr_t eip; 766 addr_t nextEbp; 767 768 if (onKernelStack && is_iframe(thread, ebp)) { 769 struct iframe *frame = (struct iframe*)ebp; 770 eip = frame->eip; 771 nextEbp = frame->ebp; 772 } else { 773 if (get_next_frame(ebp, &nextEbp, &eip) != B_OK) 774 break; 775 } 776 777 if (skipFrames <= 0 && (!userOnly || IS_USER_ADDRESS(ebp))) 778 returnAddresses[count++] = eip; 779 else 780 skipFrames--; 781 782 ebp = nextEbp; 783 } 784 785 return count; 786 } 787 788 789 /*! Returns the program counter of the currently debugged (respectively this) 790 thread where the innermost interrupts happened. Returns \c NULL, if there's 791 none or a problem occurred retrieving it. 792 */ 793 void* 794 arch_debug_get_interrupt_pc() 795 { 796 struct iframe* frame = get_current_iframe(debug_get_debugged_thread()); 797 if (frame == NULL) 798 return NULL; 799 800 return (void*)(addr_t)frame->eip; 801 } 802 803 804 bool 805 arch_is_debug_variable_defined(const char* variableName) 806 { 807 bool settable; 808 return find_debug_variable(variableName, settable); 809 } 810 811 812 status_t 813 arch_set_debug_variable(const char* variableName, uint64 value) 814 { 815 bool settable; 816 uint32* variable = find_debug_variable(variableName, settable); 817 if (variable == NULL) 818 return B_ENTRY_NOT_FOUND; 819 820 if (!settable) 821 return B_NOT_ALLOWED; 822 823 *variable = (uint32)value; 824 return B_OK; 825 } 826 827 828 status_t 829 arch_get_debug_variable(const char* variableName, uint64* value) 830 { 831 bool settable; 832 uint32* variable = find_debug_variable(variableName, settable); 833 if (variable == NULL) 834 return B_ENTRY_NOT_FOUND; 835 836 *value = *variable; 837 return B_OK; 838 } 839 840 841 status_t 842 arch_debug_init(kernel_args *args) 843 { 844 // at this stage, the debugger command system is alive 845 846 add_debugger_command("where", &stack_trace, "Same as \"sc\""); 847 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 848 add_debugger_command("sc", &stack_trace, 849 "Stack crawl for current thread (or any other)"); 850 add_debugger_command("iframe", &dump_iframes, 851 "Dump iframes for the specified thread"); 852 add_debugger_command("call", &show_call, "Show call with arguments"); 853 add_debugger_command_etc("in_context", &cmd_in_context, 854 "Executes a command in the context of a given thread", 855 "<thread ID> <command> ...\n" 856 "Executes a command in the context of a given thread.\n", 857 B_KDEBUG_DONT_PARSE_ARGUMENTS); 858 859 return B_NO_ERROR; 860 } 861 862