Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIPS Support #24

Draft
wants to merge 2 commits into
base: trunk
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:
- aarch64-unknown-linux-gnu
- riscv64gc-unknown-linux-gnu
- riscv32gc-unknown-linux-gnu
- mipsel-unknown-linux-gnu
- mips-unknown-linux-gnu
runs-on: ubuntu-latest

steps:
Expand Down
21 changes: 20 additions & 1 deletion src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,30 @@ mod aarch64 {
#[cfg(target_arch = "aarch64")]
pub use aarch64::*;

#[cfg(target_arch = "mips")]
mod mips {
use gimli::{Register, MIPS};

pub struct Arch;

#[allow(unused)]
impl Arch {
pub const SP: Register = MIPS::SP;
pub const RA: Register = MIPS::RA;

pub const UNWIND_DATA_REG: (Register, Register) = (MIPS::A0, MIPS::A1);
pub const UNWIND_PRIVATE_DATA_SIZE: usize = 2;
}
}
#[cfg(target_arch = "mips")]
pub use mips::*;

#[cfg(not(any(
target_arch = "x86_64",
target_arch = "x86",
target_arch = "riscv64",
target_arch = "riscv32",
target_arch = "aarch64"
target_arch = "aarch64",
target_arch = "mips",
)))]
compile_error!("Current architecture is not supported");
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![feature(c_unwind)]
#![feature(naked_functions)]
#![feature(non_exhaustive_omitted_patterns_lint)]
#![cfg_attr(target_arch = "mips", feature(asm_experimental_arch))]
// lang_items is an internal feature. `internal_features` lint is added recently
// so also allow unknown lints to prevent warning in older nightly versions.
#![cfg_attr(
Expand Down
289 changes: 289 additions & 0 deletions src/unwinder/arch/mips.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
use core::arch::asm;
use core::fmt;
use core::ops;
use gimli::{Register, MIPS};

// Match DWARF_FRAME_REGISTERS in libgcc
pub const MAX_REG_RULES: usize = 188;

#[repr(C)]
#[derive(Clone, Default)]
pub struct Context {
pub gp: [usize; 32],
#[cfg(target_feature = "single-float")]
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(MIPS::register_name(Register(i as _)).unwrap(), &self.gp[i]);
}
#[cfg(target_feature = "single-float")]
for i in 0..=31 {
fmt.field(
MIPS::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 = "single-float")]
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 = "single-float")]
Register(32..=63) => &mut self.fp[(reg.0 - 32) as usize],
_ => unimplemented!(),
}
}
}

macro_rules! code {
(save_gp) => {
"
sw $zero, 0x00($sp)
sw $s0, 0x40($sp)
sw $s1, 0x44($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 $k0, 0x68($sp)
sw $k1, 0x6C($sp)
sw $gp, 0x70($sp)
sw $t0, 0x74($sp)
sw $fp, 0x78($sp)
sw $ra, 0x7C($sp)
"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where's the saving code for sp?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Darn, I meant to move it and made a blunder, will fix

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not saving the correct sp. You have already clobbered it. It should be t0.

};
(save_fp) => {
"
swc1 $f0, 0x80($sp)
swc1 $f1, 0x84($sp)
swc1 $f2, 0x88($sp)
swc1 $f3, 0x8C($sp)
swc1 $f4, 0x90($sp)
swc1 $f5, 0x94($sp)
swc1 $f6, 0x98($sp)
swc1 $f7, 0x9C($sp)
swc1 $f8, 0xA0($sp)
swc1 $f9, 0xA4($sp)
swc1 $f10, 0xA8($sp)
swc1 $f11, 0xAC($sp)
swc1 $f12, 0xB0($sp)
swc1 $f13, 0xB4($sp)
swc1 $f14, 0xB8($sp)
swc1 $f15, 0xBC($sp)
swc1 $f16, 0xC0($sp)
swc1 $f17, 0xC4($sp)
swc1 $f18, 0xC8($sp)
swc1 $f19, 0xCC($sp)
swc1 $f20, 0xD0($sp)
swc1 $f21, 0xD4($sp)
swc1 $f22, 0xD8($sp)
swc1 $f23, 0xDC($sp)
swc1 $f24, 0xE0($sp)
swc1 $f25, 0xE4($sp)
swc1 $f26, 0xE8($sp)
swc1 $f27, 0xEC($sp)
swc1 $f28, 0xF0($sp)
swc1 $f29, 0xF4($sp)
swc1 $f30, 0xF8($sp)
swc1 $f31, 0xFC($sp)
"
};
(restore_gp) => {
"
lw $at, 0x04($a0)
lw $v0, 0x08($a0)
lw $v1, 0x0C($a0)
lw $a1, 0x14($a0)
lw $a2, 0x18($a0)
lw $a3, 0x1C($a0)
lw $t0, 0x20($a0)
lw $t1, 0x24($a0)
lw $t2, 0x28($a0)
lw $t3, 0x2C($a0)
lw $t4, 0x30($a0)
lw $t5, 0x34($a0)
lw $t6, 0x38($a0)
lw $t7, 0x3C($a0)
lw $s0, 0x40($a0)
lw $s1, 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 $t8, 0x60($a0)
lw $t9, 0x64($a0)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the restoring code for at, k0, k1, fp, sp? Also please arrange everything in offset order.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the storing/restoring I mostly copied the riscv as reference, and directly mapped calls where appropriate. I'll get this fixed up though, wasn't sure what registers are critical. :)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All non-volatile registers need to be saved, and all registers need to be restored.

lw $k0, 0x68($a0)
lw $k1, 0x6C($a0)
lw $gp, 0x70($a0)
lw $sp, 0x74($a0)
lw $fp, 0x78($a0)
lw $ra, 0x7C($a0)
"
};
(restore_fp) => {
"
lwc1 $f0, 0x80($a0)
lwc1 $f1, 0x84($a0)
lwc1 $f2, 0x88($a0)
lwc1 $f3, 0x8C($a0)
lwc1 $f4, 0x90($a0)
lwc1 $f5, 0x94($a0)
lwc1 $f6, 0x98($a0)
lwc1 $f7, 0x9C($a0)
lwc1 $f8, 0xA0($a0)
lwc1 $f9, 0xA4($a0)
lwc1 $f10, 0xA8($a0)
lwc1 $f11, 0xAC($a0)
lwc1 $f12, 0xB0($a0)
lwc1 $f13, 0xB4($a0)
lwc1 $f14, 0xB8($a0)
lwc1 $f15, 0xBC($a0)
lwc1 $f16, 0xC0($a0)
lwc1 $f17, 0xC4($a0)
lwc1 $f18, 0xC8($a0)
lwc1 $f19, 0xCC($a0)
lwc1 $f20, 0xD0($a0)
lwc1 $f21, 0xD4($a0)
lwc1 $f22, 0xD8($a0)
lwc1 $f23, 0xDC($a0)
lwc1 $f24, 0xE0($a0)
lwc1 $f25, 0xE4($a0)
lwc1 $f26, 0xE8($a0)
lwc1 $f27, 0xEC($a0)
lwc1 $f28, 0xF0($a0)
lwc1 $f29, 0xF4($a0)
lwc1 $f30, 0xF8($a0)
lwc1 $f31, 0xFC($a0)
"
};
}

#[naked]
pub extern "C-unwind" fn save_context(f: extern "C" fn(&mut Context, *mut ()), ptr: *mut ()) {
unsafe {
#[cfg(target_feature = "single-float")]
asm!(
"
.set noreorder
.set nomacro
.set noat
move $t0, $sp
add $sp, $sp, -0x110
sw $ra, 0x100($sp)
",
code!(save_gp),
code!(save_fp),
"
move $t9, $a0
move $a0, $sp
/* jalr must use $t9 in PIE code */
jalr $t9
nop
lw $ra, 0x100($sp)
add $sp, $sp, 0x110
jr $ra
nop
.set at
.set macro
.set reorder
",
options(noreturn)
);
#[cfg(not(target_feature = "single-float"))]
asm!(
"
.set noreorder
.set nomacro
.set noat
move $t0, $sp
add $sp, $sp, -0x90
sw $ra, 0x80($sp)
",
code!(save_gp),
"
move $t9, $a0
move $a0, $sp
/* jalr must use $t9 in PIE code */
jalr $t9
nop
lw $ra, 0x80($sp)
add $sp, $sp, 0x90
jr $ra
nop
.set at
.set macro
.set reorder
",
options(noreturn)
);
}
}

pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
unsafe {
#[cfg(target_feature = "single-float")]
asm!(
"
.set noreorder
.set nomacro
.set noat
",
code!(restore_fp),
code!(restore_gp),
"
lw $a0, 0x10($a0)
jr $ra
nop
.set at
.set macro
.set reorder
",
in("$4") ctx,
options(noreturn)
);
#[cfg(not(target_feature = "single-float"))]
asm!(
"
.set noreorder
.set nomacro
.set noat
",
code!(restore_gp),
"
lw $a0, 0x10($a0)
jr $ra
nop
.set at
.set macro
.set reorder
",
in("$4") ctx,
options(noreturn)
);
}
}
8 changes: 7 additions & 1 deletion src/unwinder/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,17 @@ mod aarch64;
#[cfg(target_arch = "aarch64")]
pub use aarch64::*;

#[cfg(target_arch = "mips")]
mod mips;
#[cfg(target_arch = "mips")]
pub use mips::*;

#[cfg(not(any(
target_arch = "x86_64",
target_arch = "x86",
target_arch = "riscv64",
target_arch = "riscv32",
target_arch = "aarch64"
target_arch = "aarch64",
target_arch = "mips",
)))]
compile_error!("Current architecture is not supported");