Refactor panic stack walking
This commit is contained in:
@@ -3,7 +3,6 @@ use core::arch::asm;
|
||||
use fdt::{node::NodeProperty, Fdt};
|
||||
|
||||
use super::gic::GicDistIf;
|
||||
use log::info;
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
Result,
|
||||
|
||||
@@ -2,8 +2,8 @@ use rmm::VirtualAddress;
|
||||
|
||||
use crate::{
|
||||
exception_stack,
|
||||
interrupt::stack_trace,
|
||||
memory::{ArchIntCtx, GenericPfFlags},
|
||||
panic::stack_trace,
|
||||
syscall,
|
||||
syscall::flag::*,
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@ pub mod trace;
|
||||
|
||||
use crate::cpu_set::LogicalCpuId;
|
||||
|
||||
pub use self::{handler::InterruptStack, trace::stack_trace};
|
||||
pub use self::handler::InterruptStack;
|
||||
|
||||
/// Clear interrupts
|
||||
#[inline(always)]
|
||||
|
||||
@@ -1,38 +1,28 @@
|
||||
use core::{arch::asm, mem};
|
||||
|
||||
use crate::{memory::KernelMapper, paging::VirtualAddress};
|
||||
pub struct StackTrace {
|
||||
pub fp: usize,
|
||||
pub pc_ptr: *const usize,
|
||||
}
|
||||
|
||||
/// Get a stack trace
|
||||
//TODO: Check for stack being mapped before dereferencing
|
||||
#[inline(never)]
|
||||
pub unsafe fn stack_trace() {
|
||||
let mut fp: usize;
|
||||
asm!("mov {}, fp", out(reg) fp);
|
||||
impl StackTrace {
|
||||
#[inline(always)]
|
||||
pub unsafe fn start() -> Option<Self> {
|
||||
let fp: usize;
|
||||
asm!("mov {}, fp", out(reg) fp);
|
||||
let pc_ptr = fp.checked_add(mem::size_of::<usize>())?;
|
||||
Some(StackTrace {
|
||||
fp,
|
||||
pc_ptr: pc_ptr as *const usize,
|
||||
})
|
||||
}
|
||||
|
||||
println!("TRACE: {:>016x}", fp);
|
||||
|
||||
let mapper = KernelMapper::lock();
|
||||
|
||||
//Maximum 64 frames
|
||||
for _frame in 0..64 {
|
||||
if let Some(pc_fp) = fp.checked_add(mem::size_of::<usize>()) {
|
||||
if mapper.translate(VirtualAddress::new(fp)).is_some()
|
||||
&& mapper.translate(VirtualAddress::new(pc_fp)).is_some()
|
||||
{
|
||||
let pc = *(pc_fp as *const usize);
|
||||
if pc == 0 {
|
||||
println!(" {:>016x}: EMPTY RETURN", fp);
|
||||
break;
|
||||
}
|
||||
println!(" FP {:>016x}: PC {:>016x}", fp, pc);
|
||||
fp = *(fp as *const usize);
|
||||
//TODO symbol_trace(pc);
|
||||
} else {
|
||||
println!(" {:>016x}: GUARD PAGE", fp);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
println!(" {:>016x}: fp OVERFLOW", fp);
|
||||
}
|
||||
pub unsafe fn next(self) -> Option<Self> {
|
||||
let fp = *(self.fp as *const usize);
|
||||
let pc_ptr = fp.checked_add(mem::size_of::<usize>())?;
|
||||
Some(StackTrace {
|
||||
fp: fp,
|
||||
pc_ptr: pc_ptr as *const usize,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use rmm::{
|
||||
VirtualAddress, KILOBYTE, MEGABYTE,
|
||||
};
|
||||
|
||||
use crate::{cpu_set::LogicalCpuId, init::device_tree::MEMORY_MAP, paging::entry::EntryFlags};
|
||||
use crate::{init::device_tree::MEMORY_MAP, paging::entry::EntryFlags};
|
||||
|
||||
use super::CurrentRmmArch as RmmA;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use x86::irq::PageFaultError;
|
||||
|
||||
use crate::{
|
||||
interrupt::stack_trace, interrupt_error, interrupt_stack, ksignal, memory::GenericPfFlags,
|
||||
paging::VirtualAddress, ptrace, syscall::flag::*,
|
||||
interrupt_error, interrupt_stack, ksignal, memory::GenericPfFlags, paging::VirtualAddress,
|
||||
panic::stack_trace, ptrace, syscall::flag::*,
|
||||
};
|
||||
|
||||
interrupt_stack!(divide_by_zero, |stack| {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use x86::irq::PageFaultError;
|
||||
|
||||
use crate::{
|
||||
interrupt::stack_trace, interrupt_error, interrupt_stack, ksignal, memory::GenericPfFlags,
|
||||
paging::VirtualAddress, ptrace, syscall::flag::*,
|
||||
interrupt_error, interrupt_stack, ksignal, memory::GenericPfFlags, paging::VirtualAddress,
|
||||
panic::stack_trace, ptrace, syscall::flag::*,
|
||||
};
|
||||
|
||||
interrupt_stack!(divide_by_zero, |stack| {
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
pub mod ipi;
|
||||
pub mod trace;
|
||||
|
||||
pub use self::trace::stack_trace;
|
||||
|
||||
pub use super::{
|
||||
device::local_apic::bsp_apic_id,
|
||||
idt::{available_irqs_iter, is_reserved, set_reserved},
|
||||
|
||||
@@ -1,107 +1,31 @@
|
||||
use core::{mem, str};
|
||||
use core::mem;
|
||||
|
||||
use goblin::elf::sym;
|
||||
use rustc_demangle::demangle;
|
||||
|
||||
use crate::{memory::KernelMapper, paging::VirtualAddress, USER_END_OFFSET};
|
||||
|
||||
/// Get a stack trace
|
||||
//TODO: Check for stack being mapped before dereferencing
|
||||
#[inline(never)]
|
||||
pub unsafe fn stack_trace() {
|
||||
let mut sp: usize;
|
||||
#[cfg(target_arch = "x86")]
|
||||
core::arch::asm!("mov {}, ebp", out(reg) sp);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
core::arch::asm!("mov {}, rbp", out(reg) sp);
|
||||
|
||||
println!("TRACE: {:>016X}", sp);
|
||||
//Maximum 64 frames
|
||||
|
||||
let mapper = KernelMapper::lock();
|
||||
|
||||
for _frame in 0..64 {
|
||||
if let Some(ip_bp) = sp.checked_add(mem::size_of::<usize>()) {
|
||||
let bp_virt = VirtualAddress::new(sp);
|
||||
let ip_bp_virt = VirtualAddress::new(ip_bp);
|
||||
if bp_virt.data() >= USER_END_OFFSET
|
||||
&& ip_bp_virt.data() >= USER_END_OFFSET
|
||||
&& mapper.translate(bp_virt).is_some()
|
||||
&& mapper.translate(ip_bp_virt).is_some()
|
||||
{
|
||||
let ip = (ip_bp as *const usize).read();
|
||||
if ip == 0 {
|
||||
println!(" {:>016X}: EMPTY RETURN", sp);
|
||||
break;
|
||||
}
|
||||
println!(" {:>016X}: {:>016X}", sp, ip);
|
||||
sp = (sp as *const usize).read();
|
||||
symbol_trace(ip);
|
||||
} else {
|
||||
println!(" {:>016X}: GUARD PAGE", sp);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
println!(" {:>016X}: RBP OVERFLOW", sp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pub struct StackTrace {
|
||||
pub fp: usize,
|
||||
pub pc_ptr: *const usize,
|
||||
}
|
||||
|
||||
/// Get a symbol
|
||||
//TODO: Do not create Elf object for every symbol lookup
|
||||
#[inline(never)]
|
||||
pub unsafe fn symbol_trace(addr: usize) {
|
||||
use core::{slice, sync::atomic::Ordering};
|
||||
impl StackTrace {
|
||||
#[inline(always)]
|
||||
pub unsafe fn start() -> Option<Self> {
|
||||
let mut fp: usize;
|
||||
#[cfg(target_arch = "x86")]
|
||||
core::arch::asm!("mov {}, ebp", out(reg) fp);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
core::arch::asm!("mov {}, rbp", out(reg) fp);
|
||||
let pc_ptr = fp.checked_add(mem::size_of::<usize>())?;
|
||||
Some(Self {
|
||||
fp,
|
||||
pc_ptr: pc_ptr as *const usize,
|
||||
})
|
||||
}
|
||||
|
||||
use crate::{
|
||||
elf::Elf,
|
||||
start::{KERNEL_BASE, KERNEL_SIZE},
|
||||
};
|
||||
|
||||
let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + crate::PHYS_OFFSET) as *const u8;
|
||||
let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));
|
||||
if let Ok(elf) = Elf::from(kernel_slice) {
|
||||
let mut strtab_opt = None;
|
||||
for section in elf.sections() {
|
||||
if section.sh_type == ::goblin::elf::section_header::SHT_STRTAB {
|
||||
strtab_opt = Some(section);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(symbols) = elf.symbols() {
|
||||
for sym in symbols {
|
||||
if sym::st_type(sym.st_info) == sym::STT_FUNC
|
||||
&& addr >= sym.st_value as usize
|
||||
&& addr < (sym.st_value + sym.st_size) as usize
|
||||
{
|
||||
println!(
|
||||
" {:>016X}+{:>04X}",
|
||||
sym.st_value,
|
||||
addr - sym.st_value as usize
|
||||
);
|
||||
|
||||
if let Some(strtab) = strtab_opt {
|
||||
let start = strtab.sh_offset as usize + sym.st_name as usize;
|
||||
let mut end = start;
|
||||
while end < elf.data.len() {
|
||||
let b = elf.data[end];
|
||||
end += 1;
|
||||
if b == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if end > start {
|
||||
let sym_slice = &elf.data[start..end - 1];
|
||||
if let Ok(sym_name) = str::from_utf8(sym_slice) {
|
||||
println!(" {:#}", demangle(sym_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub unsafe fn next(self) -> Option<Self> {
|
||||
let fp = *(self.fp as *const usize);
|
||||
let pc_ptr = fp.checked_add(mem::size_of::<usize>())?;
|
||||
Some(Self {
|
||||
fp: fp,
|
||||
pc_ptr: pc_ptr as *const usize,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,6 @@ use spinning_top::RwSpinlock;
|
||||
mod memory;
|
||||
|
||||
/// Panic
|
||||
#[cfg(not(test))]
|
||||
mod panic;
|
||||
|
||||
mod percpu;
|
||||
|
||||
+105
-3
@@ -1,16 +1,28 @@
|
||||
//! Intrinsics for panic handling
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
use core::{panic::PanicInfo, slice, str, sync::atomic::Ordering};
|
||||
use goblin::elf::sym;
|
||||
use rmm::VirtualAddress;
|
||||
use rustc_demangle::demangle;
|
||||
|
||||
use crate::{context, cpu_id, interrupt, syscall};
|
||||
use crate::{
|
||||
arch::{consts::USER_END_OFFSET, interrupt::trace::StackTrace},
|
||||
context, cpu_id,
|
||||
elf::Elf,
|
||||
interrupt,
|
||||
memory::KernelMapper,
|
||||
start::KERNEL_SIZE,
|
||||
syscall,
|
||||
};
|
||||
|
||||
/// Required to handle panics
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn rust_begin_unwind(info: &PanicInfo) -> ! {
|
||||
println!("KERNEL PANIC: {}", info);
|
||||
|
||||
unsafe {
|
||||
interrupt::stack_trace();
|
||||
stack_trace();
|
||||
}
|
||||
let context_lock = context::current();
|
||||
|
||||
@@ -33,3 +45,93 @@ fn rust_begin_unwind(info: &PanicInfo) -> ! {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a stack trace
|
||||
#[inline(never)]
|
||||
pub unsafe fn stack_trace() {
|
||||
let mapper = KernelMapper::lock();
|
||||
|
||||
let mut frame = StackTrace::start();
|
||||
|
||||
//Maximum 64 frames
|
||||
for _ in 0..64 {
|
||||
if let Some(frame_) = frame {
|
||||
let fp_virt = VirtualAddress::new(frame_.fp);
|
||||
let pc_virt = VirtualAddress::new(frame_.pc_ptr as usize);
|
||||
if fp_virt.data() >= USER_END_OFFSET
|
||||
&& pc_virt.data() >= USER_END_OFFSET
|
||||
&& (fp_virt.data() as *const usize).is_aligned()
|
||||
&& (pc_virt.data() as *const usize).is_aligned()
|
||||
&& mapper.translate(fp_virt).is_some()
|
||||
&& mapper.translate(pc_virt).is_some()
|
||||
{
|
||||
let pc = *frame_.pc_ptr;
|
||||
if pc == 0 {
|
||||
println!(" {:>016x}: EMPTY RETURN", frame_.fp);
|
||||
break;
|
||||
} else {
|
||||
println!(" FP {:>016x}: PC {:>016x}", frame_.fp, pc);
|
||||
symbol_trace(pc);
|
||||
frame = frame_.next();
|
||||
}
|
||||
} else {
|
||||
println!(" {:>016x}: GUARD PAGE", frame_.fp);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
///
|
||||
/// Get a symbol
|
||||
//TODO: Do not create Elf object for every symbol lookup
|
||||
#[inline(never)]
|
||||
pub unsafe fn symbol_trace(addr: usize) {
|
||||
let kernel_ptr = crate::KERNEL_OFFSET as *const u8;
|
||||
let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));
|
||||
|
||||
if let Ok(elf) = Elf::from(kernel_slice) {
|
||||
let mut strtab_opt = None;
|
||||
for section in elf.sections() {
|
||||
if section.sh_type == ::goblin::elf::section_header::SHT_STRTAB {
|
||||
strtab_opt = Some(section);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(symbols) = elf.symbols() {
|
||||
for sym in symbols {
|
||||
if sym::st_type(sym.st_info) == sym::STT_FUNC
|
||||
&& addr >= sym.st_value as usize
|
||||
&& addr < (sym.st_value + sym.st_size) as usize
|
||||
{
|
||||
println!(
|
||||
" {:>016X}+{:>04X}",
|
||||
sym.st_value,
|
||||
addr - sym.st_value as usize
|
||||
);
|
||||
|
||||
if let Some(strtab) = strtab_opt {
|
||||
let start = strtab.sh_offset as usize + sym.st_name as usize;
|
||||
let mut end = start;
|
||||
while end < elf.data.len() {
|
||||
let b = elf.data[end];
|
||||
end += 1;
|
||||
if b == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if end > start {
|
||||
let sym_slice = &elf.data[start..end - 1];
|
||||
if let Ok(sym_name) = str::from_utf8(sym_slice) {
|
||||
println!(" {:#}", demangle(sym_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user