kernel/arch/debug: implement for riscv64
Change-Id: Iab5cc9ef4059f968bca03683592d1ec1818a26a2 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4053 Reviewed-by: Alex von Gluck IV <[email protected]>
This commit is contained in:
@@ -9,8 +9,17 @@
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
struct kernel_args;
|
||||
|
||||
struct arch_debug_registers {
|
||||
};
|
||||
|
||||
|
||||
void WritePC(addr_t pc);
|
||||
void DoStackTrace(addr_t fp, addr_t pc);
|
||||
void WriteTrapInfo();
|
||||
|
||||
status_t arch_debug_init_early(kernel_args *args);
|
||||
|
||||
|
||||
#endif // _KERNEL_ARCH_RISCV64_DEBUG_H
|
||||
|
||||
@@ -8,11 +8,283 @@
|
||||
|
||||
|
||||
#include <arch/debug.h>
|
||||
#include <vm/VMAddressSpace.h>
|
||||
#include <vm/VMArea.h>
|
||||
#include <elf.h>
|
||||
#include <kimage.h>
|
||||
#include <arch/generic/user_memory.h>
|
||||
#include <AutoDeleterDrivers.h>
|
||||
|
||||
|
||||
kernel_args *sKernelArgs;
|
||||
bool sInitCalled = false;
|
||||
|
||||
|
||||
static void
|
||||
WriteImage(preloaded_image* _image)
|
||||
{
|
||||
preloaded_elf64_image* image = (preloaded_elf64_image*)_image;
|
||||
dprintf("image %p\n", image);
|
||||
dprintf("image \"%s\"\n", (char*)image->name);
|
||||
dprintf(" text: 0x%" B_PRIxADDR " - 0x%" B_PRIxADDR ",%"
|
||||
B_PRIdSSIZE "\n", image->text_region.start,
|
||||
image->text_region.start + image->text_region.size,
|
||||
image->text_region.delta);
|
||||
dprintf(" data: 0x%" B_PRIxADDR " - 0x%" B_PRIxADDR ", %"
|
||||
B_PRIdSSIZE "\n", image->data_region.start,
|
||||
image->data_region.start + image->data_region.size,
|
||||
image->data_region.delta);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
WriteImages()
|
||||
{
|
||||
WriteImage(sKernelArgs->kernel_image);
|
||||
|
||||
preloaded_image* image = sKernelArgs->preloaded_images;
|
||||
while (image != NULL) {
|
||||
WriteImage(image);
|
||||
image = image->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
AddressInImage(preloaded_image* _image, addr_t adr)
|
||||
{
|
||||
preloaded_elf64_image* image = (preloaded_elf64_image*)_image;
|
||||
if (adr >= image->text_region.start
|
||||
&& adr < image->text_region.start + image->text_region.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (adr >= image->data_region.start
|
||||
&& adr < image->data_region.start + image->data_region.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
SymbolAt(preloaded_image* _image, addr_t adr, const char **name, ssize_t *ofs)
|
||||
{
|
||||
preloaded_elf64_image* image = (preloaded_elf64_image*)_image;
|
||||
adr -= image->text_region.delta;
|
||||
for (uint32 i = 0; i < image->num_debug_symbols; i++) {
|
||||
Elf64_Sym& sym = image->debug_symbols[i];
|
||||
if (sym.st_shndx != STN_UNDEF && adr >= sym.st_value
|
||||
&& adr < sym.st_value + sym.st_size) {
|
||||
if (name != NULL)
|
||||
*name = &image->debug_string_table[sym.st_name];
|
||||
if (ofs != NULL)
|
||||
*ofs = adr - sym.st_value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static preloaded_image*
|
||||
FindImage(addr_t adr)
|
||||
{
|
||||
if (AddressInImage(sKernelArgs->kernel_image, adr))
|
||||
return sKernelArgs->kernel_image;
|
||||
|
||||
preloaded_image* image = sKernelArgs->preloaded_images;
|
||||
while (image != NULL) {
|
||||
if (AddressInImage(image, adr))
|
||||
return image;
|
||||
image = image->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static VMArea*
|
||||
FindArea(addr_t adr)
|
||||
{
|
||||
if (IS_KERNEL_ADDRESS(adr)) {
|
||||
VMAddressSpacePutter addrSpace(VMAddressSpace::GetKernel());
|
||||
return addrSpace->LookupArea(adr);
|
||||
}
|
||||
if (IS_USER_ADDRESS(adr)) {
|
||||
VMAddressSpacePutter addrSpace(VMAddressSpace::GetCurrent());
|
||||
return addrSpace->LookupArea(adr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
lookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress,
|
||||
const char** _symbolName, const char** _imageName, bool* _exactMatch)
|
||||
{
|
||||
status_t status = B_ENTRY_NOT_FOUND;
|
||||
|
||||
if (IS_KERNEL_ADDRESS(address)) {
|
||||
// a kernel symbol
|
||||
status = elf_debug_lookup_symbol_address(address, _baseAddress,
|
||||
_symbolName, _imageName, _exactMatch);
|
||||
} else if (true && thread != NULL && thread->team != NULL) {
|
||||
// try a lookup using the userland runtime loader structures
|
||||
status = elf_debug_lookup_user_symbol_address(thread->team, address,
|
||||
_baseAddress, _symbolName, _imageName, _exactMatch);
|
||||
|
||||
if (status != B_OK) {
|
||||
// try to locate the image in the images loaded into user space
|
||||
status = image_debug_lookup_user_symbol_address(thread->team,
|
||||
address, _baseAddress, _symbolName, _imageName, _exactMatch);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WritePCBoot(addr_t pc)
|
||||
{
|
||||
preloaded_image* image = FindImage(pc);
|
||||
if (image != NULL) {
|
||||
const char *name;
|
||||
ssize_t ofs;
|
||||
if (SymbolAt(image, pc, &name, &ofs)) {
|
||||
dprintf("<%s> %s + %" B_PRIdSSIZE, (char*)image->name, name, ofs);
|
||||
return;
|
||||
}
|
||||
dprintf("<%s> 0x%" B_PRIxADDR, (char*)image->name,
|
||||
pc - ((preloaded_elf64_image*)image)->text_region.delta);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
VMArea* area = FindArea(pc);
|
||||
if (area != NULL) {
|
||||
dprintf("<%s> 0x%" B_PRIxADDR, area->name, pc - area->Base());
|
||||
return;
|
||||
}
|
||||
*/
|
||||
dprintf("0x%" B_PRIxADDR, pc);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WritePC(addr_t pc)
|
||||
{
|
||||
dprintf("0x%" B_PRIxADDR " ", pc);
|
||||
if (!sInitCalled) {
|
||||
WritePCBoot(pc); return;
|
||||
}
|
||||
|
||||
addr_t baseAddress;
|
||||
const char* symbolName;
|
||||
const char* imageName;
|
||||
bool exactMatch;
|
||||
if (lookup_symbol(thread_get_current_thread(), pc, &baseAddress,
|
||||
&symbolName, &imageName, &exactMatch) >= B_OK) {
|
||||
if (symbolName != NULL) {
|
||||
dprintf("<%s> %s + %" B_PRIdSSIZE, imageName, symbolName,
|
||||
pc - baseAddress);
|
||||
return;
|
||||
}
|
||||
dprintf("<%s> 0x%" B_PRIxADDR, imageName, pc - baseAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
VMArea* area = FindArea(pc);
|
||||
if (area != NULL) {
|
||||
dprintf("<%s> 0x%" B_PRIxADDR, area->name, pc - area->Base());
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("0x%" B_PRIxADDR, pc);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
DumpMemory(uint64* adr, size_t len)
|
||||
{
|
||||
while (len > 0) {
|
||||
if ((addr_t)adr % 0x10 == 0)
|
||||
dprintf("%08" B_PRIxADDR " ", (addr_t)adr);
|
||||
uint64 val;
|
||||
if (user_memcpy(&val, adr++, sizeof(val)) < B_OK) {
|
||||
dprintf(" ????????????????");
|
||||
} else {
|
||||
dprintf(" %016" B_PRIx64, val);
|
||||
}
|
||||
if ((addr_t)adr % 0x10 == 0)
|
||||
dprintf("\n");
|
||||
len -= 8;
|
||||
}
|
||||
if ((addr_t)adr % 0x10 != 0)
|
||||
dprintf("\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DoStackTrace(addr_t fp, addr_t pc)
|
||||
{
|
||||
dprintf("Stack:\n");
|
||||
dprintf("FP: 0x%" B_PRIxADDR, fp);
|
||||
if (pc != 0) {
|
||||
dprintf(", PC: "); WritePC(pc);
|
||||
}
|
||||
dprintf("\n");
|
||||
addr_t oldFp = fp;
|
||||
while (fp != 0) {
|
||||
if ((pc >= (addr_t)&strcpy && pc < (addr_t)&strcpy + 32)
|
||||
|| (pc >= (addr_t)&memset && pc < (addr_t)&memset + 34)) {
|
||||
if (user_memcpy(&fp, (uint64*)fp - 1, sizeof(pc)) < B_OK)
|
||||
break;
|
||||
pc = 0;
|
||||
} else {
|
||||
if (user_memcpy(&pc, (uint64*)fp - 1, sizeof(pc)) < B_OK)
|
||||
break;
|
||||
if (user_memcpy(&fp, (uint64*)fp - 2, sizeof(pc)) < B_OK)
|
||||
break;
|
||||
}
|
||||
dprintf("FP: 0x%" B_PRIxADDR, fp);
|
||||
dprintf(", PC: "); WritePC((pc == 0) ? 0 : pc - 1);
|
||||
dprintf("\n");
|
||||
/*
|
||||
if (IS_KERNEL_ADDRESS(oldFp) && IS_KERNEL_ADDRESS(fp))
|
||||
DumpMemory((uint64*)oldFp, (addr_t)fp - (addr_t)oldFp);
|
||||
*/
|
||||
oldFp = fp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
stack_trace(int argc, char **argv)
|
||||
{
|
||||
if (argc >= 2) {
|
||||
thread_id id = strtoul(argv[1], NULL, 0);
|
||||
Thread* thread = Thread::GetDebug(id);
|
||||
if (thread == NULL) {
|
||||
kprintf("could not find thread %" B_PRId32 "\n", id);
|
||||
return 0;
|
||||
}
|
||||
uint64 oldSatp = Satp();
|
||||
SetSatp(thread->arch_info.context.satp);
|
||||
DoStackTrace(thread->arch_info.context.s[0], thread->arch_info.context.ra);
|
||||
SetSatp(oldSatp);
|
||||
return 0;
|
||||
}
|
||||
DoStackTrace(Fp(), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_debug_stack_trace(void)
|
||||
{
|
||||
DoStackTrace(Fp(), 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,10 +309,22 @@ arch_debug_save_registers(struct arch_debug_registers* registers)
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((naked))
|
||||
HandleFault()
|
||||
{
|
||||
asm volatile("ld a0, 0(sp)");
|
||||
asm volatile("li a1, 1");
|
||||
asm volatile("call longjmp");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer,
|
||||
void (*function)(void*), void* parameter)
|
||||
{
|
||||
cpu->fault_handler = (addr_t)&HandleFault;
|
||||
cpu->fault_handler_stack_pointer = (addr_t)&jumpBuffer;
|
||||
function(parameter);
|
||||
}
|
||||
|
||||
|
||||
@@ -99,14 +383,24 @@ arch_debug_unset_current_thread(void)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_debug_init_early(kernel_args *args)
|
||||
{
|
||||
dprintf("arch_debug_init_early()\n");
|
||||
sKernelArgs = args;
|
||||
WriteImages();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_debug_init(kernel_args *args)
|
||||
{
|
||||
#if 0
|
||||
sInitCalled = true;
|
||||
|
||||
add_debugger_command("where", &stack_trace, "Same as \"sc\"");
|
||||
add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
|
||||
add_debugger_command("sc", &stack_trace, "Stack crawl for current thread");
|
||||
#endif
|
||||
|
||||
return B_NO_ERROR;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -8,13 +8,38 @@
|
||||
|
||||
|
||||
#include <arch/debug_console.h>
|
||||
#include <arch/generic/debug_uart.h>
|
||||
#include <arch/generic/debug_uart_8250.h>
|
||||
#include <arch/riscv64/arch_uart_sifive.h>
|
||||
#include <boot/kernel_args.h>
|
||||
#include <kernel.h>
|
||||
#include <vm/vm.h>
|
||||
#include <Htif.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static DebugUART* sArchDebugUART = NULL;
|
||||
|
||||
|
||||
DebugUART8250*
|
||||
arch_get_uart_8250(addr_t base, int64 clock)
|
||||
{
|
||||
static char buffer[sizeof(DebugUART8250)];
|
||||
DebugUART8250* uart = new(buffer) DebugUART8250(base, clock);
|
||||
return uart;
|
||||
}
|
||||
|
||||
|
||||
ArchUARTSifive*
|
||||
arch_get_uart_sifive(addr_t base, int64 clock)
|
||||
{
|
||||
static char buffer[sizeof(ArchUARTSifive)];
|
||||
ArchUARTSifive* uart = new(buffer) ArchUARTSifive(base, clock);
|
||||
return uart;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_debug_remove_interrupt_handler(uint32 line)
|
||||
{
|
||||
@@ -52,6 +77,9 @@ arch_debug_serial_try_getchar(void)
|
||||
char
|
||||
arch_debug_serial_getchar(void)
|
||||
{
|
||||
if (sArchDebugUART != NULL)
|
||||
return sArchDebugUART->GetChar(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -59,6 +87,12 @@ arch_debug_serial_getchar(void)
|
||||
void
|
||||
arch_debug_serial_putchar(const char c)
|
||||
{
|
||||
if (sArchDebugUART != NULL) {
|
||||
sArchDebugUART->PutChar(c);
|
||||
return;
|
||||
}
|
||||
|
||||
HtifOutChar(c);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +100,12 @@ void
|
||||
arch_debug_serial_puts(const char *s)
|
||||
{
|
||||
while (*s != '\0') {
|
||||
arch_debug_serial_putchar(*s);
|
||||
char ch = *s;
|
||||
if (ch == '\n') {
|
||||
arch_debug_serial_putchar('\r');
|
||||
arch_debug_serial_putchar('\n');
|
||||
} else if (ch != '\r')
|
||||
arch_debug_serial_putchar(ch);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
@@ -75,13 +114,29 @@ arch_debug_serial_puts(const char *s)
|
||||
void
|
||||
arch_debug_serial_early_boot_message(const char *string)
|
||||
{
|
||||
// this function will only be called in fatal situations
|
||||
arch_debug_serial_puts(string);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_debug_console_init(kernel_args *args)
|
||||
{
|
||||
switch (args->arch_args.uart.kind) {
|
||||
case kUartKind8250:
|
||||
sArchDebugUART = arch_get_uart_8250(args->arch_args.uart.regs.start,
|
||||
args->arch_args.uart.clock);
|
||||
break;
|
||||
case kUartKindSifive:
|
||||
sArchDebugUART = arch_get_uart_sifive(args->arch_args.uart.regs.start,
|
||||
args->arch_args.uart.clock);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
if (sArchDebugUART != NULL)
|
||||
sArchDebugUART->InitEarly();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -91,5 +146,3 @@ arch_debug_console_init_settings(kernel_args *args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user