Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update gimli to 0.17.0 #25

Merged
merged 3 commits into from
Feb 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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