1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 * 6 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10 11 #include <arch/debug.h> 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 16 #include <cpu.h> 17 #include <debug.h> 18 #include <debug_heap.h> 19 #include <elf.h> 20 #include <kernel.h> 21 #include <kimage.h> 22 #include <thread.h> 23 #include <vm/vm.h> 24 #include <vm/vm_types.h> 25 #include <vm/VMAddressSpace.h> 26 #include <vm/VMArea.h> 27 28 #include <arch_cpu.h> 29 30 31 struct stack_frame { 32 struct stack_frame *previous; 33 addr_t return_address; 34 }; 35 36 #define NUM_PREVIOUS_LOCATIONS 32 37 38 39 static bool 40 already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 ebp) 41 { 42 int32 last = *_last; 43 int32 num = *_num; 44 int32 i; 45 46 for (i = 0; i < num; i++) { 47 if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) % NUM_PREVIOUS_LOCATIONS] == ebp) 48 return true; 49 } 50 51 *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS; 52 visited[last] = ebp; 53 54 if (num < NUM_PREVIOUS_LOCATIONS) 55 *_num = num + 1; 56 57 return false; 58 } 59 60 61 /*! Safe to be called only from outside the debugger. 62 */ 63 static status_t 64 get_next_frame_no_debugger(addr_t ebp, addr_t *_next, addr_t *_eip) 65 { 66 // TODO: Do this more efficiently in assembly. 67 stack_frame frame; 68 if (user_memcpy(&frame, (void*)ebp, sizeof(frame)) != B_OK) 69 return B_BAD_ADDRESS; 70 71 *_eip = frame.return_address; 72 *_next = (addr_t)frame.previous; 73 74 return B_OK; 75 } 76 77 78 /*! Safe to be called only from inside the debugger. 79 */ 80 static status_t 81 get_next_frame_debugger(addr_t ebp, addr_t *_next, addr_t *_eip) 82 { 83 stack_frame frame; 84 if (debug_memcpy(&frame, (void*)ebp, sizeof(frame)) != B_OK) 85 return B_BAD_ADDRESS; 86 87 *_eip = frame.return_address; 88 *_next = (addr_t)frame.previous; 89 90 return B_OK; 91 } 92 93 94 static status_t 95 lookup_symbol(struct thread* thread, addr_t address, addr_t *_baseAddress, 96 const char **_symbolName, const char **_imageName, bool *_exactMatch) 97 { 98 status_t status = B_ENTRY_NOT_FOUND; 99 100 if (IS_KERNEL_ADDRESS(address)) { 101 // a kernel symbol 102 status = elf_debug_lookup_symbol_address(address, _baseAddress, 103 _symbolName, _imageName, _exactMatch); 104 } else if (thread != NULL && thread->team != NULL) { 105 // try a lookup using the userland runtime loader structures 106 status = elf_debug_lookup_user_symbol_address(thread->team, address, 107 _baseAddress, _symbolName, _imageName, _exactMatch); 108 109 if (status != B_OK) { 110 // try to locate the image in the images loaded into user space 111 status = image_debug_lookup_user_symbol_address(thread->team, 112 address, _baseAddress, _symbolName, _imageName, _exactMatch); 113 } 114 } 115 116 return status; 117 } 118 119 120 static void 121 set_debug_argument_variable(int32 index, uint64 value) 122 { 123 char name[8]; 124 snprintf(name, sizeof(name), "_arg%ld", index); 125 set_debug_variable(name, value); 126 } 127 128 129 static status_t 130 print_demangled_call(const char* image, const char* symbol, addr_t args, 131 bool noObjectMethod, bool addDebugVariables) 132 { 133 static const size_t kBufferSize = 256; 134 char* buffer = (char*)debug_malloc(kBufferSize); 135 if (buffer == NULL) 136 return B_NO_MEMORY; 137 138 bool isObjectMethod; 139 const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize, 140 &isObjectMethod); 141 if (name == NULL) { 142 debug_free(buffer); 143 return B_ERROR; 144 } 145 146 uint32* arg = (uint32*)args; 147 148 if (noObjectMethod) 149 isObjectMethod = false; 150 if (isObjectMethod) { 151 const char* lastName = strrchr(name, ':') - 1; 152 int namespaceLength = lastName - name; 153 154 kprintf("<%s> %.*s<\33[32m%p\33[0m>%s", image, namespaceLength, name, 155 *(uint32 **)arg, lastName); 156 if (addDebugVariables) 157 set_debug_variable("_this", *(uint32 *)arg); 158 arg++; 159 } else 160 kprintf("<%s> %s", image, name); 161 162 kprintf("("); 163 164 size_t length; 165 int32 type, i = 0; 166 uint32 cookie = 0; 167 while (debug_get_next_demangled_argument(&cookie, symbol, buffer, 168 kBufferSize, &type, &length) == B_OK) { 169 if (i++ > 0) 170 kprintf(", "); 171 172 // retrieve value and type identifier 173 174 uint64 value; 175 176 switch (type) { 177 case B_INT64_TYPE: 178 value = *(int64*)arg; 179 kprintf("int64: \33[34m%Ld\33[0m", value); 180 break; 181 case B_INT32_TYPE: 182 value = *(int32*)arg; 183 kprintf("int32: \33[34m%ld\33[0m", (int32)value); 184 break; 185 case B_INT16_TYPE: 186 value = *(int16*)arg; 187 kprintf("int16: \33[34m%d\33[0m", (int16)value); 188 break; 189 case B_INT8_TYPE: 190 value = *(int8*)arg; 191 kprintf("int8: \33[34m%d\33[0m", (int8)value); 192 break; 193 case B_UINT64_TYPE: 194 value = *(uint64*)arg; 195 kprintf("uint64: \33[34m%#Lx\33[0m", value); 196 if (value < 0x100000) 197 kprintf(" (\33[34m%Lu\33[0m)", value); 198 break; 199 case B_UINT32_TYPE: 200 value = *(uint32*)arg; 201 kprintf("uint32: \33[34m%#lx\33[0m", (uint32)value); 202 if (value < 0x100000) 203 kprintf(" (\33[34m%lu\33[0m)", (uint32)value); 204 break; 205 case B_UINT16_TYPE: 206 value = *(uint16*)arg; 207 kprintf("uint16: \33[34m%#x\33[0m (\33[34m%u\33[0m)", 208 (uint16)value, (uint16)value); 209 break; 210 case B_UINT8_TYPE: 211 value = *(uint8*)arg; 212 kprintf("uint8: \33[34m%#x\33[0m (\33[34m%u\33[0m)", 213 (uint8)value, (uint8)value); 214 break; 215 case B_BOOL_TYPE: 216 value = *(uint8*)arg; 217 kprintf("\33[34m%s\33[0m", value ? "true" : "false"); 218 break; 219 default: 220 if (buffer[0]) 221 kprintf("%s: ", buffer); 222 223 if (length == 4) { 224 value = *(uint32*)arg; 225 if (value == 0 226 && (type == B_POINTER_TYPE || type == B_REF_TYPE)) 227 kprintf("NULL"); 228 else 229 kprintf("\33[34m%#lx\33[0m", (uint32)value); 230 break; 231 } 232 233 if (length == 8) 234 value = *(uint64*)arg; 235 else 236 value = (uint64)arg; 237 kprintf("\33[34m%#Lx\33[0m", value); 238 break; 239 } 240 241 if (type == B_STRING_TYPE) { 242 if (value == 0) 243 kprintf(" \33[31m\"<NULL>\"\33[0m"); 244 else if (debug_strlcpy(buffer, (char*)value, kBufferSize) < B_OK) 245 kprintf(" \33[31m\"<???>\"\33[0m"); 246 else 247 kprintf(" \33[36m\"%s\"\33[0m", buffer); 248 } 249 250 if (addDebugVariables) 251 set_debug_argument_variable(i, value); 252 arg = (uint32*)((uint8*)arg + length); 253 } 254 255 debug_free(buffer); 256 257 kprintf(")"); 258 return B_OK; 259 } 260 261 262 static void 263 print_stack_frame(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp, 264 int32 callIndex, bool demangle) 265 { 266 const char *symbol, *image; 267 addr_t baseAddress; 268 bool exactMatch; 269 status_t status; 270 addr_t diff; 271 272 diff = nextEbp - ebp; 273 274 // kernel space/user space switch 275 if (diff & 0x80000000) 276 diff = 0; 277 278 status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image, 279 &exactMatch); 280 281 kprintf("%2ld %08lx (+%4ld) %08lx ", callIndex, ebp, diff, eip); 282 283 if (status == B_OK) { 284 if (exactMatch && demangle) { 285 status = print_demangled_call(image, symbol, nextEbp + 8, false, 286 false); 287 } 288 289 if (!exactMatch || !demangle || status != B_OK) { 290 if (symbol != NULL) { 291 kprintf("<%s>:%s%s", image, symbol, 292 exactMatch ? "" : " (nearest)"); 293 } else 294 kprintf("<%s@%p>:unknown", image, (void *)baseAddress); 295 } 296 297 kprintf(" + 0x%04lx\n", eip - baseAddress); 298 } else { 299 VMArea *area = NULL; 300 if (thread != NULL && thread->team != NULL 301 && thread->team->address_space != NULL) { 302 area = thread->team->address_space->LookupArea(eip); 303 } 304 if (area != NULL) { 305 kprintf("%ld:%s@%p + %#lx\n", area->id, area->name, 306 (void*)area->Base(), eip - area->Base()); 307 } else 308 kprintf("\n"); 309 } 310 } 311 312 313 static void 314 print_iframe(struct iframe *frame) 315 { 316 bool isUser = IFRAME_IS_USER(frame); 317 kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame, 318 isUser ? (uint32*)(frame + 1) : &frame->user_esp); 319 320 kprintf(" eax 0x%-9lx ebx 0x%-9lx ecx 0x%-9lx edx 0x%lx\n", 321 frame->eax, frame->ebx, frame->ecx, frame->edx); 322 kprintf(" esi 0x%-9lx edi 0x%-9lx ebp 0x%-9lx esp 0x%lx\n", 323 frame->esi, frame->edi, frame->ebp, frame->esp); 324 kprintf(" eip 0x%-9lx eflags 0x%-9lx", frame->eip, frame->flags); 325 if (isUser) { 326 // from user space 327 kprintf("user esp 0x%lx", frame->user_esp); 328 } 329 kprintf("\n"); 330 kprintf(" vector: 0x%lx, error code: 0x%lx\n", frame->vector, 331 frame->error_code); 332 } 333 334 335 static bool 336 setup_for_thread(char *arg, struct thread **_thread, uint32 *_ebp, 337 uint32 *_oldPageDirectory) 338 { 339 struct thread *thread = NULL; 340 341 if (arg != NULL) { 342 thread_id id = strtoul(arg, NULL, 0); 343 thread = thread_get_thread_struct_locked(id); 344 if (thread == NULL) { 345 kprintf("could not find thread %ld\n", id); 346 return false; 347 } 348 349 if (id != thread_get_current_thread_id()) { 350 // switch to the page directory of the new thread to be 351 // able to follow the stack trace into userland 352 addr_t newPageDirectory = (addr_t)x86_next_page_directory( 353 thread_get_current_thread(), thread); 354 355 if (newPageDirectory != 0) { 356 read_cr3(*_oldPageDirectory); 357 write_cr3(newPageDirectory); 358 } 359 360 // read %ebp from the thread's stack stored by a pushad 361 *_ebp = thread->arch_info.current_stack.esp[2]; 362 } else 363 thread = NULL; 364 } 365 366 if (thread == NULL) { 367 // if we don't have a thread yet, we want the current one 368 // (ebp has been set by the caller for this case already) 369 thread = thread_get_current_thread(); 370 } 371 372 *_thread = thread; 373 return true; 374 } 375 376 377 static bool 378 is_double_fault_stack_address(int32 cpu, addr_t address) 379 { 380 size_t size; 381 addr_t bottom = (addr_t)x86_get_double_fault_stack(cpu, &size); 382 return address >= bottom && address < bottom + size; 383 } 384 385 386 static bool 387 is_kernel_stack_address(struct thread* thread, addr_t address) 388 { 389 // We don't have a thread pointer in the early boot process, but then we are 390 // on the kernel stack for sure. 391 if (thread == NULL) 392 return IS_KERNEL_ADDRESS(address); 393 394 return (address >= thread->kernel_stack_base 395 && address < thread->kernel_stack_top) 396 || (thread->cpu != NULL 397 && is_double_fault_stack_address(thread->cpu->cpu_num, address)); 398 } 399 400 401 static bool 402 is_iframe(struct thread* thread, addr_t frame) 403 { 404 if (!is_kernel_stack_address(thread, frame)) 405 return false; 406 407 addr_t previousFrame = *(addr_t*)frame; 408 return ((previousFrame & ~IFRAME_TYPE_MASK) == 0 && previousFrame != 0); 409 } 410 411 412 static struct iframe * 413 find_previous_iframe(struct thread *thread, addr_t frame) 414 { 415 // iterate backwards through the stack frames, until we hit an iframe 416 while (is_kernel_stack_address(thread, frame)) { 417 if (is_iframe(thread, frame)) 418 return (struct iframe*)frame; 419 420 frame = *(addr_t*)frame; 421 } 422 423 return NULL; 424 } 425 426 427 static struct iframe* 428 get_previous_iframe(struct thread* thread, struct iframe* frame) 429 { 430 if (frame == NULL) 431 return NULL; 432 433 return find_previous_iframe(thread, frame->ebp); 434 } 435 436 437 static struct iframe* 438 get_current_iframe(struct thread* thread) 439 { 440 if (thread == thread_get_current_thread()) 441 return i386_get_current_iframe(); 442 443 addr_t ebp = thread->arch_info.current_stack.esp[2]; 444 // NOTE: This doesn't work, if the thread is running (on another CPU). 445 return find_previous_iframe(thread, ebp); 446 } 447 448 449 uint32* 450 find_debug_variable(const char* variableName, bool& settable) 451 { 452 struct iframe* frame = get_current_iframe(debug_get_debugged_thread()); 453 if (frame == NULL) 454 return NULL; 455 456 settable = false; 457 458 if (strcmp(variableName, "gs") == 0) { 459 return &frame->gs; 460 } else if (strcmp(variableName, "fs") == 0) { 461 return &frame->fs; 462 } else if (strcmp(variableName, "es") == 0) { 463 return &frame->es; 464 } else if (strcmp(variableName, "ds") == 0) { 465 return &frame->ds; 466 } else if (strcmp(variableName, "cs") == 0) { 467 return &frame->cs; 468 } else if (strcmp(variableName, "edi") == 0) { 469 settable = true; 470 return &frame->edi; 471 } else if (strcmp(variableName, "esi") == 0) { 472 settable = true; 473 return &frame->esi; 474 } else if (strcmp(variableName, "ebp") == 0) { 475 settable = true; 476 return &frame->ebp; 477 } else if (strcmp(variableName, "esp") == 0) { 478 settable = true; 479 return &frame->esp; 480 } else if (strcmp(variableName, "ebx") == 0) { 481 settable = true; 482 return &frame->ebx; 483 } else if (strcmp(variableName, "edx") == 0) { 484 settable = true; 485 return &frame->edx; 486 } else if (strcmp(variableName, "ecx") == 0) { 487 settable = true; 488 return &frame->ecx; 489 } else if (strcmp(variableName, "eax") == 0) { 490 settable = true; 491 return &frame->eax; 492 } else if (strcmp(variableName, "orig_eax") == 0) { 493 settable = true; 494 return &frame->orig_eax; 495 } else if (strcmp(variableName, "orig_edx") == 0) { 496 settable = true; 497 return &frame->orig_edx; 498 } else if (strcmp(variableName, "eip") == 0) { 499 settable = true; 500 return &frame->eip; 501 } else if (strcmp(variableName, "eflags") == 0) { 502 settable = true; 503 return &frame->flags; 504 } 505 506 if (IFRAME_IS_USER(frame)) { 507 if (strcmp(variableName, "user_esp") == 0) { 508 settable = true; 509 return &frame->user_esp; 510 } else if (strcmp(variableName, "user_ss") == 0) { 511 return &frame->user_ss; 512 } 513 } 514 515 return NULL; 516 } 517 518 519 static int 520 stack_trace(int argc, char **argv) 521 { 522 static const char* usage = "usage: %s [-d] [ <thread id> ]\n" 523 "Prints a stack trace for the current, respectively the specified\n" 524 "thread.\n" 525 " -d - Disables the demangling of the symbols.\n" 526 " <thread id> - The ID of the thread for which to print the stack\n" 527 " trace.\n"; 528 bool demangle = true; 529 int32 threadIndex = 1; 530 if (argc > 1 && !strcmp(argv[1], "-d")) { 531 demangle = false; 532 threadIndex++; 533 } 534 535 if (argc > threadIndex + 1 536 || (argc == 2 && strcmp(argv[1], "--help") == 0)) { 537 kprintf(usage, argv[0]); 538 return 0; 539 } 540 541 uint32 previousLocations[NUM_PREVIOUS_LOCATIONS]; 542 struct thread *thread = NULL; 543 addr_t oldPageDirectory = 0; 544 uint32 ebp = x86_read_ebp(); 545 int32 num = 0, last = 0; 546 547 if (!setup_for_thread(argc == threadIndex + 1 ? argv[threadIndex] : NULL, 548 &thread, &ebp, &oldPageDirectory)) 549 return 0; 550 551 if (thread != NULL) { 552 kprintf("stack trace for thread %ld \"%s\"\n", thread->id, 553 thread->name); 554 555 kprintf(" kernel stack: %p to %p\n", 556 (void *)thread->kernel_stack_base, 557 (void *)(thread->kernel_stack_top)); 558 if (thread->user_stack_base != 0) { 559 kprintf(" user stack: %p to %p\n", 560 (void *)thread->user_stack_base, 561 (void *)(thread->user_stack_base + thread->user_stack_size)); 562 } 563 } 564 565 kprintf("frame caller <image>:function + offset\n"); 566 567 bool onKernelStack = true; 568 569 for (int32 callIndex = 0;; callIndex++) { 570 onKernelStack = onKernelStack 571 && is_kernel_stack_address(thread, ebp); 572 573 if (onKernelStack && is_iframe(thread, ebp)) { 574 struct iframe *frame = (struct iframe *)ebp; 575 576 print_iframe(frame); 577 print_stack_frame(thread, frame->eip, ebp, frame->ebp, callIndex, 578 demangle); 579 580 ebp = frame->ebp; 581 } else { 582 addr_t eip, nextEbp; 583 584 if (get_next_frame_debugger(ebp, &nextEbp, &eip) != B_OK) { 585 kprintf("%08lx -- read fault\n", ebp); 586 break; 587 } 588 589 if (eip == 0 || ebp == 0) 590 break; 591 592 print_stack_frame(thread, eip, ebp, nextEbp, callIndex, demangle); 593 ebp = nextEbp; 594 } 595 596 if (already_visited(previousLocations, &last, &num, ebp)) { 597 kprintf("circular stack frame: %p!\n", (void *)ebp); 598 break; 599 } 600 if (ebp == 0) 601 break; 602 } 603 604 if (oldPageDirectory != 0) { 605 // switch back to the previous page directory to no cause any troubles 606 write_cr3(oldPageDirectory); 607 } 608 609 return 0; 610 } 611 612 613 static void 614 print_call(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp, 615 int32 argCount) 616 { 617 const char *symbol, *image; 618 addr_t baseAddress; 619 bool exactMatch; 620 status_t status; 621 bool demangled = false; 622 int32 *arg = (int32 *)(nextEbp + 8); 623 624 status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image, 625 &exactMatch); 626 627 kprintf("%08lx %08lx ", ebp, eip); 628 629 if (status == B_OK) { 630 if (symbol != NULL) { 631 if (exactMatch && (argCount == 0 || argCount == -1)) { 632 status = print_demangled_call(image, symbol, (addr_t)arg, 633 argCount == -1, true); 634 if (status == B_OK) 635 demangled = true; 636 } 637 if (!demangled) { 638 kprintf("<%s>:%s%s", image, symbol, 639 exactMatch ? "" : " (nearest)"); 640 } 641 } else { 642 kprintf("<%s@%p>:unknown + 0x%04lx", image, 643 (void *)baseAddress, eip - baseAddress); 644 } 645 } else { 646 VMArea *area = NULL; 647 if (thread->team->address_space != NULL) 648 area = thread->team->address_space->LookupArea(eip); 649 if (area != NULL) { 650 kprintf("%ld:%s@%p + %#lx", area->id, area->name, 651 (void *)area->Base(), eip - area->Base()); 652 } 653 } 654 655 if (!demangled) { 656 kprintf("("); 657 658 for (int32 i = 0; i < argCount; i++) { 659 if (i > 0) 660 kprintf(", "); 661 kprintf("%#lx", *arg); 662 if (*arg > -0x10000 && *arg < 0x10000) 663 kprintf(" (%ld)", *arg); 664 665 set_debug_argument_variable(i + 1, *(uint32 *)arg); 666 arg++; 667 } 668 669 kprintf(")\n"); 670 } else 671 kprintf("\n"); 672 673 set_debug_variable("_frame", nextEbp); 674 } 675 676 677 static int 678 show_call(int argc, char **argv) 679 { 680 static const char* usage 681 = "usage: %s [ <thread id> ] <call index> [ -<arg count> ]\n" 682 "Prints a function call with parameters of the current, respectively\n" 683 "the specified thread.\n" 684 " <thread id> - The ID of the thread for which to print the call.\n" 685 " <call index> - The index of the call in the stack trace.\n" 686 " <arg count> - The number of call arguments to print (use 'c' to\n" 687 " force the C++ demangler to use class methods,\n" 688 " use 'd' to disable demangling).\n"; 689 if (argc == 2 && strcmp(argv[1], "--help") == 0) { 690 kprintf(usage, argv[0]); 691 return 0; 692 } 693 694 struct thread *thread = NULL; 695 addr_t oldPageDirectory = 0; 696 addr_t ebp = x86_read_ebp(); 697 int32 argCount = 0; 698 699 if (argc >= 2 && argv[argc - 1][0] == '-') { 700 if (argv[argc - 1][1] == 'c') 701 argCount = -1; 702 else if (argv[argc - 1][1] == 'd') 703 argCount = -2; 704 else 705 argCount = strtoul(argv[argc - 1] + 1, NULL, 0); 706 707 if (argCount < -2 || argCount > 16) { 708 kprintf("Invalid argument count \"%ld\".\n", argCount); 709 return 0; 710 } 711 argc--; 712 } 713 714 if (argc < 2 || argc > 3) { 715 kprintf(usage, argv[0]); 716 return 0; 717 } 718 719 if (!setup_for_thread(argc == 3 ? argv[1] : NULL, &thread, &ebp, 720 &oldPageDirectory)) 721 return 0; 722 723 int32 callIndex = strtoul(argv[argc == 3 ? 2 : 1], NULL, 0); 724 725 if (thread != NULL) 726 kprintf("thread %ld, %s\n", thread->id, thread->name); 727 728 bool onKernelStack = true; 729 730 for (int32 index = 0; index <= callIndex; index++) { 731 onKernelStack = onKernelStack 732 && is_kernel_stack_address(thread, ebp); 733 734 if (onKernelStack && is_iframe(thread, ebp)) { 735 struct iframe *frame = (struct iframe *)ebp; 736 737 if (index == callIndex) 738 print_call(thread, frame->eip, ebp, frame->ebp, argCount); 739 740 ebp = frame->ebp; 741 } else { 742 addr_t eip, nextEbp; 743 744 if (get_next_frame_debugger(ebp, &nextEbp, &eip) != B_OK) { 745 kprintf("%08lx -- read fault\n", ebp); 746 break; 747 } 748 749 if (eip == 0 || ebp == 0) 750 break; 751 752 if (index == callIndex) 753 print_call(thread, eip, ebp, nextEbp, argCount); 754 755 ebp = nextEbp; 756 } 757 758 if (ebp == 0) 759 break; 760 } 761 762 if (oldPageDirectory != 0) { 763 // switch back to the previous page directory to not cause any troubles 764 write_cr3(oldPageDirectory); 765 } 766 767 return 0; 768 } 769 770 771 static int 772 dump_iframes(int argc, char **argv) 773 { 774 static const char* usage = "usage: %s [ <thread id> ]\n" 775 "Prints the iframe stack for the current, respectively the specified\n" 776 "thread.\n" 777 " <thread id> - The ID of the thread for which to print the iframe\n" 778 " stack.\n"; 779 if (argc == 2 && strcmp(argv[1], "--help") == 0) { 780 kprintf(usage, argv[0]); 781 return 0; 782 } 783 784 struct thread *thread = NULL; 785 786 if (argc < 2) { 787 thread = thread_get_current_thread(); 788 } else if (argc == 2) { 789 thread_id id = strtoul(argv[1], NULL, 0); 790 thread = thread_get_thread_struct_locked(id); 791 if (thread == NULL) { 792 kprintf("could not find thread %ld\n", id); 793 return 0; 794 } 795 } else if (argc > 2) { 796 kprintf(usage, argv[0]); 797 return 0; 798 } 799 800 if (thread != NULL) 801 kprintf("iframes for thread %ld \"%s\"\n", thread->id, thread->name); 802 803 struct iframe* frame = find_previous_iframe(thread, x86_read_ebp()); 804 while (frame != NULL) { 805 print_iframe(frame); 806 frame = get_previous_iframe(thread, frame); 807 } 808 809 return 0; 810 } 811 812 813 static bool 814 is_calling(struct thread *thread, addr_t eip, const char *pattern, 815 addr_t start, addr_t end) 816 { 817 if (pattern == NULL) 818 return eip >= start && eip < end; 819 820 const char *symbol; 821 if (lookup_symbol(thread, eip, NULL, &symbol, NULL, NULL) != B_OK) 822 return false; 823 824 return strstr(symbol, pattern); 825 } 826 827 828 static int 829 cmd_in_context(int argc, char** argv) 830 { 831 if (argc != 2) { 832 print_debugger_command_usage(argv[0]); 833 return 0; 834 } 835 836 // get the thread ID 837 const char* commandLine = argv[1]; 838 char threadIDString[16]; 839 if (parse_next_debug_command_argument(&commandLine, threadIDString, 840 sizeof(threadIDString)) != B_OK) { 841 kprintf("Failed to parse thread ID.\n"); 842 return 0; 843 } 844 845 if (commandLine == NULL) { 846 print_debugger_command_usage(argv[0]); 847 return 0; 848 } 849 850 uint64 threadID; 851 if (!evaluate_debug_expression(threadIDString, &threadID, false)) 852 return 0; 853 854 // get the thread 855 struct thread* thread = thread_get_thread_struct_locked(threadID); 856 if (thread == NULL) { 857 kprintf("Could not find thread with ID \"%s\".\n", threadIDString); 858 return 0; 859 } 860 861 // switch the page directory, if necessary 862 addr_t oldPageDirectory = 0; 863 if (thread != thread_get_current_thread()) { 864 addr_t newPageDirectory = (addr_t)x86_next_page_directory( 865 thread_get_current_thread(), thread); 866 867 if (newPageDirectory != 0) { 868 read_cr3(oldPageDirectory); 869 write_cr3(newPageDirectory); 870 } 871 } 872 873 struct thread* previousThread = debug_set_debugged_thread(thread); 874 875 // execute the command 876 evaluate_debug_command(commandLine); 877 878 debug_set_debugged_thread(previousThread); 879 880 // reset the page directory 881 if (oldPageDirectory) 882 write_cr3(oldPageDirectory); 883 884 return 0; 885 } 886 887 888 // #pragma mark - 889 890 891 void 892 arch_debug_stack_trace(void) 893 { 894 stack_trace(0, NULL); 895 } 896 897 898 bool 899 arch_debug_contains_call(struct thread *thread, const char *symbol, 900 addr_t start, addr_t end) 901 { 902 addr_t ebp; 903 if (thread == thread_get_current_thread()) 904 ebp = x86_read_ebp(); 905 else 906 ebp = thread->arch_info.current_stack.esp[2]; 907 908 for (;;) { 909 if (!is_kernel_stack_address(thread, ebp)) 910 break; 911 912 if (is_iframe(thread, ebp)) { 913 struct iframe *frame = (struct iframe *)ebp; 914 915 if (is_calling(thread, frame->eip, symbol, start, end)) 916 return true; 917 918 ebp = frame->ebp; 919 } else { 920 addr_t eip, nextEbp; 921 922 if (get_next_frame_no_debugger(ebp, &nextEbp, &eip) != B_OK 923 || eip == 0 || ebp == 0) 924 break; 925 926 if (is_calling(thread, eip, symbol, start, end)) 927 return true; 928 929 ebp = nextEbp; 930 } 931 932 if (ebp == 0) 933 break; 934 } 935 936 return false; 937 } 938 939 940 void * 941 arch_debug_get_caller(void) 942 { 943 struct stack_frame *frame = (struct stack_frame *)x86_read_ebp(); 944 return (void *)frame->previous->return_address; 945 } 946 947 948 /*! Captures a stack trace (the return addresses) of the current thread. 949 \param returnAddresses The array the return address shall be written to. 950 \param maxCount The maximum number of return addresses to be captured. 951 \param skipIframes The number of interrupt frames that shall be skipped. If 952 greater than 0, \a skipFrames is ignored. 953 \param skipFrames The number of stack frames that shall be skipped. 954 \param userOnly If \c true, only userland return addresses are captured. 955 \return The number of return addresses written to the given array. 956 */ 957 int32 958 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, 959 int32 skipIframes, int32 skipFrames, bool userOnly) 960 { 961 // Keep skipping normal stack frames until we've skipped the iframes we're 962 // supposed to skip. 963 if (skipIframes > 0) { 964 skipFrames = INT_MAX; 965 } else { 966 // always skip our own frame 967 skipFrames++; 968 } 969 970 struct thread* thread = thread_get_current_thread(); 971 int32 count = 0; 972 addr_t ebp = x86_read_ebp(); 973 bool onKernelStack = true; 974 975 while (ebp != 0 && count < maxCount) { 976 onKernelStack = onKernelStack 977 && is_kernel_stack_address(thread, ebp); 978 979 addr_t eip; 980 addr_t nextEbp; 981 982 if (onKernelStack && is_iframe(thread, ebp)) { 983 struct iframe *frame = (struct iframe*)ebp; 984 eip = frame->eip; 985 nextEbp = frame->ebp; 986 987 if (skipIframes > 0) { 988 if (--skipIframes == 0) 989 skipFrames = 0; 990 } 991 } else { 992 if (get_next_frame_no_debugger(ebp, &nextEbp, &eip) != B_OK) 993 break; 994 } 995 996 if (skipFrames <= 0 && (!userOnly || IS_USER_ADDRESS(ebp))) 997 returnAddresses[count++] = eip; 998 else 999 skipFrames--; 1000 1001 ebp = nextEbp; 1002 } 1003 1004 return count; 1005 } 1006 1007 1008 /*! Returns the program counter of the currently debugged (respectively this) 1009 thread where the innermost interrupts happened. \a _isSyscall, if specified, 1010 is set to whether this interrupt frame was created by a syscall. Returns 1011 \c NULL, if there's no such frame or a problem occurred retrieving it; 1012 \a _isSyscall won't be set in this case. 1013 */ 1014 void* 1015 arch_debug_get_interrupt_pc(bool* _isSyscall) 1016 { 1017 struct iframe* frame = get_current_iframe(debug_get_debugged_thread()); 1018 if (frame == NULL) 1019 return NULL; 1020 1021 if (_isSyscall != NULL) 1022 *_isSyscall = frame->vector == 99; 1023 1024 return (void*)(addr_t)frame->eip; 1025 } 1026 1027 1028 /*! Sets the current thread to \c NULL. 1029 Invoked in the kernel debugger only. 1030 */ 1031 void 1032 arch_debug_unset_current_thread(void) 1033 { 1034 write_dr3(NULL); 1035 } 1036 1037 1038 bool 1039 arch_is_debug_variable_defined(const char* variableName) 1040 { 1041 bool settable; 1042 return find_debug_variable(variableName, settable); 1043 } 1044 1045 1046 status_t 1047 arch_set_debug_variable(const char* variableName, uint64 value) 1048 { 1049 bool settable; 1050 uint32* variable = find_debug_variable(variableName, settable); 1051 if (variable == NULL) 1052 return B_ENTRY_NOT_FOUND; 1053 1054 if (!settable) 1055 return B_NOT_ALLOWED; 1056 1057 *variable = (uint32)value; 1058 return B_OK; 1059 } 1060 1061 1062 status_t 1063 arch_get_debug_variable(const char* variableName, uint64* value) 1064 { 1065 bool settable; 1066 uint32* variable = find_debug_variable(variableName, settable); 1067 if (variable == NULL) 1068 return B_ENTRY_NOT_FOUND; 1069 1070 *value = *variable; 1071 return B_OK; 1072 } 1073 1074 1075 status_t 1076 arch_debug_init(kernel_args *args) 1077 { 1078 // at this stage, the debugger command system is alive 1079 1080 add_debugger_command("where", &stack_trace, "Same as \"sc\""); 1081 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 1082 add_debugger_command("sc", &stack_trace, 1083 "Stack crawl for current thread (or any other)"); 1084 add_debugger_command("iframe", &dump_iframes, 1085 "Dump iframes for the specified thread"); 1086 add_debugger_command("call", &show_call, "Show call with arguments"); 1087 add_debugger_command_etc("in_context", &cmd_in_context, 1088 "Executes a command in the context of a given thread", 1089 "<thread ID> <command> ...\n" 1090 "Executes a command in the context of a given thread.\n", 1091 B_KDEBUG_DONT_PARSE_ARGUMENTS); 1092 1093 return B_NO_ERROR; 1094 } 1095 1096