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:
Ingo Weinhold
2007-04-01 17:15:37 +00:00
parent 9bf1f552d9
commit 962b0b887d
5 changed files with 70 additions and 18 deletions
+46 -1
View File
@@ -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.