* Added arch_debug_contains_call() function that returns wether or not
a call chain contains a specific symbol (or address). * Added a new KDL command "calling" that you can use to get a list of threads that have a specific function in their call chain. * Removed extraneous white space. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24594 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
c32f787401
commit
758962ec3b
@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||||
@ -12,6 +12,7 @@
|
|||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
struct kernel_args;
|
struct kernel_args;
|
||||||
|
struct thread;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -20,6 +21,8 @@ extern "C" {
|
|||||||
|
|
||||||
status_t arch_debug_init(kernel_args *args);
|
status_t arch_debug_init(kernel_args *args);
|
||||||
void *arch_debug_get_caller(void);
|
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 *);
|
void arch_debug_save_registers(int *);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@ -179,7 +179,7 @@ return 0;
|
|||||||
kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id,
|
kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id,
|
||||||
thread->name);
|
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,
|
||||||
(void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE));
|
(void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE));
|
||||||
if (thread->user_stack_base != 0) {
|
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 *
|
void *
|
||||||
arch_debug_get_caller(void)
|
arch_debug_get_caller(void)
|
||||||
{
|
{
|
||||||
|
@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@ -177,7 +177,7 @@ return 0;
|
|||||||
kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id,
|
kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id,
|
||||||
thread->name);
|
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,
|
||||||
(void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE));
|
(void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE));
|
||||||
if (thread->user_stack_base != 0) {
|
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 *
|
void *
|
||||||
arch_debug_get_caller(void)
|
arch_debug_get_caller(void)
|
||||||
{
|
{
|
||||||
|
@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
* 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,
|
kprintf("stack trace for thread %ld \"%s\"\n", thread->id,
|
||||||
thread->name);
|
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,
|
||||||
(void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE));
|
(void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE));
|
||||||
if (thread->user_stack_base != 0) {
|
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 -
|
// #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 *
|
void *
|
||||||
arch_debug_get_caller(void)
|
arch_debug_get_caller(void)
|
||||||
{
|
{
|
||||||
// It looks like you would get the wrong stack frame here, but
|
// 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.
|
// be smart enough to save its original value.
|
||||||
struct stack_frame *frame = (struct stack_frame *)x86_read_ebp();
|
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("where", &stack_trace, "Same as \"sc\"");
|
||||||
add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
|
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("sc", &stack_trace,
|
||||||
add_debugger_command("iframe", &dump_iframes, "Dump iframes for the specified thread");
|
"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");
|
add_debugger_command("call", &show_call, "Show call with arguments");
|
||||||
|
|
||||||
return B_NO_ERROR;
|
return B_NO_ERROR;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
#include <util/khash.h>
|
#include <util/khash.h>
|
||||||
|
|
||||||
|
#include <arch/debug.h>
|
||||||
#include <boot/kernel_args.h>
|
#include <boot/kernel_args.h>
|
||||||
#include <condition_variable.h>
|
#include <condition_variable.h>
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
@ -624,7 +625,7 @@ thread_exit2(void *_args)
|
|||||||
TRACE(("thread_exit2: done removing thread from lists\n"));
|
TRACE(("thread_exit2: done removing thread from lists\n"));
|
||||||
|
|
||||||
if (args.death_sem >= 0)
|
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
|
// notify the debugger
|
||||||
if (args.original_team_id >= 0
|
if (args.original_team_id >= 0
|
||||||
@ -972,7 +973,7 @@ drop_into_debugger(int argc, char **argv)
|
|||||||
kprintf("drop failed\n");
|
kprintf("drop failed\n");
|
||||||
else
|
else
|
||||||
kprintf("thread %ld dropped into user debugger\n", id);
|
kprintf("thread %ld dropped into user debugger\n", id);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1121,6 +1122,10 @@ dump_thread_list(int argc, char **argv)
|
|||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
struct hash_iterator i;
|
struct hash_iterator i;
|
||||||
bool realTimeOnly = false;
|
bool realTimeOnly = false;
|
||||||
|
bool calling = false;
|
||||||
|
const char *callSymbol = NULL;
|
||||||
|
addr_t callStart = 0;
|
||||||
|
addr_t callEnd = 0;
|
||||||
int32 requiredState = 0;
|
int32 requiredState = 0;
|
||||||
team_id team = -1;
|
team_id team = -1;
|
||||||
sem_id sem = -1;
|
sem_id sem = -1;
|
||||||
@ -1139,6 +1144,17 @@ dump_thread_list(int argc, char **argv)
|
|||||||
if (sem == 0)
|
if (sem == 0)
|
||||||
kprintf("ignoring invalid semaphore argument.\n");
|
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) {
|
} else if (argc > 1) {
|
||||||
team = strtoul(argv[1], NULL, 0);
|
team = strtoul(argv[1], NULL, 0);
|
||||||
if (team == 0)
|
if (team == 0)
|
||||||
@ -1152,6 +1168,8 @@ dump_thread_list(int argc, char **argv)
|
|||||||
while ((thread = (struct thread*)hash_next(sThreadHash, &i)) != NULL) {
|
while ((thread = (struct thread*)hash_next(sThreadHash, &i)) != NULL) {
|
||||||
// filter out threads not matching the search criteria
|
// filter out threads not matching the search criteria
|
||||||
if ((requiredState && thread->state != requiredState)
|
if ((requiredState && thread->state != requiredState)
|
||||||
|
|| (calling && !arch_debug_contains_call(thread, callSymbol,
|
||||||
|
callStart, callEnd))
|
||||||
|| (sem > 0 && thread->sem.blocking != sem)
|
|| (sem > 0 && thread->sem.blocking != sem)
|
||||||
|| (team > 0 && thread->team->id != team)
|
|| (team > 0 && thread->team->id != team)
|
||||||
|| (realTimeOnly && thread->priority < B_REAL_TIME_DISPLAY_PRIORITY))
|
|| (realTimeOnly && thread->priority < B_REAL_TIME_DISPLAY_PRIORITY))
|
||||||
@ -1978,6 +1996,9 @@ thread_init(kernel_args *args)
|
|||||||
" <id> - The ID of the thread.\n"
|
" <id> - The ID of the thread.\n"
|
||||||
" <address> - The address of the thread structure.\n"
|
" <address> - The address of the thread structure.\n"
|
||||||
" <name> - The thread's name.\n", 0);
|
" <name> - 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",
|
||||||
|
"{ <symbol-pattern> | <start> <end> }\n", 0);
|
||||||
add_debugger_command_etc("unreal", &make_thread_unreal,
|
add_debugger_command_etc("unreal", &make_thread_unreal,
|
||||||
"Set realtime priority threads to normal priority",
|
"Set realtime priority threads to normal priority",
|
||||||
"[ <id> ]\n"
|
"[ <id> ]\n"
|
||||||
@ -2016,7 +2037,7 @@ status_t
|
|||||||
thread_preboot_init_percpu(struct kernel_args *args, int32 cpuNum)
|
thread_preboot_init_percpu(struct kernel_args *args, int32 cpuNum)
|
||||||
{
|
{
|
||||||
// set up the cpu pointer in the not yet initialized per-cpu idle thread
|
// 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
|
// a lot of low level routines
|
||||||
sIdleThreads[cpuNum].cpu = &gCPU[cpuNum];
|
sIdleThreads[cpuNum].cpu = &gCPU[cpuNum];
|
||||||
arch_thread_set_current_thread(&sIdleThreads[cpuNum]);
|
arch_thread_set_current_thread(&sIdleThreads[cpuNum]);
|
||||||
@ -2527,7 +2548,7 @@ thread_id
|
|||||||
_user_find_thread(const char *userName)
|
_user_find_thread(const char *userName)
|
||||||
{
|
{
|
||||||
char name[B_OS_NAME_LENGTH];
|
char name[B_OS_NAME_LENGTH];
|
||||||
|
|
||||||
if (userName == NULL)
|
if (userName == NULL)
|
||||||
return find_thread(NULL);
|
return find_thread(NULL);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user