Skip to content

Commit bb3b9db

Browse files
committed
rs: add LoongArch arch support
1 parent b45ee1d commit bb3b9db

File tree

6 files changed

+269
-0
lines changed

6 files changed

+269
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- SH arch support
1313
- Alpha arch support
1414
- HPPA arch support
15+
- LoongArch arch support
1516
- Arch-specific features flags to enable/disable arch support
1617
- Expose X86 instruction encoding info via `X86InsnDetail::encoding()`
1718
- Make RegAccessType available for ARM64

capstone-rs/src/arch/loongarch.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//! Contains loongarch-specific types
2+
3+
use core::convert::{From, TryInto};
4+
use core::{cmp, fmt, slice};
5+
6+
pub use capstone_sys::loongarch_insn as LoongArchInsn;
7+
pub use capstone_sys::loongarch_reg as LoongArchReg;
8+
use capstone_sys::{
9+
cs_ac_type, cs_loongarch, cs_loongarch_op, cs_loongarch_op__bindgen_ty_1, loongarch_op_mem, loongarch_op_type
10+
};
11+
12+
pub use crate::arch::arch_builder::loongarch::*;
13+
use crate::arch::DetailsArchInsn;
14+
use crate::instruction::{RegId, RegIdInt};
15+
use crate::RegAccessType;
16+
17+
/// Contains loongarch-specific details for an instruction
18+
pub struct LoongArchInsnDetail<'a>(pub(crate) &'a cs_loongarch);
19+
20+
impl_PartialEq_repr_fields!(LoongArchInsnDetail<'a> [ 'a ];
21+
operands
22+
);
23+
24+
/// loongarch operand
25+
#[derive(Clone, Debug, Eq, PartialEq, Default)]
26+
pub struct LoongArchOperand {
27+
/// Operand type
28+
pub op_type: LoongArchOperandType,
29+
30+
/// How is this operand accessed?
31+
///
32+
/// NOTE: this field is always `None` if the "full" feataure is not enabled.
33+
pub access: Option<RegAccessType>,
34+
}
35+
36+
impl From<&cs_loongarch_op> for LoongArchOperand {
37+
fn from(insn: &cs_loongarch_op) -> LoongArchOperand {
38+
let op_type = LoongArchOperandType::new(insn.type_, insn.__bindgen_anon_1);
39+
LoongArchOperand {
40+
op_type,
41+
access: cs_ac_type(insn.access as _).try_into().ok(),
42+
}
43+
}
44+
}
45+
46+
/// LoongArch operand
47+
#[derive(Clone, Debug, PartialEq)]
48+
pub enum LoongArchOperandType {
49+
/// Register
50+
Reg(RegId),
51+
52+
/// Immediate
53+
Imm(i64),
54+
55+
/// Memory
56+
Mem(LoongArchOpMem),
57+
58+
/// Invalid
59+
Invalid,
60+
}
61+
62+
impl LoongArchOperandType {
63+
fn new(
64+
op_type: loongarch_op_type,
65+
value: cs_loongarch_op__bindgen_ty_1,
66+
) -> LoongArchOperandType {
67+
match op_type {
68+
loongarch_op_type::LOONGARCH_OP_REG => {
69+
LoongArchOperandType::Reg(RegId(unsafe { value.reg } as RegIdInt))
70+
}
71+
loongarch_op_type::LOONGARCH_OP_IMM => LoongArchOperandType::Imm(unsafe { value.imm }),
72+
loongarch_op_type::LOONGARCH_OP_MEM => {
73+
LoongArchOperandType::Mem(LoongArchOpMem(unsafe { value.mem }))
74+
}
75+
loongarch_op_type::LOONGARCH_OP_INVALID => LoongArchOperandType::Invalid,
76+
}
77+
}
78+
}
79+
80+
impl cmp::Eq for LoongArchOperandType {}
81+
82+
impl Default for LoongArchOperandType {
83+
fn default() -> Self {
84+
LoongArchOperandType::Invalid
85+
}
86+
}
87+
88+
/// loongarch memory operand
89+
#[derive(Debug, Copy, Clone)]
90+
pub struct LoongArchOpMem(pub(crate) loongarch_op_mem);
91+
92+
impl LoongArchOpMem {
93+
/// Base register
94+
pub fn base(&self) -> RegId {
95+
RegId(self.0.base as RegIdInt)
96+
}
97+
98+
/// Index register
99+
pub fn index(&self) -> RegId {
100+
RegId(self.0.index as RegIdInt)
101+
}
102+
103+
/// Displacement/offset
104+
pub fn disp(&self) -> i64 {
105+
self.0.disp
106+
}
107+
}
108+
109+
impl_PartialEq_repr_fields!(LoongArchOpMem;
110+
base, index, disp
111+
);
112+
113+
impl cmp::Eq for LoongArchOpMem {}
114+
115+
def_arch_details_struct!(
116+
InsnDetail = LoongArchInsnDetail;
117+
Operand = LoongArchOperand;
118+
OperandIterator = LoongArchOperandIterator;
119+
OperandIteratorLife = LoongArchOperandIterator<'a>;
120+
[ pub struct LoongArchOperandIterator<'a>(slice::Iter<'a, cs_loongarch_op>); ]
121+
cs_arch_op = cs_loongarch_op;
122+
cs_arch = cs_loongarch;
123+
);

capstone-rs/src/arch/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,16 @@ macro_rules! arch_info_base {
267267
( syntax: )
268268
( both_endian: true )
269269
]
270+
[
271+
( loongarch, LOONGARCH, "arch_loongarch" )
272+
( mode:
273+
LoongArch32,
274+
LoongArch64,
275+
)
276+
( extra_modes: )
277+
( syntax: )
278+
( both_endian: false )
279+
]
270280
[
271281
( m680x, M680X, "arch_m680x" )
272282
( mode:
@@ -594,6 +604,14 @@ macro_rules! detail_arch_base {
594604
/// Returns the HPPA details, if any
595605
=> arch_name = hppa,
596606
]
607+
[
608+
detail = LoongArchDetail,
609+
insn_detail = LoongArchInsnDetail<'a>,
610+
op = LoongArchOperand,
611+
feature = "arch_loongarch",
612+
/// Returns the LoongArch details, if any
613+
=> arch_name = loongarch,
614+
]
597615
[
598616
detail = M680xDetail,
599617
insn_detail = M680xInsnDetail<'a>,

capstone-rs/src/constants.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ define_cs_enum_wrapper!(
204204
=> ALPHA = CS_ARCH_ALPHA;
205205
/// HPPA
206206
=> HPPA = CS_ARCH_HPPA;
207+
/// LoongArch
208+
=> LOONGARCH = CS_ARCH_LOONGARCH;
207209
/// MIPS
208210
=> MIPS = CS_ARCH_MIPS;
209211
/// x86 family (includes 16, 32, and 64 bit modes)
@@ -381,6 +383,10 @@ define_cs_enum_wrapper!(
381383
=> Hppa20 = { cs_mode::CS_MODE_HPPA_20 };
382384
/// HPPA 2.0 wide
383385
=> Hppa20W = { cs_mode::CS_MODE_HPPA_20W };
386+
/// LoongArch32
387+
=> LoongArch32 = { cs_mode::CS_MODE_LOONGARCH32 };
388+
/// LoongArch64
389+
=> LoongArch64 = { cs_mode::CS_MODE_LOONGARCH64 };
384390
/// Default mode for little-endian
385391
=> Default = { cs_mode::CS_MODE_LITTLE_ENDIAN };
386392
);

capstone-rs/src/instruction.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ impl InsnDetail<'_> {
502502
[BPF, BpfDetail, BpfInsnDetail, bpf, "arch_bpf"]
503503
[EVM, EvmDetail, EvmInsnDetail, evm, "arch_evm"]
504504
[HPPA, HppaDetail, HppaInsnDetail, hppa, "arch_hppa"]
505+
[LOONGARCH, LoongArchDetail, LoongArchInsnDetail, loongarch, "arch_loongarch"]
505506
[M680X, M680xDetail, M680xInsnDetail, m680x, "arch_m680x"]
506507
[M68K, M68kDetail, M68kInsnDetail, m68k, "arch_m68k"]
507508
[MIPS, MipsDetail, MipsInsnDetail, mips, "arch_mips"]

capstone-rs/src/test.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2071,6 +2071,126 @@ fn test_arch_hppa_detail() {
20712071
);
20722072
}
20732073

2074+
#[cfg(feature = "arch_loongarch")]
2075+
#[test]
2076+
fn test_arch_loongarch() {
2077+
test_arch_mode_endian_insns(
2078+
&mut Capstone::new()
2079+
.loongarch()
2080+
.mode(loongarch::ArchMode::LoongArch32)
2081+
.build()
2082+
.unwrap(),
2083+
Arch::LOONGARCH,
2084+
Mode::LoongArch32,
2085+
None,
2086+
&[],
2087+
&[
2088+
("lu12i.w", b"\x0c\x00\x08\x14"),
2089+
("addi.w", b"\x8c\xfd\xbf\x02"),
2090+
],
2091+
);
2092+
}
2093+
2094+
#[cfg(feature = "arch_loongarch")]
2095+
#[test]
2096+
fn test_arch_loongarch_detail() {
2097+
use crate::arch::loongarch::{LoongArchOpMem, LoongArchOperand};
2098+
use capstone_sys::{loongarch_op_mem, loongarch_reg::*};
2099+
2100+
test_arch_mode_endian_insns_detail(
2101+
&mut Capstone::new()
2102+
.loongarch()
2103+
.mode(loongarch::ArchMode::LoongArch32)
2104+
.build()
2105+
.unwrap(),
2106+
Arch::LOONGARCH,
2107+
Mode::LoongArch32,
2108+
None,
2109+
&[],
2110+
&[
2111+
// lu12i.w $t0, 0x4000
2112+
DII::new(
2113+
"lu12i.w",
2114+
b"\x0c\x00\x08\x14",
2115+
&[
2116+
LoongArchOperand {
2117+
op_type: loongarch::LoongArchOperandType::Reg(RegId(
2118+
LOONGARCH_REG_T0 as RegIdInt,
2119+
)),
2120+
access: Some(RegAccessType::WriteOnly),
2121+
},
2122+
LoongArchOperand {
2123+
op_type: loongarch::LoongArchOperandType::Imm(0x4000),
2124+
access: Some(RegAccessType::ReadOnly),
2125+
},
2126+
],
2127+
),
2128+
// addi.w $t0, $t0, -1
2129+
DII::new(
2130+
"addi.w",
2131+
b"\x8c\xfd\xbf\x02",
2132+
&[
2133+
LoongArchOperand {
2134+
op_type: loongarch::LoongArchOperandType::Reg(RegId(
2135+
LOONGARCH_REG_T0 as RegIdInt,
2136+
)),
2137+
access: Some(RegAccessType::WriteOnly),
2138+
},
2139+
LoongArchOperand {
2140+
op_type: loongarch::LoongArchOperandType::Reg(RegId(
2141+
LOONGARCH_REG_T0 as RegIdInt,
2142+
)),
2143+
access: Some(RegAccessType::ReadOnly),
2144+
},
2145+
LoongArchOperand {
2146+
op_type: loongarch::LoongArchOperandType::Imm(-1),
2147+
access: Some(RegAccessType::ReadOnly),
2148+
},
2149+
],
2150+
),
2151+
],
2152+
);
2153+
2154+
test_arch_mode_endian_insns_detail(
2155+
&mut Capstone::new()
2156+
.loongarch()
2157+
.mode(loongarch::ArchMode::LoongArch64)
2158+
.build()
2159+
.unwrap(),
2160+
Arch::LOONGARCH,
2161+
Mode::LoongArch64,
2162+
None,
2163+
&[],
2164+
&[
2165+
// st.d $s1, $sp, 8
2166+
DII::new(
2167+
"st.d",
2168+
b"\x78\x20\xc0\x29",
2169+
&[
2170+
LoongArchOperand {
2171+
op_type: loongarch::LoongArchOperandType::Reg(RegId(
2172+
LOONGARCH_REG_S1 as RegIdInt,
2173+
)),
2174+
// Upstream bug: should be read only
2175+
// https://github.com/capstone-engine/capstone/issues/2700
2176+
access: Some(RegAccessType::WriteOnly),
2177+
},
2178+
LoongArchOperand {
2179+
op_type: loongarch::LoongArchOperandType::Mem(LoongArchOpMem(
2180+
loongarch_op_mem {
2181+
base: LOONGARCH_REG_SP,
2182+
index: 0,
2183+
disp: 8,
2184+
},
2185+
)),
2186+
access: Some(RegAccessType::WriteOnly),
2187+
},
2188+
],
2189+
),
2190+
],
2191+
);
2192+
}
2193+
20742194
#[cfg(feature = "arch_m680x")]
20752195
#[test]
20762196
fn test_arch_m680x_detail() {

0 commit comments

Comments
 (0)