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}