Wrote stack unwinder. NEEDTO: fix NoUnwindInfo
Probably incorrect PC was set.
This commit is contained in:
Generated
+7
@@ -105,6 +105,12 @@ version = "0.7.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
|
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fallible-iterator"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -118,6 +124,7 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
"elf",
|
"elf",
|
||||||
|
"fallible-iterator",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"gimli",
|
"gimli",
|
||||||
"libm",
|
"libm",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ futures-util = { version = "0.3.31", default-features = false, features = [
|
|||||||
linked_list_allocator = { version = "0.10.5", features = ["use_spin"] }
|
linked_list_allocator = { version = "0.10.5", features = ["use_spin"] }
|
||||||
gimli = { version = "0.31.1", default-features = false, features = ["read"] }
|
gimli = { version = "0.31.1", default-features = false, features = ["read"] }
|
||||||
elf = { version = "0.7.4", default-features = false, features = ["nightly"] }
|
elf = { version = "0.7.4", default-features = false, features = ["nightly"] }
|
||||||
|
fallible-iterator = "0.3.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = "1.2.14"
|
cc = "1.2.14"
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
use core::arch::x86_64::__cpuid;
|
use core::arch::x86_64::__cpuid;
|
||||||
|
|
||||||
|
use crate::arch::x86_64::cpu::msr::*;
|
||||||
use crate::arch::x86_64::memory::mapping::PHYSICAL_MEMORY_OFFSET;
|
use crate::arch::x86_64::memory::mapping::PHYSICAL_MEMORY_OFFSET;
|
||||||
|
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
||||||
use crate::{debugln, serial_print, serial_println};
|
use crate::{debugln, serial_print, serial_println};
|
||||||
|
use x86_64::structures::paging::Translate;
|
||||||
use x86_64::{
|
use x86_64::{
|
||||||
PhysAddr, VirtAddr,
|
PhysAddr, VirtAddr,
|
||||||
structures::paging::{Mapper, Page, PageTableFlags, PhysFrame, Size4KiB},
|
structures::paging::{Mapper, Page, PageTableFlags, PhysFrame, Size4KiB},
|
||||||
};
|
};
|
||||||
use x86_64::structures::paging::Translate;
|
|
||||||
use crate::arch::x86_64::cpu::msr::*;
|
|
||||||
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
|
||||||
|
|
||||||
const IA32_APIC_BASE_MSR: u32 = 0x1b;
|
const IA32_APIC_BASE_MSR: u32 = 0x1b;
|
||||||
const IA32_APIC_BASE_MSR_BSP: u64 = 0x100;
|
const IA32_APIC_BASE_MSR_BSP: u64 = 0x100;
|
||||||
@@ -53,7 +53,8 @@ fn write_apic_register(apic_base: &PhysAddr, reg: u64, value: u32) {
|
|||||||
|
|
||||||
let virt_addr = unsafe { phys_to_virt(PhysAddr::new(reg_addr)) };
|
let virt_addr = unsafe { phys_to_virt(PhysAddr::new(reg_addr)) };
|
||||||
|
|
||||||
let phys_check = OFFSET_PAGE_TABLE.get().unwrap().lock().translate(virt_addr);
|
let phys_check =
|
||||||
|
OFFSET_PAGE_TABLE.get().unwrap().lock().translate(virt_addr);
|
||||||
debugln!("{:?}", phys_check);
|
debugln!("{:?}", phys_check);
|
||||||
|
|
||||||
unsafe { *(virt_addr.as_u64() as *mut u32) = value };
|
unsafe { *(virt_addr.as_u64() as *mut u32) = value };
|
||||||
@@ -88,9 +89,8 @@ pub fn enable_apic() {
|
|||||||
write_apic_register(
|
write_apic_register(
|
||||||
&apic_base_physical_addr,
|
&apic_base_physical_addr,
|
||||||
0xF0,
|
0xF0,
|
||||||
read_apic_register(&apic_base_physical_addr, 0xF0) | 0x1FF
|
read_apic_register(&apic_base_physical_addr, 0xF0) | 0x1FF,
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_timer() {
|
pub fn enable_timer() {
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
use crate::{debug, serial_print};
|
use crate::{debug, serial_print};
|
||||||
use pic8259::ChainedPics;
|
use pic8259::ChainedPics;
|
||||||
use x86_64::registers::control::Cr2;
|
use x86_64::registers::control::Cr2;
|
||||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
|
use x86_64::structures::idt::{
|
||||||
|
InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode,
|
||||||
|
};
|
||||||
use x86_64::structures::paging::mapper::MapperFlushAll;
|
use x86_64::structures::paging::mapper::MapperFlushAll;
|
||||||
use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB};
|
use x86_64::structures::paging::{
|
||||||
|
FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
|
||||||
|
};
|
||||||
|
|
||||||
use super::gdt;
|
use super::gdt;
|
||||||
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
||||||
@@ -25,7 +29,8 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
|||||||
idt.page_fault.set_handler_fn(page_fault_handler);
|
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||||
|
|
||||||
idt[InterruptIndex::Timer.as_u8()].set_handler_fn(timer_interrupt_handler);
|
idt[InterruptIndex::Timer.as_u8()].set_handler_fn(timer_interrupt_handler);
|
||||||
idt[InterruptIndex::Keyboard.as_u8()].set_handler_fn(keyboard_interrupt_handler);
|
idt[InterruptIndex::Keyboard.as_u8()]
|
||||||
|
.set_handler_fn(keyboard_interrupt_handler);
|
||||||
idt
|
idt
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -90,13 +95,16 @@ extern "x86-interrupt" fn double_fault_handler(
|
|||||||
panic!("Exception: Double Fault\n{:#?}", stack_frame);
|
panic!("Exception: Double Fault\n{:#?}", stack_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn keyboard_interrupt_handler(
|
||||||
|
_stack_frame: InterruptStackFrame,
|
||||||
|
) {
|
||||||
use pc_keyboard::{HandleControl, Keyboard, ScancodeSet1, layouts};
|
use pc_keyboard::{HandleControl, Keyboard, ScancodeSet1, layouts};
|
||||||
// use pc_keyboard::DecodedKey;
|
// use pc_keyboard::DecodedKey;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use x86_64::instructions::port::Port;
|
use x86_64::instructions::port::Port;
|
||||||
|
|
||||||
static KEYBOARD: Lazy<Mutex<Keyboard<layouts::Uk105Key, ScancodeSet1>>> = Lazy::new(|| {
|
static KEYBOARD: Lazy<Mutex<Keyboard<layouts::Uk105Key, ScancodeSet1>>> =
|
||||||
|
Lazy::new(|| {
|
||||||
Mutex::new(Keyboard::new(
|
Mutex::new(Keyboard::new(
|
||||||
ScancodeSet1::new(),
|
ScancodeSet1::new(),
|
||||||
layouts::Uk105Key,
|
layouts::Uk105Key,
|
||||||
@@ -116,7 +124,9 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn timer_interrupt_handler(
|
||||||
|
_stack_frame: InterruptStackFrame,
|
||||||
|
) {
|
||||||
debug!("Timer Interrupt");
|
debug!("Timer Interrupt");
|
||||||
unsafe {
|
unsafe {
|
||||||
PICS.lock()
|
PICS.lock()
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
|
use crate::arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator;
|
||||||
|
use crate::arch::x86_64::memory::units::MemoryUnits;
|
||||||
|
use crate::arch::x86_64::memory::{
|
||||||
|
FRAME_ALLOCATOR, HEAP_SIZE, HEAP_VIRTUAL_SPACE,
|
||||||
|
};
|
||||||
|
use crate::serial_println;
|
||||||
use crate::{debugln, serial_print};
|
use crate::{debugln, serial_print};
|
||||||
use core::alloc::{GlobalAlloc, Layout};
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use spin::{Mutex, MutexGuard};
|
use spin::{Mutex, MutexGuard};
|
||||||
use x86_64::structures::paging::{Size4KiB, mapper::MapToError, PageTableFlags};
|
|
||||||
use x86_64::VirtAddr;
|
use x86_64::VirtAddr;
|
||||||
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, HEAP_SIZE, HEAP_VIRTUAL_SPACE};
|
use x86_64::structures::paging::{
|
||||||
use crate::arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator;
|
PageTableFlags, Size4KiB, mapper::MapToError,
|
||||||
use crate::arch::x86_64::memory::units::MemoryUnits;
|
};
|
||||||
use crate::serial_println;
|
|
||||||
|
|
||||||
/// We are currently using a linked list heap allocator which uses our underlying page allocator.
|
/// We are currently using a linked list heap allocator which uses our
|
||||||
|
/// underlying page allocator.
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
/// This is now Rust's global allocator, so we can use stuff requiring heap allocations.
|
/// This is now Rust's global allocator, so we can use stuff requiring heap
|
||||||
static ALLOCATOR: Locked<FoundryAllocator> = Locked::new(FoundryAllocator::new());
|
/// allocations.
|
||||||
|
static ALLOCATOR: Locked<FoundryAllocator> =
|
||||||
|
Locked::new(FoundryAllocator::new());
|
||||||
|
|
||||||
/// Initializes the heap.
|
/// Initializes the heap.
|
||||||
///
|
///
|
||||||
@@ -38,7 +44,8 @@ static ALLOCATOR: Locked<FoundryAllocator> = Locked::new(FoundryAllocator::new()
|
|||||||
/// initialized successfully.
|
/// initialized successfully.
|
||||||
pub unsafe fn init_heap() -> Result<(), MapToError<Size4KiB>> {
|
pub unsafe fn init_heap() -> Result<(), MapToError<Size4KiB>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
// code to allocate frames is now done in the page fault interrupt handler!
|
// code to allocate frames is now done in the page fault interrupt
|
||||||
|
// handler!
|
||||||
ALLOCATOR.lock().init(HEAP_VIRTUAL_SPACE, HEAP_SIZE);
|
ALLOCATOR.lock().init(HEAP_VIRTUAL_SPACE, HEAP_SIZE);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -85,11 +92,13 @@ impl FoundryAllocator {
|
|||||||
fallback: Locked::new(FoundryFallbackAllocator::new()),
|
fallback: Locked::new(FoundryFallbackAllocator::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Initializes the fallback allocator with the given heap start address and size.
|
/// Initializes the fallback allocator with the given heap start address and
|
||||||
|
/// size.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function is unsafe because it does not check whether the given heap start address and size are valid.
|
/// This function is unsafe because it does not check whether the given heap
|
||||||
|
/// start address and size are valid.
|
||||||
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
|
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
|
||||||
debugln!(" => Start: {:?}", VirtAddr::new(heap_start as u64));
|
debugln!(" => Start: {:?}", VirtAddr::new(heap_start as u64));
|
||||||
debugln!(" => Size: {}", MemoryUnits::from_bytes(heap_size));
|
debugln!(" => Size: {}", MemoryUnits::from_bytes(heap_size));
|
||||||
@@ -127,7 +136,9 @@ unsafe impl GlobalAlloc for Locked<FoundryAllocator> {
|
|||||||
let block_size = BLOCK_SIZES[index];
|
let block_size = BLOCK_SIZES[index];
|
||||||
// only works if all block sizes are a power of 2
|
// only works if all block sizes are a power of 2
|
||||||
let block_align = block_size;
|
let block_align = block_size;
|
||||||
let layout = Layout::from_size_align(block_size, block_align).unwrap();
|
let layout =
|
||||||
|
Layout::from_size_align(block_size, block_align)
|
||||||
|
.unwrap();
|
||||||
unsafe { allocator.fallback_alloc(layout) }
|
unsafe { allocator.fallback_alloc(layout) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,7 +206,8 @@ impl FoundryFallbackAllocator {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function is unsafe because it does not check whether the given heap start address and size are valid.
|
/// This function is unsafe because it does not check whether the given heap
|
||||||
|
/// start address and size are valid.
|
||||||
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
|
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
|
||||||
unsafe { self.add_region(heap_start, heap_size) };
|
unsafe { self.add_region(heap_start, heap_size) };
|
||||||
}
|
}
|
||||||
@@ -222,7 +234,9 @@ impl FoundryFallbackAllocator {
|
|||||||
let mut current = &mut self.head;
|
let mut current = &mut self.head;
|
||||||
// look for a large enough memory region in linked list
|
// look for a large enough memory region in linked list
|
||||||
while let Some(ref mut region) = current.next {
|
while let Some(ref mut region) = current.next {
|
||||||
if let Ok(alloc_start) = Self::alloc_from_region(region, size, align) {
|
if let Ok(alloc_start) =
|
||||||
|
Self::alloc_from_region(region, size, align)
|
||||||
|
{
|
||||||
// region suitable for allocation -> remove node from list
|
// region suitable for allocation -> remove node from list
|
||||||
let next = region.next.take();
|
let next = region.next.take();
|
||||||
let ret = Some((current.next.take().unwrap(), alloc_start));
|
let ret = Some((current.next.take().unwrap(), alloc_start));
|
||||||
@@ -275,7 +289,8 @@ unsafe impl GlobalAlloc for Locked<FoundryFallbackAllocator> {
|
|||||||
// perform layout adjustments
|
// perform layout adjustments
|
||||||
let (size, align) = FoundryFallbackAllocator::size_align(layout);
|
let (size, align) = FoundryFallbackAllocator::size_align(layout);
|
||||||
|
|
||||||
if let Some((region, alloc_start)) = allocator.find_region(size, align) {
|
if let Some((region, alloc_start)) = allocator.find_region(size, align)
|
||||||
|
{
|
||||||
let alloc_end = alloc_start.checked_add(size).expect("overflow");
|
let alloc_end = alloc_start.checked_add(size).expect("overflow");
|
||||||
let excess_size = region.end_addr() - alloc_end;
|
let excess_size = region.end_addr() - alloc_end;
|
||||||
if excess_size > 0 {
|
if excess_size > 0 {
|
||||||
@@ -301,6 +316,11 @@ unsafe impl GlobalAlloc for Locked<FoundryFallbackAllocator> {
|
|||||||
fn ensure_mapped(virt_addr: VirtAddr) {
|
fn ensure_mapped(virt_addr: VirtAddr) {
|
||||||
if !FoundryOSFrameAllocator::is_mapped(virt_addr) {
|
if !FoundryOSFrameAllocator::is_mapped(virt_addr) {
|
||||||
let mut foundry_alloc = FRAME_ALLOCATOR.get().unwrap().lock();
|
let mut foundry_alloc = FRAME_ALLOCATOR.get().unwrap().lock();
|
||||||
foundry_alloc.allocate_page(virt_addr, PageTableFlags::PRESENT | PageTableFlags::WRITABLE).unwrap();
|
foundry_alloc
|
||||||
|
.allocate_page(
|
||||||
|
virt_addr,
|
||||||
|
PageTableFlags::PRESENT | PageTableFlags::WRITABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB, Translate};
|
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
||||||
|
use limine::memory_map::EntryType;
|
||||||
use limine::response::MemoryMapResponse;
|
use limine::response::MemoryMapResponse;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use limine::memory_map::EntryType;
|
|
||||||
use x86_64::{PhysAddr, VirtAddr};
|
|
||||||
use x86_64::structures::paging::mapper::{MapToError, TranslateResult};
|
use x86_64::structures::paging::mapper::{MapToError, TranslateResult};
|
||||||
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
use x86_64::structures::paging::{
|
||||||
|
FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB,
|
||||||
|
Translate,
|
||||||
|
};
|
||||||
|
use x86_64::{PhysAddr, VirtAddr};
|
||||||
|
|
||||||
pub struct FoundryOSFrameAllocator {
|
pub struct FoundryOSFrameAllocator {
|
||||||
memory_map: &'static MemoryMapResponse,
|
memory_map: &'static MemoryMapResponse,
|
||||||
@@ -36,7 +39,9 @@ impl FoundryOSFrameAllocator {
|
|||||||
.entries()
|
.entries()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|region| region.base..region.base + region.length)
|
.map(|region| region.base..region.base + region.length)
|
||||||
.flat_map(|r| r.step_by(4096)).count() as u64 * 4096
|
.flat_map(|r| r.step_by(4096))
|
||||||
|
.count() as u64
|
||||||
|
* 4096
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator over all usable frames in the memory map.
|
/// An iterator over all usable frames in the memory map.
|
||||||
@@ -46,10 +51,14 @@ impl FoundryOSFrameAllocator {
|
|||||||
/// This function is used to allocate frames for the page map.
|
/// This function is used to allocate frames for the page map.
|
||||||
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> + use<> {
|
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> + use<> {
|
||||||
let regions = self.memory_map.entries().iter();
|
let regions = self.memory_map.entries().iter();
|
||||||
let usable_regions = regions.filter(|region| region.entry_type == EntryType::USABLE);
|
let usable_regions =
|
||||||
let addr_ranges = usable_regions.map(|region| region.base..region.base + region.length);
|
regions.filter(|region| region.entry_type == EntryType::USABLE);
|
||||||
|
let addr_ranges = usable_regions
|
||||||
|
.map(|region| region.base..region.base + region.length);
|
||||||
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
|
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
|
||||||
frame_addresses.map(|addr| PhysFrame::from_start_address(PhysAddr::new(addr)).unwrap())
|
frame_addresses.map(|addr| {
|
||||||
|
PhysFrame::from_start_address(PhysAddr::new(addr)).unwrap()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_mapped(virt_addr: VirtAddr) -> bool {
|
pub(crate) fn is_mapped(virt_addr: VirtAddr) -> bool {
|
||||||
@@ -57,14 +66,18 @@ impl FoundryOSFrameAllocator {
|
|||||||
matches!(mapper.translate(virt_addr), TranslateResult::Mapped { .. })
|
matches!(mapper.translate(virt_addr), TranslateResult::Mapped { .. })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn allocate_page(&mut self, start_addr: VirtAddr, flags: PageTableFlags) -> Result<(), MapToError<Size4KiB>> {
|
pub(crate) fn allocate_page(
|
||||||
|
&mut self,
|
||||||
|
start_addr: VirtAddr,
|
||||||
|
flags: PageTableFlags,
|
||||||
|
) -> Result<(), MapToError<Size4KiB>> {
|
||||||
let page = Page::containing_address(start_addr);
|
let page = Page::containing_address(start_addr);
|
||||||
let frame = self.allocate_frame().ok_or(MapToError::<Size4KiB>::FrameAllocationFailed)?;
|
let frame = self
|
||||||
|
.allocate_frame()
|
||||||
|
.ok_or(MapToError::<Size4KiB>::FrameAllocationFailed)?;
|
||||||
let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock();
|
let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock();
|
||||||
|
|
||||||
unsafe {
|
unsafe { mapper.map_to(page, frame, flags, self)? }.flush();
|
||||||
mapper.map_to(page, frame, flags, self)?
|
|
||||||
}.flush();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-36
@@ -12,23 +12,33 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
use crate::{arch::x86_64::memory::init_page_table, prelude::*};
|
|
||||||
use arch::x86_64::memory::allocation::heap_alloc::init_heap;
|
use crate::{
|
||||||
|
// TODO: Fix nesting under `arch`. A lot of code does not NEED to run on
|
||||||
|
// x86_64. Note that the panic handler does.
|
||||||
|
arch::x86_64::{
|
||||||
|
cpu::apic::enable_apic,
|
||||||
|
drivers::{
|
||||||
|
ascii::screensize_chars, framebuffer::display::screensize_px,
|
||||||
|
},
|
||||||
|
memory::{
|
||||||
|
FRAME_ALLOCATOR,
|
||||||
|
allocation::{
|
||||||
|
heap_alloc::init_heap, page_alloc::FoundryOSFrameAllocator,
|
||||||
|
},
|
||||||
|
init_page_table,
|
||||||
|
units::MemoryUnits,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
use arch::x86_64::memory::mapping;
|
use arch::x86_64::memory::mapping;
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
use limine::BaseRevision;
|
use limine::BaseRevision;
|
||||||
use std::unwind;
|
|
||||||
use std::unwind::eh_info::ELF;
|
|
||||||
use x86_64::VirtAddr;
|
use x86_64::VirtAddr;
|
||||||
use arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator;
|
|
||||||
use crate::arch::x86_64::cpu::apic::enable_apic;
|
|
||||||
use crate::arch::x86_64::drivers::ascii::screensize_chars;
|
|
||||||
use crate::arch::x86_64::drivers::framebuffer::display::screensize_px;
|
|
||||||
use crate::arch::x86_64::memory::FRAME_ALLOCATOR;
|
|
||||||
use crate::arch::x86_64::memory::units::MemoryUnits;
|
|
||||||
|
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
mod panic;
|
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
#[allow(unused)] // We aren't using much of this right now.
|
#[allow(unused)] // We aren't using much of this right now.
|
||||||
pub mod std;
|
pub mod std;
|
||||||
@@ -36,11 +46,10 @@ pub mod util;
|
|||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
eprint, eprintln, print, print_log, println, println_log, serial_print,
|
debug, debugln, eprint, eprintln, print, print_log, println,
|
||||||
serial_println,
|
println_log, serial_print, serial_println,
|
||||||
debug, debugln,
|
|
||||||
std::io::{_print, _print_log, _serial_write, _print_err},
|
|
||||||
std::debug::_debug,
|
std::debug::_debug,
|
||||||
|
std::io::{_print, _print_err, _print_log, _serial_write},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,13 +63,6 @@ pub mod prelude {
|
|||||||
#[unsafe(link_section = ".requests")]
|
#[unsafe(link_section = ".requests")]
|
||||||
static BASE_REVISION: BaseRevision = BaseRevision::new();
|
static BASE_REVISION: BaseRevision = BaseRevision::new();
|
||||||
|
|
||||||
#[panic_handler]
|
|
||||||
fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
|
|
||||||
println!("Kernel panic: {}", _info);
|
|
||||||
serial_println!("Kernel panic: {}", _info);
|
|
||||||
hcf();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hcf() -> ! {
|
pub fn hcf() -> ! {
|
||||||
loop {
|
loop {
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -70,6 +72,9 @@ pub fn hcf() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Panicking before this is initialised is unwise. We should probably extract
|
||||||
|
/// very early init into it's own function because Stack Traces may require
|
||||||
|
/// allocations etc.
|
||||||
pub fn boot() -> Result<(), &'static str> {
|
pub fn boot() -> Result<(), &'static str> {
|
||||||
if !BASE_REVISION.is_supported() {
|
if !BASE_REVISION.is_supported() {
|
||||||
return Err("Base revision not supported");
|
return Err("Base revision not supported");
|
||||||
@@ -104,11 +109,16 @@ pub fn boot() -> Result<(), &'static str> {
|
|||||||
debugln!("[Success]");
|
debugln!("[Success]");
|
||||||
|
|
||||||
debugln!(" Initialising Memory Subsystem... ");
|
debugln!(" Initialising Memory Subsystem... ");
|
||||||
let physical_memory_offset = VirtAddr::new(*mapping::PHYSICAL_MEMORY_OFFSET);
|
let physical_memory_offset =
|
||||||
|
VirtAddr::new(*mapping::PHYSICAL_MEMORY_OFFSET);
|
||||||
init_page_table(physical_memory_offset);
|
init_page_table(physical_memory_offset);
|
||||||
FoundryOSFrameAllocator::init(memory_map);
|
FoundryOSFrameAllocator::init(memory_map);
|
||||||
let available_bytes = FRAME_ALLOCATOR.get().unwrap().lock().available_memory();
|
let available_bytes =
|
||||||
debugln!(" => Available Memory: {}", MemoryUnits::from_bytes(available_bytes as usize));
|
FRAME_ALLOCATOR.get().unwrap().lock().available_memory();
|
||||||
|
debugln!(
|
||||||
|
" => Available Memory: {}",
|
||||||
|
MemoryUnits::from_bytes(available_bytes as usize)
|
||||||
|
);
|
||||||
|
|
||||||
debugln!("[Success]");
|
debugln!("[Success]");
|
||||||
|
|
||||||
@@ -134,16 +144,5 @@ pub fn boot() -> Result<(), &'static str> {
|
|||||||
x86_64::instructions::interrupts::enable();
|
x86_64::instructions::interrupts::enable();
|
||||||
debugln!("[Success]");
|
debugln!("[Success]");
|
||||||
|
|
||||||
debug!(" Setting up stack unwinder, panic handler... ");
|
|
||||||
// Setup stack traces and proper panic handler. TODO: Handle panics
|
|
||||||
// differently if not initialised.
|
|
||||||
let eh_frame_ptr = ELF
|
|
||||||
.get_section_addr(".eh_frame_hdr")
|
|
||||||
.expect("Could not get `.eh_frame_hdr` address.");
|
|
||||||
|
|
||||||
let _eh_info =
|
|
||||||
unsafe { unwind::eh_info::EhInfo::from_hdr_ptr(eh_frame_ptr) };
|
|
||||||
debugln!("[Success]");
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-3
@@ -2,11 +2,10 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
use foundry_os::arch::x86_64::drivers::ascii::screensize_chars;
|
|
||||||
use foundry_os::arch::x86_64::drivers::framebuffer::display::screensize_px;
|
|
||||||
use foundry_os::arch::x86_64::processing::async_io::task::{Executor, Task};
|
use foundry_os::arch::x86_64::processing::async_io::task::{Executor, Task};
|
||||||
|
use foundry_os::prelude::*;
|
||||||
use foundry_os::util::shell::shell;
|
use foundry_os::util::shell::shell;
|
||||||
use foundry_os::{println, println_log};
|
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn kmain() -> ! {
|
extern "C" fn kmain() -> ! {
|
||||||
@@ -23,7 +22,17 @@ extern "C" fn kmain() -> ! {
|
|||||||
// println!("{}", somevec.len());
|
// println!("{}", somevec.len());
|
||||||
// println!("PASSED!");
|
// println!("PASSED!");
|
||||||
|
|
||||||
|
test1();
|
||||||
|
|
||||||
let mut executor = Executor::new();
|
let mut executor = Executor::new();
|
||||||
executor.spawn(Task::new(shell()));
|
executor.spawn(Task::new(shell()));
|
||||||
executor.run()
|
executor.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test1() {
|
||||||
|
test2()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test2() {
|
||||||
|
panic!("Test");
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
// //! Stack-unwinding code for the Kernel. This is a modified version of https://github.com/nbdd0121/unwinding/blob/trunk/src/panic_handler.rs
|
|
||||||
// //! which does not support environment variables for obvious reasons, however we
|
|
||||||
// //! may implement a cmdline similar to Linux in the near future.
|
|
||||||
|
|
||||||
// #![expect(
|
|
||||||
// clippy::empty_loop,
|
|
||||||
// reason = "We don't yet have working power management. This is OK for now."
|
|
||||||
// )]
|
|
||||||
// use crate::prelude::*;
|
|
||||||
// use alloc::boxed::Box;
|
|
||||||
// use core::any::Any;
|
|
||||||
// use core::cell::Cell;
|
|
||||||
// use core::ffi::c_void;
|
|
||||||
// use core::panic::{Location, PanicInfo};
|
|
||||||
// use unwinding::abi::*;
|
|
||||||
// use unwinding::panic::begin_panic;
|
|
||||||
|
|
||||||
// #[thread_local]
|
|
||||||
// static PANIC_COUNT: Cell<usize> = Cell::new(0);
|
|
||||||
|
|
||||||
// #[link(name = "c")]
|
|
||||||
// unsafe extern "C" {}
|
|
||||||
|
|
||||||
// fn stack_trace() {
|
|
||||||
// struct CallbackData {
|
|
||||||
// counter: usize,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// extern "C" fn callback(
|
|
||||||
// unwind_ctx: &UnwindContext<'_>,
|
|
||||||
// arg: *mut c_void,
|
|
||||||
// ) -> UnwindReasonCode {
|
|
||||||
// let data = unsafe { &mut *(arg as *mut CallbackData) };
|
|
||||||
// data.counter += 1;
|
|
||||||
// eprintln!(
|
|
||||||
// "{:4}:{:#19x} - <unknown>",
|
|
||||||
// data.counter,
|
|
||||||
// _Unwind_GetIP(unwind_ctx)
|
|
||||||
// );
|
|
||||||
// UnwindReasonCode::NO_REASON
|
|
||||||
// }
|
|
||||||
// let mut data = CallbackData { counter: 0 };
|
|
||||||
// _Unwind_Backtrace(callback, &mut data as *mut _ as _);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn do_panic(msg: Box<dyn Any + Send>) -> ! {
|
|
||||||
// if PANIC_COUNT.get() >= 1 {
|
|
||||||
// stack_trace();
|
|
||||||
// eprintln!("Thread panicked while processing panic. aborting.");
|
|
||||||
// loop {}
|
|
||||||
// }
|
|
||||||
|
|
||||||
// PANIC_COUNT.set(1);
|
|
||||||
// stack_trace();
|
|
||||||
|
|
||||||
// let code = begin_panic(Box::new(msg));
|
|
||||||
// eprintln!("Failed to initiate panic: error {}", code.0);
|
|
||||||
|
|
||||||
// loop {}
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[panic_handler]
|
|
||||||
// fn panic(info: &PanicInfo<'_>) -> ! {
|
|
||||||
// eprintln!("{}", info);
|
|
||||||
|
|
||||||
// struct NoPayload;
|
|
||||||
// do_panic(Box::new(NoPayload))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[track_caller]
|
|
||||||
// #[expect(unused, reason = "May still be used in the future.")]
|
|
||||||
// pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
|
|
||||||
// eprintln!("Panicked at {}", Location::caller());
|
|
||||||
// do_panic(Box::new(msg))
|
|
||||||
// }
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
|
use crate::prelude::{_print_log, _serial_write};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use x86_64::instructions::interrupts;
|
use x86_64::instructions::interrupts;
|
||||||
use crate::prelude::{_print_log, _serial_write};
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! debugln {
|
macro_rules! debugln {
|
||||||
@@ -19,4 +19,3 @@ pub fn _debug(args: fmt::Arguments) {
|
|||||||
_serial_write(args);
|
_serial_write(args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
pub mod application;
|
pub mod application;
|
||||||
pub mod ascii;
|
pub mod ascii;
|
||||||
|
pub mod debug;
|
||||||
pub mod elf;
|
pub mod elf;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod maths;
|
pub mod maths;
|
||||||
pub mod unwind;
|
pub mod unwind;
|
||||||
pub mod debug;
|
|
||||||
|
|||||||
@@ -21,15 +21,15 @@ use crate::{println_log, std::elf::ElfReader};
|
|||||||
/// and will later be extended as required.
|
/// and will later be extended as required.
|
||||||
pub struct EhInfo {
|
pub struct EhInfo {
|
||||||
/// A set of base addresses used for relative addressing.
|
/// A set of base addresses used for relative addressing.
|
||||||
base_addrs: BaseAddresses,
|
pub base_addrs: BaseAddresses,
|
||||||
/// The parsed `.eh_frame_hdr` section.
|
/// The parsed `.eh_frame_hdr` section.
|
||||||
hdr: &'static ParsedEhFrameHdr<EndianSlice<'static, LittleEndian>>,
|
pub hdr: &'static ParsedEhFrameHdr<EndianSlice<'static, LittleEndian>>,
|
||||||
/// The lookup table in the parsed `.eh_frame_hdr` section.
|
/// The lookup table in the parsed `.eh_frame_hdr` section.
|
||||||
/// This is a binary search table, it is optional but should be present as
|
/// This is a binary search table, it is optional but should be present as
|
||||||
/// we are linking with LLD(?) \[needs citation].
|
/// we are linking with LLD(?) \[needs citation].
|
||||||
hdr_table: EhHdrTable<'static, EndianSlice<'static, LittleEndian>>,
|
pub hdr_table: EhHdrTable<'static, EndianSlice<'static, LittleEndian>>,
|
||||||
/// The parsed `.eh_frame` containing the CFIs (call frame information).
|
/// The parsed `.eh_frame` containing the CFIs (call frame information).
|
||||||
eh_frame: EhFrame<EndianSlice<'static, LittleEndian>>,
|
pub eh_frame: EhFrame<EndianSlice<'static, LittleEndian>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the [ElfReader] struct for this ELF file.
|
/// Stores the [ElfReader] struct for this ELF file.
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
pub mod eh_info;
|
pub mod eh_info;
|
||||||
|
pub mod panic;
|
||||||
|
pub mod unwinder;
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
//! Defines a simple panic handler which handles stack traces as required.
|
||||||
|
|
||||||
|
use core::{arch::asm, panic::PanicInfo};
|
||||||
|
|
||||||
|
use alloc::string::ToString;
|
||||||
|
use fallible_iterator::FallibleIterator;
|
||||||
|
use gimli::{Register, X86_64};
|
||||||
|
|
||||||
|
use super::unwinder::Unwinder;
|
||||||
|
use crate::{
|
||||||
|
hcf,
|
||||||
|
prelude::*,
|
||||||
|
std::unwind::{eh_info::ELF, unwinder::RegisterSet},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
/// A basic panic handler which can produce a helpful stack trace.
|
||||||
|
pub fn panic_handler(info: &PanicInfo<'_>) -> ! {
|
||||||
|
println!("Kernel panic: {}", info);
|
||||||
|
serial_println!("Kernel panic: {}", info);
|
||||||
|
|
||||||
|
// Setup stack traces and proper panic handler. TODO: Handle panics
|
||||||
|
// differently if not initialised.
|
||||||
|
let eh_frame_ptr = ELF
|
||||||
|
.get_section_addr(".eh_frame_hdr")
|
||||||
|
.expect("Could not get `.eh_frame_hdr` address.");
|
||||||
|
|
||||||
|
let eh_info = unsafe { super::eh_info::EhInfo::from_hdr_ptr(eh_frame_ptr) };
|
||||||
|
let mut registers = RegisterSet::default();
|
||||||
|
|
||||||
|
let mut rip: u64;
|
||||||
|
let mut rsp: u64;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
asm!("lea {0}, [rip]",
|
||||||
|
"mov {1}, rsp",
|
||||||
|
out(reg) rip, out(reg) rsp);
|
||||||
|
}
|
||||||
|
registers.set_pc(rip);
|
||||||
|
registers.set_stack_ptr(rsp);
|
||||||
|
|
||||||
|
let mut unwinder = Unwinder::new(eh_info, registers);
|
||||||
|
while let Some(call_frame) = unwinder.next().unwrap_or_else(|err| {
|
||||||
|
// If an unwind error occurred.
|
||||||
|
eprintln!("{:?}", err);
|
||||||
|
hcf()
|
||||||
|
}) {
|
||||||
|
eprintln!("Frame: {:x?}", call_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::hcf()
|
||||||
|
}
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
//! Implements the core stack unwinding logic.
|
||||||
|
//!
|
||||||
|
//! # TODOs
|
||||||
|
//!
|
||||||
|
//! * Support evaluation of DWARF expressions, this might not be required
|
||||||
|
//! however, because Rust doesn't tend to use this DWARF feature.
|
||||||
|
|
||||||
|
use fallible_iterator::FallibleIterator;
|
||||||
|
use gimli::{
|
||||||
|
CfaRule, EndianSlice, LittleEndian, Register, RegisterRule, StoreOnHeap,
|
||||||
|
UnwindContext, UnwindSection, X86_64,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::eh_info::EhInfo;
|
||||||
|
|
||||||
|
/// Implements the core stack unwinding logic by parsing the call frame
|
||||||
|
/// information. This also stores current (DWARF) register values.
|
||||||
|
///
|
||||||
|
/// # Sources
|
||||||
|
///
|
||||||
|
/// Taken from [lesenechal.fr](https://lesenechal.fr/en/linux/unwinding-the-stack-the-hard-way)
|
||||||
|
/// with some additional features to be added soon.
|
||||||
|
pub struct Unwinder {
|
||||||
|
/// The call frame information.
|
||||||
|
eh_info: EhInfo,
|
||||||
|
/// An [UnwindContext] used by Gimli for optimisations.
|
||||||
|
unwind_ctx: UnwindContext<usize, StoreOnHeap>,
|
||||||
|
/// The current values of ABI/architecture independent registers. There are
|
||||||
|
/// used by DWARF.
|
||||||
|
regs: RegisterSet,
|
||||||
|
/// The current CFA address.
|
||||||
|
cfa: u64,
|
||||||
|
/// Is this the first iteration?
|
||||||
|
is_first: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Use map_err et al.
|
||||||
|
impl FallibleIterator for Unwinder {
|
||||||
|
type Item = CallFrame;
|
||||||
|
type Error = UnwinderError;
|
||||||
|
|
||||||
|
/// Returns call frames of calling functions. This may be called to produce
|
||||||
|
/// a stack trace or otherwise support physical unwinding.
|
||||||
|
fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
|
||||||
|
// Gets the current program counter from the DWARF register set.
|
||||||
|
let Some(pc) = self.regs.get_pc() else {
|
||||||
|
return Err(UnwinderError::NoPcRegister);
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.is_first {
|
||||||
|
self.is_first = false;
|
||||||
|
|
||||||
|
return Ok(Some(CallFrame { pc }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a row in the virtual unwind table AKA the CFI which will help
|
||||||
|
// us find the CFA (canonical frame address) for a given program
|
||||||
|
// counter.
|
||||||
|
let Ok(row) = self.eh_info.hdr_table.unwind_info_for_address(
|
||||||
|
&self.eh_info.eh_frame,
|
||||||
|
&self.eh_info.base_addrs,
|
||||||
|
&mut self.unwind_ctx,
|
||||||
|
pc,
|
||||||
|
|section, bases, offset|
|
||||||
|
// Finds a DWARF CIE using an offset as given.
|
||||||
|
section.cie_from_offset(bases, offset),
|
||||||
|
) else {
|
||||||
|
return Err(UnwinderError::NoUnwindInfo);
|
||||||
|
};
|
||||||
|
|
||||||
|
// We compute the CFA (canonical frame address from its rule).
|
||||||
|
// TODO: Support other rules such as DWARF expressions.
|
||||||
|
match row.cfa() {
|
||||||
|
CfaRule::RegisterAndOffset { register, offset } => {
|
||||||
|
let Some(reg_val) = self.regs.get(*register) else {
|
||||||
|
return Err(UnwinderError::CfaRuleUnknownRegister(
|
||||||
|
*register,
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
self.cfa = (reg_val as i64 + offset) as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Support other rules for computing the CFA.
|
||||||
|
_ => return Err(UnwinderError::UnsupportedCfaRule),
|
||||||
|
}
|
||||||
|
|
||||||
|
for reg in RegisterSet::iter() {
|
||||||
|
match row.register(reg) {
|
||||||
|
RegisterRule::Undefined => self.regs.undef(reg),
|
||||||
|
RegisterRule::SameValue => (),
|
||||||
|
RegisterRule::Offset(offset) => {
|
||||||
|
// Adds the given offset to the register contents and
|
||||||
|
// retrieve the value from the stack at address CFA +
|
||||||
|
// offset.
|
||||||
|
let ptr = (self.cfa as i64 + offset) as u64 as *const usize;
|
||||||
|
|
||||||
|
self.regs.set(reg, unsafe { ptr.read() } as u64)?
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
return Err(UnwinderError::UnimplementedRegisterRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the new value for %rip from the function return value and
|
||||||
|
// subtract one from it, because the address actually points the the
|
||||||
|
// next instruction after the call.
|
||||||
|
let Some(pc) = self.regs.get_ret() else {
|
||||||
|
return Err(UnwinderError::NoReturnAddr);
|
||||||
|
};
|
||||||
|
// REVIEWME: Must be a nicer way of doing this.
|
||||||
|
let pc = pc - 1;
|
||||||
|
|
||||||
|
self.regs.set_pc(pc);
|
||||||
|
|
||||||
|
// Set %rsp to the CFA. This simulates returning from the function,
|
||||||
|
// destroying the call frame, so we were able to virtually unwind (to
|
||||||
|
// the caller function).
|
||||||
|
self.regs.set_stack_ptr(self.cfa);
|
||||||
|
|
||||||
|
Ok(Some(CallFrame { pc }))
|
||||||
|
}
|
||||||
|
// fn next(&mut self) -> Option<Result<Option<CallFrame>, UnwinderError>> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Unwinder {
|
||||||
|
pub fn new(eh_info: EhInfo, regset: RegisterSet) -> Self {
|
||||||
|
Self {
|
||||||
|
eh_info,
|
||||||
|
regs: regset,
|
||||||
|
unwind_ctx: UnwindContext::new(),
|
||||||
|
cfa: 0,
|
||||||
|
is_first: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The set of registers used by DWARF. This struct allows future portability if
|
||||||
|
/// we want to target other architectures than x86_64.
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct RegisterSet {
|
||||||
|
rip: Option<u64>,
|
||||||
|
rsp: Option<u64>,
|
||||||
|
rbp: Option<u64>,
|
||||||
|
/// The return address register.
|
||||||
|
ret: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegisterSet {
|
||||||
|
pub const fn get(&self, reg: Register) -> Option<u64> {
|
||||||
|
match reg {
|
||||||
|
X86_64::RSP => self.rsp,
|
||||||
|
X86_64::RBP => self.rbp,
|
||||||
|
X86_64::RA => self.ret,
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn set(
|
||||||
|
&mut self,
|
||||||
|
reg: Register,
|
||||||
|
val: u64,
|
||||||
|
) -> Result<(), UnwinderError> {
|
||||||
|
*match reg {
|
||||||
|
X86_64::RSP => &mut self.rsp,
|
||||||
|
X86_64::RBP => &mut self.rbp,
|
||||||
|
X86_64::RA => &mut self.ret,
|
||||||
|
_ => return Err(UnwinderError::UnexpectedRegister(reg)),
|
||||||
|
} = Some(val);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn undef(&mut self, reg: Register) {
|
||||||
|
*match reg {
|
||||||
|
X86_64::RSP => &mut self.rsp,
|
||||||
|
X86_64::RBP => &mut self.rbp,
|
||||||
|
X86_64::RA => &mut self.ret,
|
||||||
|
_ => return,
|
||||||
|
} = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn get_pc(&self) -> Option<u64> {
|
||||||
|
self.rip
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn set_pc(&mut self, val: u64) {
|
||||||
|
self.rip = Some(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn get_ret(&self) -> Option<u64> {
|
||||||
|
self.ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn set_stack_ptr(&mut self, val: u64) {
|
||||||
|
self.rsp = Some(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter() -> impl Iterator<Item = Register> {
|
||||||
|
[X86_64::RSP, X86_64::RBP, X86_64::RA].into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The current instruction pointer.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CallFrame {
|
||||||
|
/// The current instruction pointer.
|
||||||
|
pub pc: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// A list of errors that could occur whilst unwinding the stack.
|
||||||
|
pub enum UnwinderError {
|
||||||
|
UnexpectedRegister(Register),
|
||||||
|
UnsupportedCfaRule,
|
||||||
|
UnimplementedRegisterRule,
|
||||||
|
CfaRuleUnknownRegister(Register),
|
||||||
|
NoUnwindInfo,
|
||||||
|
NoPcRegister,
|
||||||
|
NoReturnAddr,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user