diff options
Diffstat (limited to 'vendor/unwinding/src/unwinder/arch')
-rw-r--r-- | vendor/unwinding/src/unwinder/arch/aarch64.rs | 142 | ||||
-rw-r--r-- | vendor/unwinding/src/unwinder/arch/mod.rs | 33 | ||||
-rw-r--r-- | vendor/unwinding/src/unwinder/arch/riscv32.rs | 242 | ||||
-rw-r--r-- | vendor/unwinding/src/unwinder/arch/riscv64.rs | 242 | ||||
-rw-r--r-- | vendor/unwinding/src/unwinder/arch/x86.rs | 136 | ||||
-rw-r--r-- | vendor/unwinding/src/unwinder/arch/x86_64.rs | 140 |
6 files changed, 935 insertions, 0 deletions
diff --git a/vendor/unwinding/src/unwinder/arch/aarch64.rs b/vendor/unwinding/src/unwinder/arch/aarch64.rs new file mode 100644 index 000000000..f65332cc4 --- /dev/null +++ b/vendor/unwinding/src/unwinder/arch/aarch64.rs @@ -0,0 +1,142 @@ +use core::arch::asm; +use core::fmt; +use core::ops; +use gimli::{AArch64, Register}; + +// Match DWARF_FRAME_REGISTERS in libgcc +pub const MAX_REG_RULES: usize = 97; + +#[repr(C)] +#[derive(Clone, Default)] +pub struct Context { + pub gp: [usize; 31], + pub sp: usize, + pub fp: [usize; 32], +} + +impl fmt::Debug for Context { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut fmt = fmt.debug_struct("Context"); + for i in 0..=30 { + fmt.field( + AArch64::register_name(Register(i as _)).unwrap(), + &self.gp[i], + ); + } + fmt.field("sp", &self.sp); + for i in 0..=31 { + fmt.field( + AArch64::register_name(Register((i + 64) as _)).unwrap(), + &self.fp[i], + ); + } + fmt.finish() + } +} + +impl ops::Index<Register> for Context { + type Output = usize; + + fn index(&self, reg: Register) -> &usize { + match reg { + Register(0..=30) => &self.gp[reg.0 as usize], + AArch64::SP => &self.sp, + Register(64..=95) => &self.fp[(reg.0 - 64) as usize], + _ => unimplemented!(), + } + } +} + +impl ops::IndexMut<gimli::Register> for Context { + fn index_mut(&mut self, reg: Register) -> &mut usize { + match reg { + Register(0..=30) => &mut self.gp[reg.0 as usize], + AArch64::SP => &mut self.sp, + Register(64..=95) => &mut self.fp[(reg.0 - 64) as usize], + _ => unimplemented!(), + } + } +} + +#[naked] +pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) { + // No need to save caller-saved registers here. + unsafe { + asm!( + " + stp x29, x30, [sp, -16]! + sub sp, sp, 512 + mov x8, x0 + mov x0, sp + + stp d8, d9, [sp, 0x140] + stp d10, d11, [sp, 0x150] + stp d12, d13, [sp, 0x160] + stp d14, d15, [sp, 0x170] + + str x19, [sp, 0x98] + stp x20, x21, [sp, 0xA0] + stp x22, x23, [sp, 0xB0] + stp x24, x25, [sp, 0xC0] + stp x26, x27, [sp, 0xD0] + stp x28, x29, [sp, 0xE0] + add x2, sp, 528 + stp x30, x2, [sp, 0xF0] + + blr x8 + + add sp, sp, 512 + ldp x29, x30, [sp], 16 + ret + ", + options(noreturn) + ); + } +} + +#[naked] +pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { + unsafe { + asm!( + " + 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 x2, x3, [x0, 0x10] + ldp x4, x5, [x0, 0x20] + ldp x6, x7, [x0, 0x30] + ldp x8, x9, [x0, 0x40] + ldp x10, x11, [x0, 0x50] + ldp x12, x13, [x0, 0x60] + ldp x14, x15, [x0, 0x70] + ldp x16, x17, [x0, 0x80] + ldp x18, x19, [x0, 0x90] + ldp x20, x21, [x0, 0xA0] + ldp x22, x23, [x0, 0xB0] + ldp x24, x25, [x0, 0xC0] + ldp x26, x27, [x0, 0xD0] + ldp x28, x29, [x0, 0xE0] + ldp x30, x1, [x0, 0xF0] + mov sp, x1 + + ldp x0, x1, [x0, 0x00] + ret + ", + options(noreturn) + ); + } +} diff --git a/vendor/unwinding/src/unwinder/arch/mod.rs b/vendor/unwinding/src/unwinder/arch/mod.rs new file mode 100644 index 000000000..815835358 --- /dev/null +++ b/vendor/unwinding/src/unwinder/arch/mod.rs @@ -0,0 +1,33 @@ +#[cfg(target_arch = "x86_64")] +mod x86_64; +#[cfg(target_arch = "x86_64")] +pub use x86_64::*; + +#[cfg(target_arch = "x86")] +mod x86; +#[cfg(target_arch = "x86")] +pub use x86::*; + +#[cfg(target_arch = "riscv64")] +mod riscv64; +#[cfg(target_arch = "riscv64")] +pub use riscv64::*; + +#[cfg(target_arch = "riscv32")] +mod riscv32; +#[cfg(target_arch = "riscv32")] +pub use riscv32::*; + +#[cfg(target_arch = "aarch64")] +mod aarch64; +#[cfg(target_arch = "aarch64")] +pub use aarch64::*; + +#[cfg(not(any( + target_arch = "x86_64", + target_arch = "x86", + target_arch = "riscv64", + target_arch = "riscv32", + target_arch = "aarch64" +)))] +compile_error!("Current architecture is not supported"); diff --git a/vendor/unwinding/src/unwinder/arch/riscv32.rs b/vendor/unwinding/src/unwinder/arch/riscv32.rs new file mode 100644 index 000000000..1e8709e2c --- /dev/null +++ b/vendor/unwinding/src/unwinder/arch/riscv32.rs @@ -0,0 +1,242 @@ +use core::arch::asm; +use core::fmt; +use core::ops; +use gimli::{Register, RiscV}; + +// Match DWARF_FRAME_REGISTERS in libgcc +pub const MAX_REG_RULES: usize = 65; + +#[cfg(all(target_feature = "f", not(target_feature = "d")))] +compile_error!("RISC-V with only F extension is not supported"); + +#[repr(C)] +#[derive(Clone, Default)] +pub struct Context { + pub gp: [usize; 32], + #[cfg(target_feature = "d")] + pub fp: [u64; 32], +} + +impl fmt::Debug for Context { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut fmt = fmt.debug_struct("Context"); + for i in 0..=31 { + fmt.field(RiscV::register_name(Register(i as _)).unwrap(), &self.gp[i]); + } + #[cfg(target_feature = "d")] + for i in 0..=31 { + fmt.field( + RiscV::register_name(Register((i + 32) as _)).unwrap(), + &self.fp[i], + ); + } + fmt.finish() + } +} + +impl ops::Index<Register> for Context { + type Output = usize; + + fn index(&self, reg: Register) -> &usize { + match reg { + Register(0..=31) => &self.gp[reg.0 as usize], + // We cannot support indexing fp here. It is 64-bit if D extension is implemented, + // and 32-bit if only F extension is implemented. + _ => unimplemented!(), + } + } +} + +impl ops::IndexMut<gimli::Register> for Context { + fn index_mut(&mut self, reg: Register) -> &mut usize { + match reg { + Register(0..=31) => &mut self.gp[reg.0 as usize], + // We cannot support indexing fp here. It is 64-bit if D extension is implemented, + // and 32-bit if only F extension is implemented. + _ => unimplemented!(), + } + } +} + +macro_rules! code { + (save_gp) => { + " + sw x0, 0x00(sp) + sw ra, 0x04(sp) + sw t0, 0x08(sp) + sw gp, 0x0C(sp) + sw tp, 0x10(sp) + sw s0, 0x20(sp) + sw s1, 0x24(sp) + sw s2, 0x48(sp) + sw s3, 0x4C(sp) + sw s4, 0x50(sp) + sw s5, 0x54(sp) + sw s6, 0x58(sp) + sw s7, 0x5C(sp) + sw s8, 0x60(sp) + sw s9, 0x64(sp) + sw s10, 0x68(sp) + sw s11, 0x6C(sp) + " + }; + (save_fp) => { + " + fsd fs0, 0xC0(sp) + fsd fs1, 0xC8(sp) + fsd fs2, 0x110(sp) + fsd fs3, 0x118(sp) + fsd fs4, 0x120(sp) + fsd fs5, 0x128(sp) + fsd fs6, 0x130(sp) + fsd fs7, 0x138(sp) + fsd fs8, 0x140(sp) + fsd fs9, 0x148(sp) + fsd fs10, 0x150(sp) + fsd fs11, 0x158(sp) + " + }; + (restore_gp) => { + " + lw ra, 0x04(a0) + lw sp, 0x08(a0) + lw gp, 0x0C(a0) + lw tp, 0x10(a0) + lw t0, 0x14(a0) + lw t1, 0x18(a0) + lw t2, 0x1C(a0) + lw s0, 0x20(a0) + lw s1, 0x24(a0) + lw a1, 0x2C(a0) + lw a2, 0x30(a0) + lw a3, 0x34(a0) + lw a4, 0x38(a0) + lw a5, 0x3C(a0) + lw a6, 0x40(a0) + lw a7, 0x44(a0) + lw s2, 0x48(a0) + lw s3, 0x4C(a0) + lw s4, 0x50(a0) + lw s5, 0x54(a0) + lw s6, 0x58(a0) + lw s7, 0x5C(a0) + lw s8, 0x60(a0) + lw s9, 0x64(a0) + lw s10, 0x68(a0) + lw s11, 0x6C(a0) + lw t3, 0x70(a0) + lw t4, 0x74(a0) + lw t5, 0x78(a0) + lw t6, 0x7C(a0) + " + }; + (restore_fp) => { + " + fld ft0, 0x80(a0) + fld ft1, 0x88(a0) + fld ft2, 0x90(a0) + fld ft3, 0x98(a0) + fld ft4, 0xA0(a0) + fld ft5, 0xA8(a0) + fld ft6, 0xB0(a0) + fld ft7, 0xB8(a0) + fld fs0, 0xC0(a0) + fld fs1, 0xC8(a0) + fld fa0, 0xD0(a0) + fld fa1, 0xD8(a0) + fld fa2, 0xE0(a0) + fld fa3, 0xE8(a0) + fld fa4, 0xF0(a0) + fld fa5, 0xF8(a0) + fld fa6, 0x100(a0) + fld fa7, 0x108(a0) + fld fs2, 0x110(a0) + fld fs3, 0x118(a0) + fld fs4, 0x120(a0) + fld fs5, 0x128(a0) + fld fs6, 0x130(a0) + fld fs7, 0x138(a0) + fld fs8, 0x140(a0) + fld fs9, 0x148(a0) + fld fs10, 0x150(a0) + fld fs11, 0x158(a0) + fld ft8, 0x160(a0) + fld ft9, 0x168(a0) + fld ft10, 0x170(a0) + fld ft11, 0x178(a0) + " + }; +} + +#[naked] +pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) { + // No need to save caller-saved registers here. + #[cfg(target_feature = "d")] + unsafe { + asm!( + " + mv t0, sp + add sp, sp, -0x188 + sw ra, 0x180(sp) + ", + code!(save_gp), + code!(save_fp), + " + mv t0, a0 + mv a0, sp + jalr t0 + lw ra, 0x180(sp) + add sp, sp, 0x188 + ret + ", + options(noreturn) + ); + } + #[cfg(not(target_feature = "d"))] + unsafe { + asm!( + " + mv t0, sp + add sp, sp, -0x88 + sw ra, 0x80(sp) + ", + code!(save_gp), + " + mv t0, a0 + mv a0, sp + jalr t0 + lw ra, 0x80(sp) + add sp, sp, 0x88 + ret + ", + options(noreturn) + ); + } +} + +#[naked] +pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { + #[cfg(target_feature = "d")] + unsafe { + asm!( + code!(restore_fp), + code!(restore_gp), + " + lw a0, 0x28(a0) + ret + ", + options(noreturn) + ); + } + #[cfg(not(target_feature = "d"))] + unsafe { + asm!( + code!(restore_gp), + " + lw a0, 0x28(a0) + ret + ", + options(noreturn) + ); + } +} diff --git a/vendor/unwinding/src/unwinder/arch/riscv64.rs b/vendor/unwinding/src/unwinder/arch/riscv64.rs new file mode 100644 index 000000000..a680d7057 --- /dev/null +++ b/vendor/unwinding/src/unwinder/arch/riscv64.rs @@ -0,0 +1,242 @@ +use core::arch::asm; +use core::fmt; +use core::ops; +use gimli::{Register, RiscV}; + +// Match DWARF_FRAME_REGISTERS in libgcc +pub const MAX_REG_RULES: usize = 65; + +#[cfg(all(target_feature = "f", not(target_feature = "d")))] +compile_error!("RISC-V with only F extension is not supported"); + +#[repr(C)] +#[derive(Clone, Default)] +pub struct Context { + pub gp: [usize; 32], + #[cfg(target_feature = "d")] + pub fp: [usize; 32], +} + +impl fmt::Debug for Context { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut fmt = fmt.debug_struct("Context"); + for i in 0..=31 { + fmt.field(RiscV::register_name(Register(i as _)).unwrap(), &self.gp[i]); + } + #[cfg(target_feature = "d")] + for i in 0..=31 { + fmt.field( + RiscV::register_name(Register((i + 32) as _)).unwrap(), + &self.fp[i], + ); + } + fmt.finish() + } +} + +impl ops::Index<Register> for Context { + type Output = usize; + + fn index(&self, reg: Register) -> &usize { + match reg { + Register(0..=31) => &self.gp[reg.0 as usize], + #[cfg(target_feature = "d")] + Register(32..=63) => &self.fp[(reg.0 - 32) as usize], + _ => unimplemented!(), + } + } +} + +impl ops::IndexMut<gimli::Register> for Context { + fn index_mut(&mut self, reg: Register) -> &mut usize { + match reg { + Register(0..=31) => &mut self.gp[reg.0 as usize], + #[cfg(target_feature = "d")] + Register(32..=63) => &mut self.fp[(reg.0 - 32) as usize], + _ => unimplemented!(), + } + } +} + +macro_rules! code { + (save_gp) => { + " + sd x0, 0x00(sp) + sd ra, 0x08(sp) + sd t0, 0x10(sp) + sd gp, 0x18(sp) + sd tp, 0x20(sp) + sd s0, 0x40(sp) + sd s1, 0x48(sp) + sd s2, 0x90(sp) + sd s3, 0x98(sp) + sd s4, 0xA0(sp) + sd s5, 0xA8(sp) + sd s6, 0xB0(sp) + sd s7, 0xB8(sp) + sd s8, 0xC0(sp) + sd s9, 0xC8(sp) + sd s10, 0xD0(sp) + sd s11, 0xD8(sp) + " + }; + (save_fp) => { + " + fsd fs0, 0x140(sp) + fsd fs1, 0x148(sp) + fsd fs2, 0x190(sp) + fsd fs3, 0x198(sp) + fsd fs4, 0x1A0(sp) + fsd fs5, 0x1A8(sp) + fsd fs6, 0x1B0(sp) + fsd fs7, 0x1B8(sp) + fsd fs8, 0x1C0(sp) + fsd fs9, 0x1C8(sp) + fsd fs10, 0x1D0(sp) + fsd fs11, 0x1D8(sp) + " + }; + (restore_gp) => { + " + ld ra, 0x08(a0) + ld sp, 0x10(a0) + ld gp, 0x18(a0) + ld tp, 0x20(a0) + ld t0, 0x28(a0) + ld t1, 0x30(a0) + ld t2, 0x38(a0) + ld s0, 0x40(a0) + ld s1, 0x48(a0) + ld a1, 0x58(a0) + ld a2, 0x60(a0) + ld a3, 0x68(a0) + ld a4, 0x70(a0) + ld a5, 0x78(a0) + ld a6, 0x80(a0) + ld a7, 0x88(a0) + ld s2, 0x90(a0) + ld s3, 0x98(a0) + ld s4, 0xA0(a0) + ld s5, 0xA8(a0) + ld s6, 0xB0(a0) + ld s7, 0xB8(a0) + ld s8, 0xC0(a0) + ld s9, 0xC8(a0) + ld s10, 0xD0(a0) + ld s11, 0xD8(a0) + ld t3, 0xE0(a0) + ld t4, 0xE8(a0) + ld t5, 0xF0(a0) + ld t6, 0xF8(a0) + " + }; + (restore_fp) => { + " + fld ft0, 0x100(a0) + fld ft1, 0x108(a0) + fld ft2, 0x110(a0) + fld ft3, 0x118(a0) + fld ft4, 0x120(a0) + fld ft5, 0x128(a0) + fld ft6, 0x130(a0) + fld ft7, 0x138(a0) + fld fs0, 0x140(a0) + fld fs1, 0x148(a0) + fld fa0, 0x150(a0) + fld fa1, 0x158(a0) + fld fa2, 0x160(a0) + fld fa3, 0x168(a0) + fld fa4, 0x170(a0) + fld fa5, 0x178(a0) + fld fa6, 0x180(a0) + fld fa7, 0x188(a0) + fld fs2, 0x190(a0) + fld fs3, 0x198(a0) + fld fs4, 0x1A0(a0) + fld fs5, 0x1A8(a0) + fld fs6, 0x1B0(a0) + fld fs7, 0x1B8(a0) + fld fs8, 0x1C0(a0) + fld fs9, 0x1C8(a0) + fld fs10, 0x1D0(a0) + fld fs11, 0x1D8(a0) + fld ft8, 0x1E0(a0) + fld ft9, 0x1E8(a0) + fld ft10, 0x1F0(a0) + fld ft11, 0x1F8(a0) + " + }; +} + +#[naked] +pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) { + // No need to save caller-saved registers here. + #[cfg(target_feature = "d")] + unsafe { + asm!( + " + mv t0, sp + add sp, sp, -0x210 + sd ra, 0x200(sp) + ", + code!(save_gp), + code!(save_fp), + " + mv t0, a0 + mv a0, sp + jalr t0 + ld ra, 0x200(sp) + add sp, sp, 0x210 + ret + ", + options(noreturn) + ); + } + #[cfg(not(target_feature = "d"))] + unsafe { + asm!( + " + mv t0, sp + add sp, sp, -0x110 + sd ra, 0x100(sp) + ", + code!(save_gp), + " + mv t0, a0 + mv a0, sp + jalr t0 + ld ra, 0x100(sp) + add sp, sp, 0x110 + ret + ", + options(noreturn) + ); + } +} + +#[naked] +pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { + #[cfg(target_feature = "d")] + unsafe { + asm!( + code!(restore_fp), + code!(restore_gp), + " + ld a0, 0x50(a0) + ret + ", + options(noreturn) + ); + } + #[cfg(not(target_feature = "d"))] + unsafe { + asm!( + code!(restore_gp), + " + ld a0, 0x50(a0) + ret + ", + options(noreturn) + ); + } +} diff --git a/vendor/unwinding/src/unwinder/arch/x86.rs b/vendor/unwinding/src/unwinder/arch/x86.rs new file mode 100644 index 000000000..992afb66a --- /dev/null +++ b/vendor/unwinding/src/unwinder/arch/x86.rs @@ -0,0 +1,136 @@ +use core::arch::asm; +use core::fmt; +use core::ops; +use gimli::{Register, X86}; + +// Match DWARF_FRAME_REGISTERS in libgcc +pub const MAX_REG_RULES: usize = 17; + +#[repr(C)] +#[derive(Clone, Default)] +pub struct Context { + pub registers: [usize; 8], + pub ra: usize, + pub mcxsr: usize, + pub fcw: usize, +} + +impl fmt::Debug for Context { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut fmt = fmt.debug_struct("Context"); + for i in 0..=7 { + fmt.field( + X86::register_name(Register(i as _)).unwrap(), + &self.registers[i], + ); + } + fmt.field("ra", &self.ra) + .field("mcxsr", &self.mcxsr) + .field("fcw", &self.fcw) + .finish() + } +} + +impl ops::Index<Register> for Context { + type Output = usize; + + fn index(&self, reg: Register) -> &usize { + match reg { + Register(0..=7) => &self.registers[reg.0 as usize], + X86::RA => &self.ra, + X86::MXCSR => &self.mcxsr, + _ => unimplemented!(), + } + } +} + +impl ops::IndexMut<gimli::Register> for Context { + fn index_mut(&mut self, reg: Register) -> &mut usize { + match reg { + Register(0..=7) => &mut self.registers[reg.0 as usize], + X86::RA => &mut self.ra, + X86::MXCSR => &mut self.mcxsr, + _ => unimplemented!(), + } + } +} + +#[naked] +pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) { + // No need to save caller-saved registers here. + unsafe { + asm!( + " + sub esp, 52 + + mov [esp + 4], ecx + mov [esp + 8], edx + mov [esp + 12], ebx + + /* Adjust the stack to account for the return address */ + lea eax, [esp + 56] + mov [esp + 16], eax + + mov [esp + 20], ebp + mov [esp + 24], esi + mov [esp + 28], edi + + /* Return address */ + mov eax, [esp + 52] + mov [esp + 32], eax + + stmxcsr [esp + 36] + fnstcw [esp + 40] + + mov eax, [esp + 60] + mov ecx, esp + push eax + push ecx + call [esp + 64] + + add esp, 60 + ret + ", + options(noreturn) + ); + } +} + +#[naked] +pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { + unsafe { + asm!( + " + mov edx, [esp + 4] + + /* Restore stack */ + mov esp, [edx + 16] + + /* Restore callee-saved control registers */ + ldmxcsr [edx + 36] + fldcw [edx + 40] + + /* Restore return address */ + mov eax, [edx + 32] + push eax + + /* + * Restore general-purpose registers. Non-callee-saved registers are + * also restored because sometimes it's used to pass unwind arguments. + */ + mov eax, [edx + 0] + mov ecx, [edx + 4] + mov ebx, [edx + 12] + mov ebp, [edx + 20] + mov esi, [edx + 24] + mov edi, [edx + 28] + + /* EDX restored last */ + mov edx, [edx + 8] + + ret + ", + options(noreturn) + ); + } +} diff --git a/vendor/unwinding/src/unwinder/arch/x86_64.rs b/vendor/unwinding/src/unwinder/arch/x86_64.rs new file mode 100644 index 000000000..43876865c --- /dev/null +++ b/vendor/unwinding/src/unwinder/arch/x86_64.rs @@ -0,0 +1,140 @@ +use core::arch::asm; +use core::fmt; +use core::ops; +use gimli::{Register, X86_64}; + +// Match DWARF_FRAME_REGISTERS in libgcc +pub const MAX_REG_RULES: usize = 17; + +#[repr(C)] +#[derive(Clone, Default)] +pub struct Context { + pub registers: [usize; 16], + pub ra: usize, + pub mcxsr: usize, + pub fcw: usize, +} + +impl fmt::Debug for Context { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut fmt = fmt.debug_struct("Context"); + for i in 0..=15 { + fmt.field( + X86_64::register_name(Register(i as _)).unwrap(), + &self.registers[i], + ); + } + fmt.field("ra", &self.ra) + .field("mcxsr", &self.mcxsr) + .field("fcw", &self.fcw) + .finish() + } +} + +impl ops::Index<Register> for Context { + type Output = usize; + + fn index(&self, reg: Register) -> &usize { + match reg { + Register(0..=15) => &self.registers[reg.0 as usize], + X86_64::RA => &self.ra, + X86_64::MXCSR => &self.mcxsr, + X86_64::FCW => &self.fcw, + _ => unimplemented!(), + } + } +} + +impl ops::IndexMut<gimli::Register> for Context { + fn index_mut(&mut self, reg: Register) -> &mut usize { + match reg { + Register(0..=15) => &mut self.registers[reg.0 as usize], + X86_64::RA => &mut self.ra, + X86_64::MXCSR => &mut self.mcxsr, + X86_64::FCW => &mut self.fcw, + _ => unimplemented!(), + } + } +} + +#[naked] +pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) { + // No need to save caller-saved registers here. + unsafe { + asm!( + " + sub rsp, 0x98 + mov [rsp + 0x18], rbx + mov [rsp + 0x30], rbp + + /* Adjust the stack to account for the return address */ + lea rax, [rsp + 0xA0] + mov [rsp + 0x38], rax + + mov [rsp + 0x60], r12 + mov [rsp + 0x68], r13 + mov [rsp + 0x70], r14 + mov [rsp + 0x78], r15 + + /* Return address */ + mov rax, [rsp + 0x98] + mov [rsp + 0x80], rax + + stmxcsr [rsp + 0x88] + fnstcw [rsp + 0x90] + + mov rax, rdi + mov rdi, rsp + call rax + add rsp, 0x98 + ret + ", + options(noreturn) + ); + } +} + +#[naked] +pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { + unsafe { + asm!( + " + /* Restore stack */ + mov rsp, [rdi + 0x38] + + /* Restore callee-saved control registers */ + ldmxcsr [rdi + 0x88] + fldcw [rdi + 0x90] + + /* Restore return address */ + mov rax, [rdi + 0x80] + push rax + + /* + * Restore general-purpose registers. Non-callee-saved registers are + * also restored because sometimes it's used to pass unwind arguments. + */ + mov rax, [rdi + 0x00] + mov rdx, [rdi + 0x08] + mov rcx, [rdi + 0x10] + mov rbx, [rdi + 0x18] + mov rsi, [rdi + 0x20] + mov rbp, [rdi + 0x30] + mov r8 , [rdi + 0x40] + mov r9 , [rdi + 0x48] + mov r10, [rdi + 0x50] + mov r11, [rdi + 0x58] + mov r12, [rdi + 0x60] + mov r13, [rdi + 0x68] + mov r14, [rdi + 0x70] + mov r15, [rdi + 0x78] + + /* RDI restored last */ + mov rdi, [rdi + 0x28] + + ret + ", + options(noreturn) + ); + } +} |