* Changed the way the demangle functionality works: instead of having a kernel

debugger add-on set a demangle hook, all modules under debugger/demangle/ are
  now considered demangle modules.
* Added another function to the demangle module interface that gives you access
  to the arguments.
* Implemented a demangling module for GCC2.
* The older demangling module is now called "gcc3+", but doesn't support
  getting the arguments yet.
* The "call" KDL command is now using demangling to automatically show you
  the arguments of a call from a stack crawl.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28018 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-10-12 23:50:41 +00:00
parent 36bde12db2
commit ddecb4a7da
6 changed files with 652 additions and 128 deletions

View File

@ -66,6 +66,16 @@ struct debugger_module_info {
// TODO: add hooks for tunnelling gdb ?
};
struct debugger_demangle_module_info {
module_info info;
const char* (*demangle_symbol)(const char* name, char* buffer,
size_t bufferSize, bool* _isObjectMethod);
status_t (*get_next_argument)(uint32* _cookie, const char* symbol,
char* name, size_t nameSize, int32* _type, size_t* _argumentLength);
};
extern int dbg_register_file[B_MAX_CPU_COUNT][14];
typedef struct debug_page_fault_info {
@ -89,21 +99,21 @@ struct kernel_args;
extern status_t debug_init(struct kernel_args *args);
extern status_t debug_init_post_vm(struct kernel_args *args);
extern status_t debug_init_post_modules(struct kernel_args *args);
extern void debug_early_boot_message(const char *string);
extern void debug_puts(const char *s, int32 length);
extern bool debug_debugger_running(void);
extern bool debug_screen_output_enabled(void);
extern void debug_stop_screen_debug_output(void);
extern void debug_set_page_fault_info(addr_t faultAddress, addr_t pc,
uint32 flags);
extern void debug_early_boot_message(const char *string);
extern void debug_puts(const char *s, int32 length);
extern bool debug_debugger_running(void);
extern bool debug_screen_output_enabled(void);
extern void debug_stop_screen_debug_output(void);
extern void debug_set_page_fault_info(addr_t faultAddress, addr_t pc,
uint32 flags);
extern debug_page_fault_info* debug_get_page_fault_info();
extern void kputs(const char *string);
extern void kputs_unfiltered(const char *string);
extern void kprintf_unfiltered(const char *format, ...)
__attribute__ ((format (__printf__, 1, 2)));
extern void dprintf_no_syslog(const char *format, ...)
__attribute__ ((format (__printf__, 1, 2)));
extern void kputs(const char *string);
extern void kputs_unfiltered(const char *string);
extern void kprintf_unfiltered(const char *format, ...)
__attribute__ ((format (__printf__, 1, 2)));
extern void dprintf_no_syslog(const char *format, ...)
__attribute__ ((format (__printf__, 1, 2)));
extern bool is_debug_variable_defined(const char* variableName);
extern bool set_debug_variable(const char* variableName, uint64 value);
@ -125,8 +135,11 @@ extern status_t add_debugger_command_alias(const char* newName,
const char* oldName, const char* description);
extern bool print_debugger_command_usage(const char* command);
extern void debug_set_demangle_hook(const char *(*hook)(const char *));
extern const char *debug_demangle(const char *);
extern const char *debug_demangle_symbol(const char* symbol, char* buffer,
size_t bufferSize, bool* _isObjectMethod);
extern status_t debug_get_next_demangled_argument(uint32* _cookie,
const char* symbol, char* name, size_t nameSize,
int32* _type, size_t* _argumentLength);
extern struct thread* debug_set_debugged_thread(struct thread* thread);
extern struct thread* debug_get_debugged_thread();

View File

@ -1,43 +1,35 @@
SubDir HAIKU_TOP src add-ons kernel debugger demangle ;
if $(HAIKU_GCC_VERSION[1]) >= 4 {
UsePrivateHeaders kernel ;
UseHeaders [ FDirName $(HAIKU_TOP) src system kernel debug ] ;
# GCC3/4 only solution (using parts of libsubc++)
if $(HAIKU_GCC_VERSION[1]) >= 3 {
rule ExtractObject
{
SetupKernel $(2) ;
Depends $(1) : $(2) ;
Objects $(1) ;
rule ExtractObject
{
SetupKernel $(2) ;
Depends $(1) : $(2) ;
Objects $(1) ;
MakeLocateDebug $(1) ;
}
MakeLocateDebug $(1) ;
}
actions ExtractObject
{
#$(TARGET_AR) $(LINKFLAGS) -o "$(1)" "$(2)" $(LINKLIBS) ;
pwd
echo $(TARGET_AR) -x "$(2)" "$(1)"
}
actions ExtractObject
{
#$(TARGET_AR) $(LINKFLAGS) -o "$(1)" "$(2)" $(LINKLIBS) ;
pwd
echo $(TARGET_AR) -x "$(2)" "$(1)"
}
ExtractObject cp-demangle.o : $(TARGET_STATIC_LIBSUPC++) foo ;
ExtractObject cp-demangle.o : $(TARGET_STATIC_LIBSUPC++) foo ;
KernelMergeObject demangle_module.o :
demangle.cpp
:
:
;
KernelAddon <kdebug>demangle :
demangle.cpp
#demangle_module.o
cp-demangle.o
KernelAddon <kdebug>gcc3+ :
gcc3+.cpp
cp-demangle.o
;
#LINKFLAGS on <kdebug>demangle = -lsupc++ ;
}
# GCC2 solution
KernelAddon <kdebug>gcc2 :
gcc2.cpp
;

View File

@ -0,0 +1,394 @@
/*
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <TypeConstants.h>
#include <debug.h>
enum {
TYPE_FUNCTION,
TYPE_METHOD,
};
static void
ignore_qualifiers(const char** _arg)
{
while (isupper(**_arg))
(*_arg)++;
}
static uint32
argument_type(const char* arg, size_t& length)
{
length = sizeof(int);
switch (char type = arg[0]) {
case 'P': // pointer
case 'R': // reference
length = sizeof(void*);
ignore_qualifiers(&arg);
if (arg[0] == 'c')
return B_STRING_TYPE;
return type == 'P' ? B_POINTER_TYPE : B_REF_TYPE;
case 'x':
length = sizeof(long long);
return B_INT64_TYPE;
case 'l':
if (sizeof(long) == 4)
return B_INT32_TYPE;
return B_INT64_TYPE;
case 'i':
return B_INT32_TYPE;
case 's':
return B_INT16_TYPE;
case 'c':
return B_INT8_TYPE;
case 'b':
return B_BOOL_TYPE;
case 'U':
switch (arg[1]) {
case 'x':
length = sizeof(long long);
return B_UINT64_TYPE;
case 'l':
if (sizeof(long) == 4)
return B_UINT32_TYPE;
return B_UINT64_TYPE;
case 'i':
return B_UINT32_TYPE;
case 's':
return B_UINT16_TYPE;
case 'c':
return B_UINT8_TYPE;
default:
return B_UINT32_TYPE;
}
break;
default:
return B_ANY_TYPE;
}
}
static uint32
parse_number(const char** _arg, bool numberLeft)
{
const char* arg = *_arg;
while (isdigit(arg[0]))
arg++;
uint32 value;
if (arg[0] == '_' && (!numberLeft || isdigit(arg[1]))) {
// long value
value = strtoul(*_arg, (char**)_arg, 10);
if (**_arg == '_')
(*_arg)++;
} else {
value = **_arg - '0';
(*_arg)++;
}
return value;
}
static uint32
parse_repeats(const char** _arg, uint32& index)
{
if (**_arg != 'N')
return 0;
(*_arg)++;
uint32 count = parse_number(_arg, true);
index = parse_number(_arg, false);
return count;
}
static void
skip_numbers(const char** _arg, int32 count)
{
// skip leading character
(*_arg)++;
while (count-- > 0) {
parse_number(_arg, count != 0);
}
}
static uint32
argument_name_length(const char** _arg)
{
if (**_arg == 'N')
return 0;
ignore_qualifiers(_arg);
// See if it's a built-in type
if (isalpha(**_arg))
return 0;
return strtoul(*_arg, (char**)_arg, 10);
}
static uint32
argument_length(const char** _arg)
{
if (**_arg == 'N') {
// skip repeats
skip_numbers(_arg, 2);
return 0;
} else if (**_arg == 'T') {
// skip reference
skip_numbers(_arg, 1);
return 0;
}
ignore_qualifiers(_arg);
// See if it's a built-in type
if (isalpha(**_arg))
return 1;
return strtoul(*_arg, (char**)_arg, 10);
}
static const char*
next_argument(const char* arg)
{
if (arg == NULL)
return NULL;
uint32 length = argument_length(&arg);
arg += length;
if (!arg[0])
return NULL;
return arg;
}
static uint32
count_namespaces(const char** _mangled)
{
const char* mangled = *_mangled;
int32 namespaces = 0;
if (mangled[0] == 'Q') {
// more than one namespace
if (mangled[1] == '_') {
// more than 9 namespaces
namespaces = strtoul(mangled + 1, (char**)&mangled, 10);
if (mangled[0] != '_')
namespaces = 0;
} else
namespaces = mangled[1] - '0';
mangled++;
} else if (isdigit(mangled[0]))
namespaces = 1;
*_mangled = mangled;
return namespaces;
}
static const char*
first_argument(const char* mangled)
{
int32 namespaces = count_namespaces(&mangled);
while (namespaces-- > 0) {
if (!isdigit(mangled[0]))
break;
mangled += strtoul(mangled, (char**)&mangled, 10);
}
return mangled;
}
static const char*
mangled_start(const char* name, size_t* _symbolLength, int32* _symbolType)
{
if (name == NULL)
return NULL;
const char* mangled = strstr(name, "__");
if (mangled == NULL)
return NULL;
if (_symbolLength != NULL)
*_symbolLength = mangled - name;
if (mangled[2] == 'F') {
if (_symbolType != NULL)
*_symbolType = TYPE_FUNCTION;
return mangled + 3;
}
if (_symbolType != NULL)
*_symbolType = TYPE_METHOD;
return mangled + 2;
}
// #pragma mark -
const char*
demangle_symbol(const char* name, char* buffer, size_t bufferSize,
bool* _isObjectMethod)
{
size_t nameLength;
int32 type;
const char* mangled = mangled_start(name, &nameLength, &type);
if (mangled == NULL)
return NULL;
if (_isObjectMethod != NULL) {
// we can only guess with GCC2 mangling
*_isObjectMethod = type == TYPE_METHOD;
}
const char* namespaceStart = mangled;
int32 namespaces = count_namespaces(&namespaceStart);
buffer[0] = '\0';
while (namespaces-- > 0) {
if (!isdigit(namespaceStart[0]))
break;
uint32 length = strtoul(namespaceStart, (char**)&namespaceStart, 10);
uint32 max = strlen(buffer) + length + 1;
strlcat(buffer, namespaceStart, min_c(max, bufferSize));
strlcat(buffer, "::", bufferSize);
namespaceStart += length;
}
size_t max = strlen(buffer) + nameLength + 1;
strlcat(buffer, name, min_c(max, bufferSize));
return buffer;
}
status_t
get_next_argument(uint32* _cookie, const char* symbol, char* name,
size_t nameSize, int32* _type, size_t* _argumentLength)
{
const char* mangled = mangled_start(symbol, NULL, NULL);
if (mangled == NULL)
return B_BAD_VALUE;
const char* arg = first_argument(mangled);
// (void) is not an argument
if (arg != NULL && arg[0] == 'v')
return B_ENTRY_NOT_FOUND;
uint32 current = *_cookie;
for (uint32 i = 0; i < current; i++) {
arg = next_argument(arg);
if (arg != NULL && arg[0] == 'N') {
// repeat argument 'count' times
uint32 index;
uint32 count = parse_repeats(&arg, index);
if (current <= i + count) {
// it's a repeat case
status_t status = get_next_argument(&index, symbol, name,
nameSize, _type, _argumentLength);
if (status == B_OK)
(*_cookie)++;
return status;
}
i += count - 1;
}
}
if (arg == NULL)
return B_ENTRY_NOT_FOUND;
if (arg[0] == 'T') {
// duplicate argument
arg++;
uint32 index = parse_number(&arg, false);
status_t status = get_next_argument(&index, symbol, name,
nameSize, _type, _argumentLength);
if (status == B_OK)
(*_cookie)++;
return status;
}
(*_cookie)++;
size_t argumentLength;
int32 type = argument_type(arg, argumentLength);
if (_type != NULL)
*_type = type;
if (_argumentLength != NULL)
*_argumentLength = argumentLength;
uint32 length = argument_name_length(&arg);
strlcpy(name, arg, min_c(length + 1, nameSize));
return B_OK;
}
static status_t
std_ops(int32 op, ...)
{
#if __GNUC__ != 2
return B_NOT_SUPPORTED;
#else
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_BAD_VALUE;
#endif
}
static struct debugger_demangle_module_info sModuleInfo = {
{
"debugger/demangle/gcc2/v1",
0,
std_ops
},
demangle_symbol,
get_next_argument,
};
module_info *modules[] = {
(module_info *)&sModuleInfo,
NULL
};

View File

@ -2,23 +2,26 @@
* Copyright 2008, François Revol, revol@free.fr
* Distributed under the terms of the MIT License.
*/
#include <ctype.h>
#include <cxxabi.h>
#include <debug.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <debug.h>
#define DEMANGLE_BUFFER_SIZE (16*1024)
static char sDemangleBuffer[DEMANGLE_BUFFER_SIZE];
extern "C" void set_debug_demangle_hook(const char *(*demangle_hook)(const char *));
/* gcc's __cxa_demangle calls malloc and friends...
* we don't want to let it call the real one from inside the kernel debugger...
* we don't want to let it call the real one from inside the kernel debugger...
* instead we just return it a static buffer.
*/
void *malloc(size_t len)
void *
malloc(size_t len)
{
if (len < DEMANGLE_BUFFER_SIZE)
return sDemangleBuffer;
@ -26,12 +29,14 @@ void *malloc(size_t len)
}
void free(void *ptr)
void
free(void *ptr)
{
}
void *realloc(void * old_ptr, size_t new_size)
void *
realloc(void * oldPtr, size_t newSize)
{
return NULL;
}
@ -134,7 +139,10 @@ DemangleDebugOutputFilter::Print(const char* format, va_list args)
}
#endif
static const char *kdebug_demangle(const char *sym)
static const char *
demangle_symbol(const char *sym, char* buffer, size_t bufferSize,
bool* _isObjectMethod)
{
char *demangled;
size_t length = DEMANGLE_BUFFER_SIZE;
@ -147,47 +155,19 @@ static const char *kdebug_demangle(const char *sym)
return sym;
}
static void
exit_debugger()
{
}
static status_t
std_ops(int32 op, ...)
{
if (op == B_MODULE_INIT) {
#if 0
DebugOutputFilter *old;
DemangleDebugOutputFilter *filter = new(std::nothrow) DemangleDebugOutputFilter;
old = set_debug_output_filter(filter);
filter->SetChain(old);
#endif
debug_set_demangle_hook(kdebug_demangle);
return B_OK;
} else if (op == B_MODULE_UNINIT) {
return B_OK;
}
return B_BAD_VALUE;
}
static struct debugger_module_info sModuleInfo = {
static struct debugger_demangle_module_info sModuleInfo = {
{
"debugger/demangle/v1",
B_KEEP_LOADED,
&std_ops
"debugger/demangle/gcc3+/v1",
0,
NULL
},
demangle_symbol,
NULL,
exit_debugger,
NULL,
NULL
};
module_info *modules[] = {
module_info *modules[] = {
(module_info *)&sModuleInfo,
NULL
};

View File

@ -99,10 +99,6 @@ lookup_symbol(struct thread* thread, addr_t address, addr_t *_baseAddress,
}
}
if (status == B_OK) {
*_symbolName = debug_demangle(*_symbolName);
}
return status;
}
@ -126,11 +122,17 @@ print_stack_frame(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp,
status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image,
&exactMatch);
char buffer[64];
const char* name = debug_demangle_symbol(symbol, buffer, sizeof(buffer),
NULL);
if (name == NULL)
name = symbol;
kprintf("%2ld %08lx (+%4ld) %08lx", callIndex, ebp, diff, eip);
if (status == B_OK) {
if (symbol != NULL) {
kprintf(" <%s>:%s + 0x%04lx%s\n", image, symbol,
if (name != NULL) {
kprintf(" <%s>:%s + 0x%04lx%s\n", image, name,
eip - baseAddress, exactMatch ? "" : " (nearest)");
} else {
kprintf(" <%s@%p>:unknown + 0x%04lx\n", image,
@ -436,6 +438,15 @@ stack_trace(int argc, char **argv)
}
static void
set_debug_argument_variable(int32 index, uint64 value)
{
char name[8];
snprintf(name, sizeof(name), "_arg%ld", index);
set_debug_variable(name, value);
}
static void
print_call(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp,
int32 argCount)
@ -444,6 +455,9 @@ print_call(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp,
addr_t baseAddress;
bool exactMatch;
status_t status;
char buffer[64];
const char* name = NULL;
bool isObjectMethod;
status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image,
&exactMatch);
@ -452,8 +466,16 @@ print_call(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp,
if (status == B_OK) {
if (symbol != NULL) {
kprintf(" <%s>:%s%s", image, symbol,
exactMatch ? "" : " (nearest)");
if (exactMatch && argCount <= 0) {
name = debug_demangle_symbol(symbol, buffer, sizeof(buffer),
&isObjectMethod);
if (argCount < 0)
isObjectMethod = false;
}
if (name == NULL) {
kprintf(" <%s>:%s%s", image, symbol,
exactMatch ? "" : " (nearest)");
}
} else {
kprintf(" <%s@%p>:unknown + 0x%04lx", image,
(void *)baseAddress, eip - baseAddress);
@ -469,20 +491,114 @@ print_call(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp,
}
int32 *arg = (int32 *)(nextEbp + 8);
kprintf("(");
for (int32 i = 0; i < argCount; i++) {
if (i > 0)
kprintf(", ");
kprintf("%#lx", *arg);
if (*arg > -0x10000 && *arg < 0x10000)
kprintf(" (%ld)", *arg);
if (name != NULL) {
if (isObjectMethod) {
const char* lastName = strrchr(name, ':') - 1;
int namespaceLength = lastName - name;
char name[8];
snprintf(name, sizeof(name), "_arg%ld", i + 1);
set_debug_variable(name, *(uint32 *)arg);
kprintf(" <%s> %.*s<%p>%s", image, namespaceLength, name,
*(uint32 **)arg, lastName);
set_debug_variable("_this", *(uint32 *)arg);
arg++;
} else
kprintf(" <%s> %s", image, name);
arg++;
kprintf("(");
char buffer[64];
size_t length;
int32 type, i = 0;
uint32 cookie = 0;
while (debug_get_next_demangled_argument(&cookie, symbol, buffer,
sizeof(buffer), &type, &length) == B_OK) {
if (i++ > 0)
kprintf(", ");
// retrieve value and type identifier
uint64 value;
switch (type) {
case B_INT64_TYPE:
value = *(int64*)arg;
kprintf("int64: %Ld", value);
break;
case B_INT32_TYPE:
value = *(int32*)arg;
kprintf("int32: %ld", (int32)value);
break;
case B_INT16_TYPE:
value = *(int16*)arg;
kprintf("int16: %d", (int16)value);
break;
case B_INT8_TYPE:
value = *(int8*)arg;
kprintf("int8: %d", (int8)value);
break;
case B_UINT64_TYPE:
value = *(uint64*)arg;
kprintf("uint64: %Lx", value);
if (value < 0x100000)
kprintf(" (%Lu)", value);
break;
case B_UINT32_TYPE:
value = *(uint32*)arg;
kprintf("uint32: %lx", (uint32)value);
if (value < 0x100000)
kprintf(" (%lu)", (uint32)value);
break;
case B_UINT16_TYPE:
value = *(uint16*)arg;
kprintf("uint16: %#x (%u)", (uint16)value, (uint16)value);
break;
case B_UINT8_TYPE:
value = *(uint8*)arg;
kprintf("uint8: %#x (%u)", (uint8)value, (uint8)value);
break;
case B_BOOL_TYPE:
value = *(uint8*)arg;
kprintf(value ? "true" : "false");
break;
default:
if (buffer[0]) {
kprintf("%s%s: ", buffer, type == B_POINTER_TYPE ? "*"
: type == B_REF_TYPE ? "&" : "");
}
if (length == 4) {
value = *(uint32*)arg;
kprintf("%#lx", (uint32)value);
break;
}
if (length == 8)
value = *(uint64*)arg;
else
value = (uint64)arg;
kprintf("%#Lx", value);
break;
}
if (type == B_STRING_TYPE && value != 0)
kprintf(" \"%s\"", (char*)value);
set_debug_argument_variable(i, value);
arg = (int32*)((uint8*)arg + length);
}
} else {
kprintf("(");
for (int32 i = 0; i < argCount; i++) {
if (i > 0)
kprintf(", ");
kprintf("%#lx", *arg);
if (*arg > -0x10000 && *arg < 0x10000)
kprintf(" (%ld)", *arg);
set_debug_argument_variable(i + 1, *(uint32 *)arg);
arg++;
}
}
kprintf(")\n");
@ -500,7 +616,8 @@ show_call(int argc, char **argv)
"the specified thread.\n"
" <thread id> - The ID of the thread for which to print the call.\n"
" <call index> - The index of the call in the stack trace.\n"
" <arg count> - The number of call arguments to print.\n";
" <arg count> - The number of call arguments to print (use 'c' to\n"
" force the C++ demangler to use class methods).\n";
if (argc == 2 && strcmp(argv[1], "--help") == 0) {
kprintf(usage, argv[0]);
return 0;
@ -512,8 +629,11 @@ show_call(int argc, char **argv)
int32 argCount = 0;
if (argc >= 2 && argv[argc - 1][0] == '-') {
argCount = strtoul(argv[argc - 1] + 1, NULL, 0);
if (argCount < 0 || argCount > 16) {
if (argv[argc - 1][1] != 'c')
argCount = strtoul(argv[argc - 1] + 1, NULL, 0);
else
argCount = -1;
if (argCount < -1 || argCount > 16) {
kprintf("Invalid argument count \"%ld\".\n", argCount);
return 0;
}

View File

@ -81,7 +81,7 @@ static int64 sMessageRepeatFirstTime = 0;
static int64 sMessageRepeatLastTime = 0;
static int32 sMessageRepeatCount = 0;
static debugger_module_info *sDebuggerModules[8];
static debugger_module_info* sDebuggerModules[8];
static const uint32 kMaxDebuggerModules = sizeof(sDebuggerModules)
/ sizeof(sDebuggerModules[0]);
@ -91,7 +91,7 @@ static const uint32 kMaxDebuggerModules = sizeof(sDebuggerModules)
static char sLineBuffer[HISTORY_SIZE][LINE_BUFFER_SIZE] = { "", };
static int32 sCurrentLine = 0;
static const char *(*sDemangleHook)(const char *) = NULL;
static debugger_demangle_module_info* sDemangleModule;
static struct thread* sDebuggedThread;
@ -1105,7 +1105,7 @@ debug_init_post_vm(kernel_args *args)
status_t
debug_init_post_modules(struct kernel_args *args)
debug_init_post_modules(struct kernel_args* args)
{
void *cookie;
@ -1115,6 +1115,9 @@ debug_init_post_modules(struct kernel_args *args)
syslog_init_post_threads();
// load kernel debugger addons
static const char* kDemanglePrefix = "debugger/demangle/";
cookie = open_module_list("debugger");
uint32 count = 0;
while (count < kMaxDebuggerModules) {
@ -1124,7 +1127,14 @@ debug_init_post_modules(struct kernel_args *args)
if (read_next_module_name(cookie, name, &nameLength) != B_OK)
break;
if (get_module(name, (module_info **)&sDebuggerModules[count]) == B_OK) {
// get demangle module, if any
if (!strncmp(name, kDemanglePrefix, strlen(kDemanglePrefix))) {
if (sDemangleModule == NULL)
get_module(name, (module_info**)&sDemangleModule);
continue;
}
if (get_module(name, (module_info**)&sDebuggerModules[count]) == B_OK) {
dprintf("kernel debugger extension \"%s\": loaded\n", name);
count++;
} else
@ -1273,9 +1283,10 @@ flush_pending_repeats(void)
syslog_write(temp, length);
if (sBlueScreenEnabled || sDebugScreenEnabled)
blue_screen_puts(temp);
for (i = 0; sSerialDebugEnabled && i < kMaxDebuggerModules; i++)
for (i = 0; sSerialDebugEnabled && i < kMaxDebuggerModules; i++) {
if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_puts)
sDebuggerModules[i]->debugger_puts(temp, length);
}
} else {
// if we only have one repeat just reprint the last buffer
if (sSerialDebugEnabled)
@ -1284,9 +1295,12 @@ flush_pending_repeats(void)
syslog_write(sLastOutputBuffer, strlen(sLastOutputBuffer));
if (sBlueScreenEnabled || sDebugScreenEnabled)
blue_screen_puts(sLastOutputBuffer);
for (i = 0; sSerialDebugEnabled && i < kMaxDebuggerModules; i++)
if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_puts)
sDebuggerModules[i]->debugger_puts(sLastOutputBuffer, strlen(sLastOutputBuffer));
for (i = 0; sSerialDebugEnabled && i < kMaxDebuggerModules; i++) {
if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_puts) {
sDebuggerModules[i]->debugger_puts(sLastOutputBuffer,
strlen(sLastOutputBuffer));
}
}
}
sMessageRepeatFirstTime = 0;
@ -1348,9 +1362,10 @@ dprintf_args(const char *format, va_list args, bool syslogOutput)
syslog_write(sOutputBuffer, length);
if (sBlueScreenEnabled || sDebugScreenEnabled)
blue_screen_puts(sOutputBuffer);
for (i = 0; sSerialDebugEnabled && i < kMaxDebuggerModules; i++)
for (i = 0; sSerialDebugEnabled && i < kMaxDebuggerModules; i++) {
if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_puts)
sDebuggerModules[i]->debugger_puts(sOutputBuffer, length);
}
memcpy(sLastOutputBuffer, sOutputBuffer, length);
sLastOutputBuffer[length] = 0;
@ -1414,19 +1429,29 @@ kprintf_unfiltered(const char *format, ...)
}
extern void
debug_set_demangle_hook(const char *(*hook)(const char *))
const char*
debug_demangle_symbol(const char* symbol, char* buffer, size_t bufferSize,
bool* _isObjectMethod)
{
sDemangleHook = hook;
if (sDemangleModule != NULL && sDemangleModule->demangle_symbol != NULL) {
return sDemangleModule->demangle_symbol(symbol, buffer, bufferSize,
_isObjectMethod);
}
return symbol;
}
extern const char *
debug_demangle(const char *sym)
status_t
debug_get_next_demangled_argument(uint32* _cookie, const char* symbol,
char* name, size_t nameSize, int32* _type, size_t* _argumentLength)
{
if (sDemangleHook)
return sDemangleHook(sym);
return sym;
if (sDemangleModule != NULL && sDemangleModule->get_next_argument != NULL) {
return sDemangleModule->get_next_argument(_cookie, symbol, name,
nameSize, _type, _argumentLength);
}
return B_NOT_SUPPORTED;
}