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
This commit is contained in:
Stefan Kalkowski 2024-11-26 15:12:03 +01:00 committed by Norman Feske
parent cc2bcee417
commit 4730312c1e
9 changed files with 161 additions and 4 deletions

View File

@ -935,19 +935,31 @@ void Thread::_call()
void Thread::_mmu_exception() void Thread::_mmu_exception()
{ {
using namespace Genode;
using Genode::log;
_become_inactive(AWAITS_RESTART); _become_inactive(AWAITS_RESTART);
_exception_state = MMU_FAULT; _exception_state = MMU_FAULT;
Cpu::mmu_fault(*regs, _fault); Cpu::mmu_fault(*regs, _fault);
_fault.ip = regs->ip; _fault.ip = regs->ip;
if (_fault.type == Thread_fault::UNKNOWN) { if (_fault.type == Thread_fault::UNKNOWN) {
Genode::raw(*this, " raised unhandled MMU fault ", _fault); Genode::warning(*this, " raised unhandled MMU fault ", _fault);
return; return;
} }
if (_type != USER) if (_type != USER) {
Genode::raw(*this, " raised a fault, which should never happen ", error(*this, " raised a fault, which should never happen ",
_fault); _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)) { if (_pager && _pager->can_submit(1)) {
_pager->submit(1); _pager->submit(1);

View File

@ -22,6 +22,32 @@
using namespace Core; 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) Arm_cpu::Context::Context(bool privileged)
{ {
using Psr = Arm_cpu::Psr; using Psr = Arm_cpu::Psr;

View File

@ -49,6 +49,18 @@ struct Core::Arm_cpu : public Hw::Arm_cpu
struct alignas(8) Context : Cpu_state, Fpu_context struct alignas(8) Context : Cpu_state, Fpu_context
{ {
Context(bool privileged); 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];
}
}
}; };
/** /**

View File

@ -22,6 +22,22 @@
using namespace Core; 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) Cpu::Context::Context(bool privileged)
{ {
Spsr::El::set(pstate, privileged ? 1 : 0); Spsr::El::set(pstate, privileged ? 1 : 0);

View File

@ -79,6 +79,18 @@ struct Core::Cpu : Hw::Arm_64_cpu
Fpu_state fpu_state { }; Fpu_state fpu_state { };
Context(bool privileged); 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 class Mmu_context

View File

@ -25,6 +25,47 @@ using Mmu_context = Core::Cpu::Mmu_context;
using namespace Core; 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) Cpu::Context::Context(bool)
{ {
/* /*

View File

@ -56,6 +56,11 @@ class Core::Cpu : public Hw::Riscv_cpu
struct alignas(8) Context : Genode::Cpu_state struct alignas(8) Context : Genode::Cpu_state
{ {
Context(bool); Context(bool);
void print(Output &output) const;
void for_each_return_address(Const_byte_range_ptr const &,
auto const &) { }
}; };
class Mmu_context class Mmu_context

View File

@ -37,6 +37,27 @@ struct Pseudo_descriptor
} __attribute__((packed)); } __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) Cpu::Context::Context(bool core)
{ {
eflags = EFLAGS_IF_SET; eflags = EFLAGS_IF_SET;

View File

@ -100,6 +100,18 @@ class Core::Cpu : public Hw::X86_64_cpu
}; };
Context(bool privileged); 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)); } __attribute__((packed));