From 4730312c1e006e60d0064e747b7d2d2a0d874a20 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Tue, 26 Nov 2024 15:12:03 +0100 Subject: [PATCH] hw: register state and backtrace when core faults If one of core's threads is causing an MMU fault, dump the register state and stack backtrace of the faulting stack to aid debugging. Fix genodelabs/genode#5387 --- repos/base-hw/src/core/kernel/thread.cc | 20 +++++++-- repos/base-hw/src/core/spec/arm/cpu.cc | 26 ++++++++++++ repos/base-hw/src/core/spec/arm/cpu_support.h | 12 ++++++ repos/base-hw/src/core/spec/arm_v8/cpu.cc | 16 ++++++++ repos/base-hw/src/core/spec/arm_v8/cpu.h | 12 ++++++ repos/base-hw/src/core/spec/riscv/cpu.cc | 41 +++++++++++++++++++ repos/base-hw/src/core/spec/riscv/cpu.h | 5 +++ repos/base-hw/src/core/spec/x86_64/cpu.cc | 21 ++++++++++ repos/base-hw/src/core/spec/x86_64/cpu.h | 12 ++++++ 9 files changed, 161 insertions(+), 4 deletions(-) diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index 9a6374bf01..79fb99eeb3 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -935,19 +935,31 @@ void Thread::_call() void Thread::_mmu_exception() { + using namespace Genode; + using Genode::log; + _become_inactive(AWAITS_RESTART); _exception_state = MMU_FAULT; Cpu::mmu_fault(*regs, _fault); _fault.ip = regs->ip; if (_fault.type == Thread_fault::UNKNOWN) { - Genode::raw(*this, " raised unhandled MMU fault ", _fault); + Genode::warning(*this, " raised unhandled MMU fault ", _fault); return; } - if (_type != USER) - Genode::raw(*this, " raised a fault, which should never happen ", - _fault); + if (_type != USER) { + error(*this, " raised a fault, which should never happen ", + _fault); + log("Register dump: ", *regs); + log("Backtrace:"); + + Const_byte_range_ptr const stack { + (char const*)Hw::Mm::core_stack_area().base, + Hw::Mm::core_stack_area().size }; + regs->for_each_return_address(stack, [&] (void **p) { + log(*p); }); + } if (_pager && _pager->can_submit(1)) { _pager->submit(1); diff --git a/repos/base-hw/src/core/spec/arm/cpu.cc b/repos/base-hw/src/core/spec/arm/cpu.cc index 06e6f1baf5..697b9a0cf0 100644 --- a/repos/base-hw/src/core/spec/arm/cpu.cc +++ b/repos/base-hw/src/core/spec/arm/cpu.cc @@ -22,6 +22,32 @@ using namespace Core; +void Arm_cpu::Context::print(Output &output) const +{ + using namespace Genode; + using Genode::print; + + print(output, "\n"); + print(output, " r0 = ", Hex(r0), "\n"); + print(output, " r1 = ", Hex(r1), "\n"); + print(output, " r2 = ", Hex(r2), "\n"); + print(output, " r3 = ", Hex(r3), "\n"); + print(output, " r4 = ", Hex(r4), "\n"); + print(output, " r5 = ", Hex(r5), "\n"); + print(output, " r6 = ", Hex(r6), "\n"); + print(output, " r7 = ", Hex(r7), "\n"); + print(output, " r8 = ", Hex(r8), "\n"); + print(output, " r9 = ", Hex(r9), "\n"); + print(output, " r10 = ", Hex(r10), "\n"); + print(output, " r11 = ", Hex(r11), "\n"); + print(output, " r12 = ", Hex(r12), "\n"); + print(output, " ip = ", Hex(ip), "\n"); + print(output, " sp = ", Hex(sp), "\n"); + print(output, " lr = ", Hex(lr), "\n"); + print(output, " cpsr = ", Hex(cpsr)); +} + + Arm_cpu::Context::Context(bool privileged) { using Psr = Arm_cpu::Psr; diff --git a/repos/base-hw/src/core/spec/arm/cpu_support.h b/repos/base-hw/src/core/spec/arm/cpu_support.h index ef7fabdaf5..012b04eceb 100644 --- a/repos/base-hw/src/core/spec/arm/cpu_support.h +++ b/repos/base-hw/src/core/spec/arm/cpu_support.h @@ -49,6 +49,18 @@ struct Core::Arm_cpu : public Hw::Arm_cpu struct alignas(8) Context : Cpu_state, Fpu_context { Context(bool privileged); + + void print(Output &output) const; + + void for_each_return_address(Const_byte_range_ptr const &stack, + auto const &fn) + { + void **fp = (void**)r11; + while (stack.contains(fp-1) && stack.contains(fp) && fp[0]) { + fn(fp); + fp = (void **) fp[-1]; + } + } }; /** diff --git a/repos/base-hw/src/core/spec/arm_v8/cpu.cc b/repos/base-hw/src/core/spec/arm_v8/cpu.cc index e64e9f88e9..cca9f9c59e 100644 --- a/repos/base-hw/src/core/spec/arm_v8/cpu.cc +++ b/repos/base-hw/src/core/spec/arm_v8/cpu.cc @@ -22,6 +22,22 @@ using namespace Core; +void Cpu::Context::print(Output &output) const +{ + using namespace Genode; + using Genode::print; + + print(output, "\n"); + for (unsigned i = 0; i < 31; i++) + print(output, " x", i, " = ", Hex(r[i]), "\n"); + print(output, " ip = ", Hex(ip), "\n"); + print(output, " sp = ", Hex(sp), "\n"); + print(output, " esr = ", Hex(esr_el1), "\n"); + print(output, " pstate = ", Hex(pstate), "\n"); + print(output, " mdscr = ", Hex(mdscr_el1)); +} + + Cpu::Context::Context(bool privileged) { Spsr::El::set(pstate, privileged ? 1 : 0); diff --git a/repos/base-hw/src/core/spec/arm_v8/cpu.h b/repos/base-hw/src/core/spec/arm_v8/cpu.h index e4b38183cb..b48e8bec9b 100644 --- a/repos/base-hw/src/core/spec/arm_v8/cpu.h +++ b/repos/base-hw/src/core/spec/arm_v8/cpu.h @@ -79,6 +79,18 @@ struct Core::Cpu : Hw::Arm_64_cpu Fpu_state fpu_state { }; Context(bool privileged); + + void print(Output &output) const; + + void for_each_return_address(Const_byte_range_ptr const &stack, + auto const &fn) + { + void **fp = (void**)r[29]; + while (stack.contains(fp) && stack.contains(fp + 1) && fp[1]) { + fn(fp + 1); + fp = (void **) fp[0]; + } + } }; class Mmu_context diff --git a/repos/base-hw/src/core/spec/riscv/cpu.cc b/repos/base-hw/src/core/spec/riscv/cpu.cc index df9495c743..0d58bef4a6 100644 --- a/repos/base-hw/src/core/spec/riscv/cpu.cc +++ b/repos/base-hw/src/core/spec/riscv/cpu.cc @@ -25,6 +25,47 @@ using Mmu_context = Core::Cpu::Mmu_context; using namespace Core; +void Cpu::Context::print(Output &output) const +{ + using namespace Genode; + using Genode::print; + + print(output, "\n"); + print(output, " ip = ", Hex(ip), "\n"); + print(output, " ra = ", Hex(ra), "\n"); + print(output, " sp = ", Hex(sp), "\n"); + print(output, " gp = ", Hex(gp), "\n"); + print(output, " tp = ", Hex(tp), "\n"); + print(output, " t0 = ", Hex(t0), "\n"); + print(output, " t1 = ", Hex(t1), "\n"); + print(output, " t2 = ", Hex(t2), "\n"); + print(output, " s0 = ", Hex(s0), "\n"); + print(output, " s1 = ", Hex(s1), "\n"); + print(output, " a0 = ", Hex(a0), "\n"); + print(output, " a1 = ", Hex(a1), "\n"); + print(output, " a2 = ", Hex(a2), "\n"); + print(output, " a3 = ", Hex(a3), "\n"); + print(output, " a4 = ", Hex(a4), "\n"); + print(output, " a5 = ", Hex(a5), "\n"); + print(output, " a6 = ", Hex(a6), "\n"); + print(output, " a7 = ", Hex(a7), "\n"); + print(output, " s2 = ", Hex(s2), "\n"); + print(output, " s3 = ", Hex(s3), "\n"); + print(output, " s4 = ", Hex(s4), "\n"); + print(output, " s5 = ", Hex(s5), "\n"); + print(output, " s6 = ", Hex(s6), "\n"); + print(output, " s7 = ", Hex(s7), "\n"); + print(output, " s8 = ", Hex(s8), "\n"); + print(output, " s9 = ", Hex(s9), "\n"); + print(output, " s10 = ", Hex(s10), "\n"); + print(output, " s11 = ", Hex(s11), "\n"); + print(output, " t3 = ", Hex(t3), "\n"); + print(output, " t4 = ", Hex(t4), "\n"); + print(output, " t5 = ", Hex(t5), "\n"); + print(output, " t6 = ", Hex(t6)); +} + + Cpu::Context::Context(bool) { /* diff --git a/repos/base-hw/src/core/spec/riscv/cpu.h b/repos/base-hw/src/core/spec/riscv/cpu.h index 40db57db70..4d8e1a262e 100644 --- a/repos/base-hw/src/core/spec/riscv/cpu.h +++ b/repos/base-hw/src/core/spec/riscv/cpu.h @@ -56,6 +56,11 @@ class Core::Cpu : public Hw::Riscv_cpu struct alignas(8) Context : Genode::Cpu_state { Context(bool); + + void print(Output &output) const; + + void for_each_return_address(Const_byte_range_ptr const &, + auto const &) { } }; class Mmu_context diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.cc b/repos/base-hw/src/core/spec/x86_64/cpu.cc index 249b53e5ab..eb70a0e69a 100644 --- a/repos/base-hw/src/core/spec/x86_64/cpu.cc +++ b/repos/base-hw/src/core/spec/x86_64/cpu.cc @@ -37,6 +37,27 @@ struct Pseudo_descriptor } __attribute__((packed)); +void Cpu::Context::print(Output &output) const +{ + using namespace Genode; + using Genode::print; + + print(output, "\n"); + print(output, " ip = ", Hex(ip), "\n"); + print(output, " sp = ", Hex(sp), "\n"); + print(output, " cs = ", Hex(cs), "\n"); + print(output, " ss = ", Hex(ss), "\n"); + print(output, " eflags = ", Hex(eflags), "\n"); + print(output, " rax = ", Hex(rax), "\n"); + print(output, " rbx = ", Hex(rbx), "\n"); + print(output, " rcx = ", Hex(rcx), "\n"); + print(output, " rdx = ", Hex(rdx), "\n"); + print(output, " rdi = ", Hex(rdi), "\n"); + print(output, " rsi = ", Hex(rsi), "\n"); + print(output, " rbp = ", Hex(rbp)); +} + + Cpu::Context::Context(bool core) { eflags = EFLAGS_IF_SET; diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.h b/repos/base-hw/src/core/spec/x86_64/cpu.h index e612cc0321..71b4a6dc38 100644 --- a/repos/base-hw/src/core/spec/x86_64/cpu.h +++ b/repos/base-hw/src/core/spec/x86_64/cpu.h @@ -100,6 +100,18 @@ class Core::Cpu : public Hw::X86_64_cpu }; Context(bool privileged); + + void print(Output &output) const; + + void for_each_return_address(Const_byte_range_ptr const &stack, + auto const &fn) + { + void **fp = (void**)rbp; + while (stack.contains(fp) && stack.contains(fp + 1) && fp[1]) { + fn(fp + 1); + fp = (void **) fp[0]; + } + } } __attribute__((packed));