summaryrefslogtreecommitdiffstats
path: root/vendor/unwinding/src/unwinder/arch
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/unwinding/src/unwinder/arch')
-rw-r--r--vendor/unwinding/src/unwinder/arch/aarch64.rs142
-rw-r--r--vendor/unwinding/src/unwinder/arch/mod.rs33
-rw-r--r--vendor/unwinding/src/unwinder/arch/riscv32.rs242
-rw-r--r--vendor/unwinding/src/unwinder/arch/riscv64.rs242
-rw-r--r--vendor/unwinding/src/unwinder/arch/x86.rs136
-rw-r--r--vendor/unwinding/src/unwinder/arch/x86_64.rs140
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)
+ );
+ }
+}