syscalls: Add get_stack_trace and lookup_symbol syscalls.

The get_stack_trace syscall generates a stack trace using the kernel
debugging facilities and copies the resulting return address array to
the preallocated buffer from userland. It is only possible to get a
stack trace of the current thread.

The lookup_symbol syscall can be used to look up the symbol and image
name corresponding to an address. It can be used to resolve symbols
from a stack trace generated by the get_stack_trace syscall. Only
symbols of the current team can be looked up. Note that this uses
the symbol lookup of the kernel debugger which does not support lookup
of all symbols (static functions are missing for example).

This is meant to be used in situations where more elaborate stack trace
generation, like done in the userland debugging helpers, is not possible
due to constraints.
This commit is contained in:
Michael Lotz 2015-04-10 15:44:58 +02:00
parent e01de52283
commit b959d46dbd
5 changed files with 69 additions and 0 deletions

View File

@ -54,6 +54,11 @@ status_t _user_read_kernel_image_symbols(image_id id, elf_sym* symbolTable,
int32* _symbolCount, char* stringTable, size_t* _stringTableSize,
addr_t* _imageDelta);
status_t _user_lookup_symbol(addr_t address, addr_t* baseAddress,
char* symbolNameBuffer, size_t symbolNameBufferSize,
char* imageNameBuffer, size_t imageNameBufferSize,
bool* exactMatch);
#ifdef __cplusplus
}
#endif

View File

@ -289,6 +289,7 @@ status_t _user_set_debugger_breakpoint(void *address, uint32 type,
int32 length, bool watchpoint);
status_t _user_clear_debugger_breakpoint(void *address, bool watchpoint);
ssize_t _user_get_stack_trace(size_t addressCount, addr_t* returnAddresses);
#ifdef __cplusplus
} // extern "C"

View File

@ -492,6 +492,13 @@ extern status_t _kern_system_profiler_stop();
extern status_t _kern_system_profiler_recorded(
struct system_profiler_parameters* parameters);
extern ssize_t _kern_get_stack_trace(size_t addressCount,
addr_t* adresses);
extern status_t _kern_lookup_symbol(addr_t address, addr_t* baseAddress,
char* symbolNameBuffer, size_t symbolNameBufferSize,
char* imageNameBuffer, size_t imageNameBufferSize,
bool* exactMatch);
/* atomic_* ops (needed for CPUs that don't support them directly) */
#ifdef ATOMIC_FUNCS_ARE_SYSCALLS
extern void _kern_atomic_set(int32 *value, int32 newValue);

View File

@ -3000,3 +3000,21 @@ _user_clear_debugger_breakpoint(void *address, bool watchpoint)
return result;
}
ssize_t
_user_get_stack_trace(size_t addressCount, addr_t* userReturnAddresses)
{
addr_t returnAddresses[addressCount];
int32 readCount = arch_debug_get_stack_trace(returnAddresses, addressCount,
1, 0, STACK_TRACE_KERNEL | STACK_TRACE_USER);
if (readCount < 0)
return readCount;
status_t copyResult = user_memcpy(userReturnAddresses, returnAddresses,
readCount * sizeof(addr_t));
if (copyResult != B_OK)
return copyResult;
return readCount;
}

View File

@ -2686,3 +2686,41 @@ _user_read_kernel_image_symbols(image_id id, elf_sym* symbolTable,
return B_OK;
}
status_t
_user_lookup_symbol(addr_t address, addr_t* userBaseAddress,
char* userSymbolNameBuffer, size_t symbolNameBufferSize,
char* userImageNameBuffer, size_t imageNameBufferSize, bool* userExactMatch)
{
MutexLocker locker(&sImageMutex);
addr_t baseAddress;
const char *symbolName;
const char *imageName;
bool exactMatch;
status_t status;
if (IS_KERNEL_ADDRESS(address)) {
status = elf_debug_lookup_symbol_address(address, &baseAddress,
&symbolName, &imageName, &exactMatch);
} else {
status = elf_debug_lookup_user_symbol_address(
thread_get_current_thread()->team, address, &baseAddress,
&symbolName, &imageName, &exactMatch);
}
if (status != B_OK)
return status;
if (user_memcpy(userBaseAddress, &baseAddress, sizeof(addr_t)) != B_OK
|| user_memcpy(userExactMatch, &exactMatch, sizeof(bool)) != B_OK
|| user_strlcpy(userSymbolNameBuffer, symbolName, symbolNameBufferSize)
< 0
|| user_strlcpy(userImageNameBuffer, imageName, imageNameBufferSize)
< 0) {
return B_BAD_ADDRESS;
}
return B_OK;
}