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 = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"plain",
|
||||||
"rbtree",
|
"rbtree",
|
||||||
|
"rustc-demangle",
|
||||||
"seq-macro",
|
"seq-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plain"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rbtree"
|
name = "rbtree"
|
||||||
version = "0.1.0"
|
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]]
|
[[package]]
|
||||||
name = "seq-macro"
|
name = "seq-macro"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,7 @@ build-std = ["core", "alloc", "compiler_builtins"]
|
||||||
target = "x86_64-unknown-kernel.json"
|
target = "x86_64-unknown-kernel.json"
|
||||||
|
|
||||||
[target.x86_64-unknown-kernel]
|
[target.x86_64-unknown-kernel]
|
||||||
runner = "./run.sh"
|
runner = "./run.sh"
|
||||||
|
rustflags = [
|
||||||
|
"-C", "force-frame-pointers=yes",
|
||||||
|
]
|
||||||
|
|
@ -26,4 +26,6 @@ bit_field = "0.10.3"
|
||||||
bitflags = "2.13.1"
|
bitflags = "2.13.1"
|
||||||
seq-macro = "0.3.6"
|
seq-macro = "0.3.6"
|
||||||
|
|
||||||
rbtree = { path = "../crates/rbtree" }
|
rbtree = { path = "../crates/rbtree" }
|
||||||
|
plain = "0.2.3"
|
||||||
|
rustc-demangle = "0.1.28"
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ PHDRS {
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
. = 0xffffffff80000000;
|
. = 0xffffffff80000000;
|
||||||
|
__kernel_start = .;
|
||||||
|
|
||||||
.limine_requests : {
|
.limine_requests : {
|
||||||
KEEP(*(.limine_requests_start))
|
KEEP(*(.limine_requests_start))
|
||||||
KEEP(*(.limine_requests))
|
KEEP(*(.limine_requests))
|
||||||
|
|
@ -36,6 +38,16 @@ SECTIONS {
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
} :data
|
} :data
|
||||||
|
|
||||||
|
__kernel_end = .;
|
||||||
|
|
||||||
|
.symtab 0: {
|
||||||
|
*(.symtab)
|
||||||
|
}
|
||||||
|
|
||||||
|
.strtab 0: {
|
||||||
|
*(.strtab)
|
||||||
|
}
|
||||||
|
|
||||||
/DISCARD/ : {
|
/DISCARD/ : {
|
||||||
*(.eh_frame*)
|
*(.eh_frame*)
|
||||||
*(.note .note.*)
|
*(.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)]
|
#[repr(C)]
|
||||||
pub struct BaseRevision(UnsafeCell<[u64; 3]>);
|
pub struct BaseRevision(UnsafeCell<[u64; 3]>);
|
||||||
|
|
@ -272,3 +272,60 @@ impl HhdmRequest {
|
||||||
self.response().map(|response| response.response.offset)
|
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();
|
GDT.load();
|
||||||
IDT.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: 0x{:x}", _start as *const () as usize);
|
||||||
kernel::serial_println!(
|
kernel::serial_println!(
|
||||||
"entry point phy: {:?}",
|
"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 static HHDM_BASE: OnceLock<u64> = OnceLock::new();
|
||||||
|
|
||||||
pub trait VirtAddrTranslationExt {
|
pub trait VirtAddrTranslationExt: Sized {
|
||||||
fn into_phy_addr(self) -> Option<PhyAddr>;
|
fn into_phy_addr(self) -> Option<PhyAddr>;
|
||||||
|
fn is_mapped(self) -> bool {
|
||||||
|
self.into_phy_addr().is_some()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[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 {
|
impl<T> From<&T> for VirtAddr {
|
||||||
fn from(ptr: &T) -> Self {
|
fn from(ptr: &T) -> Self {
|
||||||
VirtAddr(ptr as *const T as u64)
|
VirtAddr(ptr as *const T as u64)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#![cfg(target_arch = "x86_64")]
|
#![cfg(target_arch = "x86_64")]
|
||||||
|
|
||||||
|
pub mod backtrace;
|
||||||
pub mod cpuid;
|
pub mod cpuid;
|
||||||
pub mod gdt;
|
pub mod gdt;
|
||||||
pub mod idt;
|
pub mod idt;
|
||||||
|
|
@ -212,3 +213,67 @@ impl VirtAddrExt for VirtAddr {
|
||||||
E::decompose(self.0)
|
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::{
|
use crate::{
|
||||||
serial_println,
|
serial_println,
|
||||||
x86_64::{RFlags, Registers, halt_loop},
|
x86_64::{Context, RFlags, Registers, backtrace::debug_backtrace, halt_loop},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
@ -521,6 +521,13 @@ extern "C" fn global_interrupt_handler(
|
||||||
}
|
}
|
||||||
ExceptionVector::PAGE_FAULT => {
|
ExceptionVector::PAGE_FAULT => {
|
||||||
serial_println!("Page fault occurred! Error code: {:#x}", error_code);
|
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()
|
halt_loop()
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ use bit_field::BitField;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
memory::{PhyAddr, VirtAddr, VirtAddrTranslationExt},
|
memory::{PhyAddr, VirtAddr, VirtAddrTranslationExt},
|
||||||
serial_println,
|
|
||||||
x86_64::{VirtAddrExt, registers::Cr4},
|
x86_64::{VirtAddrExt, registers::Cr4},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -186,8 +185,6 @@ impl VirtAddrTranslationExt for VirtAddr {
|
||||||
pub fn get_physical_addr(virt: VirtAddr) -> Option<PhyAddr> {
|
pub fn get_physical_addr(virt: VirtAddr) -> Option<PhyAddr> {
|
||||||
let cr3 = crate::x86_64::registers::Cr3::read();
|
let cr3 = crate::x86_64::registers::Cr3::read();
|
||||||
let cr4 = crate::x86_64::registers::Cr4::read();
|
let cr4 = crate::x86_64::registers::Cr4::read();
|
||||||
serial_println!("cr3: {:?}", cr3);
|
|
||||||
serial_println!("cr4: {:?}", cr4);
|
|
||||||
|
|
||||||
let frame = cr3.phy();
|
let frame = cr3.phy();
|
||||||
let page_table = unsafe {
|
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 }>()]
|
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 }>()];
|
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) {
|
if pdpt_entry.contains(PageTableEntryFlags::HUGE_PAGE) {
|
||||||
const PHY_MASK_1G: u64 = !((1 << 30) - 1);
|
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 }>()];
|
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) {
|
if pd_entry.contains(PageTableEntryFlags::HUGE_PAGE) {
|
||||||
const PHY_MASK_2M: u64 = !((1 << 21) - 1);
|
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 }>()];
|
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) {
|
if !pt_entry.contains(PageTableEntryFlags::PRESENT) {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue