Compare commits
1 Commits
master
...
feature/un
Author | SHA1 | Date | |
---|---|---|---|
7e5979c1a2 |
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -1825,6 +1825,14 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1230ec65f13e0f9b28d789da20d2d419511893ea9dac2c1f4ef67b8b14e5da80"
|
checksum = "1230ec65f13e0f9b28d789da20d2d419511893ea9dac2c1f4ef67b8b14e5da80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unwind"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"gimli",
|
||||||
|
"yggdrasil-rt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.2"
|
version = "2.5.2"
|
||||||
|
@ -15,7 +15,8 @@ members = [
|
|||||||
"lib/abi",
|
"lib/abi",
|
||||||
"lib/libyalloc",
|
"lib/libyalloc",
|
||||||
"lib/runtime",
|
"lib/runtime",
|
||||||
"lib/qemu"
|
"lib/qemu",
|
||||||
|
"lib/unwind"
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
@ -20,7 +20,10 @@ use yggdrasil_abi::{error::Error, io::SeekFrom, path::PathBuf};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
random,
|
random,
|
||||||
task::{process::ProcessImage, types::TlsImage},
|
task::{
|
||||||
|
process::{ProcessImage, UnwindInfo},
|
||||||
|
types::TlsImage,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
@ -207,6 +210,8 @@ pub fn load_elf_from_file<F: Read + Seek>(
|
|||||||
// Load TLS master copy somewhere into process memory
|
// Load TLS master copy somewhere into process memory
|
||||||
let tls_image = handle_tls(space, &elf, &file)?;
|
let tls_image = handle_tls(space, &elf, &file)?;
|
||||||
|
|
||||||
|
let unwind_info = extract_unwind_info(&mut elf, image_load_base, vaddr_min);
|
||||||
|
|
||||||
// Fixup relocations
|
// Fixup relocations
|
||||||
handle_relocations(&mut elf, space, image_load_base)?;
|
handle_relocations(&mut elf, space, image_load_base)?;
|
||||||
|
|
||||||
@ -219,6 +224,38 @@ pub fn load_elf_from_file<F: Read + Seek>(
|
|||||||
ip_offset,
|
ip_offset,
|
||||||
load_base: image_load_base,
|
load_base: image_load_base,
|
||||||
tls_image,
|
tls_image,
|
||||||
|
unwind_info,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_unwind_info<F: Read + Seek>(
|
||||||
|
elf: &mut ElfStream<AnyEndian, FileReader<F>>,
|
||||||
|
image_load_base: usize,
|
||||||
|
vaddr_min: usize,
|
||||||
|
) -> Option<UnwindInfo> {
|
||||||
|
let eh_frame_hdr = elf
|
||||||
|
.segments()
|
||||||
|
.iter()
|
||||||
|
.find(|e| e.p_type == elf::abi::PT_GNU_EH_FRAME)?;
|
||||||
|
let eh_frame_hdr_size = eh_frame_hdr.p_memsz as usize;
|
||||||
|
let eh_frame_hdr = eh_frame_hdr.p_vaddr as usize + image_load_base - vaddr_min;
|
||||||
|
let (sections, strtab) = elf.section_headers_with_strtab().ok()?;
|
||||||
|
let strtab = strtab?;
|
||||||
|
|
||||||
|
let eh_frame_size = sections
|
||||||
|
.iter()
|
||||||
|
.find(|e| {
|
||||||
|
strtab
|
||||||
|
.get(e.sh_name as usize)
|
||||||
|
.map(|name| name == ".eh_frame")
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
|
.map(|e| e.sh_size as usize)?;
|
||||||
|
|
||||||
|
Some(UnwindInfo {
|
||||||
|
eh_frame_hdr,
|
||||||
|
eh_frame_size,
|
||||||
|
eh_frame_hdr_size,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +197,20 @@ where
|
|||||||
val: tls_image.full_size as _,
|
val: tls_image.full_size as _,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if let Some(info) = image.unwind_info.as_ref() {
|
||||||
|
auxv.push(AuxValue {
|
||||||
|
tag: auxv::EH_FRAME_HDR,
|
||||||
|
val: info.eh_frame_hdr as _,
|
||||||
|
});
|
||||||
|
auxv.push(AuxValue {
|
||||||
|
tag: auxv::EH_FRAME_SIZE,
|
||||||
|
val: info.eh_frame_size as _,
|
||||||
|
});
|
||||||
|
auxv.push(AuxValue {
|
||||||
|
tag: auxv::EH_FRAME_HDR_SIZE,
|
||||||
|
val: info.eh_frame_hdr_size as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let argument = setup_program_env(space, virt_args_base, args, envs, &auxv)?;
|
let argument = setup_program_env(space, virt_args_base, args, envs, &auxv)?;
|
||||||
|
|
||||||
|
@ -48,6 +48,13 @@ pub struct ProcessManager {
|
|||||||
processes: IrqSafeRwLock<BTreeMap<ProcessId, Arc<Process>>>,
|
processes: IrqSafeRwLock<BTreeMap<ProcessId, Arc<Process>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct UnwindInfo {
|
||||||
|
pub eh_frame_hdr: usize,
|
||||||
|
pub eh_frame_hdr_size: usize,
|
||||||
|
pub eh_frame_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
/// Describes information about a program's image in memory
|
/// Describes information about a program's image in memory
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ProcessImage {
|
pub struct ProcessImage {
|
||||||
@ -57,6 +64,8 @@ pub struct ProcessImage {
|
|||||||
pub entry: usize,
|
pub entry: usize,
|
||||||
/// TLS master copy, if any
|
/// TLS master copy, if any
|
||||||
pub tls_image: Option<TlsImage>,
|
pub tls_image: Option<TlsImage>,
|
||||||
|
/// Unwind info table
|
||||||
|
pub unwind_info: Option<UnwindInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ProcessInner {
|
pub struct ProcessInner {
|
||||||
|
@ -26,6 +26,10 @@ pub mod auxv {
|
|||||||
|
|
||||||
pub const TLS_ALREADY_INITIALIZED: u64 = 0x86;
|
pub const TLS_ALREADY_INITIALIZED: u64 = 0x86;
|
||||||
|
|
||||||
|
pub const EH_FRAME_HDR: u64 = 0x60;
|
||||||
|
pub const EH_FRAME_HDR_SIZE: u64 = 0x61;
|
||||||
|
pub const EH_FRAME_SIZE: u64 = 0x62;
|
||||||
|
|
||||||
pub const NULL: u64 = 0x00;
|
pub const NULL: u64 = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
lib/unwind/Cargo.toml
Normal file
11
lib/unwind/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "unwind"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
yggdrasil-rt = { path = "../runtime" }
|
||||||
|
gimli = { version = "0.31.1", default-features = false, features = ["read"] }
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
4
lib/unwind/src/arch/mod.rs
Normal file
4
lib/unwind/src/arch/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
mod x86_64;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub use x86_64::{host_endian, HostEndian, RegisterSet};
|
93
lib/unwind/src/arch/x86_64.rs
Normal file
93
lib/unwind/src/arch/x86_64.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use core::{
|
||||||
|
mem::MaybeUninit,
|
||||||
|
ops::{Index, IndexMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
use gimli::{LittleEndian, X86_64};
|
||||||
|
|
||||||
|
pub type HostEndian = LittleEndian;
|
||||||
|
|
||||||
|
pub fn host_endian() -> HostEndian {
|
||||||
|
LittleEndian
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct RegisterSet {
|
||||||
|
pub rip: Option<u64>,
|
||||||
|
pub rsp: Option<u64>,
|
||||||
|
pub rbp: Option<u64>,
|
||||||
|
pub ret: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct UnwindEntryInfo {
|
||||||
|
rip: usize,
|
||||||
|
rbp: usize,
|
||||||
|
rsp: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegisterSet {
|
||||||
|
pub fn current() -> Self {
|
||||||
|
let mut cx = MaybeUninit::uninit();
|
||||||
|
let cx = unsafe { get_context(&mut cx) };
|
||||||
|
|
||||||
|
Self {
|
||||||
|
rip: Some(cx.rip as _),
|
||||||
|
rsp: Some(cx.rsp as _),
|
||||||
|
rbp: Some(cx.rbp as _),
|
||||||
|
ret: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter() -> impl Iterator<Item = gimli::Register> {
|
||||||
|
[X86_64::RA, X86_64::RBP, X86_64::RSP].into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<gimli::Register> for RegisterSet {
|
||||||
|
type Output = Option<u64>;
|
||||||
|
|
||||||
|
fn index(&self, index: gimli::Register) -> &Self::Output {
|
||||||
|
match index {
|
||||||
|
X86_64::RA => &self.ret,
|
||||||
|
X86_64::RSP => &self.rsp,
|
||||||
|
X86_64::RBP => &self.rbp,
|
||||||
|
_ => panic!("Unhandled register"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<gimli::Register> for RegisterSet {
|
||||||
|
fn index_mut(&mut self, index: gimli::Register) -> &mut Self::Output {
|
||||||
|
match index {
|
||||||
|
X86_64::RA => &mut self.ret,
|
||||||
|
X86_64::RSP => &mut self.rsp,
|
||||||
|
X86_64::RBP => &mut self.rbp,
|
||||||
|
_ => panic!("Unhandled register"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[naked]
|
||||||
|
unsafe extern "C" fn get_context(unw: &mut MaybeUninit<UnwindEntryInfo>) -> &UnwindEntryInfo {
|
||||||
|
// %rsp: return address (%rip)
|
||||||
|
// %rdi: *mut UnwindInfo unw
|
||||||
|
// %rax clobbered
|
||||||
|
core::arch::naked_asm!(
|
||||||
|
r#"
|
||||||
|
// unw.rip = [%rsp]
|
||||||
|
mov (%rsp), %rax
|
||||||
|
mov %rax, 0(%rdi)
|
||||||
|
// unw.rsp = %rsp + 8
|
||||||
|
mov %rsp, %rax
|
||||||
|
add $8, %rax
|
||||||
|
mov %rax, 16(%rdi)
|
||||||
|
// unw.rbp = %rbp
|
||||||
|
mov %rbp, 8(%rdi)
|
||||||
|
mov %rdi, %rax
|
||||||
|
ret
|
||||||
|
"#,
|
||||||
|
options(att_syntax)
|
||||||
|
)
|
||||||
|
}
|
178
lib/unwind/src/lib.rs
Normal file
178
lib/unwind/src/lib.rs
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![feature(naked_functions)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use core::{ptr, slice};
|
||||||
|
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use gimli::{
|
||||||
|
BaseAddresses, CfaRule, EhFrame, EhFrameHdr, EhHdrTable, EndianSlice, ParsedEhFrameHdr,
|
||||||
|
Pointer, RegisterRule, StoreOnHeap, UnwindContext, UnwindSection,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod arch;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
NoPc,
|
||||||
|
NoReturnAddress,
|
||||||
|
NoUnwindInfo(gimli::Error, u64),
|
||||||
|
UnknownCfaRuleRegister(gimli::Register),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UnwindBeginInfo {
|
||||||
|
pub eh_frame_hdr: *const (),
|
||||||
|
pub eh_frame_hdr_size: usize,
|
||||||
|
pub eh_frame_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EhInfo {
|
||||||
|
base_addrs: BaseAddresses,
|
||||||
|
#[allow(unused)]
|
||||||
|
hdr: Option<&'static ParsedEhFrameHdr<EndianSlice<'static, arch::HostEndian>>>,
|
||||||
|
hdr_table: Option<EhHdrTable<'static, EndianSlice<'static, arch::HostEndian>>>,
|
||||||
|
eh_frame: EhFrame<EndianSlice<'static, arch::HostEndian>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Unwinder {
|
||||||
|
eh_info: EhInfo,
|
||||||
|
unwind_ctx: UnwindContext<usize, StoreOnHeap>,
|
||||||
|
regs: arch::RegisterSet,
|
||||||
|
cfa: u64,
|
||||||
|
is_first: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CallFrame {
|
||||||
|
pub pc: u64,
|
||||||
|
pub start_address: u64,
|
||||||
|
pub end_address: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Unwinder {
|
||||||
|
fn new(eh_info: EhInfo, regs: arch::RegisterSet) -> Self {
|
||||||
|
Self {
|
||||||
|
eh_info,
|
||||||
|
regs,
|
||||||
|
unwind_ctx: UnwindContext::new(),
|
||||||
|
cfa: 0,
|
||||||
|
is_first: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(&mut self) -> Result<Option<CallFrame>, Error> {
|
||||||
|
let pc = self.regs.rip.ok_or(Error::NoPc)?;
|
||||||
|
if self.is_first {
|
||||||
|
self.is_first = false;
|
||||||
|
return Ok(Some(CallFrame {
|
||||||
|
pc,
|
||||||
|
start_address: 0,
|
||||||
|
end_address: 0,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
let hdr_table = self.eh_info.hdr_table.as_ref().unwrap();
|
||||||
|
let row = hdr_table
|
||||||
|
.unwind_info_for_address(
|
||||||
|
&self.eh_info.eh_frame,
|
||||||
|
&self.eh_info.base_addrs,
|
||||||
|
&mut self.unwind_ctx,
|
||||||
|
pc,
|
||||||
|
|section, bases, offset| section.cie_from_offset(bases, offset),
|
||||||
|
)
|
||||||
|
.map_err(|err| Error::NoUnwindInfo(err, pc))?;
|
||||||
|
|
||||||
|
match row.cfa() {
|
||||||
|
CfaRule::RegisterAndOffset { register, offset } => {
|
||||||
|
let reg_val =
|
||||||
|
self.regs[*register].ok_or(Error::UnknownCfaRuleRegister(*register))?;
|
||||||
|
self.cfa = (reg_val as i64 + *offset) as u64;
|
||||||
|
}
|
||||||
|
CfaRule::Expression(_) => todo!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for reg in arch::RegisterSet::iter() {
|
||||||
|
match row.register(reg) {
|
||||||
|
RegisterRule::Undefined => self.regs[reg] = None,
|
||||||
|
RegisterRule::SameValue => (),
|
||||||
|
RegisterRule::Offset(offset) => {
|
||||||
|
let ptr = (self.cfa as i64 + offset) as u64 as *const usize;
|
||||||
|
self.regs[reg] = Some(unsafe { ptr.read() } as u64);
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let pc = self.regs.ret.ok_or(Error::NoReturnAddress)? - 1;
|
||||||
|
self.regs.rip = Some(pc);
|
||||||
|
self.regs.rsp = Some(self.cfa);
|
||||||
|
|
||||||
|
Ok(Some(CallFrame {
|
||||||
|
pc,
|
||||||
|
start_address: row.start_address(),
|
||||||
|
end_address: row.end_address(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EhInfo {
|
||||||
|
unsafe fn from_eh_frame_hdr(begin_info: UnwindBeginInfo) -> Self {
|
||||||
|
let mut base_addrs = BaseAddresses::default();
|
||||||
|
base_addrs = base_addrs.set_eh_frame_hdr(begin_info.eh_frame_hdr.addr() as _);
|
||||||
|
|
||||||
|
let hdr = Box::leak(Box::new(
|
||||||
|
EhFrameHdr::new(
|
||||||
|
unsafe {
|
||||||
|
slice::from_raw_parts(
|
||||||
|
begin_info.eh_frame_hdr.cast(),
|
||||||
|
begin_info.eh_frame_hdr_size,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
arch::host_endian(),
|
||||||
|
)
|
||||||
|
.parse(&base_addrs, size_of::<usize>() as _)
|
||||||
|
.unwrap(),
|
||||||
|
));
|
||||||
|
|
||||||
|
let eh_frame: *mut u8 = match hdr.eh_frame_ptr() {
|
||||||
|
Pointer::Direct(ptr) => ptr::with_exposed_provenance_mut(ptr as usize),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
base_addrs = base_addrs.set_eh_frame(eh_frame.addr() as u64);
|
||||||
|
|
||||||
|
let eh_frame = EhFrame::new(
|
||||||
|
unsafe { slice::from_raw_parts(eh_frame, begin_info.eh_frame_size) },
|
||||||
|
arch::host_endian(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
base_addrs,
|
||||||
|
hdr: Some(hdr),
|
||||||
|
hdr_table: Some(hdr.table().unwrap()),
|
||||||
|
eh_frame,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn backtrace<F: FnMut(CallFrame) -> bool>(begin_info: UnwindBeginInfo, mut handler: F) {
|
||||||
|
let regs = arch::RegisterSet::current();
|
||||||
|
let eh_info = unsafe { EhInfo::from_eh_frame_hdr(begin_info) };
|
||||||
|
let mut unwinder = Unwinder::new(eh_info, regs);
|
||||||
|
loop {
|
||||||
|
match unwinder.next() {
|
||||||
|
Ok(Some(frame)) => {
|
||||||
|
if !handler(frame) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None) => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
yggdrasil_rt::debug_trace!("Unwind error: {error:?}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
userspace/lib/ygglibc/Cargo.lock
generated
15
userspace/lib/ygglibc/Cargo.lock
generated
@ -194,6 +194,12 @@ version = "2.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
|
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gimli"
|
||||||
|
version = "0.31.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.1"
|
version = "0.15.1"
|
||||||
@ -459,6 +465,14 @@ version = "1.0.13"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unwind"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"gimli",
|
||||||
|
"yggdrasil-rt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@ -585,6 +599,7 @@ dependencies = [
|
|||||||
"cbindgen",
|
"cbindgen",
|
||||||
"chrono",
|
"chrono",
|
||||||
"libyalloc",
|
"libyalloc",
|
||||||
|
"unwind",
|
||||||
"yggdrasil-abi",
|
"yggdrasil-abi",
|
||||||
"yggdrasil-rt",
|
"yggdrasil-rt",
|
||||||
]
|
]
|
||||||
|
@ -10,6 +10,7 @@ crate-type = ["cdylib", "staticlib"]
|
|||||||
yggdrasil-rt = { path = "../../../lib/runtime", features = ["__tls_get_addr"] }
|
yggdrasil-rt = { path = "../../../lib/runtime", features = ["__tls_get_addr"] }
|
||||||
yggdrasil-abi = { path = "../../../lib/abi", features = ["alloc", "bytemuck"] }
|
yggdrasil-abi = { path = "../../../lib/abi", features = ["alloc", "bytemuck"] }
|
||||||
libyalloc = { path = "../../../lib/libyalloc" }
|
libyalloc = { path = "../../../lib/libyalloc" }
|
||||||
|
unwind = { path = "../../../lib/unwind" }
|
||||||
|
|
||||||
bitflags = "2.6.0"
|
bitflags = "2.6.0"
|
||||||
chrono = { version = "0.4.31", default-features = false }
|
chrono = { version = "0.4.31", default-features = false }
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
"executables": true,
|
"executables": true,
|
||||||
"panic-strategy": "abort",
|
"panic-strategy": "abort",
|
||||||
"dynamic-linking": true,
|
"dynamic-linking": true,
|
||||||
|
"eh-frame-header": true,
|
||||||
|
"default-uwtable": true,
|
||||||
"relocation-model": "pic",
|
"relocation-model": "pic",
|
||||||
"position-independent-executables": true,
|
"position-independent-executables": true,
|
||||||
"crt-static-allows-dylibs": true,
|
"crt-static-allows-dylibs": true,
|
||||||
|
@ -16,6 +16,7 @@ use crate::{
|
|||||||
errno::Errno, string::{mem::memcpy, str::strlen}
|
errno::Errno, string::{mem::memcpy, str::strlen}
|
||||||
},
|
},
|
||||||
thread,
|
thread,
|
||||||
|
unwind,
|
||||||
util::PointerExt,
|
util::PointerExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -227,6 +228,7 @@ pub fn handle_kernel_argument(arg: usize) -> Vec<CString> {
|
|||||||
|
|
||||||
// Setup TLS from argument
|
// Setup TLS from argument
|
||||||
thread::init_main_thread(arg);
|
thread::init_main_thread(arg);
|
||||||
|
unwind::init_from_auxv(arg);
|
||||||
|
|
||||||
args
|
args
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ mod ssp;
|
|||||||
mod thread;
|
mod thread;
|
||||||
mod types;
|
mod types;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod unwind;
|
||||||
|
|
||||||
pub mod headers;
|
pub mod headers;
|
||||||
|
|
||||||
@ -76,6 +77,8 @@ unsafe extern "C" fn __ygglibc_entry(
|
|||||||
}
|
}
|
||||||
c_args.push(null());
|
c_args.push(null());
|
||||||
|
|
||||||
|
panic!("Test panic");
|
||||||
|
|
||||||
let status = main(
|
let status = main(
|
||||||
args.len().try_into().unwrap(),
|
args.len().try_into().unwrap(),
|
||||||
c_args.as_ptr(),
|
c_args.as_ptr(),
|
||||||
|
@ -91,6 +91,12 @@ fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeln!(printer, "Stack trace:");
|
||||||
|
crate::unwind::unwind(|frame| {
|
||||||
|
writeln!(printer, "* {:#x}", frame.pc);
|
||||||
|
true
|
||||||
|
});
|
||||||
|
|
||||||
printer.flush();
|
printer.flush();
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
|
40
userspace/lib/ygglibc/src/unwind.rs
Normal file
40
userspace/lib/ygglibc/src/unwind.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use core::{ptr, sync::atomic::{AtomicUsize, Ordering}};
|
||||||
|
|
||||||
|
use unwind::UnwindBeginInfo;
|
||||||
|
use yggdrasil_rt::{
|
||||||
|
process::{auxv, AuxValue, ProgramArgumentInner},
|
||||||
|
sync::once::Once,
|
||||||
|
};
|
||||||
|
|
||||||
|
static EH_FRAME_HDR: Once<usize> = Once::uninit();
|
||||||
|
static EH_FRAME_HDR_SIZE: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
static EH_FRAME_SIZE: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
pub fn init_from_auxv(arg: &ProgramArgumentInner) {
|
||||||
|
let mut auxv = arg.auxv();
|
||||||
|
for entry in auxv {
|
||||||
|
match entry.tag {
|
||||||
|
auxv::EH_FRAME_HDR => {
|
||||||
|
EH_FRAME_HDR.init_with(|| entry.val as usize);
|
||||||
|
}
|
||||||
|
auxv::EH_FRAME_SIZE => {
|
||||||
|
EH_FRAME_SIZE.store(entry.val as usize, Ordering::Release);
|
||||||
|
}
|
||||||
|
auxv::EH_FRAME_HDR_SIZE => {
|
||||||
|
EH_FRAME_HDR_SIZE.store(entry.val as usize, Ordering::Release);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwind<F: FnMut(unwind::CallFrame) -> bool>(handler: F) {
|
||||||
|
if let Some(&eh_frame_hdr) = EH_FRAME_HDR.try_get() {
|
||||||
|
let info = UnwindBeginInfo {
|
||||||
|
eh_frame_hdr: ptr::with_exposed_provenance(eh_frame_hdr),
|
||||||
|
eh_frame_size: EH_FRAME_SIZE.load(Ordering::Acquire),
|
||||||
|
eh_frame_hdr_size: EH_FRAME_HDR_SIZE.load(Ordering::Acquire)
|
||||||
|
};
|
||||||
|
unwind::backtrace(info, handler);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user