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:
X512
2021-08-06 15:19:22 +00:00
committed by Alex von Gluck IV
parent 4a32f48e70
commit e013897fcf
3 changed files with 363 additions and 7 deletions
@@ -9,8 +9,17 @@
#include <SupportDefs.h> #include <SupportDefs.h>
struct kernel_args;
struct arch_debug_registers { 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 #endif // _KERNEL_ARCH_RISCV64_DEBUG_H
+297 -3
View File
@@ -8,11 +8,283 @@
#include <arch/debug.h> #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 void
arch_debug_stack_trace(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 void
arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer, arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer,
void (*function)(void*), void* parameter) 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 status_t
arch_debug_init(kernel_args *args) arch_debug_init(kernel_args *args)
{ {
#if 0 sInitCalled = true;
add_debugger_command("where", &stack_trace, "Same as \"sc\""); add_debugger_command("where", &stack_trace, "Same as \"sc\"");
add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); 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/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 <boot/kernel_args.h>
#include <kernel.h> #include <kernel.h>
#include <vm/vm.h> #include <vm/vm.h>
#include <Htif.h>
#include <string.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 void
arch_debug_remove_interrupt_handler(uint32 line) arch_debug_remove_interrupt_handler(uint32 line)
{ {
@@ -52,6 +77,9 @@ arch_debug_serial_try_getchar(void)
char char
arch_debug_serial_getchar(void) arch_debug_serial_getchar(void)
{ {
if (sArchDebugUART != NULL)
return sArchDebugUART->GetChar(false);
return 0; return 0;
} }
@@ -59,6 +87,12 @@ arch_debug_serial_getchar(void)
void void
arch_debug_serial_putchar(const char c) 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) arch_debug_serial_puts(const char *s)
{ {
while (*s != '\0') { 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++; s++;
} }
} }
@@ -75,13 +114,29 @@ arch_debug_serial_puts(const char *s)
void void
arch_debug_serial_early_boot_message(const char *string) 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 status_t
arch_debug_console_init(kernel_args *args) 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; return B_OK;
} }
@@ -91,5 +146,3 @@ arch_debug_console_init_settings(kernel_args *args)
{ {
return B_OK; return B_OK;
} }