Add debug infos on panic
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = [ "user/*"]
|
||||
exclude = ["library"]
|
||||
members = ["user/*"]
|
||||
exclude = ["library", "build-tools"]
|
||||
|
||||
[package]
|
||||
name = "kernel-rust"
|
||||
|
||||
2
build-tools/.cargo/config.toml
Normal file
2
build-tools/.cargo/config.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[build]
|
||||
target = "x86_64-unknown-linux-gnu"
|
||||
14
build-tools/Cargo.toml
Normal file
14
build-tools/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "build-tools"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[[bin]]
|
||||
name = "gen-symbols"
|
||||
path = "src/gen_symbols.rs"
|
||||
|
||||
[dependencies]
|
||||
rayon = "1.11"
|
||||
object = "0.32"
|
||||
addr2line = "0.21"
|
||||
rustc-demangle = "0.1"
|
||||
128
build-tools/src/gen_symbols.rs
Normal file
128
build-tools/src/gen_symbols.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use addr2line::Context;
|
||||
use object::{Object, ObjectSymbol, SymbolKind};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::path::Path;
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
#[derive(Debug)]
|
||||
struct RawSymbol {
|
||||
addr: u64,
|
||||
line: u32,
|
||||
name_off: u32,
|
||||
file_off: u32,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let elf_path = "../target/riscv64/debug/kernel-rust";
|
||||
let bin_data = std::fs::read(elf_path)?;
|
||||
let obj_file = object::File::parse(&*bin_data)?;
|
||||
|
||||
let context = Context::new(&obj_file)?;
|
||||
|
||||
let mut symbols_list = Vec::new();
|
||||
let mut string_table = Vec::new();
|
||||
let mut str_cache = HashMap::new();
|
||||
|
||||
// Helper pour gérer la table des chaînes (String Table)
|
||||
let mut add_string = |s: &str| -> u32 {
|
||||
*str_cache.entry(s.to_string()).or_insert_with(|| {
|
||||
let off = string_table.len() as u32;
|
||||
string_table.extend_from_slice(s.as_bytes());
|
||||
string_table.push(0); // Null terminator
|
||||
off
|
||||
})
|
||||
};
|
||||
|
||||
println!("Extraction des symboles depuis {}...", elf_path);
|
||||
|
||||
obj_file.symbols().enumerate().for_each(|(i, sym)| {
|
||||
// On ne garde que les fonctions (Text)
|
||||
if sym.kind() == SymbolKind::Text && sym.size() > 0 {
|
||||
let addr = sym.address();
|
||||
let raw_name = sym.name().unwrap_or("unknown");
|
||||
let name = format!("{:#}", rustc_demangle::demangle(raw_name));
|
||||
|
||||
let mut frames = context.find_frames(addr).skip_all_loads().unwrap();
|
||||
|
||||
let (file, line) = if let Ok(Some(frame)) = frames.next() {
|
||||
let f = frame
|
||||
.location
|
||||
.as_ref()
|
||||
.and_then(|l| {
|
||||
l.file.and_then(|file| {
|
||||
Path::new(file)
|
||||
.strip_prefix(std::env::current_dir().unwrap().parent().unwrap())
|
||||
.map_or(Some(file), |p| p.to_str())
|
||||
})
|
||||
})
|
||||
.unwrap_or("unknown");
|
||||
let l = frame.location.as_ref().and_then(|l| l.line).unwrap_or(0);
|
||||
(f, l)
|
||||
} else {
|
||||
("unknown", 0)
|
||||
};
|
||||
|
||||
symbols_list.push(RawSymbol {
|
||||
addr,
|
||||
line,
|
||||
name_off: add_string(&name),
|
||||
file_off: add_string(file),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Tri par adresse pour la recherche binaire au runtime
|
||||
symbols_list.sort_by_key(|s| s.addr);
|
||||
|
||||
let idx = match symbols_list.binary_search_by_key(&(0x000000008004073c), |s| s.addr) {
|
||||
Ok(i) => i,
|
||||
Err(i) if i > 0 => i - 1,
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
println!("{:?}", unsafe {
|
||||
get_str(
|
||||
string_table
|
||||
.as_ptr()
|
||||
.add(symbols_list[idx].name_off as usize),
|
||||
)
|
||||
});
|
||||
|
||||
// Écriture du fichier symbols.bin
|
||||
let mut f = BufWriter::new(File::create("../target/symbols.bin")?);
|
||||
|
||||
// Header : [u64: count] [u64: string_table_offset]
|
||||
let header_size = 16;
|
||||
let sym_table_size = symbols_list.len() * std::mem::size_of::<RawSymbol>();
|
||||
f.write_all(&(symbols_list.len() as u64).to_le_bytes())?;
|
||||
f.write_all(&((header_size + sym_table_size) as u64).to_le_bytes())?;
|
||||
|
||||
// Table des symboles
|
||||
for sym in &symbols_list {
|
||||
unsafe {
|
||||
let bytes = std::slice::from_raw_parts(
|
||||
(sym as *const RawSymbol) as *const u8,
|
||||
std::mem::size_of::<RawSymbol>(),
|
||||
);
|
||||
f.write_all(bytes)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Table des noms
|
||||
f.write_all(&string_table)?;
|
||||
|
||||
println!(
|
||||
"Terminé ! {} symboles écrits dans symbols.bin",
|
||||
symbols_list.len()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
unsafe fn get_str(ptr: *const u8) -> &'static str {
|
||||
let mut len = 0;
|
||||
while *ptr.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
core::str::from_utf8_unchecked(core::slice::from_raw_parts(ptr, len))
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
use core::{alloc::Layout, time::Duration};
|
||||
|
||||
use bffs::path::Path;
|
||||
use io::SeekFrom;
|
||||
|
||||
use crate::fs::File;
|
||||
|
||||
#[repr(u64)]
|
||||
pub enum SysCall {
|
||||
Read = 0,
|
||||
@@ -100,10 +95,12 @@ macro_rules! syscall {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn exit() {
|
||||
pub fn exit() -> ! {
|
||||
unsafe {
|
||||
syscall!(SysCall::Exit);
|
||||
}
|
||||
#[allow(clippy::empty_loop)]
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub fn sleep(duration: Duration) {
|
||||
@@ -128,6 +125,8 @@ pub fn write_int_temp(content: u64) {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unknown_lints)]
|
||||
#[allow(fuzzy_provenance_casts)]
|
||||
pub fn alloc(layout: Layout) -> *mut u8 {
|
||||
unsafe {
|
||||
let size = layout.size();
|
||||
@@ -143,13 +142,12 @@ pub fn dealloc(ptr: *mut u8, layout: core::alloc::Layout) {
|
||||
syscall!(SysCall::Dealloc, ptr as u64, size as u64, align as u64);
|
||||
}
|
||||
}
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> File {
|
||||
pub fn open(path: &str) -> u64 {
|
||||
unsafe {
|
||||
let path_str = path.as_ref().as_str();
|
||||
let ptr = path_str.as_ptr();
|
||||
let size = path_str.len();
|
||||
let ptr = path.as_ptr();
|
||||
let size = path.len();
|
||||
let (fd, ..) = syscall!(SysCall::Open, ptr as u64, size as u64);
|
||||
File::from_raw_fd(fd)
|
||||
fd
|
||||
}
|
||||
}
|
||||
pub fn close(file_descriptor: u64) {
|
||||
@@ -173,29 +171,23 @@ pub fn read(file_descriptor: u64, buf: &mut [u8]) -> u64 {
|
||||
len
|
||||
}
|
||||
}
|
||||
pub fn seek(file_descriptor: u64, seek: SeekFrom) {
|
||||
/// seek_type: 0 -> start, 1 -> end, 2 -> current
|
||||
pub fn seek(file_descriptor: u64, seek_type: u8, seek: u64) {
|
||||
unsafe {
|
||||
let (discriminant, value) = match seek {
|
||||
SeekFrom::Start(v) => (0, v),
|
||||
SeekFrom::End(v) => (1, v as u64),
|
||||
SeekFrom::Current(v) => (2, v as u64),
|
||||
};
|
||||
syscall!(SysCall::Seek, file_descriptor, discriminant, value);
|
||||
syscall!(SysCall::Seek, file_descriptor, seek_type as u64, seek);
|
||||
}
|
||||
}
|
||||
pub fn spawn<P: AsRef<Path>>(path: P) {
|
||||
pub fn spawn(path: &str) {
|
||||
unsafe {
|
||||
let path_str = path.as_ref().as_str();
|
||||
let ptr = path_str.as_ptr();
|
||||
let size = path_str.len();
|
||||
let ptr = path.as_ptr();
|
||||
let size = path.len();
|
||||
syscall!(SysCall::Spawn, ptr as u64, size as u64);
|
||||
}
|
||||
}
|
||||
pub fn execve<P: AsRef<Path>>(path: P) {
|
||||
pub fn execve(path: &str) {
|
||||
unsafe {
|
||||
let path_str = path.as_ref().as_str();
|
||||
let ptr = path_str.as_ptr();
|
||||
let size = path_str.len();
|
||||
let ptr = path.as_ptr();
|
||||
let size = path.len();
|
||||
syscall!(SysCall::ExecVE, ptr as u64, size as u64);
|
||||
}
|
||||
}
|
||||
|
||||
7
justfile
7
justfile
@@ -25,11 +25,15 @@ build_user_prog prog:
|
||||
fi
|
||||
cp {{ bin_path / prog + "-stripped" }} {{ "mnt/usr/bin" / prog }}
|
||||
|
||||
make-symbols:
|
||||
cd build-tools && cargo r --bin gen-symbols --release
|
||||
|
||||
build: mount_filesystem
|
||||
@for file in `ls user`; do \
|
||||
{{ just_executable() }} release="{{ release }}" cargo_flags="{{ cargo_flags }}" build_user_prog $file ; \
|
||||
done
|
||||
RUSTFLAGS="-Clink-arg=-Tilm.ld --sysroot {{ justfile_directory() / "sysroot" }}" cargo b {{ cargo_flags }}
|
||||
RUSTFLAGS="-Cforce-frame-pointers=yes -Clink-arg=-Tilm.ld --sysroot {{ justfile_directory() / "sysroot" }}" cargo b {{ cargo_flags }}
|
||||
{{ just_executable() }} make-symbols
|
||||
sync
|
||||
|
||||
run: build (runner f"{{bin_path / "kernel-rust"}}")
|
||||
@@ -41,6 +45,7 @@ QEMU := f"qemu-system-riscv64 \
|
||||
-device virtio-keyboard-pci \
|
||||
-device virtio-mouse-pci \
|
||||
-device loader,file=disk.img,addr=0xA0000000 \
|
||||
-device loader,file=target/symbols.bin,addr=0xB0000000 \
|
||||
-bios none -m 1024M {{qemu_flags}}"
|
||||
|
||||
# -trace \"virtio*\"
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
62a \ target_os = "survos" => { \
|
||||
mod unsupported; \
|
||||
pub use self::unsupported::*; \
|
||||
mod survos; \
|
||||
pub use self::survos::*; \
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
#[path = "unsupported/mod.rs"]
|
||||
mod unsupported;
|
||||
pub use self::unsupported::*;
|
||||
|
||||
#[path = "../../../../../crates/shared/src/syscall.rs"]
|
||||
mod syscall;
|
||||
|
||||
/// # Safety
|
||||
/// `argc` and `argv` are passed by the kernel
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -9,3 +16,8 @@ pub unsafe extern "C" fn _start(argc: isize, argv: *const *const u8) -> isize {
|
||||
|
||||
unsafe { main(argc, argv) }
|
||||
}
|
||||
|
||||
pub fn abort_internal() -> ! {
|
||||
// todo real abort
|
||||
syscall::exit()
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
|
||||
|
||||
#[path = "unsupported.rs"]
|
||||
mod unsupported;
|
||||
pub use self::unsupported::{STDIN_BUF_SIZE, Stderr, Stdin, is_ebadf, panic_output};
|
||||
pub use self::unsupported::{STDIN_BUF_SIZE, Stderr, Stdin, is_ebadf};
|
||||
|
||||
pub struct Stdout;
|
||||
// pub struct Stdin;
|
||||
@@ -36,6 +36,11 @@ impl io::Write for Stdout {
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn panic_output() -> Option<impl io::Write> {
|
||||
// Todo, use Stderr
|
||||
Some(Stdout::new())
|
||||
}
|
||||
|
||||
#[repr(u64)]
|
||||
pub enum SysCall {
|
||||
Read = 0,
|
||||
|
||||
@@ -18,6 +18,14 @@ pub extern "C" fn _start() {
|
||||
naked_asm!(
|
||||
"
|
||||
la sp, _heap_end
|
||||
|
||||
// Set BSS to zero
|
||||
la t0, __bss_start
|
||||
la t1, __bss_end
|
||||
1: sd zero, 0(t0)
|
||||
addi t0, t0, 8
|
||||
bleu t0, t1, 1b
|
||||
|
||||
jal machine_mode_entry
|
||||
1:
|
||||
j 1b"
|
||||
|
||||
@@ -61,7 +61,7 @@ mod virtio;
|
||||
mod virtual_console;
|
||||
mod virtual_fs;
|
||||
|
||||
pub const HEAP_SIZE: usize = 1024 * 1024 * 32; // 32Mo RAM
|
||||
pub const HEAP_SIZE: usize = 1024 * 1024 * 128; // 128Mo RAM
|
||||
#[global_allocator]
|
||||
static HEAP: Heap = Heap::empty();
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
//! framebuffer before halting the CPU.
|
||||
use core::arch::riscv64::wfi;
|
||||
|
||||
use alloc::{format, string::ToString};
|
||||
use alloc::{
|
||||
format,
|
||||
string::{String, ToString},
|
||||
};
|
||||
use log::error;
|
||||
|
||||
use crate::{
|
||||
@@ -14,6 +17,27 @@ use crate::{
|
||||
vga::Vga,
|
||||
};
|
||||
|
||||
fn print_stack_trace() {
|
||||
let mut fp: usize;
|
||||
unsafe {
|
||||
core::arch::asm!("mv {}, s0", out(reg) fp);
|
||||
}
|
||||
|
||||
error!("STACK TRACE:");
|
||||
for i in 0..10 {
|
||||
if fp == 0 || !fp.is_multiple_of(8) {
|
||||
break;
|
||||
}
|
||||
unsafe {
|
||||
// On RISC-V with FP :
|
||||
// fp - 8 => Return Address (ra)
|
||||
// fp - 16 => Previous Frame Pointer
|
||||
let ra = *((fp - 8) as *const usize);
|
||||
error!(" [{}] 0x{:016x} {}", i, ra, resolve_symbol(ra));
|
||||
fp = *((fp - 16) as *const usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
#[panic_handler]
|
||||
/// Kernel panic handler that displays the panic message on the framebuffer and halts.
|
||||
fn panic(panic_info: &core::panic::PanicInfo) -> ! {
|
||||
@@ -26,6 +50,7 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
|
||||
panic_message = format!("{panic_message} at {}:{}", location.file(), location.line());
|
||||
}
|
||||
error!("{panic_message}");
|
||||
print_stack_trace();
|
||||
|
||||
Vga.clear_screen(Color::WHITE);
|
||||
unsafe { Vga.draw_string(0, 0, "PANIC !", Color::BLACK, Color::WHITE) };
|
||||
@@ -44,3 +69,47 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
|
||||
unsafe { wfi() }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
#[derive(Debug)]
|
||||
struct RawSymbol {
|
||||
addr: u64,
|
||||
line: u32,
|
||||
name_off: u32,
|
||||
file_off: u32,
|
||||
}
|
||||
pub fn resolve_symbol(pc: usize) -> String {
|
||||
let start = 0xB000_0000 as *const u8;
|
||||
|
||||
let count = unsafe { *(start as *const u64) };
|
||||
let str_table_off = unsafe { *((start as *const u64).add(1)) };
|
||||
let symbol_ptr = unsafe { start.add(16) as *const RawSymbol };
|
||||
let str_table_ptr = unsafe { start.add(str_table_off as usize) };
|
||||
|
||||
let symbols = unsafe { core::slice::from_raw_parts(symbol_ptr, count as usize) };
|
||||
|
||||
let idx = match symbols.binary_search_by_key(&(pc as u64), |s| s.addr) {
|
||||
Ok(i) => i,
|
||||
Err(i) if i > 0 => i - 1,
|
||||
_ => return Default::default(),
|
||||
};
|
||||
|
||||
let sym = &symbols[idx];
|
||||
|
||||
unsafe {
|
||||
let name = get_str(str_table_ptr.add(sym.name_off as usize));
|
||||
let file = get_str(str_table_ptr.add(sym.file_off as usize));
|
||||
|
||||
format!("at {} ({}:{})", name, file, sym.line)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn get_str(ptr: *const u8) -> &'static str {
|
||||
unsafe {
|
||||
let mut len = 0;
|
||||
while *ptr.add(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
core::str::from_utf8_unchecked(core::slice::from_raw_parts(ptr, len))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
};
|
||||
|
||||
/// Size of the stack allocated to each process (in 64-bit words).
|
||||
const STACK_SIZE: usize = 4096;
|
||||
const STACK_SIZE: usize = 1024 * 1024 * 2;
|
||||
|
||||
/// Represents the state of a process in the system.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
@@ -197,7 +197,6 @@ impl Scheduler {
|
||||
if ph.p_type == goblin::elf::program_header::PT_LOAD {
|
||||
let dst = unsafe { base.add((ph.p_vaddr - min_vaddr) as usize) };
|
||||
let src_off = ph.p_offset as usize;
|
||||
println!("off{:x?}", dst);
|
||||
let copy_len = ph.p_filesz as usize;
|
||||
if copy_len > 0 {
|
||||
unsafe {
|
||||
@@ -208,6 +207,12 @@ impl Scheduler {
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for ph in gelf.program_headers.iter() {
|
||||
if ph.p_type == goblin::elf::program_header::PT_LOAD {
|
||||
let dst = unsafe { base.add((ph.p_vaddr - min_vaddr) as usize) };
|
||||
let copy_len = ph.p_filesz as usize;
|
||||
if ph.p_memsz as usize > copy_len {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
@@ -229,16 +234,6 @@ impl Scheduler {
|
||||
let where_off = (rela.r_offset - min_vaddr) as usize;
|
||||
let where_ptr = unsafe { base.add(where_off) } as *mut u64;
|
||||
let val = (base as u64).wrapping_add(rela.r_addend.unwrap() as u64);
|
||||
if rela.r_addend.unwrap() == 0x5bfb8 {
|
||||
println!(
|
||||
"Relocating GLOBAL_PANIC_COUNT: at {:p}, setting value to {:x}",
|
||||
where_ptr, val
|
||||
);
|
||||
assert!(
|
||||
val % 8 == 0,
|
||||
"DANGER: Address of GLOBAL_PANIC_COUNT is not 8-aligned!"
|
||||
);
|
||||
}
|
||||
unsafe { core::ptr::write_unaligned(where_ptr, val) };
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#![allow(unused)]
|
||||
#![feature(panic_internals, core_intrinsics)]
|
||||
|
||||
use core::sync::atomic::AtomicUsize;
|
||||
use io::{Read as Readio, Write};
|
||||
use shared::syscall;
|
||||
use shared::{fs::File, syscall};
|
||||
use std::io::{Read, Stdin, stdin};
|
||||
|
||||
static FOO: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
fn main() {
|
||||
let mut input = String::new();
|
||||
input.push('a');
|
||||
@@ -13,13 +15,15 @@ fn main() {
|
||||
// syscall::write(&mut file, &[255; 6400 * 50]);
|
||||
// syscall::sleep(Duration::from_secs_f64(2.0));
|
||||
syscall::close(0);
|
||||
let mut tty = syscall::open("/dev/tty0");
|
||||
let mut tty = unsafe { File::from_raw_fd(syscall::open("/dev/tty0")) };
|
||||
syscall::close(1);
|
||||
let _ = syscall::open("/dev/tty0");
|
||||
println!("test from test_pic");
|
||||
tty.write(input.as_bytes()).unwrap();
|
||||
syscall::spawn("/usr/bin/shell");
|
||||
core::panicking::panic("explicit panic");
|
||||
// panic!("explicit panic");
|
||||
// std::process::abort();
|
||||
unsafe {core::arch::asm!("unimp")};
|
||||
loop {
|
||||
let mut test = [0; 2];
|
||||
// let len = stdin().read(&mut test);
|
||||
|
||||
Reference in New Issue
Block a user