capstone_git/
capstone.rs

1use alloc::boxed::Box;
2use alloc::string::String;
3use core::convert::From;
4use core::ffi::{c_int, c_uint, c_void, CStr};
5use core::marker::PhantomData;
6use core::mem::MaybeUninit;
7#[cfg(feature = "std")]
8use std::ffi::CString;
9
10use capstone_sys::cs_opt_value::*;
11use capstone_sys::*;
12
13use crate::arch::CapstoneBuilder;
14use crate::constants::{Arch, Endian, ExtraMode, Mode, OptValue, Syntax};
15use crate::instruction::{Insn, InsnDetail, InsnGroupId, InsnId, Instructions, RegId};
16use crate::{error::*, PartialInitRegsAccess};
17
18use {crate::ffi::str_from_cstr_ptr, alloc::string::ToString};
19
20/// Length of `cs_regs`
21pub(crate) const REGS_ACCESS_BUF_LEN: usize = 64;
22
23// todo(tmfink) When MSRV is 1.75 or later, can use:
24//pub(crate) const REGS_ACCESS_BUF_LEN: usize = unsafe { core::mem::zeroed::<cs_regs>() }.len();
25
26/// Equivalent to `MaybeUninit<cs_regs>`
27pub(crate) type RegsAccessBuf = [MaybeUninit<RegId>; REGS_ACCESS_BUF_LEN];
28
29static_assertions::assert_eq_size!(RegId, u16);
30static_assertions::assert_eq_size!(RegsAccessBuf, cs_regs);
31static_assertions::assert_type_eq_all!([u16; REGS_ACCESS_BUF_LEN], cs_regs);
32
33/// An instance of the capstone disassembler
34///
35/// Create with an instance with [`.new()`](Self::new) and disassemble bytes with [`.disasm_all()`](Self::disasm_all).
36#[derive(Debug)]
37pub struct Capstone {
38    /// Opaque handle to cs_engine
39    /// Stored as a pointer to ensure `Capstone` is `!Send`/`!Sync`
40    csh: *mut c_void,
41
42    /// Internal mode bitfield
43    mode: cs_mode,
44
45    /// Internal endian bitfield
46    endian: cs_mode,
47
48    /// Syntax
49    syntax: cs_opt_value::Type,
50
51    /// Internal extra mode bitfield
52    extra_mode: cs_mode,
53
54    /// Whether to get extra details when disassembling
55    detail_enabled: bool,
56
57    /// Whether to skipdata when disassembling
58    skipdata_enabled: bool,
59
60    /// Whether to print unsigned immediate
61    unsigned_enabled: bool,
62
63    /// We *must* set `mode`, `extra_mode`, and `endian` at once because `capstone`
64    /// handles them inside the arch-specific handler. We store the bitwise OR of these flags that
65    /// can be passed directly to `cs_option()`.
66    raw_mode: cs_mode,
67
68    /// Architecture
69    arch: Arch,
70}
71
72/// Defines a setter on `Capstone` that speculatively changes the arch-specific mode (which
73/// includes `mode`, `endian`, and `extra_mode`). The setter takes a `capstone-rs` type and changes
74/// the internal `capstone-sys` type.
75macro_rules! define_set_mode {
76    (
77        $( #[$func_attr:meta] )*
78        => $($visibility:ident)*, $fn_name:ident,
79            $opt_type:ident, $param_name:ident : $param_type:ident ;
80        $cs_base_type:ident
81    ) => {
82        $( #[$func_attr] )*
83        $($visibility)* fn $fn_name(&mut self, $param_name: $param_type) -> CsResult<()> {
84            let old_val = self.$param_name;
85            self.$param_name = $cs_base_type::from($param_name);
86
87            let old_raw_mode = self.raw_mode;
88            let new_raw_mode = self.update_raw_mode();
89
90            let result = self._set_cs_option(
91                cs_opt_type::$opt_type,
92                new_raw_mode.0 as usize,
93            );
94
95            if result.is_err() {
96                // On error, restore old values
97                self.raw_mode = old_raw_mode;
98                self.$param_name = old_val;
99            }
100
101            result
102        }
103    }
104}
105
106/// Represents that no extra modes are enabled. Can be passed to `Capstone::new_raw()` as the
107/// `extra_mode` argument.
108pub static NO_EXTRA_MODE: EmptyExtraModeIter = EmptyExtraModeIter(PhantomData);
109
110/// Represents an empty set of `ExtraMode`.
111#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
112pub struct EmptyExtraModeIter(PhantomData<()>);
113
114impl Iterator for EmptyExtraModeIter {
115    type Item = ExtraMode;
116
117    fn next(&mut self) -> Option<Self::Item> {
118        None
119    }
120}
121
122#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
123pub struct RegAccessRef<'a> {
124    pub(crate) read: &'a [RegId],
125    pub(crate) write: &'a [RegId],
126}
127
128impl RegAccessRef<'_> {
129    pub fn read(&self) -> &[RegId] {
130        self.read
131    }
132
133    pub fn write(&self) -> &[RegId] {
134        self.write
135    }
136}
137
138impl Capstone {
139    /// Create a new instance of the decompiler using the builder pattern interface.
140    /// This is the recommended interface to `Capstone`.
141    ///
142    /// ```
143    /// use capstone::prelude::*;
144    /// let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build();
145    /// ```
146    #[allow(clippy::new_ret_no_self)]
147    pub fn new() -> CapstoneBuilder {
148        CapstoneBuilder::new()
149    }
150
151    /// Create a new instance of the decompiler using the "raw" interface.
152    /// The user must ensure that only sensible `Arch`/`Mode` combinations are used.
153    ///
154    /// ```
155    /// use capstone::{Arch, Capstone, NO_EXTRA_MODE, Mode};
156    /// let cs = Capstone::new_raw(Arch::X86, Mode::Mode64, NO_EXTRA_MODE, None);
157    /// assert!(cs.is_ok());
158    /// ```
159    pub fn new_raw<T: Iterator<Item = ExtraMode>>(
160        arch: Arch,
161        mode: Mode,
162        extra_mode: T,
163        endian: Option<Endian>,
164    ) -> CsResult<Capstone> {
165        let mut handle: csh = 0;
166        let csarch: cs_arch = arch.into();
167        let csmode: cs_mode = mode.into();
168
169        // todo(tmfink): test valid modes at run time (or modify upstream capstone)
170
171        let endian = match endian {
172            Some(endian) => cs_mode::from(endian),
173            None => cs_mode(0),
174        };
175        let extra_mode = Self::extra_mode_value(extra_mode);
176
177        let combined_mode = csmode | endian | extra_mode;
178        let err = unsafe { cs_open(csarch, combined_mode, &mut handle) };
179
180        if cs_err::CS_ERR_OK == err {
181            let syntax = CS_OPT_SYNTAX_DEFAULT;
182            let raw_mode = cs_mode(0);
183            let detail_enabled = false;
184            let skipdata_enabled = false;
185            let unsigned_enabled = false;
186
187            let mut cs = Capstone {
188                csh: handle as *mut c_void,
189                syntax,
190                endian,
191                mode: csmode,
192                extra_mode,
193                detail_enabled,
194                skipdata_enabled,
195                unsigned_enabled,
196                raw_mode,
197                arch,
198            };
199            cs.update_raw_mode();
200            Ok(cs)
201        } else {
202            Err(err.into())
203        }
204    }
205
206    /// Disassemble and iterate instructions from user-provided buffer `code` using `cs_disasm_iter`.
207    /// The disassembled address of the buffer is assumed to be `addr`.
208    /// It uses less memory and reduces memory allocations.
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// # use capstone::prelude::*;
214    /// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
215    /// let mut iter = cs.disasm_iter(b"\x90", 0x1000).unwrap();
216    /// assert_eq!(iter.next().unwrap().mnemonic(), Some("nop"));
217    /// assert!(iter.next().is_none());
218    /// ```
219    ///
220    /// # Errors
221    ///
222    /// If `cs_malloc` failed due to OOM, [`Err(Error::OutOfMemory)`](Error::OutOfMemory) is returned.
223    pub fn disasm_iter<'a, 'b>(
224        &'a self,
225        code: &'b [u8],
226        addr: u64,
227    ) -> CsResult<DisasmIter<'a, 'b>> {
228        let insn = unsafe { cs_malloc(self.csh()) };
229        if insn.is_null() {
230            return Err(Error::OutOfMemory);
231        }
232        Ok(DisasmIter {
233            insn,
234            csh: self.csh,
235            code: code.as_ptr(),
236            size: code.len(),
237            addr,
238            _data1: PhantomData,
239            _data2: PhantomData,
240        })
241    }
242
243    /// Disassemble all instructions in buffer
244    ///
245    /// ```
246    /// # use capstone::prelude::*;
247    /// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
248    /// cs.disasm_all(b"\x90", 0x1000).unwrap();
249    /// ```
250    pub fn disasm_all<'a>(&'a self, code: &[u8], addr: u64) -> CsResult<Instructions<'a>> {
251        self.disasm(code, addr, 0)
252    }
253
254    /// Disassemble `count` instructions in `code`
255    pub fn disasm_count<'a>(
256        &'a self,
257        code: &[u8],
258        addr: u64,
259        count: usize,
260    ) -> CsResult<Instructions<'a>> {
261        if count == 0 {
262            return Err(Error::CustomError("Invalid dissasemble count; must be > 0"));
263        }
264        self.disasm(code, addr, count)
265    }
266
267    /// Disassembles a `&[u8]` full of instructions.
268    ///
269    /// Pass `count = 0` to disassemble all instructions in the buffer.
270    fn disasm<'a>(&'a self, code: &[u8], addr: u64, count: usize) -> CsResult<Instructions<'a>> {
271        // SAFETY NOTE: `cs_disasm()` will write the error state into the
272        // `struct cs_struct` (true form of the `self.csh`) `errnum` field.
273        // CLAIM: since:
274        // - `Capstone` is not `Send`/`Sync`
275        // - The mutation is done through a `*mut c_void` (not through a const reference)
276        // it *should* be safe to accept `&self` (instead of `&mut self`) in this method.
277
278        let mut ptr: *mut cs_insn = core::ptr::null_mut();
279        let insn_count =
280            unsafe { cs_disasm(self.csh(), code.as_ptr(), code.len(), addr, count, &mut ptr) };
281        if insn_count == 0 {
282            match self.error_result() {
283                Ok(_) => Ok(Instructions::new_empty()),
284                Err(err) => Err(err),
285            }
286        } else {
287            Ok(unsafe { Instructions::from_raw_parts(ptr, insn_count) })
288        }
289    }
290
291    /// Returns csh handle
292    #[inline]
293    fn csh(&self) -> csh {
294        self.csh as csh
295    }
296
297    /// Returns the raw mode value, which is useful for debugging
298    #[allow(dead_code)]
299    pub(crate) fn raw_mode(&self) -> cs_mode {
300        self.raw_mode
301    }
302
303    /// Update `raw_mode` with the bitwise OR of `mode`, `extra_mode`, and `endian`.
304    ///
305    /// Returns the new `raw_mode`.
306    fn update_raw_mode(&mut self) -> cs_mode {
307        self.raw_mode = self.mode | self.extra_mode | self.endian;
308        self.raw_mode
309    }
310
311    /// Return the integer value used by capstone to represent the set of extra modes
312    fn extra_mode_value<T: Iterator<Item = ExtraMode>>(extra_mode: T) -> cs_mode {
313        // Bitwise OR extra modes
314        extra_mode.fold(cs_mode(0), |acc, x| acc | cs_mode::from(x))
315    }
316
317    /// Set extra modes in addition to normal `mode`
318    pub fn set_extra_mode<T: Iterator<Item = ExtraMode>>(&mut self, extra_mode: T) -> CsResult<()> {
319        let old_val = self.extra_mode;
320
321        self.extra_mode = Self::extra_mode_value(extra_mode);
322
323        let old_mode = self.raw_mode;
324        let new_mode = self.update_raw_mode();
325        let result = self._set_cs_option(cs_opt_type::CS_OPT_MODE, new_mode.0 as usize);
326
327        if result.is_err() {
328            // On error, restore old values
329            self.raw_mode = old_mode;
330            self.extra_mode = old_val;
331        }
332
333        result
334    }
335
336    /// Set the assembly syntax (has no effect on some platforms)
337    pub fn set_syntax(&mut self, syntax: Syntax) -> CsResult<()> {
338        // Todo(tmfink) check for valid syntax
339        let syntax_int = cs_opt_value::Type::from(syntax);
340        let result = self._set_cs_option(cs_opt_type::CS_OPT_SYNTAX, syntax_int as usize);
341
342        if result.is_ok() {
343            self.syntax = syntax_int;
344        }
345
346        result
347    }
348
349    define_set_mode!(
350    /// Set the endianness (has no effect on some platforms).
351    => pub, set_endian, CS_OPT_MODE, endian : Endian; cs_mode);
352    define_set_mode!(
353    /// Sets the engine's disassembly mode.
354    /// Be careful, various combinations of modes aren't supported
355    /// See the capstone-sys documentation for more information.
356    => pub, set_mode, CS_OPT_MODE, mode : Mode; cs_mode);
357
358    /// Returns a `CsResult` based on current `errno`.
359    /// If the `errno` is `CS_ERR_OK`, then `Ok(())` is returned. Otherwise, the error is returned.
360    fn error_result(&self) -> CsResult<()> {
361        let errno = unsafe { cs_errno(self.csh()) };
362        if errno == cs_err::CS_ERR_OK {
363            Ok(())
364        } else {
365            Err(errno.into())
366        }
367    }
368
369    /// Sets disassembling options at runtime.
370    ///
371    /// Acts as a safe wrapper around capstone's `cs_option`.
372    fn _set_cs_option(&mut self, option_type: cs_opt_type, option_value: usize) -> CsResult<()> {
373        let err = unsafe { cs_option(self.csh(), option_type, option_value) };
374
375        if cs_err::CS_ERR_OK == err {
376            Ok(())
377        } else {
378            Err(err.into())
379        }
380    }
381
382    /// Controls whether to capstone will generate extra details about disassembled instructions.
383    ///
384    /// Pass `true` to enable detail or `false` to disable detail.
385    pub fn set_detail(&mut self, enable_detail: bool) -> CsResult<()> {
386        let option_value: usize = OptValue::from(enable_detail).0 as usize;
387        let result = self._set_cs_option(cs_opt_type::CS_OPT_DETAIL, option_value);
388
389        // Only update internal state on success
390        if result.is_ok() {
391            self.detail_enabled = enable_detail;
392        }
393
394        result
395    }
396
397    /// Controls whether capstone will skip over invalid or data instructions.
398    ///
399    /// Pass `true` to enable skipdata or `false` to disable skipdata.
400    pub fn set_skipdata(&mut self, enable_skipdata: bool) -> CsResult<()> {
401        let option_value: usize = OptValue::from(enable_skipdata).0 as usize;
402        let result = self._set_cs_option(cs_opt_type::CS_OPT_SKIPDATA, option_value);
403
404        // Only update internal state on success
405        if result.is_ok() {
406            self.skipdata_enabled = enable_skipdata;
407        }
408
409        result
410    }
411
412    /// Controls whether capstone will print immediate operands in unsigned form.
413    ///
414    /// Pass `true` to enable unsigned or `false` to disable unsigned.
415    pub fn set_unsigned(&mut self, enable_unsigned: bool) -> CsResult<()> {
416        let option_value: usize = OptValue::from(enable_unsigned).0 as usize;
417        let result = self._set_cs_option(cs_opt_type::CS_OPT_UNSIGNED, option_value);
418
419        // Only update internal state on success
420        if result.is_ok() {
421            self.unsigned_enabled = enable_unsigned;
422        }
423
424        result
425    }
426
427    /// Customize mnemonic for instructions with alternative name.
428    ///
429    /// Pass `Some(mnemonic)` to enable custom mnemonic or `None` to revert to default.
430    #[cfg(feature = "std")]
431    pub fn set_mnemonic(&mut self, insn_id: InsnId, mnemonic: Option<&str>) -> CsResult<()> {
432        let mnemonic_cstr = match mnemonic {
433            Some(s) => Some(CString::new(s).map_err(|_err| {
434                Error::CustomError(
435                    "Failed to convert mnemonic to C-String due to internal NUL characters",
436                )
437            })?),
438            None => None,
439        };
440        self.set_mnemonic_cstr(insn_id, mnemonic_cstr.as_deref())
441    }
442
443    /// Customize mnemonic for instructions with alternative name, passing a core::ffi::CStr.
444    ///
445    /// Pass `Some(mnemonic)` to enable custom mnemonic or `None` to revert to default.
446    pub fn set_mnemonic_cstr(
447        &mut self,
448        insn_id: InsnId,
449        mnemonic_cstr: Option<&CStr>,
450    ) -> CsResult<()> {
451        let option_value: cs_opt_mnem = cs_opt_mnem {
452            id: insn_id.0,
453            mnemonic: mnemonic_cstr
454                .map(|s| s.as_ptr())
455                .unwrap_or(core::ptr::null()),
456        };
457        self._set_cs_option(
458            cs_opt_type::CS_OPT_MNEMONIC,
459            &option_value as *const cs_opt_mnem as usize,
460        )
461    }
462
463    /// Converts a register id `reg_id` to a `String` containing the register name.
464    /// Unavailable in Diet mode
465    pub fn reg_name(&self, reg_id: RegId) -> Option<String> {
466        if cfg!(feature = "full") {
467            let reg_name = unsafe {
468                let _reg_name = cs_reg_name(self.csh(), c_uint::from(reg_id.0));
469                str_from_cstr_ptr(_reg_name)?.to_string()
470            };
471            Some(reg_name)
472        } else {
473            None
474        }
475    }
476
477    /// Converts an instruction id `insn_id` to a `String` containing the instruction name.
478    /// Unavailable in Diet mode.
479    /// Note: This function ignores the current syntax and uses the default syntax.
480    pub fn insn_name(&self, insn_id: InsnId) -> Option<String> {
481        if cfg!(feature = "full") {
482            let insn_name = unsafe {
483                let _insn_name = cs_insn_name(self.csh(), insn_id.0 as c_uint);
484                str_from_cstr_ptr(_insn_name)?.to_string()
485            };
486
487            Some(insn_name)
488        } else {
489            None
490        }
491    }
492
493    /// Get the registers are which are read and written
494    pub(crate) fn regs_access<'buf>(
495        &self,
496        insn: &Insn,
497        regs_read: &'buf mut RegsAccessBuf,
498        regs_write: &'buf mut RegsAccessBuf,
499    ) -> CsResult<RegAccessRef<'buf>> {
500        if cfg!(feature = "full") {
501            let mut regs_read_count: u8 = 0;
502            let mut regs_write_count: u8 = 0;
503
504            let err = unsafe {
505                cs_regs_access(
506                    self.csh(),
507                    &insn.insn as *const cs_insn,
508                    regs_read.as_mut_ptr() as *mut cs_regs,
509                    &mut regs_read_count as *mut _,
510                    regs_write.as_mut_ptr() as *mut cs_regs,
511                    &mut regs_write_count as *mut _,
512                )
513            };
514
515            if err != cs_err::CS_ERR_OK {
516                return Err(err.into());
517            }
518
519            // SAFETY: count indicates how many elements are initialized;
520            let regs_read_slice: &[RegId] = unsafe {
521                core::slice::from_raw_parts(
522                    regs_read.as_mut_ptr() as *mut RegId,
523                    regs_read_count as usize,
524                )
525            };
526
527            // SAFETY: count indicates how many elements are initialized
528            let regs_write_slice: &[RegId] = unsafe {
529                core::slice::from_raw_parts(
530                    regs_write.as_mut_ptr() as *mut RegId,
531                    regs_write_count as usize,
532                )
533            };
534
535            Ok(RegAccessRef {
536                read: regs_read_slice,
537                write: regs_write_slice,
538            })
539        } else {
540            Err(Error::DetailOff)
541        }
542    }
543
544    /// Converts a group id `group_id` to a `String` containing the group name.
545    /// Unavailable in Diet mode
546    pub fn group_name(&self, group_id: InsnGroupId) -> Option<String> {
547        if cfg!(feature = "full") {
548            let group_name = unsafe {
549                let _group_name = cs_group_name(self.csh(), c_uint::from(group_id.0));
550                str_from_cstr_ptr(_group_name)?.to_string()
551            };
552
553            Some(group_name)
554        } else {
555            None
556        }
557    }
558
559    /// Returns `Detail` structure for a given instruction
560    ///
561    /// Requires:
562    ///
563    /// 1. Instruction was created with detail enabled
564    /// 2. Skipdata is disabled
565    pub fn insn_detail<'s, 'i: 's>(&'s self, insn: &'i Insn) -> CsResult<InsnDetail<'i>> {
566        if !self.detail_enabled {
567            Err(Error::DetailOff)
568        } else if insn.id().0 == 0 {
569            Err(Error::IrrelevantDataInSkipData)
570        } else {
571            // Call regs_access to get "extra" read/write registers for the instruction.
572            // Capstone only supports this for some architectures, so ignore errors if there are
573            // any.
574            //
575            // This *could* results in wasted effort if the read/write regs are not checked. As
576            // an optimization, we could call regs_access() lazily (i.e. only if InsnDetail
577            // regs_read()/regs_write() are called).
578            let partial_init_regs_access = {
579                let mut regs_buf = Box::new(crate::RWRegsAccessBuf::new());
580                match self.regs_access(insn, &mut regs_buf.read_buf, &mut regs_buf.write_buf) {
581                    Ok(regs_access) => {
582                        let read_len = regs_access.read.len() as u16;
583                        let write_len = regs_access.write.len() as u16;
584                        Some(PartialInitRegsAccess {
585                            regs_buf,
586                            read_len,
587                            write_len,
588                        })
589                    }
590                    Err(_) => None,
591                }
592            };
593
594            Ok(unsafe { insn.detail(self.arch, partial_init_regs_access) })
595        }
596    }
597
598    /// Returns a tuple (major, minor) indicating the version of the capstone C library.
599    pub fn lib_version() -> (u32, u32) {
600        let mut major: c_int = 0;
601        let mut minor: c_int = 0;
602        let major_ptr: *mut c_int = &mut major;
603        let minor_ptr: *mut c_int = &mut minor;
604
605        // We can ignore the "hexical" version returned by capstone because we already have the
606        // major and minor versions
607        let _ = unsafe { cs_version(major_ptr, minor_ptr) };
608
609        (major as u32, minor as u32)
610    }
611
612    /// Returns whether the capstone library supports a given architecture.
613    pub fn supports_arch(arch: Arch) -> bool {
614        unsafe { cs_support(cs_arch::from(arch) as c_int) }
615    }
616
617    /// Returns whether the capstone library was compiled in diet mode.
618    pub fn is_diet() -> bool {
619        unsafe { cs_support(CS_SUPPORT_DIET as c_int) }
620    }
621}
622
623impl Drop for Capstone {
624    fn drop(&mut self) {
625        unsafe { cs_close(&mut self.csh()) };
626    }
627}
628
629/// Structure to handle iterative disassembly.
630///
631/// Create with a [`Capstone`](Capstone) instance: [`Capstone::disasm_iter()`](Capstone::disasm_iter).
632///
633/// # Lifetimes
634///
635/// `'cs` is the lifetime of the [`Capstone`](Capstone) instance.
636/// `'buf` is the lifetime of the user provided code buffer in [`Capstone::disasm_iter()`](Capstone::disasm_iter).
637///
638pub struct DisasmIter<'cs, 'buf> {
639    insn: *mut cs_insn,            // space for current instruction to be processed
640    csh: *mut c_void,              // reference to the the capstone handle required by disasm_iter
641    code: *const u8,               // pointer to the code buffer
642    size: usize,                   // size of the code buffer
643    addr: u64,                     // current address
644    _data1: PhantomData<&'cs ()>, // used to make sure DisasmIter lifetime doesn't exceed Capstone's lifetime
645    _data2: PhantomData<&'buf ()>, // used to make sure code lifetime doesn't exceed user provided array
646}
647
648impl<'cs, 'buf> Drop for DisasmIter<'cs, 'buf> {
649    fn drop(&mut self) {
650        unsafe { cs_free(self.insn, 1) };
651    }
652}
653
654impl<'cs, 'buf> DisasmIter<'cs, 'buf> {
655    /// Get next instruction if available.
656    ///
657    /// # Examples
658    ///
659    /// ```
660    /// # use capstone::prelude::*;
661    /// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
662    /// let code = b"\x90";
663    /// let mut iter = cs.disasm_iter(code, 0x1000).unwrap();
664    /// while let Some(insn) = iter.next() {
665    ///     println!("{insn}");
666    /// }
667    /// ```
668    ///
669    /// At most one instruction can be accessed at the same time:
670    ///
671    /// ```compile_fail
672    /// # use capstone::prelude::*;
673    /// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
674    /// let code = b"\x90";
675    /// let mut iter = cs.disasm_iter(code, 0x1000).unwrap();
676    /// let insn1 = iter.next().unwrap();
677    /// let insn2 = iter.next().unwrap();
678    /// // fails with: cannot borrow `iter` as mutable more than once at a time,
679    /// // `insn1` cannot be used after calling `iter.next()` again,
680    /// // as `iter` is mutably borrowed during the second call to `next()`.
681    /// println!("{insn1}");
682    /// ```
683    pub fn next<'iter>(&'iter mut self) -> Option<Insn<'iter>> {
684        unsafe {
685            if cs_disasm_iter(
686                self.csh as csh,
687                &mut self.code,
688                &mut self.size,
689                &mut self.addr,
690                self.insn,
691            ) {
692                return Some(Insn::from_raw(self.insn));
693            }
694        }
695
696        None
697    }
698
699    /// Get the slice of the code yet to be disassembled
700    ///
701    /// ```
702    /// # use capstone::prelude::*;
703    /// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
704    /// let code = b"\x90";
705    /// let mut iter = cs.disasm_iter(code, 0x1000).unwrap();
706    /// assert_eq!(iter.code(), code);
707    /// iter.next();
708    /// assert_eq!(iter.code(), b"");
709    /// ```
710    pub fn code(&self) -> &[u8] {
711        unsafe { core::slice::from_raw_parts(self.code, self.size) }
712    }
713
714    /// Get the address of the next instruction to be disassembled
715    ///
716    /// ```
717    /// # use capstone::prelude::*;
718    /// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
719    /// let code = b"\x90";
720    /// let mut iter = cs.disasm_iter(code, 0x1000).unwrap();
721    /// assert_eq!(iter.addr(), 0x1000);
722    /// iter.next();
723    /// assert_eq!(iter.addr(), 0x1001);
724    /// ```
725    pub fn addr(&self) -> u64 {
726        self.addr
727    }
728
729    /// Reset the iterator to disassemble in the specified code buffer
730    ///
731    /// ```
732    /// # use capstone::prelude::*;
733    /// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
734    /// let code = b"\x90";
735    /// let mut iter = cs.disasm_iter(code, 0x1000).unwrap();
736    /// assert_eq!(iter.addr(), 0x1000);
737    /// assert_eq!(iter.code(), code);
738    /// iter.next();
739    /// assert_eq!(iter.addr(), 0x1001);
740    /// assert_eq!(iter.code(), b"");
741    /// let new_code = b"\xc3";
742    /// iter.reset(new_code, 0x2000);
743    /// assert_eq!(iter.addr(), 0x2000);
744    /// assert_eq!(iter.code(), new_code);
745    /// ```
746    pub fn reset(&mut self, code: &'buf [u8], addr: u64) {
747        self.code = code.as_ptr();
748        self.size = code.len();
749        self.addr = addr;
750    }
751}