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>
|
#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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user