Add support for userspace stack traces using usercopy
This commit is contained in:
@@ -5,7 +5,6 @@ use crate::{
|
||||
context::signal::excp_handler,
|
||||
exception_stack,
|
||||
memory::{ArchIntCtx, GenericPfFlags},
|
||||
panic::stack_trace,
|
||||
sync::CleanLockToken,
|
||||
syscall::{self, flag::*},
|
||||
};
|
||||
@@ -14,8 +13,7 @@ use super::InterruptStack;
|
||||
|
||||
exception_stack!(synchronous_exception_at_el1_with_sp0, |stack| {
|
||||
println!("Synchronous exception at EL1 with SP0");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
stack.trace();
|
||||
loop {}
|
||||
});
|
||||
|
||||
@@ -162,8 +160,7 @@ exception_stack!(synchronous_exception_at_el1_with_spx, |stack| {
|
||||
let far_el1 = far_el1();
|
||||
println!("USER FAR_EL1 = 0x{:08x}", far_el1);
|
||||
}
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
stack.trace();
|
||||
loop {}
|
||||
}
|
||||
});
|
||||
@@ -205,8 +202,7 @@ exception_stack!(synchronous_exception_at_el0, |stack| {
|
||||
);
|
||||
println!("FAR_EL1: {:#0x}", far_el1());
|
||||
//crate::debugger::debugger(None);
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 0, // TODO
|
||||
});
|
||||
@@ -217,8 +213,7 @@ exception_stack!(synchronous_exception_at_el0, |stack| {
|
||||
|
||||
exception_stack!(unhandled_exception, |stack| {
|
||||
println!("Unhandled exception");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
stack.trace();
|
||||
loop {}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::syscall::IntRegisters;
|
||||
use crate::{panic, syscall::IntRegisters};
|
||||
|
||||
#[derive(Default)]
|
||||
#[repr(C, packed)]
|
||||
@@ -120,6 +120,12 @@ pub struct InterruptStack {
|
||||
|
||||
impl InterruptStack {
|
||||
pub fn init(&mut self) {}
|
||||
pub fn frame_pointer(&self) -> usize {
|
||||
self.preserved.x29
|
||||
}
|
||||
pub fn stack_pointer(&self) -> usize {
|
||||
self.iret.sp_el0
|
||||
}
|
||||
pub fn set_stack_pointer(&mut self, sp: usize) {
|
||||
self.iret.sp_el0 = sp;
|
||||
}
|
||||
@@ -137,6 +143,13 @@ impl InterruptStack {
|
||||
self.scratch.dump();
|
||||
self.preserved.dump();
|
||||
}
|
||||
pub fn trace(&self) {
|
||||
self.dump();
|
||||
unsafe {
|
||||
panic::user_stack_trace(&self);
|
||||
panic::stack_trace();
|
||||
}
|
||||
}
|
||||
|
||||
/// Saves all registers to a struct used by the proc:
|
||||
/// scheme to read/write registers.
|
||||
|
||||
@@ -132,15 +132,14 @@ unsafe fn handle_system_exception(scause: usize, regs: &InterruptStack) {
|
||||
"S-mode exception! scause={:#016x}, stval={:#016x}",
|
||||
scause, stval
|
||||
);
|
||||
regs.dump();
|
||||
|
||||
if tp == 0 {
|
||||
// Early failure - before misc::init and potentially before RMM init
|
||||
// Do not attempt to trace stack because it would probably trap again
|
||||
loop {}
|
||||
regs.dump();
|
||||
} else {
|
||||
regs.trace();
|
||||
}
|
||||
|
||||
stack_trace();
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{memory::ArchIntCtx, syscall::IntRegisters};
|
||||
use crate::{memory::ArchIntCtx, panic, syscall::IntRegisters};
|
||||
use core::mem::size_of;
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -99,12 +99,15 @@ impl InterruptStack {
|
||||
assert!(32 * 8 == size_of::<InterruptStack>());
|
||||
}
|
||||
}
|
||||
pub fn set_stack_pointer(&mut self, sp: usize) {
|
||||
self.registers.x2 = sp;
|
||||
pub fn frame_pointer(&self) -> usize {
|
||||
self.registers.x8
|
||||
}
|
||||
pub fn stack_pointer(&self) -> usize {
|
||||
self.registers.x2
|
||||
}
|
||||
pub fn set_stack_pointer(&mut self, sp: usize) {
|
||||
self.registers.x2 = sp;
|
||||
}
|
||||
pub fn set_instr_pointer(&mut self, ip: usize) {
|
||||
self.iret.sepc = ip;
|
||||
}
|
||||
@@ -124,6 +127,14 @@ impl InterruptStack {
|
||||
self.registers.dump();
|
||||
}
|
||||
|
||||
pub fn trace(&self) {
|
||||
self.dump();
|
||||
unsafe {
|
||||
panic::user_stack_trace(&self);
|
||||
panic::stack_trace();
|
||||
}
|
||||
}
|
||||
|
||||
/// Saves all registers to a struct used by the proc:
|
||||
/// scheme to read/write registers.
|
||||
pub fn save(&self, all: &mut IntRegisters) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core::mem;
|
||||
|
||||
use crate::{memory::ArchIntCtx, syscall::IntRegisters};
|
||||
use crate::{memory::ArchIntCtx, panic, syscall::IntRegisters};
|
||||
|
||||
use super::super::flags::*;
|
||||
|
||||
@@ -88,6 +88,13 @@ impl InterruptStack {
|
||||
self.scratch.dump();
|
||||
self.preserved.dump();
|
||||
}
|
||||
pub fn trace(&self) {
|
||||
self.dump();
|
||||
unsafe {
|
||||
panic::user_stack_trace(&self);
|
||||
panic::stack_trace();
|
||||
}
|
||||
}
|
||||
/// Saves all registers to a struct used by the proc:
|
||||
/// scheme to read/write registers.
|
||||
pub fn save(&self, all: &mut IntRegisters) {
|
||||
@@ -124,6 +131,12 @@ impl InterruptStack {
|
||||
all.ss = self.iret.ss;
|
||||
}
|
||||
}
|
||||
pub fn frame_pointer(&self) -> usize {
|
||||
self.preserved.ebp
|
||||
}
|
||||
pub fn stack_pointer(&self) -> usize {
|
||||
self.iret.esp
|
||||
}
|
||||
pub fn set_stack_pointer(&mut self, esp: usize) {
|
||||
self.iret.esp = esp;
|
||||
}
|
||||
@@ -188,6 +201,13 @@ impl InterruptErrorStack {
|
||||
println!("CODE: {:08x}", { self.code });
|
||||
self.inner.dump();
|
||||
}
|
||||
pub fn trace(&self) {
|
||||
self.dump();
|
||||
unsafe {
|
||||
panic::user_stack_trace(&self.inner);
|
||||
panic::stack_trace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{memory::ArchIntCtx, syscall::IntRegisters};
|
||||
use crate::{memory::ArchIntCtx, panic, syscall::IntRegisters};
|
||||
|
||||
use super::super::flags::*;
|
||||
|
||||
@@ -102,6 +102,12 @@ impl InterruptStack {
|
||||
self.iret.cs = (crate::gdt::GDT_USER_CODE << 3) | 3;
|
||||
self.iret.ss = (crate::gdt::GDT_USER_DATA << 3) | 3;
|
||||
}
|
||||
pub fn frame_pointer(&self) -> usize {
|
||||
self.preserved.rbp
|
||||
}
|
||||
pub fn stack_pointer(&self) -> usize {
|
||||
self.iret.rsp
|
||||
}
|
||||
pub fn set_stack_pointer(&mut self, rsp: usize) {
|
||||
self.iret.rsp = rsp;
|
||||
}
|
||||
@@ -120,6 +126,13 @@ impl InterruptStack {
|
||||
self.scratch.dump();
|
||||
self.preserved.dump();
|
||||
}
|
||||
pub fn trace(&self) {
|
||||
self.dump();
|
||||
unsafe {
|
||||
panic::user_stack_trace(&self);
|
||||
panic::stack_trace();
|
||||
}
|
||||
}
|
||||
/// Saves all registers to a struct used by the proc:
|
||||
/// scheme to read/write registers.
|
||||
pub fn save(&self, all: &mut IntRegisters) {
|
||||
|
||||
@@ -3,13 +3,12 @@ use x86::irq::PageFaultError;
|
||||
|
||||
use crate::{
|
||||
arch::x86_shared::interrupt, context::signal::excp_handler, memory::GenericPfFlags,
|
||||
paging::VirtualAddress, panic::stack_trace, ptrace, sync::CleanLockToken, syscall::flag::*,
|
||||
paging::VirtualAddress, ptrace, sync::CleanLockToken, syscall::flag::*,
|
||||
};
|
||||
|
||||
interrupt_stack!(divide_by_zero, |stack| {
|
||||
println!("Divide by zero");
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 0,
|
||||
..Default::default()
|
||||
@@ -92,8 +91,7 @@ interrupt_stack!(breakpoint, |stack| {
|
||||
|
||||
interrupt_stack!(overflow, |stack| {
|
||||
println!("Overflow trap");
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 4,
|
||||
..Default::default()
|
||||
@@ -102,8 +100,7 @@ interrupt_stack!(overflow, |stack| {
|
||||
|
||||
interrupt_stack!(bound_range, |stack| {
|
||||
println!("Bound range exceeded fault");
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 5,
|
||||
..Default::default()
|
||||
@@ -112,8 +109,7 @@ interrupt_stack!(bound_range, |stack| {
|
||||
|
||||
interrupt_stack!(invalid_opcode, |stack| {
|
||||
println!("Invalid opcode fault");
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 6,
|
||||
..Default::default()
|
||||
@@ -122,8 +118,7 @@ interrupt_stack!(invalid_opcode, |stack| {
|
||||
|
||||
interrupt_stack!(device_not_available, |stack| {
|
||||
println!("Device not available fault");
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 7,
|
||||
..Default::default()
|
||||
@@ -132,9 +127,8 @@ interrupt_stack!(device_not_available, |stack| {
|
||||
|
||||
interrupt_error!(double_fault, |stack, _code| {
|
||||
println!("Double fault");
|
||||
stack.dump();
|
||||
stack.trace();
|
||||
unsafe {
|
||||
stack_trace();
|
||||
loop {
|
||||
interrupt::disable();
|
||||
interrupt::halt();
|
||||
@@ -144,8 +138,7 @@ interrupt_error!(double_fault, |stack, _code| {
|
||||
|
||||
interrupt_error!(invalid_tss, |stack, code| {
|
||||
println!("Invalid TSS fault");
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 10,
|
||||
code,
|
||||
@@ -155,8 +148,7 @@ interrupt_error!(invalid_tss, |stack, code| {
|
||||
|
||||
interrupt_error!(segment_not_present, |stack, code| {
|
||||
println!("Segment not present fault");
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 11,
|
||||
code,
|
||||
@@ -166,8 +158,7 @@ interrupt_error!(segment_not_present, |stack, code| {
|
||||
|
||||
interrupt_error!(stack_segment, |stack, code| {
|
||||
println!("Stack segment fault");
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 12,
|
||||
code,
|
||||
@@ -177,8 +168,7 @@ interrupt_error!(stack_segment, |stack, code| {
|
||||
|
||||
interrupt_error!(protection, |stack, code| {
|
||||
println!("Protection fault code={:#0x}", code);
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 13,
|
||||
code,
|
||||
@@ -215,8 +205,7 @@ interrupt_error!(page, |stack, code| {
|
||||
#[cfg(target_arch = "x86")]
|
||||
if crate::memory::page_fault_handler(&mut stack.inner, generic_flags, cr2).is_err() {
|
||||
println!("Page fault: {:>08X} {:#?}", cr2.data(), arch_flags);
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 14,
|
||||
code,
|
||||
@@ -227,8 +216,7 @@ interrupt_error!(page, |stack, code| {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
if crate::memory::page_fault_handler(stack, generic_flags, cr2).is_err() {
|
||||
println!("Page fault: {:>016X} {:#?}", cr2.data(), arch_flags);
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 14,
|
||||
code,
|
||||
@@ -239,8 +227,7 @@ interrupt_error!(page, |stack, code| {
|
||||
|
||||
interrupt_stack!(fpu_fault, |stack| {
|
||||
println!("FPU floating point fault");
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 16,
|
||||
..Default::default()
|
||||
@@ -249,8 +236,7 @@ interrupt_stack!(fpu_fault, |stack| {
|
||||
|
||||
interrupt_error!(alignment_check, |stack, code| {
|
||||
println!("Alignment check fault");
|
||||
stack.dump();
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 17,
|
||||
code,
|
||||
@@ -260,9 +246,8 @@ interrupt_error!(alignment_check, |stack, code| {
|
||||
|
||||
interrupt_stack!(machine_check, @paranoid, |stack| {
|
||||
println!("Machine check fault");
|
||||
stack.dump();
|
||||
stack.trace();
|
||||
unsafe {
|
||||
stack_trace();
|
||||
loop {
|
||||
interrupt::disable();
|
||||
interrupt::halt();
|
||||
@@ -272,11 +257,10 @@ interrupt_stack!(machine_check, @paranoid, |stack| {
|
||||
|
||||
interrupt_stack!(simd, |stack| {
|
||||
println!("SIMD floating point fault");
|
||||
stack.dump();
|
||||
let mut mxcsr = 0_usize;
|
||||
unsafe { core::arch::asm!("stmxcsr [{}]", in(reg) core::ptr::addr_of_mut!(mxcsr)) };
|
||||
println!("MXCSR {:#0x}", mxcsr);
|
||||
unsafe { stack_trace() };
|
||||
stack.trace();
|
||||
excp_handler(Exception {
|
||||
kind: 19,
|
||||
..Default::default()
|
||||
@@ -285,9 +269,8 @@ interrupt_stack!(simd, |stack| {
|
||||
|
||||
interrupt_stack!(virtualization, |stack| {
|
||||
println!("Virtualization fault");
|
||||
stack.dump();
|
||||
stack.trace();
|
||||
unsafe {
|
||||
stack_trace();
|
||||
loop {
|
||||
interrupt::disable();
|
||||
interrupt::halt();
|
||||
@@ -297,9 +280,8 @@ interrupt_stack!(virtualization, |stack| {
|
||||
|
||||
interrupt_error!(security, |stack, _code| {
|
||||
println!("Security exception");
|
||||
stack.dump();
|
||||
stack.trace();
|
||||
unsafe {
|
||||
stack_trace();
|
||||
loop {
|
||||
interrupt::disable();
|
||||
interrupt::halt();
|
||||
|
||||
+53
-3
@@ -1,6 +1,6 @@
|
||||
//! Intrinsics for panic handling
|
||||
|
||||
use core::{panic::PanicInfo, slice};
|
||||
use core::{mem, panic::PanicInfo, slice};
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
use object::elf::FileHeader32 as FileHeader;
|
||||
@@ -16,10 +16,11 @@ use rustc_demangle::demangle;
|
||||
|
||||
use crate::{
|
||||
arch::{consts::USER_END_OFFSET, interrupt::trace::StackTrace},
|
||||
context, cpu_id, interrupt,
|
||||
context, cpu_id,
|
||||
interrupt::{self, InterruptStack},
|
||||
memory::KernelMapper,
|
||||
sync::CleanLockToken,
|
||||
syscall,
|
||||
syscall::{self, usercopy::UserSliceRo},
|
||||
};
|
||||
|
||||
/// Required to handle panics
|
||||
@@ -147,3 +148,52 @@ pub unsafe fn stack_trace() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a user stack trace
|
||||
#[inline(never)]
|
||||
pub unsafe fn user_stack_trace(stack: &InterruptStack) {
|
||||
let mut fp = stack.frame_pointer();
|
||||
let sp = stack.stack_pointer();
|
||||
|
||||
if fp < sp {
|
||||
println!(" <Unable to generate stack while frame pointers omitted>");
|
||||
return;
|
||||
}
|
||||
if fp >= crate::USER_END_OFFSET {
|
||||
return;
|
||||
}
|
||||
|
||||
for _ in 0..64 {
|
||||
if fp == 0 || fp >= crate::USER_END_OFFSET {
|
||||
break;
|
||||
}
|
||||
let rip_addr = fp + size_of::<usize>();
|
||||
let rip = match UserSliceRo::new(rip_addr, mem::size_of::<usize>())
|
||||
.and_then(|x| x.read_usize())
|
||||
{
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
println!(" <Failed to read RIP 0x{:>016x}>: {}", fp, err);
|
||||
break;
|
||||
}
|
||||
};
|
||||
println!(" FP {:>016x}: PC {:>016x}", fp, rip);
|
||||
if rip == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let next_fp =
|
||||
match UserSliceRo::new(fp, mem::size_of::<usize>()).and_then(|x| x.read_usize()) {
|
||||
Ok(val) => val,
|
||||
Err(_err) => break,
|
||||
};
|
||||
if next_fp <= fp {
|
||||
println!(
|
||||
" <Invalid next frame pointer 0x{:>016x}; stack walk ended>",
|
||||
next_fp
|
||||
);
|
||||
break;
|
||||
}
|
||||
fp = next_fp;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user