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}