Skip to content
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
197 changes: 180 additions & 17 deletions src/unwinder/arch/riscv32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,29 @@ use super::maybe_cfi;
// 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");
#[cfg(all(target_feature = "e", target_feature = "f"))]
compile_error!("RISC-V RV32E with F extension is not supported");

#[repr(C)]
#[derive(Clone, Default)]
pub struct Context {
#[cfg(not(target_feature = "e"))]
pub gp: [usize; 32],
#[cfg(target_feature = "e")]
pub gp: [usize; 16],
#[cfg(all(target_feature = "f", not(target_feature = "d")))]
pub fp: [u32; 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]);
for (i, gp) in self.gp.iter().enumerate() {
fmt.field(RiscV::register_name(Register(i as _)).unwrap(), gp);
}
#[cfg(target_feature = "d")]
#[cfg(target_feature = "f")]
for i in 0..=31 {
fmt.field(
RiscV::register_name(Register((i + 32) as _)).unwrap(),
Expand Down Expand Up @@ -60,7 +65,8 @@ impl ops::IndexMut<gimli::Register> for Context {
}

macro_rules! code {
(save_gp) => {
// RV32*
(save_gp_0_to_15) => {
"
sw x0, 0x00(sp)
sw ra, 0x04(sp)
Expand All @@ -69,6 +75,11 @@ macro_rules! code {
sw tp, 0x10(sp)
sw s0, 0x20(sp)
sw s1, 0x24(sp)
"
};
// RV32I*
(save_gp_16_to_31) => {
"
sw s2, 0x48(sp)
sw s3, 0x4C(sp)
sw s4, 0x50(sp)
Expand All @@ -81,7 +92,29 @@ macro_rules! code {
sw s11, 0x6C(sp)
"
};
(save_fp) => {
// RV32IF
(save_fp_f) => {
// arch option manipulation needed due to LLVM/Rust bug, see rust-lang/rust#80608
"
.option push
.option arch, +f
fsw fs0, 0xA0(sp)
fsw fs1, 0xA4(sp)
fsw fs2, 0xC8(sp)
fsw fs3, 0xCC(sp)
fsw fs4, 0xD0(sp)
fsw fs5, 0xD4(sp)
fsw fs6, 0xD8(sp)
fsw fs7, 0xDC(sp)
fsw fs8, 0xE0(sp)
fsw fs9, 0xE4(sp)
fsw fs10, 0xE8(sp)
fsw fs11, 0xEC(sp)
.option pop
"
};
// RV32IFD
(save_fp_d) => {
// arch option manipulation needed due to LLVM/Rust bug, see rust-lang/rust#80608
"
.option push
Expand All @@ -101,7 +134,8 @@ macro_rules! code {
.option pop
"
};
(restore_gp) => {
// RV32*
(restore_gp_0_to_15) => {
"
lw ra, 0x04(a0)
lw sp, 0x08(a0)
Expand All @@ -117,6 +151,11 @@ macro_rules! code {
lw a3, 0x34(a0)
lw a4, 0x38(a0)
lw a5, 0x3C(a0)
"
};
// RV32I*
(restore_gp_16_to_31) => {
"
lw a6, 0x40(a0)
lw a7, 0x44(a0)
lw s2, 0x48(a0)
Expand All @@ -135,7 +174,45 @@ macro_rules! code {
lw t6, 0x7C(a0)
"
};
(restore_fp) => {
// RV32IF
(restore_fp_f) => {
"
flw ft0, 0x80(a0)
flw ft1, 0x84(a0)
flw ft2, 0x88(a0)
flw ft3, 0x8C(a0)
flw ft4, 0x90(a0)
flw ft5, 0x94(a0)
flw ft6, 0x98(a0)
flw ft7, 0x9C(a0)
flw fs0, 0xA0(a0)
flw fs1, 0xA4(a0)
flw fa0, 0xA8(a0)
flw fa1, 0xAC(a0)
flw fa2, 0xB0(a0)
flw fa3, 0xB4(a0)
flw fa4, 0xB8(a0)
flw fa5, 0xBC(a0)
flw fa6, 0xC0(a0)
flw fa7, 0xC4(a0)
flw fs2, 0xC8(a0)
flw fs3, 0xCC(a0)
flw fs4, 0xD0(a0)
flw fs5, 0xD4(a0)
flw fs6, 0xD8(a0)
flw fs7, 0xDC(a0)
flw fs8, 0xE0(a0)
flw fs9, 0xE4(a0)
flw fs10, 0xE8(a0)
flw fs11, 0xEC(a0)
flw ft8, 0xF0(a0)
flw ft9, 0xF4(a0)
flw ft10, 0xF8(a0)
flw ft11, 0xFC(a0)
"
};
// RV32IFD
(restore_fp_d) => {
"
fld ft0, 0x80(a0)
fld ft1, 0x88(a0)
Expand Down Expand Up @@ -176,6 +253,7 @@ macro_rules! code {
#[unsafe(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.
// RV32IFD
#[cfg(target_feature = "d")]
core::arch::naked_asm!(
maybe_cfi!(".cfi_startproc"),
Expand All @@ -186,8 +264,9 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p
maybe_cfi!(".cfi_def_cfa_offset 0x190"),
"sw ra, 0x180(sp)",
maybe_cfi!(".cfi_offset ra, -16"),
code!(save_gp),
code!(save_fp),
code!(save_gp_0_to_15),
code!(save_gp_16_to_31),
code!(save_fp_d),
"
mv t0, a0
mv a0, sp
Expand All @@ -200,7 +279,34 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p
"ret",
maybe_cfi!(".cfi_endproc"),
);
#[cfg(not(target_feature = "d"))]
// RV32IF
#[cfg(all(target_feature = "f", not(target_feature = "d")))]
core::arch::naked_asm!(
maybe_cfi!(".cfi_startproc"),
"
mv t0, sp
add sp, sp, -0x110
",
maybe_cfi!(".cfi_def_cfa_offset 0x110"),
"sw ra, 0x100(sp)",
maybe_cfi!(".cfi_offset ra, -16"),
code!(save_gp_0_to_15),
code!(save_gp_16_to_31),
code!(save_fp_f),
"
mv t0, a0
mv a0, sp
jalr t0
lw ra, 0x100(sp)
add sp, sp, 0x110
",
maybe_cfi!(".cfi_def_cfa_offset 0"),
maybe_cfi!(".cfi_restore ra"),
"ret",
maybe_cfi!(".cfi_endproc"),
);
// RV32I
#[cfg(all(not(target_feature = "f"), not(target_feature = "e")))]
core::arch::naked_asm!(
maybe_cfi!(".cfi_startproc"),
"
Expand All @@ -210,7 +316,8 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p
maybe_cfi!(".cfi_def_cfa_offset 0x90"),
"sw ra, 0x80(sp)",
maybe_cfi!(".cfi_offset ra, -16"),
code!(save_gp),
code!(save_gp_0_to_15),
code!(save_gp_16_to_31),
"
mv t0, a0
mv a0, sp
Expand All @@ -223,14 +330,69 @@ pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), p
"ret",
maybe_cfi!(".cfi_endproc")
);
// RV32E
#[cfg(target_feature = "e")]
core::arch::naked_asm!(
maybe_cfi!(".cfi_startproc"),
"
mv t0, sp
add sp, sp, -0x50
",
maybe_cfi!(".cfi_def_cfa_offset 0x50"),
"sw ra, 0x40(sp)",
maybe_cfi!(".cfi_offset ra, -16"),
code!(save_gp_0_to_15),
"
mv t0, a0
mv a0, sp
jalr t0
lw ra, 0x40(sp)
add sp, sp, 0x50
",
maybe_cfi!(".cfi_def_cfa_offset 0"),
maybe_cfi!(".cfi_restore ra"),
"ret",
maybe_cfi!(".cfi_endproc")
);
}

pub unsafe fn restore_context(ctx: &Context) -> ! {
// RV32IFD
#[cfg(target_feature = "d")]
unsafe {
core::arch::asm!(
code!(restore_fp),
code!(restore_gp),
code!(restore_fp_d),
code!(restore_gp_0_to_15),
code!(restore_gp_16_to_31),
"
lw a0, 0x28(a0)
ret
",
in("a0") ctx,
options(noreturn)
);
}
// RV32IF
#[cfg(all(target_feature = "f", not(target_feature = "d")))]
unsafe {
core::arch::asm!(
code!(restore_fp_f),
code!(restore_gp_0_to_15),
code!(restore_gp_16_to_31),
"
lw a0, 0x28(a0)
ret
",
in("a0") ctx,
options(noreturn)
);
}
// RV32I
#[cfg(all(not(target_feature = "f"), not(target_feature = "e")))]
unsafe {
core::arch::asm!(
code!(restore_gp_0_to_15),
code!(restore_gp_16_to_31),
"
lw a0, 0x28(a0)
ret
Expand All @@ -239,10 +401,11 @@ pub unsafe fn restore_context(ctx: &Context) -> ! {
options(noreturn)
);
}
#[cfg(not(target_feature = "d"))]
// RV32E
#[cfg(target_feature = "e")]
unsafe {
core::arch::asm!(
code!(restore_gp),
code!(restore_gp_0_to_15),
"
lw a0, 0x28(a0)
ret
Expand Down
5 changes: 4 additions & 1 deletion src/unwinder/arch/riscv64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use super::maybe_cfi;
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");
compile_error!("RISC-V RV64 with only F extension is not supported");

#[cfg(target_feature = "e")]
compile_error!("RISC-V RV64E is not supported");

#[repr(C)]
#[derive(Clone, Default)]
Expand Down