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