Save failed stack trace code for future reference.
This commit is contained in:
@@ -17,8 +17,5 @@ runner = "scripts/run_debug.sh"
|
||||
[target.'cfg(all(target_arch = "x86_64", target_os = "none", not(debug_assertions)))']
|
||||
runner = "scripts/run_release.sh"
|
||||
|
||||
[target.x86_64-kernel]
|
||||
rustflags = ["-C", "force-unwind-tables"]
|
||||
|
||||
[registries.gitea]
|
||||
index = "sparse+https://git.zxq5.dev/api/packages/OsDev/cargo/" # Sparse index
|
||||
|
||||
Generated
-21
@@ -99,18 +99,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "elf"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@@ -123,10 +111,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"crossbeam",
|
||||
"elf",
|
||||
"fallible-iterator",
|
||||
"futures-util",
|
||||
"gimli",
|
||||
"libm",
|
||||
"limine",
|
||||
"linked_list_allocator",
|
||||
@@ -160,12 +145,6 @@ dependencies = [
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
|
||||
+5
-3
@@ -19,9 +19,11 @@ futures-util = { version = "0.3.31", default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
linked_list_allocator = { version = "0.10.5", features = ["use_spin"] }
|
||||
gimli = { version = "0.31.1", default-features = false, features = ["read"] }
|
||||
elf = { version = "0.7.4", default-features = false, features = ["nightly"] }
|
||||
fallible-iterator = "0.3.0"
|
||||
# gimli = { version = "0.31.1", default-features = false, features = ["read"] }
|
||||
# elf = { version = "0.7.4", default-features = false, features = ["nightly"] }
|
||||
# fallible-iterator = "0.3.0"
|
||||
# framehop = { version = "0.13.2", default-features = false }
|
||||
# object = { version = "0.36.7", default-features = false, features = ["read"] }
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.2.14"
|
||||
|
||||
@@ -138,10 +138,10 @@ extern "x86-interrupt" fn page_fault_handler(
|
||||
_stack_frame: InterruptStackFrame,
|
||||
_error_code: PageFaultErrorCode,
|
||||
) {
|
||||
serial_println!("Exception: Page Fault");
|
||||
serial_println!("Accessed Address: {:?}", Cr2::read());
|
||||
serial_println!("Error Code: {:?}", _error_code);
|
||||
serial_println!("{:#?}", _stack_frame);
|
||||
// serial_println!("Exception: Page Fault");
|
||||
// serial_println!("Accessed Address: {:?}", Cr2::read());
|
||||
// serial_println!("Error Code: {:?}", _error_code);
|
||||
// serial_println!("{:#?}", _stack_frame);
|
||||
|
||||
if let Some(frame_allocator) = FRAME_ALLOCATOR.get() {
|
||||
let mut f = frame_allocator.lock();
|
||||
|
||||
@@ -11,12 +11,15 @@ use x86_64::{
|
||||
structures::paging::{OffsetPageTable, PageTable},
|
||||
};
|
||||
|
||||
pub const STACK_VIRTUAL_SPACE: usize = 0x5555_5555_0000; // start address of the memory space where we store allocated stacks
|
||||
pub const HEAP_VIRTUAL_SPACE: usize = 0x4444_4444_0000; // start address of heap allocated memory
|
||||
/// Start address of the memory space where we store allocated stacks.
|
||||
pub const STACK_VIRTUAL_SPACE: usize = 0x5555_5555_0000;
|
||||
/// Start address of heap allocated memory.
|
||||
pub const HEAP_VIRTUAL_SPACE: usize = 0x4444_4444_0000;
|
||||
pub const HEAP_SIZE: usize = MiB(1).to_bytes();
|
||||
|
||||
pub static FRAME_ALLOCATOR: Once<Mutex<FoundryOSFrameAllocator>> = Once::new();
|
||||
pub static OFFSET_PAGE_TABLE: Once<Mutex<OffsetPageTable>> = Once::new();
|
||||
|
||||
/// Returns a mutable reference to the current level 4 page table.
|
||||
///
|
||||
/// # Safety
|
||||
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
#![no_std]
|
||||
#![feature(abi_x86_interrupt)]
|
||||
#![feature(abi_x86_interrupt, breakpoint)]
|
||||
#![warn(
|
||||
clippy::correctness,
|
||||
clippy::nursery,
|
||||
@@ -35,7 +35,6 @@ use crate::{
|
||||
use alloc::{boxed::Box, format};
|
||||
use core::arch::asm;
|
||||
use limine::BaseRevision;
|
||||
use std::{debug, unwind::UNWINDER};
|
||||
use x86_64::VirtAddr;
|
||||
|
||||
pub mod arch;
|
||||
@@ -83,6 +82,7 @@ impl core::error::Error for NoError {}
|
||||
/// 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.
|
||||
#[inline(never)]
|
||||
pub fn boot() -> Result<(), Box<dyn core::error::Error>> {
|
||||
if !BASE_REVISION.is_supported() {
|
||||
return Err("Base revision not supported.".into());
|
||||
@@ -149,10 +149,9 @@ pub fn boot() -> Result<(), Box<dyn core::error::Error>> {
|
||||
x86_64::instructions::interrupts::enable();
|
||||
debugln!("[Success]");
|
||||
|
||||
// Initialises the stack unwinder once and only once because this makes a
|
||||
// heap allocation.
|
||||
debug!(" Initializing Stack Unwinder... ");
|
||||
UNWINDER.lock();
|
||||
// Force evaluate the constructor.
|
||||
// let _unwinder = &*UNWINDER;
|
||||
debugln!("[Success]");
|
||||
|
||||
Ok(())
|
||||
|
||||
+73
-10
@@ -3,9 +3,18 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use foundry_os::arch::x86_64::processing::async_io::task::{Executor, Task};
|
||||
use foundry_os::prelude::*;
|
||||
use foundry_os::util::shell::shell;
|
||||
use core::arch::asm;
|
||||
|
||||
use foundry_os::{
|
||||
// arch::x86_64::processing::async_io::task::{Executor, Task},
|
||||
prelude::*,
|
||||
// std::unwind::UNWINDER,
|
||||
// util::shell::shell,
|
||||
};
|
||||
// use framehop::{
|
||||
// x86_64::{CacheX86_64, UnwindRegsX86_64},
|
||||
// *,
|
||||
// };
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn kmain() -> ! {
|
||||
@@ -24,15 +33,69 @@ extern "C" fn kmain() -> ! {
|
||||
|
||||
test1();
|
||||
|
||||
let mut executor = Executor::new();
|
||||
executor.spawn(Task::new(shell()));
|
||||
executor.run()
|
||||
// let mut executor = Executor::new();
|
||||
// executor.spawn(Task::new(shell()));
|
||||
// executor.run()
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn test1() {
|
||||
test2()
|
||||
#[inline(never)]
|
||||
pub fn test1() {
|
||||
test2();
|
||||
}
|
||||
|
||||
fn test2() {
|
||||
panic!("Test");
|
||||
#[inline(never)]
|
||||
pub fn test2() {
|
||||
test3();
|
||||
}
|
||||
|
||||
const fn read_stack(addr: u64) -> Result<u64, ()> {
|
||||
Ok(unsafe { *(addr as *const u64) })
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn test3() {
|
||||
// let mut cache = CacheX86_64::new();
|
||||
// let unwinder = &*UNWINDER;
|
||||
|
||||
// let mut rip: u64;
|
||||
// let mut rsp: u64;
|
||||
// let mut rbp: u64;
|
||||
// let mut read_stack_fn = read_stack;
|
||||
|
||||
// unsafe {
|
||||
// asm!("lea {0}, [rip]",
|
||||
// "mov {1}, rsp",
|
||||
// "mov {2}, rbp",
|
||||
// out(reg) rip,
|
||||
// out(reg) rsp,
|
||||
// out(reg) rbp);
|
||||
// }
|
||||
|
||||
// let regs = UnwindRegsX86_64::new(rip, rsp, rbp);
|
||||
// let mut frame_iter =
|
||||
// unwinder.iter_frames(rip, regs, &mut cache, &mut read_stack_fn);
|
||||
|
||||
// // This is just me testing the unwinding. It seems to not return any
|
||||
// stack // frames for some odd reason.
|
||||
// loop {
|
||||
// match frame_iter.next() {
|
||||
// Ok(Some(frame)) => {
|
||||
// debugln!("Got function with {:x?}",
|
||||
// frame.address_for_lookup()); // match frame {
|
||||
// // FrameAddress::InstructionPointer(rip) => (),
|
||||
// // FrameAddress::ReturnAddress(ra) => {}
|
||||
// // }
|
||||
// }
|
||||
// Ok(None) => {
|
||||
// debugln!("Hit end of stack.");
|
||||
// break;
|
||||
// }
|
||||
// Err(why) => {
|
||||
// debugln!("{}", why);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pub use crate::{
|
||||
arch::x86_64::drivers::framebuffer::colour::Colour,
|
||||
debug, debugln, eprint, eprintln, print, print_log, print_oneshot, println,
|
||||
println_log, serial_print, serial_println,
|
||||
debug, debugln, eprint, eprintln, hcf, print, print_log, print_oneshot,
|
||||
println, println_log, serial_print, serial_println,
|
||||
std::debug::_debug,
|
||||
std::io::{_print, _print_err, _print_log, _serial_write},
|
||||
};
|
||||
|
||||
+62
-18
@@ -11,14 +11,14 @@
|
||||
//! * Add support for loading binary programs (this should probably be written
|
||||
//! in a different module)
|
||||
|
||||
use alloc::format;
|
||||
use alloc::{format, vec::Vec};
|
||||
use elf::{
|
||||
ElfBytes, ParseError,
|
||||
endian::LittleEndian,
|
||||
parse::{ParseAt, ParsingTable},
|
||||
section::{SectionHeader, SectionHeaderTable},
|
||||
string_table::StringTable,
|
||||
symbol::SymbolTable,
|
||||
symbol::{Symbol, SymbolTable},
|
||||
};
|
||||
use limine::request::KernelFileRequest;
|
||||
|
||||
@@ -38,6 +38,8 @@ pub static KERNEL_FILE_REQUEST: KernelFileRequest = KernelFileRequest::new();
|
||||
pub enum ElfError {
|
||||
/// Returned if a section did not exist in [ElfReader::get_section_size].
|
||||
SectionNotExists,
|
||||
/// Returned if we failed to fetch the symbol table.
|
||||
Symtab,
|
||||
/// Parse errors returned by the `elf` crate.
|
||||
OtherParseError(elf::ParseError),
|
||||
}
|
||||
@@ -49,8 +51,14 @@ impl From<elf::ParseError> for ElfError {
|
||||
}
|
||||
|
||||
pub struct ElfReader {
|
||||
/// The underlying bytes for the ELF file.
|
||||
pub bytes: &'static [u8],
|
||||
/// Structure returned by the `elf` crate having parsed the ELF header.
|
||||
elf: ElfBytes<'static, LittleEndian>,
|
||||
pub elf: ElfBytes<'static, LittleEndian>,
|
||||
/// A sorted list of symbols to binary search.
|
||||
pub sorted_syms: Vec<Symbol>,
|
||||
/// The string table for looking up symbol names.
|
||||
pub symbol_strtab: StringTable<'static>,
|
||||
}
|
||||
|
||||
impl ElfReader {
|
||||
@@ -65,23 +73,26 @@ impl ElfReader {
|
||||
/// Both of these should be satisfied, but this function is marked unsafe
|
||||
/// just in case, because we are derefererencing arbitrary pointers.
|
||||
pub unsafe fn new() -> Result<Self, ElfError> {
|
||||
let response = KERNEL_FILE_REQUEST
|
||||
.get_response()
|
||||
.expect("Didn't get the kernel file from Limine. That's odd.");
|
||||
|
||||
// We fetch these from Limine and use them to parse our own ELF file.
|
||||
let file = response.file();
|
||||
let file_start_ptr = file.addr();
|
||||
let file_size = file.size() as usize;
|
||||
|
||||
// Safety: This slice should contain the whole bytes of the ELF file.
|
||||
let elf_hdr_slice =
|
||||
unsafe { core::slice::from_raw_parts(file_start_ptr, file_size) };
|
||||
// Store this for use with other libraries.
|
||||
let bytes = get_elf_slice();
|
||||
|
||||
let elf: ElfBytes<'static, LittleEndian> =
|
||||
elf::ElfBytes::minimal_parse(elf_hdr_slice)?;
|
||||
elf::ElfBytes::minimal_parse(bytes)?;
|
||||
|
||||
Ok(Self { elf })
|
||||
let Some((symtab, strtab)) = elf.symbol_table()? else {
|
||||
return Err(ElfError::Symtab);
|
||||
};
|
||||
|
||||
// Sort the symtab for later use and store the strtab.
|
||||
let mut symbols = symtab.into_iter().collect::<Vec<Symbol>>();
|
||||
symbols.sort_by_key(|sym| sym.st_value);
|
||||
|
||||
Ok(Self {
|
||||
elf,
|
||||
sorted_syms: symbols,
|
||||
symbol_strtab: strtab,
|
||||
bytes,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_symbol_table(
|
||||
@@ -112,7 +123,7 @@ impl ElfReader {
|
||||
/// Gets the section header of `section_name`.
|
||||
pub fn get_section_header(
|
||||
&self,
|
||||
section_name: &'static str,
|
||||
section_name: &str,
|
||||
) -> Result<SectionHeader, ElfError> {
|
||||
let section_hdr = self
|
||||
.elf
|
||||
@@ -121,4 +132,37 @@ impl ElfReader {
|
||||
|
||||
section_hdr.ok_or(ElfError::SectionNotExists)
|
||||
}
|
||||
|
||||
pub fn search_symbol(&self, address: u64) -> Option<elf::symbol::Symbol> {
|
||||
let entries = self.sorted_syms.iter().collect::<Vec<_>>();
|
||||
|
||||
let idx = entries
|
||||
.as_slice()
|
||||
.binary_search_by_key(&address, |sym| sym.st_value)
|
||||
.ok()?;
|
||||
|
||||
Some(entries[idx].clone())
|
||||
}
|
||||
|
||||
pub fn get_symbol_name(
|
||||
&self,
|
||||
sym: elf::symbol::Symbol,
|
||||
) -> Option<&'static str> {
|
||||
self.symbol_strtab.get(sym.st_name as usize).ok()
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a slice of the bytes of the kernel ELF file.
|
||||
pub fn get_elf_slice() -> &'static [u8] {
|
||||
let response = KERNEL_FILE_REQUEST
|
||||
.get_response()
|
||||
.expect("Didn't get the kernel file from Limine. That's odd.");
|
||||
|
||||
// We fetch these from Limine and use them to parse our own ELF file.
|
||||
let file = response.file();
|
||||
let file_start_ptr = file.addr();
|
||||
let file_size = file.size() as usize;
|
||||
|
||||
// Safety: This slice should contain the whole bytes of the ELF file.
|
||||
(unsafe { core::slice::from_raw_parts(file_start_ptr, file_size) }) as _
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pub mod application;
|
||||
pub mod ascii;
|
||||
pub mod debug;
|
||||
pub mod elf;
|
||||
// pub mod elf;
|
||||
pub mod io;
|
||||
pub mod maths;
|
||||
pub mod unwind;
|
||||
// pub mod unwind;
|
||||
|
||||
@@ -1,23 +1,31 @@
|
||||
use core::arch::asm;
|
||||
|
||||
use eh_info::ELF;
|
||||
use alloc::vec::Vec;
|
||||
use framehop::{
|
||||
x86_64::{CacheX86_64, UnwinderX86_64},
|
||||
*,
|
||||
};
|
||||
use spin::{Lazy, Mutex};
|
||||
use unwinder::{RegisterSet, Unwinder};
|
||||
|
||||
use crate::arch::x86_64::memory::mapping::KERNEL_ADDRESS_REQUEST;
|
||||
|
||||
pub mod eh_info;
|
||||
pub mod panic;
|
||||
pub mod unwinder;
|
||||
|
||||
/// We should initialise on program start.
|
||||
pub static UNWINDER: Lazy<Mutex<Unwinder>> = Lazy::new(|| {
|
||||
// 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.");
|
||||
pub static UNWINDER: Lazy<framehop::x86_64::UnwinderX86_64<Vec<u8>>> =
|
||||
Lazy::new(|| {
|
||||
let mut unwinder: UnwinderX86_64<_, MayAllocateDuringUnwind> =
|
||||
UnwinderX86_64::new();
|
||||
|
||||
let eh_info = unsafe { eh_info::EhInfo::from_hdr_ptr(eh_frame_ptr) };
|
||||
let mut registers = RegisterSet::default();
|
||||
panic::add_object(
|
||||
&mut unwinder,
|
||||
KERNEL_ADDRESS_REQUEST
|
||||
.get_response()
|
||||
.unwrap()
|
||||
.virtual_base(),
|
||||
);
|
||||
|
||||
Mutex::new(Unwinder::new(eh_info, registers))
|
||||
});
|
||||
unwinder
|
||||
});
|
||||
|
||||
+156
-39
@@ -1,16 +1,25 @@
|
||||
//! Defines a simple panic handler which handles stack traces as required.
|
||||
|
||||
use core::{arch::asm, panic::PanicInfo};
|
||||
use core::{arch::asm, ops::Range, panic::PanicInfo};
|
||||
|
||||
use alloc::string::ToString;
|
||||
use fallible_iterator::FallibleIterator;
|
||||
use gimli::{Register, X86_64};
|
||||
use alloc::{
|
||||
borrow::{Cow, ToOwned},
|
||||
slice,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use elf::segment::ProgramHeader;
|
||||
use framehop::x86_64::{CacheX86_64, UnwinderX86_64};
|
||||
use framehop::{Unwinder, x86_64::UnwindRegsX86_64};
|
||||
|
||||
use super::unwinder::Unwinder;
|
||||
use crate::{
|
||||
hcf,
|
||||
arch::x86_64::memory::mapping::KERNEL_ADDRESS_REQUEST,
|
||||
prelude::*,
|
||||
std::unwind::{UNWINDER, eh_info::ELF, unwinder::RegisterSet},
|
||||
std::{
|
||||
self,
|
||||
elf::ElfReader,
|
||||
unwind::{UNWINDER, eh_info::ELF},
|
||||
},
|
||||
};
|
||||
|
||||
#[panic_handler]
|
||||
@@ -18,37 +27,145 @@ use crate::{
|
||||
pub fn panic_handler(info: &PanicInfo<'_>) -> ! {
|
||||
debugln!("Kernel panic: {}", info);
|
||||
|
||||
let mut rip: u64;
|
||||
let mut rsp: u64;
|
||||
unsafe {
|
||||
asm!("lea {0}, [rip]",
|
||||
"mov {1}, rsp",
|
||||
out(reg) rip, out(reg) rsp);
|
||||
}
|
||||
|
||||
let mut unwinder = UNWINDER.lock();
|
||||
unwinder.regs.set_pc(rip);
|
||||
unwinder.regs.set_stack_ptr(rsp);
|
||||
|
||||
while let Some(call_frame) = unwinder.next().unwrap_or_else(|err| {
|
||||
// If an unwind error occurred.
|
||||
debugln!("{:?}", err);
|
||||
hcf()
|
||||
}) {
|
||||
serial_println!("Got frame: {:x?}", call_frame);
|
||||
let Some((symtab, strtab)) =
|
||||
ELF.get_symbol_table().unwrap_or_else(|e| {
|
||||
debugln!("{:?}", e);
|
||||
hcf()
|
||||
})
|
||||
else {
|
||||
// TODO: Omit symbol names but just print addresses.
|
||||
debugln!("Didn't find symtab and strtab!");
|
||||
hcf()
|
||||
};
|
||||
|
||||
// let sym_name = symtab.get(call_frame.pc as usize).unwrap();
|
||||
}
|
||||
|
||||
crate::hcf()
|
||||
}
|
||||
|
||||
use object::{Object, ObjectSection, ObjectSegment};
|
||||
|
||||
use framehop::*;
|
||||
|
||||
pub fn add_object<U>(unwinder: &mut U, base_avma: u64)
|
||||
where
|
||||
U: Unwinder<Module = Module<Vec<u8>>>,
|
||||
{
|
||||
let mut buf = ELF.bytes;
|
||||
|
||||
let file = object::File::parse(buf).expect("Could not parse object file");
|
||||
|
||||
struct Module<'a>(object::File<'a, &'a [u8]>);
|
||||
|
||||
impl ModuleSectionInfo<Vec<u8>> for Module<'_> {
|
||||
fn base_svma(&self) -> u64 {
|
||||
relative_address_base(&self.0)
|
||||
}
|
||||
|
||||
fn section_svma_range(&mut self, name: &[u8]) -> Option<Range<u64>> {
|
||||
let section = self.0.section_by_name_bytes(name)?;
|
||||
Some(section.address()..section.address() + section.size())
|
||||
}
|
||||
|
||||
fn section_data(&mut self, name: &[u8]) -> Option<Vec<u8>> {
|
||||
match self.0.section_by_name_bytes(name) {
|
||||
Some(section) => {
|
||||
section.data().ok().map(|data| data.to_owned())
|
||||
}
|
||||
None if name == b".debug_frame" => {
|
||||
let section =
|
||||
self.0.section_by_name_bytes(b"__zdebug_frame")?;
|
||||
get_uncompressed_section_data(§ion)
|
||||
.map(|d| d.into_owned())
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn segment_svma_range(&mut self, name: &[u8]) -> Option<Range<u64>> {
|
||||
let segment = self
|
||||
.0
|
||||
.segments()
|
||||
.find(|s| s.name_bytes() == Ok(Some(name)))?;
|
||||
Some(segment.address()..segment.address() + segment.size())
|
||||
}
|
||||
|
||||
fn segment_data(&mut self, name: &[u8]) -> Option<Vec<u8>> {
|
||||
let segment = self
|
||||
.0
|
||||
.segments()
|
||||
.find(|s| s.name_bytes() == Ok(Some(name)))?;
|
||||
segment.data().ok().map(|data| data.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
let module = framehop::Module::new(
|
||||
"Kernel".to_string(),
|
||||
base_avma..(base_avma + buf.len() as u64),
|
||||
base_avma,
|
||||
Module(file),
|
||||
);
|
||||
unwinder.add_module(module);
|
||||
}
|
||||
|
||||
fn get_uncompressed_section_data<'a>(
|
||||
section: &impl object::ObjectSection<'a>,
|
||||
) -> Option<Cow<'a, [u8]>> {
|
||||
// let section_data = section.uncompressed_data().ok()?;
|
||||
|
||||
// // Make sure the data is actually decompressed.
|
||||
// if section.name_bytes().ok()?.starts_with(b"__zdebug_")
|
||||
// && section_data.starts_with(b"ZLIB\0\0\0\0")
|
||||
// {
|
||||
// // Object's built-in compressed section handling didn't detect this
|
||||
// as a // compressed section. This happens on Go binaries which use
|
||||
// compressed // sections like __zdebug_ranges, which is generally
|
||||
// uncommon on macOS, // so object's mach-O parser doesn't handle
|
||||
// them. // But we want to handle them.
|
||||
// // Go stopped using zdebug sections for ELF files in https://github.com/golang/go/issues/50796
|
||||
// // but still uses them for mach-O builds.
|
||||
// let b = section_data.get(8..12)?;
|
||||
// let uncompressed_size = u32::from_be_bytes([b[0], b[1], b[2], b[3]]);
|
||||
// let compressed_bytes = §ion_data[12..];
|
||||
|
||||
// let mut decompressed = Vec::with_capacity(uncompressed_size as
|
||||
// usize); let mut decompress = flate2::Decompress::new(true);
|
||||
// decompress
|
||||
// .decompress_vec(
|
||||
// compressed_bytes,
|
||||
// &mut decompressed,
|
||||
// flate2::FlushDecompress::Finish,
|
||||
// )
|
||||
// .ok()?;
|
||||
// Some(Cow::Owned(decompressed))
|
||||
// } else {
|
||||
// Some(section_data)
|
||||
// }
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Relative addresses are u32 offsets which are relative to some "base
|
||||
/// address".
|
||||
///
|
||||
/// This function computes that base address. It is defined as follows:
|
||||
///
|
||||
/// - For Windows binaries, the base address is the "image base address".
|
||||
/// - For mach-O binaries, the base address is the vmaddr of the __TEXT
|
||||
/// segment.
|
||||
/// - For ELF binaries, the base address is zero.
|
||||
///
|
||||
/// Stand-alone mach-O dylibs usually have a base address of zero because their
|
||||
/// __TEXT segment is at address zero.
|
||||
///
|
||||
/// In the following cases, the base address is usually non-zero:
|
||||
///
|
||||
/// - The "image base address" of Windows binaries is usually non-zero.
|
||||
/// - mach-O executable files (not dylibs) usually have their __TEXT segment at
|
||||
/// address 0x100000000.
|
||||
/// - mach-O libraries in the dyld shared cache have a __TEXT segment at some
|
||||
/// non-zero address in the cache.
|
||||
pub fn relative_address_base<'data>(
|
||||
object_file: &impl object::Object<'data>,
|
||||
) -> u64 {
|
||||
if let Some(text_segment) = object_file
|
||||
.segments()
|
||||
.find(|s| s.name() == Ok(Some("__TEXT")))
|
||||
{
|
||||
// This is a mach-O image. "Relative addresses" are relative to the
|
||||
// vmaddr of the __TEXT segment.
|
||||
return text_segment.address();
|
||||
}
|
||||
|
||||
// For PE binaries, relative_address_base() returns the image base address.
|
||||
// Otherwise it returns zero. This gives regular ELF images a base address
|
||||
// of zero, which is what we want.
|
||||
object_file.relative_address_base()
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ impl FallibleIterator for Unwinder {
|
||||
let Some(pc) = self.regs.get_pc() else {
|
||||
return Err(UnwinderError::NoPcRegister);
|
||||
};
|
||||
// 0xffffffff8000014b b - 7 = 11 - 7 = 4
|
||||
|
||||
if self.is_first {
|
||||
self.is_first = false;
|
||||
|
||||
@@ -32,7 +32,7 @@ else
|
||||
fi
|
||||
|
||||
# Set up test-specific flags
|
||||
if [ $is_test -eq 1 ]; then
|
||||
if [$is_test]; then
|
||||
test_flags="-device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none"
|
||||
serial_flags="-serial stdio"
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user