1use crate::arch::{
2 arm, arm64, evm, m680x, m68k, mips, mos65xx, ppc, sparc, sysz, tms320c64x, x86, xcore,
3 InsnGroup, Reg,
4};
5use crate::{sys, util, Arch};
6use core::marker::PhantomData;
7
8const MNEMONIC_SIZE: usize = 32;
9
10#[repr(C)]
12pub struct Insn<'a> {
13 pub(crate) id: libc::c_uint,
20
21 address: u64,
24
25 size: u16,
28
29 bytes: [u8; 24],
32
33 mnemonic: [libc::c_char; MNEMONIC_SIZE],
36
37 op_str: [libc::c_char; 160],
40
41 pub(crate) detail: *mut DetailsInner,
49
50 _phan: PhantomData<&'a ()>,
52}
53
54impl<'a> Insn<'a> {
55 #[inline]
57 pub fn address(&self) -> u64 {
58 self.address
59 }
60
61 #[inline]
63 pub fn size(&self) -> usize {
64 self.size as usize
65 }
66
67 #[inline]
71 pub fn bytes(&self) -> &[u8] {
72 unsafe { core::slice::from_raw_parts(self.bytes.as_ptr(), self.size()) }
73 }
74
75 #[inline]
77 pub fn mnemonic(&self) -> &str {
78 unsafe { util::cstr(self.mnemonic.as_ptr(), MNEMONIC_SIZE) }
79 }
80
81 #[inline]
83 pub fn operands(&self) -> &str {
84 unsafe { util::cstr(self.op_str.as_ptr(), 160) }
85 }
86}
87
88pub struct InsnBuffer<'a> {
90 inner: *mut Insn<'a>,
91 count: usize,
92 _phan: PhantomData<&'a Insn<'a>>,
93}
94
95impl<'a> InsnBuffer<'a> {
96 pub(crate) fn new(insn: *mut Insn<'a>, count: usize) -> InsnBuffer<'a> {
97 InsnBuffer {
98 inner: insn,
99 count,
100 _phan: PhantomData,
101 }
102 }
103
104 fn free(&mut self) {
107 if self.count == 0 || self.inner.is_null() {
108 return;
109 }
110 unsafe { sys::cs_free(self.inner as *mut Insn, self.count as libc::size_t) };
111 self.inner = core::ptr::null_mut();
112 self.count = 0;
113 }
114}
115
116impl<'a> core::ops::Deref for InsnBuffer<'a> {
117 type Target = [Insn<'a>];
118
119 #[inline]
120 fn deref(&self) -> &Self::Target {
121 unsafe { core::slice::from_raw_parts(self.inner, self.count) }
122 }
123}
124
125impl<'a> Drop for InsnBuffer<'a> {
126 fn drop(&mut self) {
127 self.free();
128 }
129}
130
131pub struct InsnIter<'a> {
134 caps: &'a super::Capstone,
135 insn: *mut Insn<'a>,
136 code: *const u8,
137 size: libc::size_t,
138 addr: u64,
139}
140
141impl<'a> InsnIter<'a> {
142 pub(crate) fn new(
143 caps: &'a super::Capstone,
144 insn: *mut Insn<'a>,
145 code: *const u8,
146 size: libc::size_t,
147 addr: u64,
148 ) -> InsnIter<'a> {
149 InsnIter {
150 caps,
151 insn,
152 code,
153 size,
154 addr,
155 }
156 }
157
158 fn free(&mut self) {
161 if self.insn.is_null() {
162 return;
163 }
164 unsafe { sys::cs_free(self.insn as *mut Insn, 1) };
165 self.insn = core::ptr::null_mut();
166 }
167}
168
169impl<'a> Iterator for InsnIter<'a> {
170 type Item = Result<&'a Insn<'a>, super::Error>;
171
172 fn next(&mut self) -> Option<Self::Item> {
173 let success = unsafe {
174 sys::cs_disasm_iter(
175 self.caps.handle,
176 &mut self.code,
177 &mut self.size,
178 &mut self.addr,
179 self.insn,
180 )
181 };
182
183 #[cfg(feature = "std")]
184 self.caps.resume_panic();
185
186 if !success {
187 match self.caps.errno() {
188 Ok(_) => return None,
189 Err(err) => return Some(Err(err)),
190 }
191 }
192
193 Ok(unsafe { self.insn.as_ref() }).transpose()
194 }
195}
196
197impl<'a> Drop for InsnIter<'a> {
198 fn drop(&mut self) {
199 self.free();
200 }
201}
202
203#[derive(Copy, Clone)]
205pub struct Details<'i> {
206 arch: Arch,
207 inner: &'i DetailsInner,
208}
209
210impl<'i> Details<'i> {
211 pub(crate) fn wrap(arch: Arch, inner: &'i DetailsInner) -> Details<'i> {
212 Details { arch, inner }
213 }
214
215 pub fn regs_read(self) -> &'i [Reg] {
219 unsafe {
220 &*(&self.inner.regs_read[..self.inner.regs_read_count as usize] as *const [u16]
221 as *const [Reg])
222 }
223 }
224
225 pub fn regs_write(self) -> &'i [Reg] {
229 unsafe {
230 &*(&self.inner.regs_write[..self.inner.regs_write_count as usize] as *const [u16]
231 as *const [Reg])
232 }
233 }
234
235 pub fn groups(self) -> &'i [InsnGroup] {
236 unsafe {
237 &*(&self.inner.groups[..self.inner.groups_count as usize] as *const [u8]
238 as *const [InsnGroup])
239 }
240 }
241
242 pub fn arch(self) -> ArchDetails<'i> {
244 match self.arch {
245 Arch::Arm => ArchDetails::Arm(unsafe { &self.inner.arch.arm }),
246 Arch::Arm64 => ArchDetails::Arm64(unsafe { &self.inner.arch.arm64 }),
247 Arch::Mips => ArchDetails::Mips(unsafe { &self.inner.arch.mips }),
248 Arch::X86 => ArchDetails::X86(unsafe { &self.inner.arch.x86 }),
249 Arch::PowerPc => ArchDetails::PowerPc(unsafe { &self.inner.arch.ppc }),
250 Arch::Sparc => ArchDetails::Sparc(unsafe { &self.inner.arch.sparc }),
251 Arch::SystemZ => ArchDetails::SystemZ(unsafe { &self.inner.arch.sysz }),
252 Arch::XCore => ArchDetails::XCore(unsafe { &self.inner.arch.xcore }),
253 Arch::M68K => ArchDetails::M68K(unsafe { &self.inner.arch.m68k }),
254 Arch::Tms320C64X => ArchDetails::Tms320C64X(unsafe { &self.inner.arch.tms320c64x }),
255 Arch::M680X => ArchDetails::M680X(unsafe { &self.inner.arch.m680x }),
256 Arch::Evm => ArchDetails::Evm(unsafe { &self.inner.arch.evm }),
257 Arch::Mos65xx => ArchDetails::Mos65xx(unsafe { &self.inner.arch.mos65xx }),
258 }
259 }
260
261 pub fn x86(self) -> Option<&'i x86::Details<'i>> {
265 if self.arch == Arch::X86 {
266 Some(unsafe { &self.inner.arch.x86 })
267 } else {
268 None
269 }
270 }
271}
272
273#[repr(C)]
275pub(crate) struct DetailsInner {
276 regs_read: [u16; 16],
278
279 regs_read_count: u8,
281
282 regs_write: [u16; 20],
284
285 regs_write_count: u8,
287
288 groups: [u8; 8],
290
291 groups_count: u8,
293
294 pub(crate) arch: ArchDetailsUnion,
296}
297
298#[repr(C)]
299pub(crate) union ArchDetailsUnion {
300 pub x86: x86::Details<'static>,
301 pub arm64: arm64::Details<'static>,
302 pub arm: arm::Details<'static>,
303 pub m68k: m68k::Details<'static>,
304 pub mips: mips::Details<'static>,
305 pub ppc: ppc::Details<'static>,
306 pub sparc: sparc::Details<'static>,
307 pub sysz: sysz::Details<'static>,
308 pub xcore: xcore::Details<'static>,
309 pub tms320c64x: tms320c64x::Details<'static>,
310 pub m680x: m680x::Details<'static>,
311 pub evm: evm::Details<'static>,
312 pub mos65xx: mos65xx::Details<'static>,
313}
314
315#[derive(Copy, Clone)]
316pub enum ArchDetails<'i> {
317 X86(&'i x86::Details<'i>),
318 Arm64(&'i arm64::Details<'i>),
319 Arm(&'i arm::Details<'i>),
320 M68K(&'i m68k::Details<'i>),
321 Mips(&'i mips::Details<'i>),
322 PowerPc(&'i ppc::Details<'i>),
323 Sparc(&'i sparc::Details<'i>),
324 SystemZ(&'i sysz::Details<'i>),
325 XCore(&'i xcore::Details<'i>),
326 Tms320C64X(&'i tms320c64x::Details<'i>),
327 M680X(&'i m680x::Details<'i>),
328 Evm(&'i evm::Details<'i>),
329 Mos65xx(&'i mos65xx::Details<'i>),
330}
331
332#[cfg(test)]
333mod test {
334 use super::*;
335 use crate::sys;
336
337 #[test]
338 fn detail_size_and_alignment() {
339 assert_eq!(
340 core::mem::size_of::<DetailsInner>(),
341 sys::get_test_val("sizeof(cs_detail)")
342 );
343
344 assert_eq!(
345 core::mem::align_of::<DetailsInner>(),
346 sys::get_test_val("alignof(cs_detail)")
347 );
348 }
349
350 #[test]
351 fn insn_size_and_alignment() {
352 assert_eq!(
353 core::mem::size_of::<Insn>(),
354 sys::get_test_val("sizeof(cs_insn)")
355 );
356
357 assert_eq!(
358 core::mem::align_of::<Insn>(),
359 sys::get_test_val("alignof(cs_insn)")
360 );
361 }
362}