Skip to content

Commit 581dc89

Browse files
committed
Add WIP aarch64 unwinder
1 parent d4c9064 commit 581dc89

File tree

8 files changed

+277
-57
lines changed

8 files changed

+277
-57
lines changed

unwind/build.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ use std::env;
33

44
fn main() {
55
match env::var("CARGO_FEATURE_NIGHTLY") {
6-
Err(env::VarError::NotPresent) => {
7-
gcc::Build::new()
8-
.file("src/unwind_helper.c")
9-
.compile("unwind_helper");
10-
},
11-
_ => ()
6+
Err(env::VarError::NotPresent) => (),
7+
_ => return
128
}
9+
10+
gcc::Build::new()
11+
.file(format!("src/glue/{}_helper.S", env::var("CARGO_CFG_TARGET_ARCH").expect("Didn't run with cargo")))
12+
.include("src/glue")
13+
.compile("unwind_helper");
1314
}

unwind/src/glue/aarch64.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
use {UnwindPayload, StackFrames};
2+
use registers::{Registers, DwarfRegisterAArch64};
3+
4+
#[allow(improper_ctypes)] // trampoline just forwards the ptr
5+
extern "C" {
6+
#[cfg(not(feature = "nightly"))]
7+
pub fn unwind_trampoline(payload: *mut UnwindPayload);
8+
#[cfg(not(feature = "nightly"))]
9+
fn unwind_lander(regs: *const LandingRegisters);
10+
}
11+
12+
#[cfg(feature = "nightly")]
13+
#[naked]
14+
pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) {
15+
asm!("
16+
mov x1, sp
17+
sub sp, sp, 0x70
18+
.cfi_adjust_cfa_offset 0x70
19+
str lr, [sp, #0x60]
20+
.cfi_rel_offset lr, 0x60
21+
stp x19, x20, [sp, #0x00]
22+
stp x21, x22, [sp, #0x10]
23+
stp x23, x24, [sp, #0x20]
24+
stp x25, x26, [sp, #0x30]
25+
stp x27, x28, [sp, #0x40]
26+
stp x29, lr, [sp, #0x50]
27+
mov x2, sp
28+
bl unwind_recorder
29+
ldr lr, [sp, #0x60]
30+
.cfi_restore lr
31+
add sp, sp, 0x70
32+
.cfi_adjust_cfa_offset -0x70
33+
ret
34+
");
35+
::std::hint::unreachable_unchecked();
36+
}
37+
38+
#[cfg(feature = "nightly")]
39+
#[naked]
40+
unsafe extern fn unwind_lander(_regs: *const LandingRegisters) {
41+
asm!("
42+
ldp x2, x3, [x0, #0x010]
43+
ldp x4, x5, [x0, #0x020]
44+
ldp x6, x7, [x0, #0x030]
45+
ldp x8, x9, [x0, #0x040]
46+
ldp x10, x11, [x0, #0x050]
47+
ldp x12, x13, [x0, #0x060]
48+
ldp x14, x15, [x0, #0x070]
49+
ldp x16, x17, [x0, #0x080]
50+
ldp x18, x19, [x0, #0x090]
51+
ldp x20, x21, [x0, #0x0A0]
52+
ldp x22, x23, [x0, #0x0B0]
53+
ldp x24, x25, [x0, #0x0C0]
54+
ldp x26, x27, [x0, #0x0D0]
55+
ldp x28, x29, [x0, #0x0E0]
56+
ldp x30, x1, [x0, #0x0F0]
57+
mov x1, sp
58+
59+
ldp d0, d1, [x0, #0x110]
60+
ldp d2, d3, [x0, #0x120]
61+
ldp d4, d5, [x0, #0x130]
62+
ldp d6, d7, [x0, #0x140]
63+
ldp d8, d9, [x0, #0x150]
64+
ldp d10, d11, [x0, #0x160]
65+
ldp d12, d13, [x0, #0x170]
66+
ldp d14, d15, [x0, #0x180]
67+
ldp d16, d17, [x0, #0x190]
68+
ldp d18, d19, [x0, #0x1A0]
69+
ldp d20, d21, [x0, #0x1B0]
70+
ldp d22, d23, [x0, #0x1C0]
71+
ldp d24, d25, [x0, #0x1D0]
72+
ldp d26, d27, [x0, #0x1E0]
73+
ldp d28, d29, [x0, #0x1F0]
74+
ldr d30, [x0, #0x200]
75+
ldr d31, [x0, #0x208]
76+
77+
ldp x0, x1, [x0, #0x000]
78+
ret x30 // HYPERSPACE JUMP :D
79+
");
80+
::std::hint::unreachable_unchecked();
81+
}
82+
83+
#[repr(C)]
84+
struct LandingRegisters {
85+
r: [u64; 29], // x0-x28
86+
fp: u64, // x29, Frame Pointer
87+
lr: u64, // x30, Link Register
88+
sp: u64, // x31, Stack Pointer
89+
90+
pad: u64,
91+
vector_half: [u64; 32], // d0-d31
92+
}
93+
94+
// TODO: Doc hidden
95+
#[repr(C)]
96+
pub struct SavedRegs {
97+
r: [u64; 11], // x19-x29
98+
lr: u64
99+
}
100+
101+
// TODO: doc hidden
102+
#[no_mangle]
103+
pub unsafe extern "C" fn unwind_recorder(payload: *mut UnwindPayload, stack: u64, saved_regs: *mut SavedRegs) {
104+
let payload = &mut *payload;
105+
let saved_regs = &*saved_regs;
106+
107+
let mut registers = Registers::default();
108+
for (regnum, v) in saved_regs.r.iter().enumerate() {
109+
registers[DwarfRegisterAArch64::X19 as u8 + regnum as u8] = Some(*v);
110+
}
111+
registers[DwarfRegisterAArch64::SP] = Some(stack);
112+
registers[DwarfRegisterAArch64::IP] = Some(saved_regs.lr);
113+
114+
let mut frames = StackFrames {
115+
unwinder: payload.unwinder,
116+
registers,
117+
state: None,
118+
};
119+
120+
(payload.tracer)(&mut frames);
121+
}
122+
123+
pub unsafe fn land(regs: &Registers) {
124+
let mut lr = LandingRegisters {
125+
r: [0; 29],
126+
fp: regs[DwarfRegisterAArch64::X29].unwrap_or(0),
127+
lr: regs[DwarfRegisterAArch64::IP].unwrap_or(0),
128+
sp: regs[DwarfRegisterAArch64::SP].unwrap_or(0),
129+
pad: 0,
130+
vector_half: [0; 32]
131+
};
132+
for (i, v) in lr.r.iter_mut().enumerate() {
133+
*v = regs[i as u8].unwrap_or(0);
134+
}
135+
unwind_lander(&lr);
136+
}

unwind/src/glue/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#[cfg(target_arch = "x86_64")]
2+
#[path = "x86_64.rs"]
3+
mod imp;
4+
5+
#[cfg(target_arch = "aarch64")]
6+
#[path = "aarch64.rs"]
7+
mod imp;
8+
9+
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
10+
compiler_error!("Unsupported architecture");
11+
12+
pub use self::imp::{unwind_trampoline, land};
13+
// TODO: doc hidden
14+
pub use self::imp::unwind_recorder;

unwind/src/glue.rs renamed to unwind/src/glue/x86_64.rs

Lines changed: 10 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{UnwindPayload, StackFrames};
1+
use {UnwindPayload, StackFrames};
22
use registers::{Registers, DwarfRegister};
33

44
#[allow(improper_ctypes)] // trampoline just forwards the ptr
@@ -12,50 +12,14 @@ extern "C" {
1212
#[cfg(feature = "nightly")]
1313
#[naked]
1414
pub unsafe extern fn unwind_trampoline(_payload: *mut UnwindPayload) {
15-
asm!("
16-
movq %rsp, %rsi
17-
.cfi_def_cfa rsi, 8
18-
pushq %rbp
19-
.cfi_offset rbp, -16
20-
pushq %rbx
21-
pushq %r12
22-
pushq %r13
23-
pushq %r14
24-
pushq %r15
25-
movq %rsp, %rdx
26-
subq 0x08, %rsp
27-
.cfi_def_cfa rsp, 0x40
28-
call unwind_recorder
29-
addq 0x38, %rsp
30-
.cfi_def_cfa rsp, 8
31-
ret
32-
");
15+
asm!(include_str!("x86_64_trampoline.S"));
3316
::std::hint::unreachable_unchecked();
3417
}
3518

3619
#[cfg(feature = "nightly")]
3720
#[naked]
3821
unsafe extern fn unwind_lander(_regs: *const LandingRegisters) {
39-
asm!("
40-
movq %rdi, %rsp
41-
popq %rax
42-
popq %rbx
43-
popq %rcx
44-
popq %rdx
45-
popq %rdi
46-
popq %rsi
47-
popq %rbp
48-
popq %r8
49-
popq %r9
50-
popq %r10
51-
popq %r11
52-
popq %r12
53-
popq %r13
54-
popq %r14
55-
popq %r15
56-
movq 0(%rsp), %rsp
57-
ret // HYPERSPACE JUMP :D
58-
");
22+
asm!(include_str!("x86_64_lander.S"));
5923
::std::hint::unreachable_unchecked();
6024
}
6125

@@ -82,14 +46,15 @@ struct LandingRegisters {
8246

8347
#[repr(C)]
8448
pub struct SavedRegs {
85-
pub r15: u64,
86-
pub r14: u64,
87-
pub r13: u64,
88-
pub r12: u64,
89-
pub rbx: u64,
90-
pub rbp: u64,
49+
r15: u64,
50+
r14: u64,
51+
r13: u64,
52+
r12: u64,
53+
rbx: u64,
54+
rbp: u64,
9155
}
9256

57+
// TODO: doc hidden
9358
#[no_mangle]
9459
pub unsafe extern "C" fn unwind_recorder(payload: *mut UnwindPayload, stack: u64, saved_regs: *mut SavedRegs) {
9560
let payload = &mut *payload;

unwind/src/glue/x86_64_helper.S

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.global unwind_trampoline
2+
unwind_trampoline:
3+
.cfi_startproc
4+
.include "x86_64_trampoline.S"
5+
.cfi_endproc
6+
7+
.global unwind_lander
8+
unwind_lander:
9+
.include "x86_64_lander.S"

unwind/src/glue/x86_64_lander.S

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
movq %rdi, %rsp
2+
popq %rax
3+
popq %rbx
4+
popq %rcx
5+
popq %rdx
6+
popq %rdi
7+
popq %rsi
8+
popq %rbp
9+
popq %r8
10+
popq %r9
11+
popq %r10
12+
popq %r11
13+
popq %r12
14+
popq %r13
15+
popq %r14
16+
popq %r15
17+
movq 0(%rsp), %rsp
18+
ret /* HYPERSPACE JUMP :D */
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
movq %rsp, %rsi
2+
.cfi_def_cfa rsi, 8
3+
pushq %rbp
4+
.cfi_offset rbp, -16
5+
pushq %rbx
6+
pushq %r12
7+
pushq %r13
8+
pushq %r14
9+
pushq %r15
10+
movq %rsp, %rdx
11+
subq $0x08, %rsp
12+
.cfi_def_cfa rsp, 0x40
13+
call unwind_recorder
14+
addq $0x38, %rsp
15+
.cfi_def_cfa rsp, 8
16+
ret

unwind/src/registers.rs

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::ops::{Index, IndexMut};
33

44
#[derive(Default, Clone, PartialEq, Eq)]
55
pub struct Registers {
6-
registers: [Option<u64>; 17],
6+
registers: [Option<u64>; 32],
77
}
88

99
impl Debug for Registers {
@@ -32,21 +32,35 @@ impl IndexMut<u8> for Registers {
3232
}
3333
}
3434

35-
impl Index<DwarfRegister> for Registers {
35+
impl Index<DwarfRegisterAMD64> for Registers {
3636
type Output = Option<u64>;
3737

38-
fn index(&self, reg: DwarfRegister) -> &Option<u64> {
38+
fn index(&self, reg: DwarfRegisterAMD64) -> &Option<u64> {
3939
&self[reg as u8]
4040
}
4141
}
4242

43-
impl IndexMut<DwarfRegister> for Registers {
44-
fn index_mut(&mut self, reg: DwarfRegister) -> &mut Option<u64> {
43+
impl IndexMut<DwarfRegisterAMD64> for Registers {
44+
fn index_mut(&mut self, reg: DwarfRegisterAMD64) -> &mut Option<u64> {
4545
&mut self[reg as u8]
4646
}
4747
}
4848

49-
pub enum DwarfRegister {
49+
impl Index<DwarfRegisterAArch64> for Registers {
50+
type Output = Option<u64>;
51+
52+
fn index(&self, reg: DwarfRegisterAArch64) -> &Option<u64> {
53+
&self[reg as u8]
54+
}
55+
}
56+
57+
impl IndexMut<DwarfRegisterAArch64> for Registers {
58+
fn index_mut(&mut self, reg: DwarfRegisterAArch64) -> &mut Option<u64> {
59+
&mut self[reg as u8]
60+
}
61+
}
62+
63+
pub enum DwarfRegisterAMD64 {
5064
SP = 7,
5165
IP = 16,
5266

@@ -66,3 +80,50 @@ pub enum DwarfRegister {
6680
R14 = 14,
6781
R15 = 15,
6882
}
83+
84+
pub enum DwarfRegisterAArch64 {
85+
X0 = 0,
86+
X1 = 1,
87+
X2 = 2,
88+
X3 = 3,
89+
X4 = 4,
90+
X5 = 5,
91+
X6 = 6,
92+
X7 = 7,
93+
X8 = 8,
94+
X9 = 9,
95+
X10 = 10,
96+
X11 = 11,
97+
X12 = 12,
98+
X13 = 13,
99+
X14 = 14,
100+
X15 = 15,
101+
X16 = 16,
102+
X17 = 17,
103+
X18 = 18,
104+
X19 = 19,
105+
X20 = 20,
106+
X21 = 21,
107+
X22 = 22,
108+
X23 = 23,
109+
X24 = 24,
110+
X25 = 25,
111+
X26 = 26,
112+
X27 = 27,
113+
X28 = 28,
114+
X29 = 29, // Frame Pointer
115+
IP = 30, // Link register, x30, IP is restored in it?
116+
SP = 31,
117+
118+
// ELR_mode
119+
// Vector regs
120+
}
121+
122+
#[cfg(target_arch = "x86_64")]
123+
pub use self::DwarfRegisterAMD64 as DwarfRegister;
124+
125+
#[cfg(target_arch = "aarch64")]
126+
pub use self::DwarfRegisterAArch64 as DwarfRegister;
127+
128+
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
129+
compiler_error!("Unsupported architecture");

0 commit comments

Comments
 (0)