diff --git a/headers/private/kernel/arch/debug.h b/headers/private/kernel/arch/debug.h index 72af6e03ef..c52b1d2f98 100644 --- a/headers/private/kernel/arch/debug.h +++ b/headers/private/kernel/arch/debug.h @@ -1,5 +1,5 @@ /* - * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -12,6 +12,7 @@ #include struct kernel_args; +struct thread; #ifdef __cplusplus @@ -20,6 +21,8 @@ extern "C" { status_t arch_debug_init(kernel_args *args); void *arch_debug_get_caller(void); +bool arch_debug_contains_call(struct thread *thread, const char *symbol, + addr_t start, addr_t end); void arch_debug_save_registers(int *); #ifdef __cplusplus diff --git a/src/system/kernel/arch/m68k/arch_debug.cpp b/src/system/kernel/arch/m68k/arch_debug.cpp index 8b37c950ca..e796358b30 100644 --- a/src/system/kernel/arch/m68k/arch_debug.cpp +++ b/src/system/kernel/arch/m68k/arch_debug.cpp @@ -1,5 +1,5 @@ -/* - * Copyright 2003-2007, Haiku Inc. All rights reserved. +/* + * Copyright 2003-2008, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -179,7 +179,7 @@ return 0; kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id, thread->name); - kprintf(" kernel stack: %p to %p\n", + kprintf(" kernel stack: %p to %p\n", (void *)thread->kernel_stack_base, (void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE)); if (thread->user_stack_base != 0) { @@ -264,6 +264,14 @@ arch_debug_save_registers(int *regs) } +bool +arch_debug_contains_call(struct thread *thread, const char *symbol, + addr_t start, addr_t end) +{ + return false; +} + + void * arch_debug_get_caller(void) { diff --git a/src/system/kernel/arch/ppc/arch_debug.cpp b/src/system/kernel/arch/ppc/arch_debug.cpp index 6b5dd896a2..de9139985a 100644 --- a/src/system/kernel/arch/ppc/arch_debug.cpp +++ b/src/system/kernel/arch/ppc/arch_debug.cpp @@ -1,5 +1,5 @@ -/* - * Copyright 2003-2006, Haiku Inc. All rights reserved. +/* + * Copyright 2003-2008, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -177,7 +177,7 @@ return 0; kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id, thread->name); - kprintf(" kernel stack: %p to %p\n", + kprintf(" kernel stack: %p to %p\n", (void *)thread->kernel_stack_base, (void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE)); if (thread->user_stack_base != 0) { @@ -270,6 +270,14 @@ arch_debug_save_registers(int *regs) } +bool +arch_debug_contains_call(struct thread *thread, const char *symbol, + addr_t start, addr_t end) +{ + return false; +} + + void * arch_debug_get_caller(void) { diff --git a/src/system/kernel/arch/x86/arch_debug.cpp b/src/system/kernel/arch/x86/arch_debug.cpp index e5463dc7e2..736c8043ef 100644 --- a/src/system/kernel/arch/x86/arch_debug.cpp +++ b/src/system/kernel/arch/x86/arch_debug.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001, Travis Geiselbrecht. All rights reserved. @@ -279,7 +279,7 @@ stack_trace(int argc, char **argv) kprintf("stack trace for thread %ld \"%s\"\n", thread->id, thread->name); - kprintf(" kernel stack: %p to %p\n", + kprintf(" kernel stack: %p to %p\n", (void *)thread->kernel_stack_base, (void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE)); if (thread->user_stack_base != 0) { @@ -519,14 +519,73 @@ dump_iframes(int argc, char **argv) } +static bool +is_calling(struct thread *thread, addr_t eip, const char *pattern, + addr_t start, addr_t end) +{ + if (pattern == NULL) + return eip >= start && eip < end; + + const char *symbol; + if (lookup_symbol(thread, eip, NULL, &symbol, NULL, NULL) != B_OK) + return false; + + return strstr(symbol, pattern); +} + + // #pragma mark - +bool +arch_debug_contains_call(struct thread *thread, const char *symbol, + addr_t start, addr_t end) +{ + addr_t ebp; + if (thread == thread_get_current_thread()) + ebp = x86_read_ebp(); + else + ebp = thread->arch_info.current_stack.esp[2]; + + bool onKernelStack = true; + + for (;;) { + onKernelStack = onKernelStack + && is_kernel_stack_address(thread, ebp); + + if (onKernelStack && is_iframe(thread, ebp)) { + struct iframe *frame = (struct iframe *)ebp; + + if (is_calling(thread, frame->eip, symbol, start, end)) + return true; + + ebp = frame->ebp; + } else { + addr_t eip, nextEbp; + + if (get_next_frame(ebp, &nextEbp, &eip) != B_OK + || eip == 0 || ebp == 0) + break; + + if (is_calling(thread, eip, symbol, start, end)) + return true; + + ebp = nextEbp; + } + + if (ebp == 0) + break; + } + + return false; +} + + void * arch_debug_get_caller(void) { // It looks like you would get the wrong stack frame here, but - // since read_ebp() is an assembler inline macro, GCC seems to + // since read_ebp() is an assembler inline macro, GCC seems to // be smart enough to save its original value. struct stack_frame *frame = (struct stack_frame *)x86_read_ebp(); @@ -541,8 +600,10 @@ arch_debug_init(kernel_args *args) add_debugger_command("where", &stack_trace, "Same as \"sc\""); add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); - add_debugger_command("sc", &stack_trace, "Stack crawl for current thread (or any other)"); - add_debugger_command("iframe", &dump_iframes, "Dump iframes for the specified thread"); + add_debugger_command("sc", &stack_trace, + "Stack crawl for current thread (or any other)"); + add_debugger_command("iframe", &dump_iframes, + "Dump iframes for the specified thread"); add_debugger_command("call", &show_call, "Show call with arguments"); return B_NO_ERROR; diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 791d4a84e4..0ada2035b0 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -624,7 +625,7 @@ thread_exit2(void *_args) TRACE(("thread_exit2: done removing thread from lists\n")); if (args.death_sem >= 0) - release_sem_etc(args.death_sem, 1, B_DO_NOT_RESCHEDULE); + release_sem_etc(args.death_sem, 1, B_DO_NOT_RESCHEDULE); // notify the debugger if (args.original_team_id >= 0 @@ -972,7 +973,7 @@ drop_into_debugger(int argc, char **argv) kprintf("drop failed\n"); else kprintf("thread %ld dropped into user debugger\n", id); - + return 0; } @@ -1121,6 +1122,10 @@ dump_thread_list(int argc, char **argv) struct thread *thread; struct hash_iterator i; bool realTimeOnly = false; + bool calling = false; + const char *callSymbol = NULL; + addr_t callStart = 0; + addr_t callEnd = 0; int32 requiredState = 0; team_id team = -1; sem_id sem = -1; @@ -1139,6 +1144,17 @@ dump_thread_list(int argc, char **argv) if (sem == 0) kprintf("ignoring invalid semaphore argument.\n"); } + } else if (!strcmp(argv[0], "calling")) { + if (argc < 2) { + kprintf("Need to give a symbol name or start and end arguments.\n"); + return 0; + } else if (argc == 3) { + callStart = parse_expression(argv[1]); + callEnd = parse_expression(argv[2]); + } else + callSymbol = argv[1]; + + calling = true; } else if (argc > 1) { team = strtoul(argv[1], NULL, 0); if (team == 0) @@ -1152,6 +1168,8 @@ dump_thread_list(int argc, char **argv) while ((thread = (struct thread*)hash_next(sThreadHash, &i)) != NULL) { // filter out threads not matching the search criteria if ((requiredState && thread->state != requiredState) + || (calling && !arch_debug_contains_call(thread, callSymbol, + callStart, callEnd)) || (sem > 0 && thread->sem.blocking != sem) || (team > 0 && thread->team->id != team) || (realTimeOnly && thread->priority < B_REAL_TIME_DISPLAY_PRIORITY)) @@ -1978,6 +1996,9 @@ thread_init(kernel_args *args) " - The ID of the thread.\n" "
- The address of the thread structure.\n" " - The thread's name.\n", 0); + add_debugger_command_etc("calling", &dump_thread_list, + "Show all threads that have a specific address in their call chain", + "{ | }\n", 0); add_debugger_command_etc("unreal", &make_thread_unreal, "Set realtime priority threads to normal priority", "[ ]\n" @@ -2016,7 +2037,7 @@ status_t thread_preboot_init_percpu(struct kernel_args *args, int32 cpuNum) { // set up the cpu pointer in the not yet initialized per-cpu idle thread - // so that get_current_cpu and friends will work, which is crucial for + // so that get_current_cpu and friends will work, which is crucial for // a lot of low level routines sIdleThreads[cpuNum].cpu = &gCPU[cpuNum]; arch_thread_set_current_thread(&sIdleThreads[cpuNum]); @@ -2527,7 +2548,7 @@ thread_id _user_find_thread(const char *userName) { char name[B_OS_NAME_LENGTH]; - + if (userName == NULL) return find_thread(NULL);