From 420e080a87403d1a6acb1bef2b73ffbd8f184c59 Mon Sep 17 00:00:00 2001 From: roblabla Date: Sat, 28 Jul 2018 01:15:30 +0200 Subject: [PATCH 01/10] Match libunwind baremetal symbol name --- unwind/src/find_cfi/baremetal.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/unwind/src/find_cfi/baremetal.rs b/unwind/src/find_cfi/baremetal.rs index abf10f7..b00f17e 100644 --- a/unwind/src/find_cfi/baremetal.rs +++ b/unwind/src/find_cfi/baremetal.rs @@ -4,8 +4,8 @@ use super::EhRef; extern "C" { static __text_start: usize; static __text_end: usize; - static __ehframehdr_start: usize; - static __ehframehdr_end: usize; + static __eh_frame_hdr_start: usize; + static __eh_frame_hdr_end: usize; } pub fn find_cfi_sections() -> Vec { @@ -15,8 +15,8 @@ pub fn find_cfi_sections() -> Vec { // 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 cfi_start = &__eh_frame_hdr_start as *const _ as u64; + let cfi_end = &__eh_frame_hdr_end as *const _ as u64; cfi.push(EhRef { obj_base: 0, From 1d57ac41397d92f58d4828501f887510976ab607 Mon Sep 17 00:00:00 2001 From: roblabla Date: Sat, 28 Jul 2018 01:17:44 +0200 Subject: [PATCH 02/10] Remove hardcoded register number in common unwind code --- unwind/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unwind/src/lib.rs b/unwind/src/lib.rs index 89c729d..852c72c 100644 --- a/unwind/src/lib.rs +++ b/unwind/src/lib.rs @@ -170,7 +170,7 @@ impl<'a> FallibleIterator for StackFrames<'a> { newregs[DwarfRegister::IP] = None; for &(reg, ref rule) in row.registers() { trace!("rule {} {:?}", reg, rule); - assert!(reg != 7); // stack = cfa + assert!(reg != DwarfRegister::SP as u8); // stack = cfa newregs[reg] = match *rule { RegisterRule::Undefined => unreachable!(), // registers[reg], RegisterRule::SameValue => Some(registers[reg].unwrap()), // not sure why this exists @@ -182,7 +182,7 @@ impl<'a> FallibleIterator for StackFrames<'a> { RegisterRule::Architectural => unreachable!(), }; } - newregs[7] = Some(cfa); + newregs[DwarfRegister::SP] = Some(cfa); *registers = newregs; trace!("registers:{:?}", registers); From dd462c43445ef5f72c118a91c9de48de7a5028db Mon Sep 17 00:00:00 2001 From: roblabla Date: Sat, 28 Jul 2018 01:18:49 +0200 Subject: [PATCH 03/10] Add WIP aarch64 unwinder --- unwind/build.rs | 13 +-- unwind/src/glue/aarch64.rs | 136 +++++++++++++++++++++++++ unwind/src/glue/mod.rs | 14 +++ unwind/src/{glue.rs => glue/x86_64.rs} | 55 ++-------- unwind/src/glue/x86_64_helper.S | 9 ++ unwind/src/glue/x86_64_lander.S | 18 ++++ unwind/src/glue/x86_64_trampoline.S | 16 +++ unwind/src/registers.rs | 73 +++++++++++-- 8 files changed, 277 insertions(+), 57 deletions(-) create mode 100644 unwind/src/glue/aarch64.rs create mode 100644 unwind/src/glue/mod.rs rename unwind/src/{glue.rs => glue/x86_64.rs} (77%) create mode 100644 unwind/src/glue/x86_64_helper.S create mode 100644 unwind/src/glue/x86_64_lander.S create mode 100644 unwind/src/glue/x86_64_trampoline.S diff --git a/unwind/build.rs b/unwind/build.rs index 2ebae21..63bb0f4 100644 --- a/unwind/build.rs +++ b/unwind/build.rs @@ -3,11 +3,12 @@ use std::env; fn main() { match env::var("CARGO_FEATURE_NIGHTLY") { - Err(env::VarError::NotPresent) => { - gcc::Build::new() - .file("src/unwind_helper.c") - .compile("unwind_helper"); - }, - _ => () + Err(env::VarError::NotPresent) => (), + _ => return } + + gcc::Build::new() + .file(format!("src/glue/{}_helper.S", env::var("CARGO_CFG_TARGET_ARCH").expect("Didn't run with cargo"))) + .include("src/glue") + .compile("unwind_helper"); } diff --git a/unwind/src/glue/aarch64.rs b/unwind/src/glue/aarch64.rs new file mode 100644 index 0000000..90e8457 --- /dev/null +++ b/unwind/src/glue/aarch64.rs @@ -0,0 +1,136 @@ +use {UnwindPayload, StackFrames}; +use registers::{Registers, DwarfRegisterAArch64}; + +#[allow(improper_ctypes)] // trampoline just forwards the ptr +extern "C" { + #[cfg(not(feature = "nightly"))] + pub fn unwind_trampoline(payload: *mut UnwindPayload); + #[cfg(not(feature = "nightly"))] + fn unwind_lander(regs: *const LandingRegisters); +} + +#[cfg(feature = "nightly")] +#[naked] +pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) { + asm!(" + mov x1, sp + sub sp, sp, 0x70 + .cfi_adjust_cfa_offset 0x70 + str lr, [sp, #0x60] + .cfi_rel_offset lr, 0x60 + stp x19, x20, [sp, #0x00] + stp x21, x22, [sp, #0x10] + stp x23, x24, [sp, #0x20] + stp x25, x26, [sp, #0x30] + stp x27, x28, [sp, #0x40] + stp x29, lr, [sp, #0x50] + mov x2, sp + bl unwind_recorder + ldr lr, [sp, #0x60] + .cfi_restore lr + add sp, sp, 0x70 + .cfi_adjust_cfa_offset -0x70 + ret + "); + ::std::hint::unreachable_unchecked(); +} + +#[cfg(feature = "nightly")] +#[naked] +unsafe extern fn unwind_lander(_regs: *const LandingRegisters) { + asm!(" + ldp x2, x3, [x0, #0x010] + ldp x4, x5, [x0, #0x020] + ldp x6, x7, [x0, #0x030] + ldp x8, x9, [x0, #0x040] + ldp x10, x11, [x0, #0x050] + ldp x12, x13, [x0, #0x060] + ldp x14, x15, [x0, #0x070] + ldp x16, x17, [x0, #0x080] + ldp x18, x19, [x0, #0x090] + ldp x20, x21, [x0, #0x0A0] + ldp x22, x23, [x0, #0x0B0] + ldp x24, x25, [x0, #0x0C0] + ldp x26, x27, [x0, #0x0D0] + ldp x28, x29, [x0, #0x0E0] + ldp x30, x1, [x0, #0x0F0] + mov x1, sp + + ldp d0, d1, [x0, #0x110] + ldp d2, d3, [x0, #0x120] + ldp d4, d5, [x0, #0x130] + ldp d6, d7, [x0, #0x140] + ldp d8, d9, [x0, #0x150] + ldp d10, d11, [x0, #0x160] + ldp d12, d13, [x0, #0x170] + ldp d14, d15, [x0, #0x180] + ldp d16, d17, [x0, #0x190] + ldp d18, d19, [x0, #0x1A0] + ldp d20, d21, [x0, #0x1B0] + ldp d22, d23, [x0, #0x1C0] + ldp d24, d25, [x0, #0x1D0] + ldp d26, d27, [x0, #0x1E0] + ldp d28, d29, [x0, #0x1F0] + ldr d30, [x0, #0x200] + ldr d31, [x0, #0x208] + + ldp x0, x1, [x0, #0x000] + ret x30 // HYPERSPACE JUMP :D + "); + ::std::hint::unreachable_unchecked(); +} + +#[repr(C)] +struct LandingRegisters { + r: [u64; 29], // x0-x28 + fp: u64, // x29, Frame Pointer + lr: u64, // x30, Link Register + sp: u64, // x31, Stack Pointer + + pad: u64, + vector_half: [u64; 32], // d0-d31 +} + +// TODO: Doc hidden +#[repr(C)] +pub struct SavedRegs { + r: [u64; 11], // x19-x29 + lr: u64 +} + +// TODO: doc hidden +#[no_mangle] +pub unsafe extern "C" fn unwind_recorder(payload: *mut UnwindPayload, stack: u64, saved_regs: *mut SavedRegs) { + let payload = &mut *payload; + let saved_regs = &*saved_regs; + + let mut registers = Registers::default(); + for (regnum, v) in saved_regs.r.iter().enumerate() { + registers[DwarfRegisterAArch64::X19 as u8 + regnum as u8] = Some(*v); + } + registers[DwarfRegisterAArch64::SP] = Some(stack); + registers[DwarfRegisterAArch64::IP] = Some(saved_regs.lr); + + let mut frames = StackFrames { + unwinder: payload.unwinder, + registers, + state: None, + }; + + (payload.tracer)(&mut frames); +} + +pub unsafe fn land(regs: &Registers) { + let mut lr = LandingRegisters { + r: [0; 29], + fp: regs[DwarfRegisterAArch64::X29].unwrap_or(0), + lr: regs[DwarfRegisterAArch64::IP].unwrap_or(0), + sp: regs[DwarfRegisterAArch64::SP].unwrap_or(0), + pad: 0, + vector_half: [0; 32] + }; + for (i, v) in lr.r.iter_mut().enumerate() { + *v = regs[i as u8].unwrap_or(0); + } + unwind_lander(&lr); +} diff --git a/unwind/src/glue/mod.rs b/unwind/src/glue/mod.rs new file mode 100644 index 0000000..a57adc6 --- /dev/null +++ b/unwind/src/glue/mod.rs @@ -0,0 +1,14 @@ +#[cfg(target_arch = "x86_64")] +#[path = "x86_64.rs"] +mod imp; + +#[cfg(target_arch = "aarch64")] +#[path = "aarch64.rs"] +mod imp; + +#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))] +compiler_error!("Unsupported architecture"); + +pub use self::imp::{unwind_trampoline, land}; +// TODO: doc hidden +pub use self::imp::unwind_recorder; diff --git a/unwind/src/glue.rs b/unwind/src/glue/x86_64.rs similarity index 77% rename from unwind/src/glue.rs rename to unwind/src/glue/x86_64.rs index 03de7d5..55d1753 100644 --- a/unwind/src/glue.rs +++ b/unwind/src/glue/x86_64.rs @@ -1,4 +1,4 @@ -use super::{UnwindPayload, StackFrames}; +use {UnwindPayload, StackFrames}; use registers::{Registers, DwarfRegister}; #[allow(improper_ctypes)] // trampoline just forwards the ptr @@ -12,50 +12,14 @@ extern "C" { #[cfg(feature = "nightly")] #[naked] pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) { - asm!(" - movq %rsp, %rsi - .cfi_def_cfa rsi, 8 - pushq %rbp - .cfi_offset rbp, -16 - pushq %rbx - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - movq %rsp, %rdx - subq 0x08, %rsp - .cfi_def_cfa rsp, 0x40 - call unwind_recorder - addq 0x38, %rsp - .cfi_def_cfa rsp, 8 - ret - "); + asm!(include_str!("x86_64_trampoline.S")); ::std::hint::unreachable_unchecked(); } #[cfg(feature = "nightly")] #[naked] unsafe extern fn unwind_lander(_regs: *const LandingRegisters) { - asm!(" - movq %rdi, %rsp - popq %rax - popq %rbx - popq %rcx - popq %rdx - popq %rdi - popq %rsi - popq %rbp - popq %r8 - popq %r9 - popq %r10 - popq %r11 - popq %r12 - popq %r13 - popq %r14 - popq %r15 - movq 0(%rsp), %rsp - ret // HYPERSPACE JUMP :D - "); + asm!(include_str!("x86_64_lander.S")); ::std::hint::unreachable_unchecked(); } @@ -82,14 +46,15 @@ struct LandingRegisters { #[repr(C)] pub struct SavedRegs { - pub r15: u64, - pub r14: u64, - pub r13: u64, - pub r12: u64, - pub rbx: u64, - pub rbp: u64, + r15: u64, + r14: u64, + r13: u64, + r12: u64, + rbx: u64, + rbp: u64, } +// TODO: doc hidden #[no_mangle] pub unsafe extern "C" fn unwind_recorder(payload: *mut UnwindPayload, stack: u64, saved_regs: *mut SavedRegs) { let payload = &mut *payload; diff --git a/unwind/src/glue/x86_64_helper.S b/unwind/src/glue/x86_64_helper.S new file mode 100644 index 0000000..2ec1024 --- /dev/null +++ b/unwind/src/glue/x86_64_helper.S @@ -0,0 +1,9 @@ +.global unwind_trampoline +unwind_trampoline: +.cfi_startproc +.include "x86_64_trampoline.S" +.cfi_endproc + +.global unwind_lander +unwind_lander: +.include "x86_64_lander.S" diff --git a/unwind/src/glue/x86_64_lander.S b/unwind/src/glue/x86_64_lander.S new file mode 100644 index 0000000..a5a3b3a --- /dev/null +++ b/unwind/src/glue/x86_64_lander.S @@ -0,0 +1,18 @@ +movq %rdi, %rsp +popq %rax +popq %rbx +popq %rcx +popq %rdx +popq %rdi +popq %rsi +popq %rbp +popq %r8 +popq %r9 +popq %r10 +popq %r11 +popq %r12 +popq %r13 +popq %r14 +popq %r15 +movq 0(%rsp), %rsp +ret /* HYPERSPACE JUMP :D */ diff --git a/unwind/src/glue/x86_64_trampoline.S b/unwind/src/glue/x86_64_trampoline.S new file mode 100644 index 0000000..313ca6b --- /dev/null +++ b/unwind/src/glue/x86_64_trampoline.S @@ -0,0 +1,16 @@ +movq %rsp, %rsi +.cfi_def_cfa rsi, 8 +pushq %rbp +.cfi_offset rbp, -16 +pushq %rbx +pushq %r12 +pushq %r13 +pushq %r14 +pushq %r15 +movq %rsp, %rdx +subq $0x08, %rsp +.cfi_def_cfa rsp, 0x40 +call unwind_recorder +addq $0x38, %rsp +.cfi_def_cfa rsp, 8 +ret diff --git a/unwind/src/registers.rs b/unwind/src/registers.rs index f5fdc95..4c0a5ba 100644 --- a/unwind/src/registers.rs +++ b/unwind/src/registers.rs @@ -3,7 +3,7 @@ use std::ops::{Index, IndexMut}; #[derive(Default, Clone, PartialEq, Eq)] pub struct Registers { - registers: [Option; 17], + registers: [Option; 32], } impl Debug for Registers { @@ -32,21 +32,35 @@ impl IndexMut for Registers { } } -impl Index for Registers { +impl Index for Registers { type Output = Option; - fn index(&self, reg: DwarfRegister) -> &Option { + fn index(&self, reg: DwarfRegisterAMD64) -> &Option { &self[reg as u8] } } -impl IndexMut for Registers { - fn index_mut(&mut self, reg: DwarfRegister) -> &mut Option { +impl IndexMut for Registers { + fn index_mut(&mut self, reg: DwarfRegisterAMD64) -> &mut Option { &mut self[reg as u8] } } -pub enum DwarfRegister { +impl Index for Registers { + type Output = Option; + + fn index(&self, reg: DwarfRegisterAArch64) -> &Option { + &self[reg as u8] + } +} + +impl IndexMut for Registers { + fn index_mut(&mut self, reg: DwarfRegisterAArch64) -> &mut Option { + &mut self[reg as u8] + } +} + +pub enum DwarfRegisterAMD64 { SP = 7, IP = 16, @@ -66,3 +80,50 @@ pub enum DwarfRegister { R14 = 14, R15 = 15, } + +pub enum DwarfRegisterAArch64 { + X0 = 0, + X1 = 1, + X2 = 2, + X3 = 3, + X4 = 4, + X5 = 5, + X6 = 6, + X7 = 7, + X8 = 8, + X9 = 9, + X10 = 10, + X11 = 11, + X12 = 12, + X13 = 13, + X14 = 14, + X15 = 15, + X16 = 16, + X17 = 17, + X18 = 18, + X19 = 19, + X20 = 20, + X21 = 21, + X22 = 22, + X23 = 23, + X24 = 24, + X25 = 25, + X26 = 26, + X27 = 27, + X28 = 28, + X29 = 29, // Frame Pointer + IP = 30, // Link register, x30, IP is restored in it? + SP = 31, + + // ELR_mode + // Vector regs +} + +#[cfg(target_arch = "x86_64")] +pub use self::DwarfRegisterAMD64 as DwarfRegister; + +#[cfg(target_arch = "aarch64")] +pub use self::DwarfRegisterAArch64 as DwarfRegister; + +#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] +compiler_error!("Unsupported architecture"); From 353b12fa0d2f44bdf32f6cc177648b26ad3846dc Mon Sep 17 00:00:00 2001 From: roblabla Date: Sat, 28 Jul 2018 01:38:11 +0200 Subject: [PATCH 04/10] fixup! Add WIP aarch64 unwinder --- unwind/src/unwind_helper.c | 46 -------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 unwind/src/unwind_helper.c diff --git a/unwind/src/unwind_helper.c b/unwind/src/unwind_helper.c deleted file mode 100644 index 25c1ba4..0000000 --- a/unwind/src/unwind_helper.c +++ /dev/null @@ -1,46 +0,0 @@ - -asm ( - ".global unwind_trampoline \n" - "unwind_trampoline: \n" - ".cfi_startproc \n" - "movq %rsp, %rsi \n" - ".cfi_def_cfa rsi, 8 \n" - "pushq %rbp \n" - ".cfi_offset rbp, -16 \n" - "pushq %rbx \n" - "pushq %r12 \n" - "pushq %r13 \n" - "pushq %r14 \n" - "pushq %r15 \n" - "movq %rsp, %rdx \n" - "subq $0x08, %rsp \n" - ".cfi_def_cfa rsp, 0x40 \n" - "call unwind_recorder \n" - "addq $0x38, %rsp \n" - ".cfi_def_cfa rsp, 8 \n" - "ret \n" - ".cfi_endproc" - ); - -asm ( - ".global unwind_lander \n" - "unwind_lander: \n" - "movq %rdi, %rsp \n" - "popq %rax \n" - "popq %rbx \n" - "popq %rcx \n" - "popq %rdx \n" - "popq %rdi \n" - "popq %rsi \n" - "popq %rbp \n" - "popq %r8 \n" - "popq %r9 \n" - "popq %r10 \n" - "popq %r11 \n" - "popq %r12 \n" - "popq %r13 \n" - "popq %r14 \n" - "popq %r15 \n" - "movq 0(%rsp), %rsp \n" - "ret \n" // HYPERSPACE JUMP :D - ); From 7a19e648977cafd2baf1ff20fb5f4f0b3dfcdb59 Mon Sep 17 00:00:00 2001 From: roblabla Date: Sun, 29 Jul 2018 20:08:28 +0200 Subject: [PATCH 05/10] I'm drunk --- unwind/src/glue/aarch64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unwind/src/glue/aarch64.rs b/unwind/src/glue/aarch64.rs index 90e8457..b75886b 100644 --- a/unwind/src/glue/aarch64.rs +++ b/unwind/src/glue/aarch64.rs @@ -54,7 +54,7 @@ unsafe extern fn unwind_lander(_regs: *const LandingRegisters) { ldp x26, x27, [x0, #0x0D0] ldp x28, x29, [x0, #0x0E0] ldp x30, x1, [x0, #0x0F0] - mov x1, sp + mov sp, x1 ldp d0, d1, [x0, #0x110] ldp d2, d3, [x0, #0x120] From 69aefa0493354bb66f1c8d91e9c19eb21c1c7aa4 Mon Sep 17 00:00:00 2001 From: roblabla Date: Sun, 29 Jul 2018 22:30:42 +0200 Subject: [PATCH 06/10] Add SIMD vector register support --- unwind/src/glue/aarch64.rs | 58 ++++++++++++++++++++++---------------- unwind/src/registers.rs | 50 +++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/unwind/src/glue/aarch64.rs b/unwind/src/glue/aarch64.rs index b75886b..4bb5c81 100644 --- a/unwind/src/glue/aarch64.rs +++ b/unwind/src/glue/aarch64.rs @@ -14,8 +14,8 @@ extern "C" { pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) { asm!(" mov x1, sp - sub sp, sp, 0x70 - .cfi_adjust_cfa_offset 0x70 + sub sp, sp, 0xB0 + .cfi_adjust_cfa_offset 0xB0 str lr, [sp, #0x60] .cfi_rel_offset lr, 0x60 stp x19, x20, [sp, #0x00] @@ -24,12 +24,16 @@ pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) { stp x25, x26, [sp, #0x30] stp x27, x28, [sp, #0x40] stp x29, lr, [sp, #0x50] + stp d8, d9, [sp, #0x70] + stp d10, d11, [sp, #0x80] + stp d12, d13, [sp, #0x90] + stp d14, d15, [sp, #0xA0] mov x2, sp bl unwind_recorder ldr lr, [sp, #0x60] .cfi_restore lr - add sp, sp, 0x70 - .cfi_adjust_cfa_offset -0x70 + add sp, sp, 0xB0 + .cfi_adjust_cfa_offset -0xB0 ret "); ::std::hint::unreachable_unchecked(); @@ -56,23 +60,22 @@ unsafe extern fn unwind_lander(_regs: *const LandingRegisters) { ldp x30, x1, [x0, #0x0F0] mov sp, x1 - ldp d0, d1, [x0, #0x110] - ldp d2, d3, [x0, #0x120] - ldp d4, d5, [x0, #0x130] - ldp d6, d7, [x0, #0x140] - ldp d8, d9, [x0, #0x150] - ldp d10, d11, [x0, #0x160] - ldp d12, d13, [x0, #0x170] - ldp d14, d15, [x0, #0x180] - ldp d16, d17, [x0, #0x190] - ldp d18, d19, [x0, #0x1A0] - ldp d20, d21, [x0, #0x1B0] - ldp d22, d23, [x0, #0x1C0] - ldp d24, d25, [x0, #0x1D0] - ldp d26, d27, [x0, #0x1E0] - ldp d28, d29, [x0, #0x1F0] - ldr d30, [x0, #0x200] - ldr d31, [x0, #0x208] + ldp d0, d1, [x0, #0x100] + ldp d2, d3, [x0, #0x110] + ldp d4, d5, [x0, #0x120] + ldp d6, d7, [x0, #0x130] + ldp d8, d9, [x0, #0x140] + ldp d10, d11, [x0, #0x150] + ldp d12, d13, [x0, #0x160] + ldp d14, d15, [x0, #0x170] + ldp d16, d17, [x0, #0x180] + ldp d18, d19, [x0, #0x190] + ldp d20, d21, [x0, #0x1A0] + ldp d22, d23, [x0, #0x1B0] + ldp d24, d25, [x0, #0x1C0] + ldp d26, d27, [x0, #0x1D0] + ldp d28, d29, [x0, #0x1E0] + ldp d30, d31, [x0, #0x1F0] ldp x0, x1, [x0, #0x000] ret x30 // HYPERSPACE JUMP :D @@ -86,8 +89,6 @@ struct LandingRegisters { fp: u64, // x29, Frame Pointer lr: u64, // x30, Link Register sp: u64, // x31, Stack Pointer - - pad: u64, vector_half: [u64; 32], // d0-d31 } @@ -95,7 +96,8 @@ struct LandingRegisters { #[repr(C)] pub struct SavedRegs { r: [u64; 11], // x19-x29 - lr: u64 + lr: u64, + vector_half: [u64; 8], // d8-d15 } // TODO: doc hidden @@ -108,6 +110,9 @@ pub unsafe extern "C" fn unwind_recorder(payload: *mut UnwindPayload, stack: u64 for (regnum, v) in saved_regs.r.iter().enumerate() { registers[DwarfRegisterAArch64::X19 as u8 + regnum as u8] = Some(*v); } + for (regnum, v) in saved_regs.vector_half.iter().enumerate() { + registers[DwarfRegisterAArch64::V8 as u8 + regnum as u8] = Some(*v); + } registers[DwarfRegisterAArch64::SP] = Some(stack); registers[DwarfRegisterAArch64::IP] = Some(saved_regs.lr); @@ -126,11 +131,14 @@ pub unsafe fn land(regs: &Registers) { fp: regs[DwarfRegisterAArch64::X29].unwrap_or(0), lr: regs[DwarfRegisterAArch64::IP].unwrap_or(0), sp: regs[DwarfRegisterAArch64::SP].unwrap_or(0), - pad: 0, vector_half: [0; 32] }; for (i, v) in lr.r.iter_mut().enumerate() { *v = regs[i as u8].unwrap_or(0); } + + for (i, v) in lr.vector_half.iter_mut().enumerate() { + *v = regs[DwarfRegisterAArch64::V0 as u8 + i as u8].unwrap_or(0); + } unwind_lander(&lr); } diff --git a/unwind/src/registers.rs b/unwind/src/registers.rs index 4c0a5ba..626ca92 100644 --- a/unwind/src/registers.rs +++ b/unwind/src/registers.rs @@ -1,14 +1,22 @@ use std::fmt::{Debug, Formatter, Result as FmtResult}; use std::ops::{Index, IndexMut}; -#[derive(Default, Clone, PartialEq, Eq)] +#[derive(Clone)] pub struct Registers { - registers: [Option; 32], + registers: [Option; 96], +} + +impl Default for Registers { + fn default() -> Registers { + Registers { + registers: [Some(0); 96] + } + } } impl Debug for Registers { fn fmt(&self, fmt: &mut Formatter) -> FmtResult { - for reg in &self.registers { + for reg in &self.registers[..] { match *reg { None => write!(fmt, " XXX")?, Some(x) => write!(fmt, " 0x{:x}", x)?, @@ -115,8 +123,42 @@ pub enum DwarfRegisterAArch64 { IP = 30, // Link register, x30, IP is restored in it? SP = 31, - // ELR_mode + + // TODO: ELR_mode + // Vector regs + V0 = 64, + V1 = 65, + V2 = 66, + V3 = 67, + V4 = 68, + V5 = 69, + V6 = 70, + V7 = 71, + V8 = 72, + V9 = 73, + V10 = 74, + V11 = 75, + V12 = 76, + V13 = 77, + V14 = 78, + V15 = 79, + V16 = 80, + V17 = 81, + V18 = 82, + V19 = 83, + V20 = 84, + V21 = 85, + V22 = 86, + V23 = 87, + V24 = 88, + V25 = 89, + V26 = 90, + V27 = 91, + V28 = 92, + V29 = 93, + V30 = 94, + V31 = 95, } #[cfg(target_arch = "x86_64")] From 56637ce833dba06280c060ac4fc8affc4846e872 Mon Sep 17 00:00:00 2001 From: roblabla Date: Mon, 30 Jul 2018 01:19:36 +0200 Subject: [PATCH 07/10] Only store lr once, fixup an off-by-one in the trampoline --- unwind/src/glue/aarch64.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/unwind/src/glue/aarch64.rs b/unwind/src/glue/aarch64.rs index 4bb5c81..f85cc54 100644 --- a/unwind/src/glue/aarch64.rs +++ b/unwind/src/glue/aarch64.rs @@ -14,26 +14,25 @@ extern "C" { pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) { asm!(" mov x1, sp - sub sp, sp, 0xB0 - .cfi_adjust_cfa_offset 0xB0 - str lr, [sp, #0x60] - .cfi_rel_offset lr, 0x60 + sub sp, sp, 0xA0 + .cfi_adjust_cfa_offset 0xA0 stp x19, x20, [sp, #0x00] stp x21, x22, [sp, #0x10] stp x23, x24, [sp, #0x20] stp x25, x26, [sp, #0x30] stp x27, x28, [sp, #0x40] stp x29, lr, [sp, #0x50] - stp d8, d9, [sp, #0x70] - stp d10, d11, [sp, #0x80] - stp d12, d13, [sp, #0x90] - stp d14, d15, [sp, #0xA0] + .cfi_rel_offset lr, 0x58 + stp d8, d9, [sp, #0x60] + stp d10, d11, [sp, #0x70] + stp d12, d13, [sp, #0x80] + stp d14, d15, [sp, #0x90] mov x2, sp bl unwind_recorder - ldr lr, [sp, #0x60] + ldr lr, [sp, #0x58] .cfi_restore lr - add sp, sp, 0xB0 - .cfi_adjust_cfa_offset -0xB0 + add sp, sp, 0xA0 + .cfi_adjust_cfa_offset -0xA0 ret "); ::std::hint::unreachable_unchecked(); From c61fcc14f1f6e40d9ace1920fad76dc083179870 Mon Sep 17 00:00:00 2001 From: roblabla Date: Mon, 30 Jul 2018 01:20:53 +0200 Subject: [PATCH 08/10] Move to global_asm, naked functions are too unstable --- unwind/src/glue/aarch64.rs | 23 ++++++++---------- unwind/src/glue/x86_64.rs | 15 +----------- unwind/src/glue/x86_64_helper.S | 36 +++++++++++++++++++++++++++-- unwind/src/glue/x86_64_lander.S | 18 --------------- unwind/src/glue/x86_64_trampoline.S | 16 ------------- unwind/src/lib.rs | 2 +- 6 files changed, 45 insertions(+), 65 deletions(-) delete mode 100644 unwind/src/glue/x86_64_lander.S delete mode 100644 unwind/src/glue/x86_64_trampoline.S diff --git a/unwind/src/glue/aarch64.rs b/unwind/src/glue/aarch64.rs index f85cc54..21a648d 100644 --- a/unwind/src/glue/aarch64.rs +++ b/unwind/src/glue/aarch64.rs @@ -3,16 +3,16 @@ use registers::{Registers, DwarfRegisterAArch64}; #[allow(improper_ctypes)] // trampoline just forwards the ptr extern "C" { - #[cfg(not(feature = "nightly"))] pub fn unwind_trampoline(payload: *mut UnwindPayload); - #[cfg(not(feature = "nightly"))] fn unwind_lander(regs: *const LandingRegisters); } #[cfg(feature = "nightly")] -#[naked] -pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) { - asm!(" +global_asm! { +r#" +.global unwind_trampoline +unwind_trampoline: +.cfi_startproc mov x1, sp sub sp, sp, 0xA0 .cfi_adjust_cfa_offset 0xA0 @@ -34,14 +34,10 @@ pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) { add sp, sp, 0xA0 .cfi_adjust_cfa_offset -0xA0 ret - "); - ::std::hint::unreachable_unchecked(); -} +.cfi_endproc -#[cfg(feature = "nightly")] -#[naked] -unsafe extern fn unwind_lander(_regs: *const LandingRegisters) { - asm!(" +.global unwind_lander +unwind_lander: ldp x2, x3, [x0, #0x010] ldp x4, x5, [x0, #0x020] ldp x6, x7, [x0, #0x030] @@ -78,8 +74,7 @@ unsafe extern fn unwind_lander(_regs: *const LandingRegisters) { ldp x0, x1, [x0, #0x000] ret x30 // HYPERSPACE JUMP :D - "); - ::std::hint::unreachable_unchecked(); +"# } #[repr(C)] diff --git a/unwind/src/glue/x86_64.rs b/unwind/src/glue/x86_64.rs index 55d1753..ac441c7 100644 --- a/unwind/src/glue/x86_64.rs +++ b/unwind/src/glue/x86_64.rs @@ -3,25 +3,12 @@ use registers::{Registers, DwarfRegister}; #[allow(improper_ctypes)] // trampoline just forwards the ptr extern "C" { - #[cfg(not(feature = "nightly"))] pub fn unwind_trampoline(payload: *mut UnwindPayload); - #[cfg(not(feature = "nightly"))] fn unwind_lander(regs: *const LandingRegisters); } #[cfg(feature = "nightly")] -#[naked] -pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) { - asm!(include_str!("x86_64_trampoline.S")); - ::std::hint::unreachable_unchecked(); -} - -#[cfg(feature = "nightly")] -#[naked] -unsafe extern fn unwind_lander(_regs: *const LandingRegisters) { - asm!(include_str!("x86_64_lander.S")); - ::std::hint::unreachable_unchecked(); -} +global_asm!(include_str!("x86_64_helper.S")); #[repr(C)] struct LandingRegisters { diff --git a/unwind/src/glue/x86_64_helper.S b/unwind/src/glue/x86_64_helper.S index 2ec1024..982332a 100644 --- a/unwind/src/glue/x86_64_helper.S +++ b/unwind/src/glue/x86_64_helper.S @@ -1,9 +1,41 @@ .global unwind_trampoline unwind_trampoline: .cfi_startproc -.include "x86_64_trampoline.S" +movq %rsp, %rsi +.cfi_def_cfa rsi, 8 +pushq %rbp +.cfi_offset rbp, -16 +pushq %rbx +pushq %r12 +pushq %r13 +pushq %r14 +pushq %r15 +movq %rsp, %rdx +subq $0x08, %rsp +.cfi_def_cfa rsp, 0x40 +call unwind_recorder +addq $0x38, %rsp +.cfi_def_cfa rsp, 8 +ret .cfi_endproc .global unwind_lander unwind_lander: -.include "x86_64_lander.S" +movq %rdi, %rsp +popq %rax +popq %rbx +popq %rcx +popq %rdx +popq %rdi +popq %rsi +popq %rbp +popq %r8 +popq %r9 +popq %r10 +popq %r11 +popq %r12 +popq %r13 +popq %r14 +popq %r15 +movq 0(%rsp), %rsp +ret /* HYPERSPACE JUMP :D */ diff --git a/unwind/src/glue/x86_64_lander.S b/unwind/src/glue/x86_64_lander.S deleted file mode 100644 index a5a3b3a..0000000 --- a/unwind/src/glue/x86_64_lander.S +++ /dev/null @@ -1,18 +0,0 @@ -movq %rdi, %rsp -popq %rax -popq %rbx -popq %rcx -popq %rdx -popq %rdi -popq %rsi -popq %rbp -popq %r8 -popq %r9 -popq %r10 -popq %r11 -popq %r12 -popq %r13 -popq %r14 -popq %r15 -movq 0(%rsp), %rsp -ret /* HYPERSPACE JUMP :D */ diff --git a/unwind/src/glue/x86_64_trampoline.S b/unwind/src/glue/x86_64_trampoline.S deleted file mode 100644 index 313ca6b..0000000 --- a/unwind/src/glue/x86_64_trampoline.S +++ /dev/null @@ -1,16 +0,0 @@ -movq %rsp, %rsi -.cfi_def_cfa rsi, 8 -pushq %rbp -.cfi_offset rbp, -16 -pushq %rbx -pushq %r12 -pushq %r13 -pushq %r14 -pushq %r15 -movq %rsp, %rdx -subq $0x08, %rsp -.cfi_def_cfa rsp, 0x40 -call unwind_recorder -addq $0x38, %rsp -.cfi_def_cfa rsp, 8 -ret diff --git a/unwind/src/lib.rs b/unwind/src/lib.rs index 852c72c..714b185 100644 --- a/unwind/src/lib.rs +++ b/unwind/src/lib.rs @@ -1,4 +1,4 @@ -#![cfg_attr(feature = "nightly", feature(asm, naked_functions))] +#![cfg_attr(feature = "nightly", feature(global_asm))] extern crate gimli; extern crate libc; From 348490dfe0ba99d333dabe50a0d4f3e288b0bba1 Mon Sep 17 00:00:00 2001 From: roblabla Date: Mon, 30 Jul 2018 01:21:11 +0200 Subject: [PATCH 09/10] Use default to init the registers --- unwind/src/registers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unwind/src/registers.rs b/unwind/src/registers.rs index 626ca92..94afb0c 100644 --- a/unwind/src/registers.rs +++ b/unwind/src/registers.rs @@ -9,7 +9,7 @@ pub struct Registers { impl Default for Registers { fn default() -> Registers { Registers { - registers: [Some(0); 96] + registers: [Default::default(); 96] } } } From eb96f33598318c7192fa3d422f8e97259cfad9db Mon Sep 17 00:00:00 2001 From: roblabla Date: Mon, 30 Jul 2018 18:26:06 +0200 Subject: [PATCH 10/10] Properly propagate errors in _Unwind_Backtrace --- unwind/src/libunwind_shim.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/unwind/src/libunwind_shim.rs b/unwind/src/libunwind_shim.rs index 2db3d16..1eff0f2 100644 --- a/unwind/src/libunwind_shim.rs +++ b/unwind/src/libunwind_shim.rs @@ -156,17 +156,27 @@ unsafe fn unwind_tracer(mut frames: &mut ::StackFrames, exception: *mut _Unwind_ pub unsafe extern "C" fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, trace_argument: *mut c_void) -> _Unwind_Reason_Code { + let mut reterr = _Unwind_Reason_Code::_URC_END_OF_STACK; DwarfUnwinder::default().trace(|mut frames| { - while let Some(frame) = frames.next().unwrap() { - let mut ctx = _Unwind_Context { - lsda: frame.lsda.unwrap_or(0), - ip: frames.registers()[DwarfRegister::IP].unwrap(), - initial_address: frame.initial_address, - registers: frames.registers(), - }; - - trace(&mut ctx, trace_argument); + loop { + match frames.next() { + Ok(Some(frame)) => { + let mut ctx = _Unwind_Context { + lsda: frame.lsda.unwrap_or(0), + ip: frames.registers()[DwarfRegister::IP].unwrap(), + initial_address: frame.initial_address, + registers: frames.registers(), + }; + + trace(&mut ctx, trace_argument); + }, + Ok(None) => break, + Err(err) => { + reterr = _Unwind_Reason_Code::_URC_FATAL_PHASE1_ERROR; + break; + } + } } }); - _Unwind_Reason_Code::_URC_END_OF_STACK + reterr }