From 962b0b887d830b7f7bfd47de10112609302bbd82 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 1 Apr 2007 17:15:37 +0000 Subject: [PATCH] Added a wrapper function for the invocation of debugger commands. It sets a fault handler, so that an invalid memory access while executing the command (address typos always do the trick :-) won't result in another KDL session on top of the current one, which wouldn't even be "cont"able. All pieces of code setting a fault handler do now save and reset the previous one, so that e.g. a user_memcpy() in a debugger command doesn't disturb the mechanism. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20500 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/arch/ppc/arch_cpu.cpp | 15 +++++--- src/system/kernel/arch/ppc/arch_debug.cpp | 6 +-- src/system/kernel/arch/x86/arch_cpu.c | 15 +++++--- src/system/kernel/arch/x86/arch_debug.c | 5 ++- src/system/kernel/debug/debug.c | 47 ++++++++++++++++++++++- 5 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/system/kernel/arch/ppc/arch_cpu.cpp b/src/system/kernel/arch/ppc/arch_cpu.cpp index a9f9ce0708..a27c179d9c 100644 --- a/src/system/kernel/arch/ppc/arch_cpu.cpp +++ b/src/system/kernel/arch/ppc/arch_cpu.cpp @@ -151,6 +151,7 @@ arch_cpu_user_memcpy(void *to, const void *from, size_t size, { char *tmp = (char *)to; char *s = (char *)from; + addr_t oldFaultHandler = *faultHandler; if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) goto error; @@ -158,11 +159,11 @@ arch_cpu_user_memcpy(void *to, const void *from, size_t size, while (size--) *tmp++ = *s++; - *faultHandler = 0; + *faultHandler = oldFaultHandler; return 0; error: - *faultHandler = 0; + *faultHandler = oldFaultHandler; return B_BAD_ADDRESS; } @@ -181,6 +182,7 @@ ssize_t arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler) { int from_length = 0; + addr_t oldFaultHandler = *faultHandler; if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) goto error; @@ -197,11 +199,11 @@ arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHand while (*from++ != '\0') from_length++; - *faultHandler = 0; + *faultHandler = oldFaultHandler; return from_length; error: - *faultHandler = 0; + *faultHandler = oldFaultHandler; return B_BAD_ADDRESS; } @@ -210,6 +212,7 @@ status_t arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) { char *xs = (char *)s; + addr_t oldFaultHandler = *faultHandler; if (ppc_set_fault_handler(faultHandler, (addr_t)&&error)) goto error; @@ -217,11 +220,11 @@ arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) while (count--) *xs++ = c; - *faultHandler = 0; + *faultHandler = oldFaultHandler; return 0; error: - *faultHandler = 0; + *faultHandler = oldFaultHandler; return B_BAD_ADDRESS; } diff --git a/src/system/kernel/arch/ppc/arch_debug.cpp b/src/system/kernel/arch/ppc/arch_debug.cpp index 088562a619..6b5dd896a2 100644 --- a/src/system/kernel/arch/ppc/arch_debug.cpp +++ b/src/system/kernel/arch/ppc/arch_debug.cpp @@ -65,6 +65,7 @@ static status_t get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) { struct thread *thread = thread_get_current_thread(); + addr_t oldFaultHandler = thread->fault_handler; // set fault handler, so that we can safely access user stacks if (thread) { @@ -76,11 +77,11 @@ get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) *next = (addr_t)((struct stack_frame *)framePointer)->previous; if (thread) - thread->fault_handler = NULL; + thread->fault_handler = oldFaultHandler; return B_OK; error: - thread->fault_handler = NULL; + thread->fault_handler = oldFaultHandler; return B_BAD_ADDRESS; } @@ -287,4 +288,3 @@ arch_debug_init(kernel_args *args) return B_NO_ERROR; } - diff --git a/src/system/kernel/arch/x86/arch_cpu.c b/src/system/kernel/arch/x86/arch_cpu.c index 7c8a68752e..8640c4dd13 100644 --- a/src/system/kernel/arch/x86/arch_cpu.c +++ b/src/system/kernel/arch/x86/arch_cpu.c @@ -586,6 +586,7 @@ arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr_t *faultHandl { char *tmp = (char *)to; char *s = (char *)from; + addr_t oldFaultHandler = *faultHandler; // this check is to trick the gcc4 compiler and have it keep the error label if (to == NULL) @@ -596,11 +597,11 @@ arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr_t *faultHandl while (size--) *tmp++ = *s++; - *faultHandler = 0; + *faultHandler = oldFaultHandler; return 0; error: - *faultHandler = 0; + *faultHandler = oldFaultHandler; return B_BAD_ADDRESS; } @@ -609,6 +610,7 @@ ssize_t arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler) { int fromLength = 0; + addr_t oldFaultHandler = *faultHandler; // this check is to trick the gcc4 compiler and have it keep the error label if (to == NULL) @@ -629,11 +631,11 @@ arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHand fromLength++; } - *faultHandler = 0; + *faultHandler = oldFaultHandler; return fromLength; error: - *faultHandler = 0; + *faultHandler = oldFaultHandler; return B_BAD_ADDRESS; } @@ -642,6 +644,7 @@ status_t arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) { char *xs = (char *)s; + addr_t oldFaultHandler = *faultHandler; // this check is to trick the gcc4 compiler and have it keep the error label if (s == NULL) @@ -652,11 +655,11 @@ arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) while (count--) *xs++ = c; - *faultHandler = 0; + *faultHandler = oldFaultHandler; return 0; error: - *faultHandler = 0; + *faultHandler = oldFaultHandler; return B_BAD_ADDRESS; } diff --git a/src/system/kernel/arch/x86/arch_debug.c b/src/system/kernel/arch/x86/arch_debug.c index bbfe17353c..a25e20aaab 100644 --- a/src/system/kernel/arch/x86/arch_debug.c +++ b/src/system/kernel/arch/x86/arch_debug.c @@ -56,6 +56,7 @@ static status_t get_next_frame(addr_t ebp, addr_t *_next, addr_t *_eip) { // set fault handler, so that we can safely access user stacks + addr_t oldFaultHandler = thread_get_current_thread()->fault_handler; thread_get_current_thread()->fault_handler = (addr_t)&&error; // Fake goto to trick the compiler not to optimize the code at the label // away. @@ -65,11 +66,11 @@ get_next_frame(addr_t ebp, addr_t *_next, addr_t *_eip) *_eip = ((struct stack_frame *)ebp)->return_address; *_next = (addr_t)((struct stack_frame *)ebp)->previous; - thread_get_current_thread()->fault_handler = NULL; + thread_get_current_thread()->fault_handler = oldFaultHandler; return B_OK; error: - thread_get_current_thread()->fault_handler = NULL; + thread_get_current_thread()->fault_handler = oldFaultHandler; return B_BAD_ADDRESS; } diff --git a/src/system/kernel/debug/debug.c b/src/system/kernel/debug/debug.c index 6fc2db4978..8ae443de2f 100644 --- a/src/system/kernel/debug/debug.c +++ b/src/system/kernel/debug/debug.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,7 @@ #include #include +#include #include #include #include @@ -59,6 +61,9 @@ static bool sSyslogDropped = false; static struct debugger_command *sCommands; +static jmp_buf sInvokeCommandEnv; +static bool sInvokeCommandDirectly = false; + #define SYSLOG_BUFFER_SIZE 65536 #define OUTPUT_BUFFER_SIZE 1024 static char sOutputBuffer[OUTPUT_BUFFER_SIZE]; @@ -316,6 +321,46 @@ parse_line(const char *buffer, char **argv, int *_argc, int32 maxArgs) return *_argc = index; } +/*! This function is a safe gate through which debugger commands are invoked. + It sets a fault handler before invoking the command, so that an invalid + memory access will not result in another KDL session on top of this one + (and "cont" not to work anymore). We use setjmp() + longjmp() to "unwind" + the stack after catching a fault. + */ +static int +invoke_command(int (*command)(int, char **), int argc, char** argv) +{ + struct thread* thread = thread_get_current_thread(); + addr_t oldFaultHandler = thread->fault_handler; + + // Invoking the command directly might be useful when debugging debugger + // commands. + if (sInvokeCommandDirectly) + return command(argc, argv); + + if (setjmp(sInvokeCommandEnv) == 0) { + int result; + thread->fault_handler = (addr_t)&&error; + // Fake goto to trick the compiler not to optimize the code at the label + // away. + if (!thread) + goto error; + + result = command(argc, argv); + thread->fault_handler = oldFaultHandler; + return result; + +error: + longjmp(sInvokeCommandEnv, 1); + // jump into the else branch + } else { + kprintf("\n[*** READ/WRITE FAULT ***]\n"); + } + + thread->fault_handler = oldFaultHandler; + return 0; +} + static void kernel_debugger_loop(void) @@ -347,7 +392,7 @@ kernel_debugger_loop(void) if (cmd == NULL) kprintf("unknown command, enter \"help\" to get a list of all supported commands\n"); else { - int rc = cmd->func(argc, args); + int rc = invoke_command(cmd->func, argc, args); if (rc == B_KDEBUG_QUIT) break; // okay, exit now.