kernel: backtrace
This commit is contained in:
parent
6b65dc594c
commit
723063d31e
14
Cargo.lock
generated
14
Cargo.lock
generated
|
|
@ -20,14 +20,28 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bit_field",
|
||||
"bitflags",
|
||||
"plain",
|
||||
"rbtree",
|
||||
"rustc-demangle",
|
||||
"seq-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plain"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
|
||||
[[package]]
|
||||
name = "rbtree"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb"
|
||||
|
||||
[[package]]
|
||||
name = "seq-macro"
|
||||
version = "0.3.6"
|
||||
|
|
|
|||
|
|
@ -8,3 +8,6 @@ target = "x86_64-unknown-kernel.json"
|
|||
|
||||
[target.x86_64-unknown-kernel]
|
||||
runner = "./run.sh"
|
||||
rustflags = [
|
||||
"-C", "force-frame-pointers=yes",
|
||||
]
|
||||
|
|
@ -27,3 +27,5 @@ bitflags = "2.13.1"
|
|||
seq-macro = "0.3.6"
|
||||
|
||||
rbtree = { path = "../crates/rbtree" }
|
||||
plain = "0.2.3"
|
||||
rustc-demangle = "0.1.28"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ PHDRS {
|
|||
|
||||
SECTIONS {
|
||||
. = 0xffffffff80000000;
|
||||
__kernel_start = .;
|
||||
|
||||
.limine_requests : {
|
||||
KEEP(*(.limine_requests_start))
|
||||
KEEP(*(.limine_requests))
|
||||
|
|
@ -36,6 +38,16 @@ SECTIONS {
|
|||
*(COMMON)
|
||||
} :data
|
||||
|
||||
__kernel_end = .;
|
||||
|
||||
.symtab 0: {
|
||||
*(.symtab)
|
||||
}
|
||||
|
||||
.strtab 0: {
|
||||
*(.strtab)
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame*)
|
||||
*(.note .note.*)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use core::{cell::UnsafeCell, fmt::Debug, ptr::NonNull};
|
||||
use core::{cell::UnsafeCell, ffi::CStr, fmt::Debug, ptr::NonNull};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct BaseRevision(UnsafeCell<[u64; 3]>);
|
||||
|
|
@ -272,3 +272,60 @@ impl HhdmRequest {
|
|||
self.response().map(|response| response.response.offset)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct ExecutableFileResponse {
|
||||
file: *const LimineFile,
|
||||
}
|
||||
|
||||
unsafe impl Send for ExecutableFileResponse {}
|
||||
unsafe impl Sync for ExecutableFileResponse {}
|
||||
|
||||
pub type ExecutableFileRequest = Request<ExecutableFileResponse>;
|
||||
|
||||
impl ExecutableFileRequest {
|
||||
const ID: [u64; 2] = [0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69];
|
||||
|
||||
pub const fn new() -> Self {
|
||||
Self::new_raw(Self::ID, 0, ())
|
||||
}
|
||||
|
||||
pub fn file(&self) -> Option<&LimineFile> {
|
||||
self.response()
|
||||
.and_then(|response| unsafe { response.response.file.as_ref() })
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct LimineFile {
|
||||
pub revision: u64,
|
||||
pub addr: *const u8,
|
||||
pub length: u64,
|
||||
pub path: *const i8,
|
||||
pub string: *const i8,
|
||||
pub media_type: u32,
|
||||
pub _padding: [u8; 4],
|
||||
pub tftp_ipv4_addr: [u8; 4],
|
||||
pub tftp_port: u32,
|
||||
pub partition_index: u32,
|
||||
pub mbr_disk_id: u32,
|
||||
pub gpt_disk_uuid: [u8; 16],
|
||||
pub gpt_part_uuid: [u8; 16],
|
||||
pub part_uuid: [u8; 16],
|
||||
}
|
||||
|
||||
impl LimineFile {
|
||||
pub const MEDIA_TYPE_GENERIC: u32 = 0;
|
||||
pub const MEDIA_TYPE_OPTICAL: u32 = 1;
|
||||
pub const MEDIA_TYPE_TFTP: u32 = 2;
|
||||
|
||||
pub fn bytes(&self) -> &'static [u8] {
|
||||
unsafe { core::slice::from_raw_parts(self.addr, self.length as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
#[used]
|
||||
#[unsafe(link_section = ".limine_requests")]
|
||||
pub static EXECUTABLE_FILE_REQUEST: ExecutableFileRequest = ExecutableFileRequest::new();
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ extern "C" fn _start() -> ! {
|
|||
GDT.load();
|
||||
IDT.load();
|
||||
|
||||
unsafe { (0 as *mut u8).write_volatile(0x42) };
|
||||
|
||||
kernel::serial_println!("entry point: 0x{:x}", _start as *const () as usize);
|
||||
kernel::serial_println!(
|
||||
"entry point phy: {:?}",
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@ use crate::{serial_println, sync::OnceLock, x86_64::PAGE_SIZE};
|
|||
|
||||
pub static HHDM_BASE: OnceLock<u64> = OnceLock::new();
|
||||
|
||||
pub trait VirtAddrTranslationExt {
|
||||
pub trait VirtAddrTranslationExt: Sized {
|
||||
fn into_phy_addr(self) -> Option<PhyAddr>;
|
||||
fn is_mapped(self) -> bool {
|
||||
self.into_phy_addr().is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
|
|
@ -51,6 +54,12 @@ impl Debug for PhyAddr {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<u64> for VirtAddr {
|
||||
fn from(value: u64) -> Self {
|
||||
VirtAddr(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<&T> for VirtAddr {
|
||||
fn from(ptr: &T) -> Self {
|
||||
VirtAddr(ptr as *const T as u64)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#![cfg(target_arch = "x86_64")]
|
||||
|
||||
pub mod backtrace;
|
||||
pub mod cpuid;
|
||||
pub mod gdt;
|
||||
pub mod idt;
|
||||
|
|
@ -212,3 +213,67 @@ impl VirtAddrExt for VirtAddr {
|
|||
E::decompose(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Context {
|
||||
pub registers: Registers,
|
||||
pub rip: u64,
|
||||
pub rflags: RFlags,
|
||||
pub rsp: u64,
|
||||
/// The code segment selector.
|
||||
pub cs: u16,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for Context {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
writeln!(f, "RIP - {:>#018x} \tRSP - {:>#018x}", self.rip, self.rsp)?;
|
||||
writeln!(
|
||||
f,
|
||||
"FLAGS - {:>#018x} \tCS - {:>#018x}",
|
||||
self.rflags.bits(),
|
||||
self.cs
|
||||
)?;
|
||||
|
||||
writeln!(
|
||||
f,
|
||||
"RAX: {:>#018x} \tRCX: {:>#018x}",
|
||||
self.registers.rax, self.registers.rcx
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"RDX: {:>#018x} \tRBX: {:>#018x}",
|
||||
self.registers.rdx, self.registers.rbx
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"RSP: {:>#018x} \tRBP: {:>#018x}",
|
||||
self.rsp, self.registers.rbp
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"RSI: {:>#018x} \tRDI: {:>#018x}",
|
||||
self.registers.rsi, self.registers.rdi
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"R8 : {:>#018x} \tR9 : {:>#018x}",
|
||||
self.registers.r8, self.registers.r9
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"R10: {:>#018x} \tR11: {:>#018x}",
|
||||
self.registers.r10, self.registers.r11
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"R12: {:>#018x} \tR13: {:>#018x}",
|
||||
self.registers.r12, self.registers.r13
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"R14: {:>#018x} \tR15: {:>#018x}",
|
||||
self.registers.r14, self.registers.r15
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
495
kernel/src/x86_64/backtrace.rs
Normal file
495
kernel/src/x86_64/backtrace.rs
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
use core::ffi::{CStr, c_void};
|
||||
|
||||
use crate::{
|
||||
limine::LimineFile,
|
||||
memory::{VirtAddr, VirtAddrTranslationExt},
|
||||
serial_println,
|
||||
sync::LazyLock,
|
||||
x86_64::{Context, VirtAddrExt},
|
||||
};
|
||||
|
||||
unsafe extern "C" {
|
||||
static __kernel_start: c_void;
|
||||
static __kernel_end: c_void;
|
||||
}
|
||||
|
||||
pub struct Frame {
|
||||
pub rip: u64,
|
||||
pub rbp: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum Elf64SymBind {
|
||||
Local = 0,
|
||||
Global = 1,
|
||||
Weak = 2,
|
||||
Loos = 10,
|
||||
Hios = 12,
|
||||
Loproc = 13,
|
||||
Hiproc = 15,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum Elf64SymType {
|
||||
Notype = 0,
|
||||
Object = 1,
|
||||
Func = 2,
|
||||
Section = 3,
|
||||
File = 4,
|
||||
Common = 5,
|
||||
Tls = 6,
|
||||
Loos = 10,
|
||||
Hios = 12,
|
||||
Loproc = 13,
|
||||
Hiproc = 15,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct Elf64Sym {
|
||||
name: u32,
|
||||
info: u8,
|
||||
other: u8,
|
||||
shndx: u16,
|
||||
value: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
unsafe impl plain::Plain for Elf64Sym {}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum SectionHeaderType {
|
||||
Null = 0,
|
||||
Progbits = 1,
|
||||
Symtab = 2,
|
||||
Strtab = 3,
|
||||
Rela = 4,
|
||||
Hash = 5,
|
||||
Dynamic = 6,
|
||||
Note = 7,
|
||||
Nobits = 8,
|
||||
Rel = 9,
|
||||
Shlib = 10,
|
||||
Dynsym = 11,
|
||||
InitArray = 14,
|
||||
FiniArray = 15,
|
||||
PreinitArray = 16,
|
||||
Group = 17,
|
||||
SymtabShndx = 18,
|
||||
Num = 19,
|
||||
GnuAttributes = 0x6ffffff5,
|
||||
GnuHash = 0x6ffffff6,
|
||||
GnuLiblist = 0x6ffffff7,
|
||||
Checksum = 0x6ffffff8,
|
||||
Losunwind = 0x6ffffffa,
|
||||
Amd64Unwind = 0x7000001,
|
||||
OsSpecific(u32),
|
||||
ProcSpecific(u32),
|
||||
UserSpecific(u32),
|
||||
Unknown = 0xffffffff,
|
||||
}
|
||||
|
||||
impl SectionHeaderType {
|
||||
fn from_u32(value: u32) -> Self {
|
||||
match value {
|
||||
0 => Self::Null,
|
||||
1 => Self::Progbits,
|
||||
2 => Self::Symtab,
|
||||
3 => Self::Strtab,
|
||||
4 => Self::Rela,
|
||||
5 => Self::Hash,
|
||||
6 => Self::Dynamic,
|
||||
7 => Self::Note,
|
||||
8 => Self::Nobits,
|
||||
9 => Self::Rel,
|
||||
10 => Self::Shlib,
|
||||
11 => Self::Dynsym,
|
||||
14 => Self::InitArray,
|
||||
15 => Self::FiniArray,
|
||||
16 => Self::PreinitArray,
|
||||
17 => Self::Group,
|
||||
18 => Self::SymtabShndx,
|
||||
19 => Self::Num,
|
||||
0x6ffffff5 => Self::GnuAttributes,
|
||||
0x6ffffff6 => Self::GnuHash,
|
||||
0x6ffffff7 => Self::GnuLiblist,
|
||||
0x6ffffff8 => Self::Checksum,
|
||||
0x6ffffffa => Self::Losunwind,
|
||||
0x7000001 => Self::Amd64Unwind,
|
||||
0x60000000..=0x6fffffff => Self::OsSpecific(value),
|
||||
0x70000000..=0x7fffffff => Self::ProcSpecific(value),
|
||||
0x80000000..=0x8fffffff => Self::UserSpecific(value),
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_u32(self) -> u32 {
|
||||
match self {
|
||||
Self::Null => 0,
|
||||
Self::Progbits => 1,
|
||||
Self::Symtab => 2,
|
||||
Self::Strtab => 3,
|
||||
Self::Rela => 4,
|
||||
Self::Hash => 5,
|
||||
Self::Dynamic => 6,
|
||||
Self::Note => 7,
|
||||
Self::Nobits => 8,
|
||||
Self::Rel => 9,
|
||||
Self::Shlib => 10,
|
||||
Self::Dynsym => 11,
|
||||
Self::InitArray => 14,
|
||||
Self::FiniArray => 15,
|
||||
Self::PreinitArray => 16,
|
||||
Self::Group => 17,
|
||||
Self::SymtabShndx => 18,
|
||||
Self::Num => 19,
|
||||
Self::GnuAttributes => 0x6ffffff5,
|
||||
Self::GnuHash => 0x6ffffff6,
|
||||
Self::GnuLiblist => 0x6ffffff7,
|
||||
Self::Checksum => 0x6ffffff8,
|
||||
Self::Losunwind => 0x6ffffffa,
|
||||
Self::Amd64Unwind => 0x7000001,
|
||||
Self::OsSpecific(value) | Self::ProcSpecific(value) | Self::UserSpecific(value) => {
|
||||
value
|
||||
}
|
||||
Self::Unknown => 0xffffffff,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct SectionHeader {
|
||||
name: u32,
|
||||
sh_type: u32,
|
||||
flags: u64,
|
||||
addr: u64,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
link: u32,
|
||||
info: u32,
|
||||
addralign: u64,
|
||||
entsize: u64,
|
||||
}
|
||||
|
||||
unsafe impl plain::Plain for SectionHeader {}
|
||||
|
||||
impl SectionHeader {
|
||||
fn bytes<'a>(&self, bytes: &'a [u8]) -> Option<&'a [u8]> {
|
||||
let offset = self.offset as usize;
|
||||
let size = self.size as usize;
|
||||
|
||||
if offset + size > bytes.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(&bytes[offset..offset + size])
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct Elf64Ehdr {
|
||||
ident: [u8; 16],
|
||||
kind: u16,
|
||||
machine: u16,
|
||||
version: u32,
|
||||
entry: u64,
|
||||
phoff: u64,
|
||||
shoff: u64,
|
||||
flags: u32,
|
||||
ehsize: u16,
|
||||
phentsize: u16,
|
||||
phnum: u16,
|
||||
shentsize: u16,
|
||||
shnum: u16,
|
||||
shstrndx: u16,
|
||||
}
|
||||
|
||||
unsafe impl plain::Plain for Elf64Ehdr {}
|
||||
|
||||
struct SectionHeaders<'a> {
|
||||
headers: &'a [SectionHeader],
|
||||
}
|
||||
|
||||
impl<'a> SectionHeaders<'a> {
|
||||
fn symtab_hdr(&self) -> Option<&'a SectionHeader> {
|
||||
self.headers
|
||||
.iter()
|
||||
.find(|header| SectionHeaderType::from_u32(header.sh_type) == SectionHeaderType::Symtab)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Strtab<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Strtab<'a> {
|
||||
fn len(&self) -> usize {
|
||||
self.bytes.len()
|
||||
}
|
||||
fn get_str(&self, offset: u32) -> Option<&'a str> {
|
||||
let offset = offset as usize;
|
||||
|
||||
if offset >= self.bytes.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let bytes = &self.bytes[offset..];
|
||||
|
||||
let nul_pos = bytes.iter().position(|&b| b == 0)?;
|
||||
|
||||
core::str::from_utf8(&bytes[..nul_pos]).ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl Elf64Ehdr {
|
||||
fn section_headers<'a>(&self, bytes: &'a [u8]) -> SectionHeaders<'a> {
|
||||
let shoff = self.shoff as usize;
|
||||
// let shentsize = self.shentsize as usize;
|
||||
let shnum = self.shnum as usize;
|
||||
|
||||
unsafe {
|
||||
SectionHeaders {
|
||||
headers: core::slice::from_raw_parts(
|
||||
bytes.as_ptr().byte_add(shoff).cast::<SectionHeader>(),
|
||||
shnum,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn shstrtab<'a>(&self, bytes: &'a [u8]) -> Option<Strtab<'a>> {
|
||||
let shstrndx = self.shstrndx as usize;
|
||||
let section_headers = self.section_headers(bytes);
|
||||
|
||||
if shstrndx >= section_headers.headers.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let shstrtab_header = §ion_headers.headers[shstrndx];
|
||||
serial_println!("shstrtab_header: {:#?}", shstrtab_header);
|
||||
let offset = shstrtab_header.offset as usize;
|
||||
let size = shstrtab_header.size as usize;
|
||||
|
||||
if offset + size > bytes.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Strtab {
|
||||
bytes: &bytes[offset..offset + size],
|
||||
})
|
||||
}
|
||||
|
||||
fn find_shdr_by_name<'a>(&self, bytes: &'a [u8], name: &str) -> Option<&'a SectionHeader> {
|
||||
let shstrtab = self.shstrtab(bytes)?;
|
||||
let section_headers = self.section_headers(bytes);
|
||||
|
||||
section_headers
|
||||
.headers
|
||||
.iter()
|
||||
.find(|header| shstrtab.get_str(header.name) == Some(name))
|
||||
}
|
||||
|
||||
fn strtab<'a>(&self, bytes: &'a [u8]) -> Option<Strtab<'a>> {
|
||||
let strtab = self.find_shdr_by_name(bytes, ".strtab")?;
|
||||
|
||||
let offset = strtab.offset as usize;
|
||||
let size = strtab.size as usize;
|
||||
|
||||
if offset + size > bytes.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Strtab {
|
||||
bytes: &bytes[offset..offset + size],
|
||||
})
|
||||
}
|
||||
|
||||
fn symtab<'a>(&self, bytes: &'a [u8]) -> Option<&'a [Elf64Sym]> {
|
||||
let section_headers = self.section_headers(bytes);
|
||||
let symtab_header = section_headers.symtab_hdr()?;
|
||||
|
||||
let offset = symtab_header.offset as usize;
|
||||
let size = symtab_header.size as usize;
|
||||
|
||||
if offset + size > bytes.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let num_symbols = size / core::mem::size_of::<Elf64Sym>();
|
||||
|
||||
unsafe {
|
||||
Some(core::slice::from_raw_parts(
|
||||
bytes.as_ptr().byte_add(offset).cast::<Elf64Sym>(),
|
||||
num_symbols,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Elf64Sym {
|
||||
fn symbols() -> &'static [Elf64Sym] {
|
||||
static SYMBOLS: LazyLock<&'static [Elf64Sym]> = LazyLock::new(|| {
|
||||
if let Some(bytes) = crate::limine::EXECUTABLE_FILE_REQUEST
|
||||
.file()
|
||||
.map(LimineFile::bytes)
|
||||
{
|
||||
if let Ok(ehdr) = plain::from_bytes::<Elf64Ehdr>(bytes) {
|
||||
if let Some(symtab) = ehdr.symtab(bytes) {
|
||||
return symtab;
|
||||
}
|
||||
}
|
||||
}
|
||||
&[]
|
||||
});
|
||||
|
||||
SYMBOLS.as_ref()
|
||||
}
|
||||
|
||||
fn find(addr: u64) -> Option<&'static Elf64Sym> {
|
||||
Self::symbols()
|
||||
.iter()
|
||||
.find(|&sym| sym.range().contains(&addr))
|
||||
.map(|v| v as _)
|
||||
}
|
||||
|
||||
fn find_type(addr: u64, kind: Elf64SymType) -> Option<&'static Elf64Sym> {
|
||||
Self::symbols()
|
||||
.iter()
|
||||
.find(|&sym| sym.kind() == kind && sym.range().contains(&addr))
|
||||
.map(|v| v as _)
|
||||
}
|
||||
|
||||
fn bind(&self) -> Elf64SymBind {
|
||||
match self.info >> 4 {
|
||||
0 => Elf64SymBind::Local,
|
||||
1 => Elf64SymBind::Global,
|
||||
2 => Elf64SymBind::Weak,
|
||||
10 => Elf64SymBind::Loos,
|
||||
12 => Elf64SymBind::Hios,
|
||||
13 => Elf64SymBind::Loproc,
|
||||
15 => Elf64SymBind::Hiproc,
|
||||
_ => panic!("Invalid bind value"),
|
||||
}
|
||||
}
|
||||
fn kind(&self) -> Elf64SymType {
|
||||
match self.info & 0xf {
|
||||
0 => Elf64SymType::Notype,
|
||||
1 => Elf64SymType::Object,
|
||||
2 => Elf64SymType::Func,
|
||||
3 => Elf64SymType::Section,
|
||||
4 => Elf64SymType::File,
|
||||
5 => Elf64SymType::Common,
|
||||
6 => Elf64SymType::Tls,
|
||||
10 => Elf64SymType::Loos,
|
||||
12 => Elf64SymType::Hios,
|
||||
13 => Elf64SymType::Loproc,
|
||||
15 => Elf64SymType::Hiproc,
|
||||
_ => panic!("Invalid type value"),
|
||||
}
|
||||
}
|
||||
|
||||
fn range(&self) -> core::ops::Range<u64> {
|
||||
self.value..(self.value.saturating_add(self.size))
|
||||
}
|
||||
|
||||
fn name(&self) -> Option<&str> {
|
||||
static STRTAB: LazyLock<Strtab<'static>> = LazyLock::new(|| {
|
||||
if let Some(bytes) = crate::limine::EXECUTABLE_FILE_REQUEST
|
||||
.file()
|
||||
.map(LimineFile::bytes)
|
||||
&& let Ok(ehdr) = plain::from_bytes::<Elf64Ehdr>(bytes)
|
||||
{
|
||||
serial_println!("ELF64 Header: {:#?}", ehdr);
|
||||
return ehdr.strtab(bytes).unwrap_or_default();
|
||||
}
|
||||
|
||||
Strtab::default()
|
||||
});
|
||||
|
||||
let len = STRTAB.len();
|
||||
|
||||
if self.name == 0 || self.name as usize >= len {
|
||||
return None;
|
||||
}
|
||||
|
||||
STRTAB.get_str(self.name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn backtrace(ctx: &Context) -> impl Iterator<Item = Frame> {
|
||||
Backtrace {
|
||||
frame: Some(Frame {
|
||||
rip: ctx.rip,
|
||||
rbp: ctx.registers.rbp,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debug_backtrace(ctx: &Context) {
|
||||
serial_println!("{ctx}");
|
||||
for frame in backtrace(ctx) {
|
||||
if let Some(sym) = Elf64Sym::find(frame.rip) {
|
||||
if sym.kind() == Elf64SymType::Func
|
||||
&& sym.shndx != 0
|
||||
&& let Some(name) = sym.name()
|
||||
{
|
||||
serial_println!(
|
||||
"0x{:016x} - {} + 0x{:x}",
|
||||
frame.rip,
|
||||
rustc_demangle::demangle(name),
|
||||
frame.rip - sym.value
|
||||
);
|
||||
} else {
|
||||
serial_println!("{sym:#?}");
|
||||
serial_println!(
|
||||
"0x{:016x} - <unknown> + 0x{:x}",
|
||||
frame.rip,
|
||||
frame.rip - sym.value
|
||||
);
|
||||
}
|
||||
} else {
|
||||
serial_println!("0x{:016x} - <unknown>", frame.rip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Backtrace {
|
||||
frame: Option<Frame>,
|
||||
}
|
||||
|
||||
impl Iterator for Backtrace {
|
||||
type Item = Frame;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let frame = self.frame.take()?;
|
||||
|
||||
let next_frame = {
|
||||
let rsp = VirtAddr::from(frame.rbp);
|
||||
if rsp.is_canonical() && rsp.is_mapped() {
|
||||
// The stack frame layout is as follows:
|
||||
// | Our Function |
|
||||
// +-----------------+
|
||||
// | Previous RBP | <- RBP points here
|
||||
// +-----------------+
|
||||
// | Return Address | <- RBP + 8 points here
|
||||
// +-----------------+
|
||||
// | Parent Function |
|
||||
//
|
||||
let rip = unsafe { *(rsp.as_ptr::<u64>().add(1)) };
|
||||
let rbp = unsafe { *(rsp.as_ptr::<u64>()) };
|
||||
|
||||
Some(Frame { rip, rbp })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
self.frame = next_frame;
|
||||
|
||||
Some(frame)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ use bit_field::BitField;
|
|||
|
||||
use crate::{
|
||||
serial_println,
|
||||
x86_64::{RFlags, Registers, halt_loop},
|
||||
x86_64::{Context, RFlags, Registers, backtrace::debug_backtrace, halt_loop},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
|
@ -521,6 +521,13 @@ extern "C" fn global_interrupt_handler(
|
|||
}
|
||||
ExceptionVector::PAGE_FAULT => {
|
||||
serial_println!("Page fault occurred! Error code: {:#x}", error_code);
|
||||
debug_backtrace(&Context {
|
||||
rip: frame.instruction_pointer,
|
||||
registers: *registers,
|
||||
rsp: frame.stack_pointer,
|
||||
rflags: frame.flags,
|
||||
cs: frame.code_segment,
|
||||
});
|
||||
halt_loop()
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use bit_field::BitField;
|
|||
|
||||
use crate::{
|
||||
memory::{PhyAddr, VirtAddr, VirtAddrTranslationExt},
|
||||
serial_println,
|
||||
x86_64::{VirtAddrExt, registers::Cr4},
|
||||
};
|
||||
|
||||
|
|
@ -186,8 +185,6 @@ impl VirtAddrTranslationExt for VirtAddr {
|
|||
pub fn get_physical_addr(virt: VirtAddr) -> Option<PhyAddr> {
|
||||
let cr3 = crate::x86_64::registers::Cr3::read();
|
||||
let cr4 = crate::x86_64::registers::Cr4::read();
|
||||
serial_println!("cr3: {:?}", cr3);
|
||||
serial_println!("cr4: {:?}", cr4);
|
||||
|
||||
let frame = cr3.phy();
|
||||
let page_table = unsafe {
|
||||
|
|
@ -208,10 +205,7 @@ pub fn get_physical_addr(virt: VirtAddr) -> Option<PhyAddr> {
|
|||
page_table[virt.page_table_index::<{ VirtAddr::PML4 }>()]
|
||||
};
|
||||
|
||||
serial_println!("pml4_entry: {:?}", pml4_entry);
|
||||
|
||||
let pdpt_entry = pml4_entry.try_as_page_table()?[virt.page_table_index::<{ VirtAddr::PDPT }>()];
|
||||
serial_println!("pdpt_entry: {:?}", pdpt_entry);
|
||||
|
||||
if pdpt_entry.contains(PageTableEntryFlags::HUGE_PAGE) {
|
||||
const PHY_MASK_1G: u64 = !((1 << 30) - 1);
|
||||
|
|
@ -220,7 +214,6 @@ pub fn get_physical_addr(virt: VirtAddr) -> Option<PhyAddr> {
|
|||
}
|
||||
|
||||
let pd_entry = pdpt_entry.try_as_page_table()?[virt.page_table_index::<{ VirtAddr::PD }>()];
|
||||
serial_println!("pd_entry: {:?}", pd_entry);
|
||||
|
||||
if pd_entry.contains(PageTableEntryFlags::HUGE_PAGE) {
|
||||
const PHY_MASK_2M: u64 = !((1 << 21) - 1);
|
||||
|
|
@ -229,7 +222,6 @@ pub fn get_physical_addr(virt: VirtAddr) -> Option<PhyAddr> {
|
|||
}
|
||||
|
||||
let pt_entry = pd_entry.try_as_page_table()?[virt.page_table_index::<{ VirtAddr::PT }>()];
|
||||
serial_println!("pt_entry: {:?}", pt_entry);
|
||||
|
||||
if !pt_entry.contains(PageTableEntryFlags::PRESENT) {
|
||||
return None;
|
||||
|
|
|
|||
Loading…
Reference in a new issue