* 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:
parent
36bde12db2
commit
ddecb4a7da
@ -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();
|
||||
|
@ -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
|
||||
;
|
||||
|
394
src/add-ons/kernel/debugger/demangle/gcc2.cpp
Normal file
394
src/add-ons/kernel/debugger/demangle/gcc2.cpp
Normal 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
|
||||
};
|
||||
|
@ -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
|
||||
};
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user