RISC-V unwinder support

This commit is contained in:
Gary Guo 2021-08-26 12:58:22 +01:00
parent f34aa1824f
commit 57b6852c97
2 changed files with 200 additions and 0 deletions

View File

@ -2,3 +2,8 @@
mod x86_64;
#[cfg(target_arch = "x86_64")]
pub use x86_64::*;
#[cfg(target_arch = "riscv64")]
mod riscv64;
#[cfg(target_arch = "riscv64")]
pub use riscv64::*;

View File

@ -0,0 +1,195 @@
use core::fmt;
use core::ops;
use gimli::{Register, RiscV};
#[repr(C)]
#[derive(Clone, Default)]
pub struct Context {
pub gp: [usize; 32],
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]);
}
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],
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],
Register(32..=63) => &mut self.fp[(reg.0 - 32) as usize],
_ => unimplemented!(),
}
}
}
macro_rules! code {
(save_gp) => {
"
sd x0, 0x00(a0)
sd ra, 0x08(a0)
sd sp, 0x10(a0)
sd gp, 0x18(a0)
sd tp, 0x20(a0)
sd s0, 0x40(a0)
sd s1, 0x48(a0)
sd s2, 0x90(a0)
sd s3, 0x98(a0)
sd s4, 0xA0(a0)
sd s5, 0xA8(a0)
sd s6, 0xB0(a0)
sd s7, 0xB8(a0)
sd s8, 0xC0(a0)
sd s9, 0xC8(a0)
sd s10, 0xD0(a0)
sd s11, 0xD8(a0)
"
};
(save_fp) => {
"
fsd fs0, 0x140(a0)
fsd fs1, 0x148(a0)
fsd fs2, 0x190(a0)
fsd fs3, 0x198(a0)
fsd fs4, 0x1A0(a0)
fsd fs5, 0x1A8(a0)
fsd fs6, 0x1B0(a0)
fsd fs7, 0x1B8(a0)
fsd fs8, 0x1C0(a0)
fsd fs9, 0x1C8(a0)
fsd fs10, 0x1D0(a0)
fsd fs11, 0x1D8(a0)
"
};
(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() -> Context {
// No need to save caller-saved registers here.
#[cfg(target_feature = "d")]
unsafe {
asm!(
concat!(code!(save_gp), code!(save_fp), "ret"),
options(noreturn)
);
}
#[cfg(not(target_feature = "d"))]
unsafe {
asm!(
concat!(code!(save_gp), "ret"),
options(noreturn)
);
}
}
#[naked]
pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
#[cfg(target_feature = "d")]
unsafe {
asm!(
concat!(code!(restore_fp), code!(restore_gp), "ld a0, 0x50(a0)\nret"),
options(noreturn)
);
}
#[cfg(not(target_feature = "d"))]
unsafe {
asm!(
concat!(code!(restore_gp), "ld a0, 0x50(a0)\nret"),
options(noreturn)
);
}
}