* Copyright 2002-2008, Axel DΓΆrfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <debugger.h>
#include <OS.h>
#include <Debug.h>
#include "syscalls.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct debug_string_entry {
const char *string;
uint32 code;
} debug_string_entry;
static const debug_string_entry sDebugMessageStrings[] = {
{ "Thread not running", B_DEBUGGER_MESSAGE_THREAD_DEBUGGED },
{ "Debugger call", B_DEBUGGER_MESSAGE_DEBUGGER_CALL },
{ "Breakpoint hit", B_DEBUGGER_MESSAGE_BREAKPOINT_HIT },
{ "Watchpoint hit", B_DEBUGGER_MESSAGE_WATCHPOINT_HIT },
{ "Single step", B_DEBUGGER_MESSAGE_SINGLE_STEP },
{ "Before syscall", B_DEBUGGER_MESSAGE_PRE_SYSCALL },
{ "After syscall", B_DEBUGGER_MESSAGE_POST_SYSCALL },
{ "Signal received", B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED },
{ "Exception occurred", B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED },
{ "Team created", B_DEBUGGER_MESSAGE_TEAM_CREATED },
{ "Team deleted", B_DEBUGGER_MESSAGE_TEAM_DELETED },
{ "Thread created", B_DEBUGGER_MESSAGE_THREAD_CREATED },
{ "Thread created", B_DEBUGGER_MESSAGE_THREAD_DELETED },
{ "Image created", B_DEBUGGER_MESSAGE_IMAGE_CREATED },
{ "Image deleted", B_DEBUGGER_MESSAGE_IMAGE_DELETED },
{ NULL, 0 }
};
static const debug_string_entry sDebugExceptionTypeStrings[] = {
{ "Non-maskable interrupt", B_NON_MASKABLE_INTERRUPT },
{ "Machine check exception", B_MACHINE_CHECK_EXCEPTION },
{ "Segment violation", B_SEGMENT_VIOLATION },
{ "Alignment exception", B_ALIGNMENT_EXCEPTION },
{ "Divide error", B_DIVIDE_ERROR },
{ "Overflow exception", B_OVERFLOW_EXCEPTION },
{ "Bounds check exception", B_BOUNDS_CHECK_EXCEPTION },
{ "Invalid opcode exception", B_INVALID_OPCODE_EXCEPTION },
{ "Segment not present", B_SEGMENT_NOT_PRESENT },
{ "Stack fault", B_STACK_FAULT },
{ "General protection fault", B_GENERAL_PROTECTION_FAULT },
{ "Floating point exception", B_FLOATING_POINT_EXCEPTION },
{ NULL, 0 }
};
bool _rtDebugFlag = true;
void
debugger(const char *message)
{
debug_printf("%" B_PRId32 ": DEBUGGER: %s\n", find_thread(NULL), message);
_kern_debugger(message);
}
int
disable_debugger(int state)
{
return _kern_disable_debugger(state);
}
status_t
install_default_debugger(port_id debuggerPort)
{
return _kern_install_default_debugger(debuggerPort);
}
port_id
install_team_debugger(team_id team, port_id debuggerPort)
{
return _kern_install_team_debugger(team, debuggerPort);
}
status_t
remove_team_debugger(team_id team)
{
return _kern_remove_team_debugger(team);
}
status_t
debug_thread(thread_id thread)
{
return _kern_debug_thread(thread);
}
* team.
*
* As soon as this happens (immediately, if a debugger is already installed)
* the thread stops for debugging. This is desirable for debuggers that spawn
* their debugged teams via fork() and want the child to wait till they have
* installed themselves as team debugger before continuing with exec*().
*/
void
wait_for_debugger(void)
{
_kern_wait_for_debugger();
}
status_t
set_debugger_breakpoint(void *address)
{
return _kern_set_debugger_breakpoint(address, 0, 0, false);
}
status_t
clear_debugger_breakpoint(void *address)
{
return _kern_clear_debugger_breakpoint(address, false);
}
status_t
set_debugger_watchpoint(void *address, uint32 type, int32 length)
{
return _kern_set_debugger_breakpoint(address, type, length, true);
}
status_t
clear_debugger_watchpoint(void *address)
{
return _kern_clear_debugger_breakpoint(address, true);
}
static void
get_debug_string(const debug_string_entry *stringEntries,
const char *defaultString, uint32 code, char *buffer, int32 bufferSize)
{
int i;
if (!buffer || bufferSize <= 0)
return;
for (i = 0; stringEntries[i].string; i++) {
if (stringEntries[i].code == code) {
strlcpy(buffer, stringEntries[i].string, bufferSize);
return;
}
}
snprintf(buffer, bufferSize, defaultString, code);
}
void
get_debug_message_string(debug_debugger_message message, char *buffer,
int32 bufferSize)
{
get_debug_string(sDebugMessageStrings, "Unknown message %lu",
(uint32)message, buffer, bufferSize);
}
void
get_debug_exception_string(debug_exception_type exception, char *buffer,
int32 bufferSize)
{
get_debug_string(sDebugExceptionTypeStrings, "Unknown exception %lu",
(uint32)exception, buffer, bufferSize);
}
bool
_debugFlag(void)
{
return _rtDebugFlag;
}
bool
_setDebugFlag(bool flag)
{
bool previous = _rtDebugFlag;
_rtDebugFlag = flag;
return previous;
}
int
_debugPrintf(const char *fmt, ...)
{
va_list ap;
int ret;
if (!_rtDebugFlag)
return 0;
va_start(ap, fmt);
ret = vfprintf(stdout, fmt, ap);
va_end(ap);
return ret;
}
int
_sPrintf(const char *fmt, ...)
{
char buffer[512];
va_list ap;
int ret;
if (!_rtDebugFlag)
return 0;
va_start(ap, fmt);
ret = vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
if (ret >= 0)
_kern_debug_output(buffer);
return ret;
}
int
_xdebugPrintf(const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = vfprintf(stdout, fmt, ap);
va_end(ap);
return ret;
}
int
_debuggerAssert(const char *file, int line, const char *message)
{
char buffer[1024];
snprintf(buffer, sizeof(buffer),
"Assert failed: File: %s, Line: %d, %s",
file, line, message);
debug_printf("%" B_PRId32 ": ASSERT: %s:%d %s\n", find_thread(NULL), file,
line, buffer);
_kern_debugger(buffer);
return 0;
}
int
debug_printf(const char *format, ...)
{
int count;
va_list list;
va_start(list, format);
count = debug_vprintf(format, list);
va_end(list);
return count;
}
int
debug_vprintf(const char *format, va_list args)
{
char buffer[1024];
int count = vsnprintf(buffer, sizeof(buffer), format, args);
_kern_debug_output(buffer);
return count;
}
void
ktrace_printf(const char *format, ...)
{
va_list list;
va_start(list, format);
ktrace_vprintf(format, list);
va_end(list);
}
void
ktrace_vprintf(const char *format, va_list args)
{
char buffer[1024];
vsnprintf(buffer, sizeof(buffer), format, args);
_kern_ktrace_output(buffer);
}