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
This commit is contained in:
parent
9bf1f552d9
commit
962b0b887d
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <frame_buffer_console.h>
|
||||
#include <int.h>
|
||||
#include <smp.h>
|
||||
#include <thread.h>
|
||||
#include <vm.h>
|
||||
|
||||
#include <arch/debug_console.h>
|
||||
@ -25,6 +26,7 @@
|
||||
#include <syslog_daemon.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user