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:
@@ -151,6 +151,7 @@ arch_cpu_user_memcpy(void *to, const void *from, size_t size,
|
|||||||
{
|
{
|
||||||
char *tmp = (char *)to;
|
char *tmp = (char *)to;
|
||||||
char *s = (char *)from;
|
char *s = (char *)from;
|
||||||
|
addr_t oldFaultHandler = *faultHandler;
|
||||||
|
|
||||||
if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
|
if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
|
||||||
goto error;
|
goto error;
|
||||||
@@ -158,11 +159,11 @@ arch_cpu_user_memcpy(void *to, const void *from, size_t size,
|
|||||||
while (size--)
|
while (size--)
|
||||||
*tmp++ = *s++;
|
*tmp++ = *s++;
|
||||||
|
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return B_BAD_ADDRESS;
|
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)
|
arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
|
||||||
{
|
{
|
||||||
int from_length = 0;
|
int from_length = 0;
|
||||||
|
addr_t oldFaultHandler = *faultHandler;
|
||||||
|
|
||||||
if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
|
if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
|
||||||
goto 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')
|
while (*from++ != '\0')
|
||||||
from_length++;
|
from_length++;
|
||||||
|
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return from_length;
|
return from_length;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,6 +212,7 @@ status_t
|
|||||||
arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
|
arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
|
||||||
{
|
{
|
||||||
char *xs = (char *)s;
|
char *xs = (char *)s;
|
||||||
|
addr_t oldFaultHandler = *faultHandler;
|
||||||
|
|
||||||
if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
|
if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
|
||||||
goto error;
|
goto error;
|
||||||
@@ -217,11 +220,11 @@ arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
|
|||||||
while (count--)
|
while (count--)
|
||||||
*xs++ = c;
|
*xs++ = c;
|
||||||
|
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ static status_t
|
|||||||
get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip)
|
get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip)
|
||||||
{
|
{
|
||||||
struct thread *thread = thread_get_current_thread();
|
struct thread *thread = thread_get_current_thread();
|
||||||
|
addr_t oldFaultHandler = thread->fault_handler;
|
||||||
|
|
||||||
// set fault handler, so that we can safely access user stacks
|
// set fault handler, so that we can safely access user stacks
|
||||||
if (thread) {
|
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;
|
*next = (addr_t)((struct stack_frame *)framePointer)->previous;
|
||||||
|
|
||||||
if (thread)
|
if (thread)
|
||||||
thread->fault_handler = NULL;
|
thread->fault_handler = oldFaultHandler;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
thread->fault_handler = NULL;
|
thread->fault_handler = oldFaultHandler;
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,4 +288,3 @@ arch_debug_init(kernel_args *args)
|
|||||||
return B_NO_ERROR;
|
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 *tmp = (char *)to;
|
||||||
char *s = (char *)from;
|
char *s = (char *)from;
|
||||||
|
addr_t oldFaultHandler = *faultHandler;
|
||||||
|
|
||||||
// this check is to trick the gcc4 compiler and have it keep the error label
|
// this check is to trick the gcc4 compiler and have it keep the error label
|
||||||
if (to == NULL)
|
if (to == NULL)
|
||||||
@@ -596,11 +597,11 @@ arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr_t *faultHandl
|
|||||||
while (size--)
|
while (size--)
|
||||||
*tmp++ = *s++;
|
*tmp++ = *s++;
|
||||||
|
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return B_BAD_ADDRESS;
|
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)
|
arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
|
||||||
{
|
{
|
||||||
int fromLength = 0;
|
int fromLength = 0;
|
||||||
|
addr_t oldFaultHandler = *faultHandler;
|
||||||
|
|
||||||
// this check is to trick the gcc4 compiler and have it keep the error label
|
// this check is to trick the gcc4 compiler and have it keep the error label
|
||||||
if (to == NULL)
|
if (to == NULL)
|
||||||
@@ -629,11 +631,11 @@ arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHand
|
|||||||
fromLength++;
|
fromLength++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return fromLength;
|
return fromLength;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,6 +644,7 @@ status_t
|
|||||||
arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
|
arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
|
||||||
{
|
{
|
||||||
char *xs = (char *)s;
|
char *xs = (char *)s;
|
||||||
|
addr_t oldFaultHandler = *faultHandler;
|
||||||
|
|
||||||
// this check is to trick the gcc4 compiler and have it keep the error label
|
// this check is to trick the gcc4 compiler and have it keep the error label
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
@@ -652,11 +655,11 @@ arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
|
|||||||
while (count--)
|
while (count--)
|
||||||
*xs++ = c;
|
*xs++ = c;
|
||||||
|
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
*faultHandler = 0;
|
*faultHandler = oldFaultHandler;
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ static status_t
|
|||||||
get_next_frame(addr_t ebp, addr_t *_next, addr_t *_eip)
|
get_next_frame(addr_t ebp, addr_t *_next, addr_t *_eip)
|
||||||
{
|
{
|
||||||
// set fault handler, so that we can safely access user stacks
|
// 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;
|
thread_get_current_thread()->fault_handler = (addr_t)&&error;
|
||||||
// Fake goto to trick the compiler not to optimize the code at the label
|
// Fake goto to trick the compiler not to optimize the code at the label
|
||||||
// away.
|
// away.
|
||||||
@@ -65,11 +66,11 @@ get_next_frame(addr_t ebp, addr_t *_next, addr_t *_eip)
|
|||||||
*_eip = ((struct stack_frame *)ebp)->return_address;
|
*_eip = ((struct stack_frame *)ebp)->return_address;
|
||||||
*_next = (addr_t)((struct stack_frame *)ebp)->previous;
|
*_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;
|
return B_OK;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
thread_get_current_thread()->fault_handler = NULL;
|
thread_get_current_thread()->fault_handler = oldFaultHandler;
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <frame_buffer_console.h>
|
#include <frame_buffer_console.h>
|
||||||
#include <int.h>
|
#include <int.h>
|
||||||
#include <smp.h>
|
#include <smp.h>
|
||||||
|
#include <thread.h>
|
||||||
#include <vm.h>
|
#include <vm.h>
|
||||||
|
|
||||||
#include <arch/debug_console.h>
|
#include <arch/debug_console.h>
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
#include <syslog_daemon.h>
|
#include <syslog_daemon.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <setjmp.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -59,6 +61,9 @@ static bool sSyslogDropped = false;
|
|||||||
|
|
||||||
static struct debugger_command *sCommands;
|
static struct debugger_command *sCommands;
|
||||||
|
|
||||||
|
static jmp_buf sInvokeCommandEnv;
|
||||||
|
static bool sInvokeCommandDirectly = false;
|
||||||
|
|
||||||
#define SYSLOG_BUFFER_SIZE 65536
|
#define SYSLOG_BUFFER_SIZE 65536
|
||||||
#define OUTPUT_BUFFER_SIZE 1024
|
#define OUTPUT_BUFFER_SIZE 1024
|
||||||
static char sOutputBuffer[OUTPUT_BUFFER_SIZE];
|
static char sOutputBuffer[OUTPUT_BUFFER_SIZE];
|
||||||
@@ -316,6 +321,46 @@ parse_line(const char *buffer, char **argv, int *_argc, int32 maxArgs)
|
|||||||
return *_argc = index;
|
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
|
static void
|
||||||
kernel_debugger_loop(void)
|
kernel_debugger_loop(void)
|
||||||
@@ -347,7 +392,7 @@ kernel_debugger_loop(void)
|
|||||||
if (cmd == NULL)
|
if (cmd == NULL)
|
||||||
kprintf("unknown command, enter \"help\" to get a list of all supported commands\n");
|
kprintf("unknown command, enter \"help\" to get a list of all supported commands\n");
|
||||||
else {
|
else {
|
||||||
int rc = cmd->func(argc, args);
|
int rc = invoke_command(cmd->func, argc, args);
|
||||||
|
|
||||||
if (rc == B_KDEBUG_QUIT)
|
if (rc == B_KDEBUG_QUIT)
|
||||||
break; // okay, exit now.
|
break; // okay, exit now.
|
||||||
|
|||||||
Reference in New Issue
Block a user