mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
feat: add backtrace support
This commit is contained in:
parent
e6abb50f86
commit
4647d1fd2a
66
kernel/src/arch/riscv/backtrace.rs
Normal file
66
kernel/src/arch/riscv/backtrace.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use super::layout::{BSS_END, BSS_START, TEXT_END, TEXT_START};
|
||||||
|
use crate::plat::backtrace::FrameWalker;
|
||||||
|
use vspace::addr::{AddressOps, VirtAddr};
|
||||||
|
|
||||||
|
impl FrameWalker {
|
||||||
|
fn read_fp() -> usize {
|
||||||
|
let fp;
|
||||||
|
unsafe { core::arch::asm!("mv {}, fp", out(reg) fp) }
|
||||||
|
fp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_ra() -> usize {
|
||||||
|
let ra;
|
||||||
|
unsafe { core::arch::asm!("mv {}, ra", out(reg) ra) }
|
||||||
|
ra
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_valid(&self) -> bool {
|
||||||
|
let fp_valid = unsafe { BSS_START.as_virt_addr() <= self.current_fp && self.current_fp < BSS_END.as_virt_addr() };
|
||||||
|
let pc_valid = unsafe { TEXT_START.as_virt_addr() <= self.current_pc && self.current_pc < TEXT_END.as_virt_addr() };
|
||||||
|
fp_valid && pc_valid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
// current_{fp, pc} is deliberately missed for printing
|
||||||
|
Self {
|
||||||
|
current_fp: VirtAddr::from(FrameWalker::read_fp()),
|
||||||
|
current_pc: VirtAddr::from(FrameWalker::read_ra()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for crate::plat::backtrace::FrameWalker {
|
||||||
|
type Item = Self;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
/*
|
||||||
|
* Prologue like this:
|
||||||
|
* > addi sp,sp,-16
|
||||||
|
* > sd ra,8(sp)
|
||||||
|
* > sd s0,0(sp)
|
||||||
|
* > addi s0,sp,16
|
||||||
|
*
|
||||||
|
* Epilogue like this:
|
||||||
|
* > ld ra,8(sp)
|
||||||
|
* > ld s0,0(sp)
|
||||||
|
* > addi sp,sp,16
|
||||||
|
* > jr ra
|
||||||
|
*
|
||||||
|
* prev_fp = *(current_fp - 16)
|
||||||
|
* prev_pc = *(current_fp - 8)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if !self.is_valid() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev_fp = unsafe { *(self.current_fp.as_const_ptr() as *const usize).offset(-2) };
|
||||||
|
let prev_pc = unsafe { *(self.current_fp.as_const_ptr() as *const usize).offset(-1) };
|
||||||
|
|
||||||
|
self.current_fp = VirtAddr::from(prev_fp);
|
||||||
|
self.current_pc = VirtAddr::from(prev_pc);
|
||||||
|
|
||||||
|
Some(*self)
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod backtrace;
|
||||||
mod entry;
|
mod entry;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
mod lowlevel;
|
mod lowlevel;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
use crate::plat::{
|
||||||
|
backtrace::dump_backtrace,
|
||||||
|
lowlevel::{Hardware, LowLevel},
|
||||||
|
};
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
use crate::plat::lowlevel::{Hardware, LowLevel};
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
error!("Kernel panic!");
|
error!("Kernel panic!");
|
||||||
@ -19,5 +20,7 @@ fn panic(info: &PanicInfo) -> ! {
|
|||||||
None => error!("[lang] Panicked: {}", info.message().unwrap()),
|
None => error!("[lang] Panicked: {}", info.message().unwrap()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe { dump_backtrace() };
|
||||||
|
|
||||||
Hardware::shutdown(true);
|
Hardware::shutdown(true);
|
||||||
}
|
}
|
||||||
|
26
kernel/src/plat/backtrace.rs
Normal file
26
kernel/src/plat/backtrace.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use log::error;
|
||||||
|
use vspace::addr::VirtAddr;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct FrameWalker {
|
||||||
|
pub current_fp: VirtAddr,
|
||||||
|
pub current_pc: VirtAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn dump_backtrace() {
|
||||||
|
let mut depth = 0;
|
||||||
|
|
||||||
|
error!("Dumping stack trace ...");
|
||||||
|
|
||||||
|
let walker = FrameWalker::new();
|
||||||
|
for frame in walker {
|
||||||
|
error!("#{:02} PC: {:#x?} FP: {:#x?}", depth, frame.current_pc, frame.current_fp);
|
||||||
|
depth += 1;
|
||||||
|
if depth >= 100 {
|
||||||
|
error!("Backtrace is too deep, aborting ...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error!("Backtrace complete");
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
pub mod backtrace;
|
||||||
pub mod console;
|
pub mod console;
|
||||||
pub mod lowlevel;
|
pub mod lowlevel;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
@ -19,8 +19,12 @@ impl Arch {
|
|||||||
"-Zbuild-std=core,compiler_builtins,alloc",
|
"-Zbuild-std=core,compiler_builtins,alloc",
|
||||||
"-Zbuild-std-features=compiler-builtins-mem",
|
"-Zbuild-std-features=compiler-builtins-mem",
|
||||||
];
|
];
|
||||||
const FLAGS_RELOCATION: [&'static str; 3] =
|
const FLAGS_RELOCATION: [&'static str; 4] = [
|
||||||
["-Crelocation-model=static", "-Ccode-model=medium", "-Ctarget-feature=+relax"];
|
"-Crelocation-model=static",
|
||||||
|
"-Ccode-model=medium",
|
||||||
|
"-Ctarget-feature=+relax",
|
||||||
|
"-Cforce-frame-pointers=yes",
|
||||||
|
];
|
||||||
|
|
||||||
pub fn cargo_args(&self, test: bool) -> Vec<String> {
|
pub fn cargo_args(&self, test: bool) -> Vec<String> {
|
||||||
let mut args: Vec<String> = Vec::new();
|
let mut args: Vec<String> = Vec::new();
|
||||||
|
Loading…
Reference in New Issue
Block a user