Skip to content

Commit

Permalink
Merge pull request #25 from philipc/gimli
Browse files Browse the repository at this point in the history
Update gimli to 0.17.0
  • Loading branch information
philipc authored Feb 25, 2019
2 parents 1813bf0 + f5fbf20 commit 3b90740
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 104 deletions.
3 changes: 2 additions & 1 deletion unwind/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
authors = ["main() <[email protected]>"]

[dependencies]
gimli = "0.16.1"
gimli = "0.17"
libc = "0.2"
fallible-iterator = "0.1"
log = "0.4"
Expand All @@ -18,3 +18,4 @@ env_logger = "0.6"

[features]
nightly = []
asm = ["nightly"]
2 changes: 1 addition & 1 deletion unwind/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ extern crate gcc;
use std::env;

fn main() {
match env::var("CARGO_FEATURE_NIGHTLY") {
match env::var("CARGO_FEATURE_ASM") {
Err(env::VarError::NotPresent) => {
gcc::Build::new()
.file("src/unwind_helper.c")
Expand Down
21 changes: 12 additions & 9 deletions unwind/src/find_cfi/baremetal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@ pub fn find_cfi_sections() -> Vec<EhRef> {
unsafe {
// Safety: None of those are actual accesses - we only get the address
// of those values.
let text_start = &__text_start as *const _ as u64;
let text_end = &__text_end as *const _ as u64;
let cfi_start = &__ehframehdr_start as *const _ as u64;
let cfi_end = &__ehframehdr_end as *const _ as u64;
let ehframe_end = &__ehframe_end as *const _ as u64;
let text = AddrRange {
start: &__text_start as *const _ as u64,
end: &__text_end as *const _ as u64,
};
let eh_frame_hdr = AddrRange {
start: &__ehframehdr_start as *const _ as u64,
end: &__ehframehdr_end as *const _ as u64,
};
let eh_frame_end = &__ehframe_end as *const _ as u64;

cfi.push(EhRef {
obj_base: 0,
text: AddrRange { start: text_start, end: text_end },
cfi: AddrRange { start: cfi_start, end: cfi_end },
ehframe_end,
text,
eh_frame_hdr,
eh_frame_end,
});
}
trace!("CFI sections: {:?}", cfi);
Expand Down
11 changes: 5 additions & 6 deletions unwind/src/find_cfi/ld.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,17 @@ extern "C" fn callback(info: *const DlPhdrInfo, size: usize, data: *mut c_void)
let phdr = slice::from_raw_parts((*info).phdr, (*info).phnum as usize);

if let Some(text) = phdr.iter().filter(|x| x.type_ == PT_LOAD && x.flags & PF_X != 0).next() {
if let Some(eh_frame) = phdr.iter().filter(|x| x.type_ == PT_GNU_EH_FRAME).next() {
if let Some(eh_frame_hdr) = phdr.iter().filter(|x| x.type_ == PT_GNU_EH_FRAME).next() {
let start_addr = (*info).addr + text.vaddr;
let cfi_start = (*info).addr + eh_frame.vaddr;
let eh_frame_hdr_start = (*info).addr + eh_frame_hdr.vaddr;
let max_vaddr = phdr.iter().filter(|x| x.type_ == PT_LOAD)
.fold(0, |vaddr, x| cmp::max(vaddr, x.vaddr + x.memsz));
// This is an upper bound, not the exact address.
let ehframe_end = (*info).addr + max_vaddr;
let eh_frame_end = (*info).addr + max_vaddr;
(*data).push(EhRef {
obj_base: (*info).addr,
text: AddrRange { start: start_addr, end: start_addr + text.memsz },
cfi: AddrRange { start: cfi_start, end: cfi_start + eh_frame.memsz },
ehframe_end,
eh_frame_hdr: AddrRange { start: eh_frame_hdr_start, end: eh_frame_hdr_start + eh_frame_hdr.memsz },
eh_frame_end,
});
}
}
Expand Down
5 changes: 2 additions & 3 deletions unwind/src/find_cfi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ use range::AddrRange;

#[derive(Debug)]
pub struct EhRef {
pub obj_base: u64,
pub text: AddrRange,
pub cfi: AddrRange,
pub ehframe_end: u64,
pub eh_frame_hdr: AddrRange,
pub eh_frame_end: u64,
}

#[cfg(unix)]
Expand Down
61 changes: 31 additions & 30 deletions unwind/src/glue.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use gimli::X86_64;
use super::{UnwindPayload, StackFrames};
use registers::{Registers, DwarfRegister};
use registers::Registers;

#[allow(improper_ctypes)] // trampoline just forwards the ptr
extern "C" {
#[cfg(not(feature = "nightly"))]
#[cfg(not(feature = "asm"))]
pub fn unwind_trampoline(payload: *mut UnwindPayload);
#[cfg(not(feature = "nightly"))]
#[cfg(not(feature = "asm"))]
fn unwind_lander(regs: *const LandingRegisters);
}

#[cfg(feature = "nightly")]
#[cfg(feature = "asm")]
#[naked]
pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) {
asm!("
Expand All @@ -33,7 +34,7 @@ pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) {
::std::hint::unreachable_unchecked();
}

#[cfg(feature = "nightly")]
#[cfg(feature = "asm")]
#[naked]
unsafe extern fn unwind_lander(_regs: *const LandingRegisters) {
asm!("
Expand Down Expand Up @@ -96,14 +97,14 @@ pub unsafe extern "C" fn unwind_recorder(payload: *mut UnwindPayload, stack: u64
let saved_regs = &*saved_regs;

let mut registers = Registers::default();
registers[DwarfRegister::Rbx] = Some(saved_regs.rbx);
registers[DwarfRegister::Rbp] = Some(saved_regs.rbp);
registers[DwarfRegister::SP] = Some(stack + 8);
registers[DwarfRegister::R12] = Some(saved_regs.r12);
registers[DwarfRegister::R13] = Some(saved_regs.r13);
registers[DwarfRegister::R14] = Some(saved_regs.r14);
registers[DwarfRegister::R15] = Some(saved_regs.r15);
registers[DwarfRegister::IP] = Some(*(stack as *const u64));
registers[X86_64::RBX] = Some(saved_regs.rbx);
registers[X86_64::RBP] = Some(saved_regs.rbp);
registers[X86_64::RSP] = Some(stack + 8);
registers[X86_64::R12] = Some(saved_regs.r12);
registers[X86_64::R13] = Some(saved_regs.r13);
registers[X86_64::R14] = Some(saved_regs.r14);
registers[X86_64::R15] = Some(saved_regs.r15);
registers[X86_64::RA] = Some(*(stack as *const u64));

let mut frames = StackFrames {
unwinder: payload.unwinder,
Expand All @@ -116,24 +117,24 @@ pub unsafe extern "C" fn unwind_recorder(payload: *mut UnwindPayload, stack: u64

pub unsafe fn land(regs: &Registers) {
let mut lr = LandingRegisters {
rax: regs[DwarfRegister::Rax].unwrap_or(0),
rbx: regs[DwarfRegister::Rbx].unwrap_or(0),
rcx: regs[DwarfRegister::Rcx].unwrap_or(0),
rdx: regs[DwarfRegister::Rdx].unwrap_or(0),
rdi: regs[DwarfRegister::Rdi].unwrap_or(0),
rsi: regs[DwarfRegister::Rsi].unwrap_or(0),
rbp: regs[DwarfRegister::Rbp].unwrap_or(0),
r8: regs[DwarfRegister::R8 ].unwrap_or(0),
r9: regs[DwarfRegister::R9 ].unwrap_or(0),
r10: regs[DwarfRegister::R10].unwrap_or(0),
r11: regs[DwarfRegister::R11].unwrap_or(0),
r12: regs[DwarfRegister::R12].unwrap_or(0),
r13: regs[DwarfRegister::R13].unwrap_or(0),
r14: regs[DwarfRegister::R14].unwrap_or(0),
r15: regs[DwarfRegister::R15].unwrap_or(0),
rsp: regs[DwarfRegister::SP].unwrap(),
rax: regs[X86_64::RAX].unwrap_or(0),
rbx: regs[X86_64::RBX].unwrap_or(0),
rcx: regs[X86_64::RCX].unwrap_or(0),
rdx: regs[X86_64::RDX].unwrap_or(0),
rdi: regs[X86_64::RDI].unwrap_or(0),
rsi: regs[X86_64::RSI].unwrap_or(0),
rbp: regs[X86_64::RBP].unwrap_or(0),
r8: regs[X86_64::R8 ].unwrap_or(0),
r9: regs[X86_64::R9 ].unwrap_or(0),
r10: regs[X86_64::R10].unwrap_or(0),
r11: regs[X86_64::R11].unwrap_or(0),
r12: regs[X86_64::R12].unwrap_or(0),
r13: regs[X86_64::R13].unwrap_or(0),
r14: regs[X86_64::R14].unwrap_or(0),
r15: regs[X86_64::R15].unwrap_or(0),
rsp: regs[X86_64::RSP].unwrap(),
};
lr.rsp -= 8;
*(lr.rsp as *mut u64) = regs[DwarfRegister::IP].unwrap();
*(lr.rsp as *mut u64) = regs[X86_64::RA].unwrap();
unwind_lander(&lr);
}
34 changes: 18 additions & 16 deletions unwind/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
#![cfg_attr(feature = "nightly", feature(asm, naked_functions))]
#![cfg_attr(feature = "nightly", feature(unwind_attributes))]
#![cfg_attr(feature = "asm", feature(asm, naked_functions))]

extern crate gimli;
extern crate libc;
extern crate fallible_iterator;
#[macro_use] extern crate log;

use gimli::{UnwindSection, UnwindTable, UnwindTableRow, EhFrame, BaseAddresses, UninitializedUnwindContext, Pointer, Reader, EndianSlice, NativeEndian, CfaRule, RegisterRule, EhFrameHdr, ParsedEhFrameHdr};
use gimli::{UnwindSection, UnwindTable, UnwindTableRow, EhFrame, BaseAddresses, UninitializedUnwindContext, Pointer, Reader, EndianSlice, NativeEndian, CfaRule, RegisterRule, EhFrameHdr, ParsedEhFrameHdr, X86_64};
use fallible_iterator::FallibleIterator;

mod registers;
mod find_cfi;
mod range;
pub mod libunwind_shim;
pub mod glue;
use registers::{Registers, DwarfRegister};
use registers::Registers;
use find_cfi::EhRef;


Expand All @@ -28,7 +29,6 @@ pub struct StackFrame {
personality: Option<u64>,
lsda: Option<u64>,
initial_address: u64,
pub object_base: u64, // FIXME hack, remove this
}

pub trait Unwinder: Default {
Expand All @@ -53,20 +53,23 @@ impl Default for DwarfUnwinder {
fn default() -> DwarfUnwinder {
let cfi = find_cfi::find_cfi_sections().into_iter().map(|er| {
unsafe {
let bases = BaseAddresses::default().set_cfi(er.cfi.start);
// TODO: set_got()
let bases = BaseAddresses::default()
.set_eh_frame_hdr(er.eh_frame_hdr.start)
.set_text(er.text.start);

let eh_frame_hdr: &'static [u8] = std::slice::from_raw_parts(er.cfi.start as *const u8, er.cfi.len() as usize);
let eh_frame_hdr: &'static [u8] = std::slice::from_raw_parts(er.eh_frame_hdr.start as *const u8, er.eh_frame_hdr.len() as usize);

let eh_frame_hdr = EhFrameHdr::new(eh_frame_hdr, NativeEndian).parse(&bases, 8).unwrap();

let cfi_addr = deref_ptr(eh_frame_hdr.eh_frame_ptr());
let cfi_sz = er.ehframe_end.saturating_sub(cfi_addr);
let eh_frame_addr = deref_ptr(eh_frame_hdr.eh_frame_ptr());
let eh_frame_sz = er.eh_frame_end.saturating_sub(eh_frame_addr);

let eh_frame: &'static [u8] = std::slice::from_raw_parts(cfi_addr as *const u8, cfi_sz as usize);
trace!("cfi at {:p} sz {:x}", cfi_addr as *const u8, cfi_sz);
let eh_frame: &'static [u8] = std::slice::from_raw_parts(eh_frame_addr as *const u8, eh_frame_sz as usize);
trace!("eh_frame at {:p} sz {:x}", eh_frame_addr as *const u8, eh_frame_sz);
let eh_frame = EhFrame::new(eh_frame, NativeEndian);

let bases = bases.set_cfi(cfi_addr).set_data(er.cfi.start);
let bases = bases.set_eh_frame(eh_frame_addr);

ObjectRecord { er, eh_frame_hdr, eh_frame, bases }
}
Expand Down Expand Up @@ -167,10 +170,10 @@ impl<'a> FallibleIterator for StackFrames<'a> {

if let Some((row, cfa)) = self.state.take() {
let mut newregs = registers.clone();
newregs[DwarfRegister::IP] = None;
newregs[X86_64::RA] = None;
for &(reg, ref rule) in row.registers() {
trace!("rule {} {:?}", reg, rule);
assert!(reg != 7); // stack = cfa
trace!("rule {:?} {:?}", reg, rule);
assert!(reg != X86_64::RSP); // stack = cfa
newregs[reg] = match *rule {
RegisterRule::Undefined => unreachable!(), // registers[reg],
RegisterRule::SameValue => Some(registers[reg].unwrap()), // not sure why this exists
Expand All @@ -189,7 +192,7 @@ impl<'a> FallibleIterator for StackFrames<'a> {
}


if let Some(mut caller) = registers[DwarfRegister::IP] {
if let Some(mut caller) = registers[X86_64::RA] {
caller -= 1; // THIS IS NECESSARY
debug!("caller is 0x{:x}", caller);

Expand All @@ -210,7 +213,6 @@ impl<'a> FallibleIterator for StackFrames<'a> {
self.state = Some((row, cfa));

Ok(Some(StackFrame {
object_base: rec.er.obj_base,
personality: personality.map(|x| unsafe { deref_ptr(x) }),
lsda: lsda.map(|x| unsafe { deref_ptr(x) }),
initial_address,
Expand Down
24 changes: 17 additions & 7 deletions unwind/src/libunwind_shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

use libc::{c_void, c_int};
use fallible_iterator::FallibleIterator;
use gimli::X86_64;

use registers::{Registers, DwarfRegister};
use registers::Registers;
use super::{DwarfUnwinder, Unwinder};

#[repr(C)]
Expand Down Expand Up @@ -53,6 +54,8 @@ pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c
-> _Unwind_Reason_Code;
type PersonalityRoutine = extern "C" fn(version: c_int, actions: c_int, class: u64, object: *mut _Unwind_Exception, context: *mut _Unwind_Context) -> _Unwind_Reason_Code;

// FIXME: we skip over this function when unwinding, so we should ensure
// it never needs any cleanup. Currently this is not true.
#[no_mangle]
pub unsafe extern "C" fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> ! {
DwarfUnwinder::default().trace(|frames| unwind_tracer(frames, exception));
Expand Down Expand Up @@ -87,12 +90,12 @@ pub unsafe extern "C" fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Conte

#[no_mangle]
pub unsafe extern "C" fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
(*(*ctx).registers)[reg_index as u8] = Some(value as u64);
(*(*ctx).registers)[reg_index as u16] = Some(value as u64);
}

#[no_mangle]
pub unsafe extern "C" fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word) {
(*(*ctx).registers)[DwarfRegister::IP] = Some(value as u64);
(*(*ctx).registers)[X86_64::RA] = Some(value as u64);
}

#[no_mangle]
Expand All @@ -107,6 +110,13 @@ pub unsafe extern "C" fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut
pc // FIXME: implement this
}

// FIXME: Set `unwind(allowed)` because we need to be able to unwind this function as
// part of its operation. But this means any panics in this function are undefined
// behaviour, and we don't currently ensure it doesn't panic.
//
// On stable (1.32), `unwind(allowed)` is the default, but this will change in 1.33, with
// no stable way of setting `unwind(allowed)`, so this function will always abort in 1.33.
#[cfg_attr(feature = "nightly", unwind(allowed))]
#[no_mangle]
pub unsafe extern "C" fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
(*exception).private_contptr = None;
Expand All @@ -118,7 +128,7 @@ unsafe fn unwind_tracer(frames: &mut ::StackFrames, exception: *mut _Unwind_Exce
if let Some(contptr) = (*exception).private_contptr {
loop {
if let Some(frame) = frames.next().unwrap() {
if frames.registers()[DwarfRegister::SP].unwrap() == contptr {
if frames.registers()[X86_64::RSP].unwrap() == contptr {
break;
}
} else {
Expand All @@ -134,12 +144,12 @@ unsafe fn unwind_tracer(frames: &mut ::StackFrames, exception: *mut _Unwind_Exce

let mut ctx = _Unwind_Context {
lsda: frame.lsda.unwrap(),
ip: frames.registers()[DwarfRegister::IP].unwrap(),
ip: frames.registers()[X86_64::RA].unwrap(),
initial_address: frame.initial_address,
registers: frames.registers(),
};

(*exception).private_contptr = frames.registers()[DwarfRegister::SP];
(*exception).private_contptr = frames.registers()[X86_64::RSP];

// ABI specifies that phase 1 is optional, so we just run phase 2 (CLEANUP_PHASE)
match personality(1, _Unwind_Action::_UA_CLEANUP_PHASE as c_int, (*exception).exception_class,
Expand All @@ -160,7 +170,7 @@ pub unsafe extern "C" fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
while let Some(frame) = frames.next().unwrap() {
let mut ctx = _Unwind_Context {
lsda: frame.lsda.unwrap_or(0),
ip: frames.registers()[DwarfRegister::IP].unwrap(),
ip: frames.registers()[X86_64::RA].unwrap(),
initial_address: frame.initial_address,
registers: frames.registers(),
};
Expand Down
Loading

0 comments on commit 3b90740

Please sign in to comment.