Skip to content

Commit aca4722

Browse files
committed
Merge branch 'recursive2'
2 parents 9ec8f57 + 8577759 commit aca4722

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

capstone-rs/src/capstone.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,43 @@ impl Capstone {
205205
}
206206
}
207207

208+
/// Disassemble and iterate instructions from user-provided buffer `code` using `cs_disasm_iter`.
209+
/// The disassembled address of the buffer is assumed to be `addr`.
210+
/// It uses less memory and reduces memory allocations.
211+
///
212+
/// # Examples
213+
///
214+
/// ```
215+
/// # use capstone::prelude::*;
216+
/// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
217+
/// let mut iter = cs.disasm_iter(b"\x90", 0x1000).unwrap();
218+
/// assert_eq!(iter.next().unwrap().mnemonic(), Some("nop"));
219+
/// assert!(iter.next().is_none());
220+
/// ```
221+
///
222+
/// # Errors
223+
///
224+
/// If `cs_malloc` failed due to OOM, [`Err(Error::OutOfMemory)`](Error::OutOfMemory) is returned.
225+
pub fn disasm_iter<'a, 'b>(
226+
&'a self,
227+
code: &'b [u8],
228+
addr: u64,
229+
) -> CsResult<DisasmIter<'a, 'b>> {
230+
let insn = unsafe { cs_malloc(self.csh()) };
231+
if insn.is_null() {
232+
return Err(Error::OutOfMemory);
233+
}
234+
Ok(DisasmIter {
235+
insn,
236+
csh: self.csh,
237+
code: code.as_ptr(),
238+
size: code.len(),
239+
addr,
240+
_data1: PhantomData,
241+
_data2: PhantomData,
242+
})
243+
}
244+
208245
/// Disassemble all instructions in buffer
209246
///
210247
/// ```
@@ -590,3 +627,103 @@ impl Drop for Capstone {
590627
unsafe { cs_close(&mut self.csh()) };
591628
}
592629
}
630+
631+
/// Structure to handle iterative disassembly.
632+
///
633+
/// Create with a [`Capstone`](Capstone) instance: [`Capstone::disasm_iter()`](Capstone::disasm_iter).
634+
///
635+
/// # Lifetimes
636+
///
637+
/// `'cs` is the lifetime of the [`Capstone`](Capstone) instance.
638+
/// `'buf` is the lifetime of the user provided code buffer in [`Capstone::disasm_iter()`](Capstone::disasm_iter).
639+
///
640+
pub struct DisasmIter<'cs, 'buf> {
641+
insn: *mut cs_insn, // space for current instruction to be processed
642+
csh: *mut c_void, // reference to the the capstone handle required by disasm_iter
643+
code: *const u8, // pointer to the code buffer
644+
size: usize, // size of the code buffer
645+
addr: u64, // current address
646+
_data1: PhantomData<&'cs ()>, // used to make sure DisasmIter lifetime doesn't exceed Capstone's lifetime
647+
_data2: PhantomData<&'buf ()>, // used to make sure code lifetime doesn't exceed user provided array
648+
}
649+
650+
impl<'cs, 'buf> Drop for DisasmIter<'cs, 'buf> {
651+
fn drop(&mut self) {
652+
unsafe { cs_free(self.insn, 1) };
653+
}
654+
}
655+
656+
impl<'cs, 'buf> Iterator for DisasmIter<'cs, 'buf> {
657+
type Item = Insn<'cs>;
658+
659+
fn next(&mut self) -> Option<Self::Item> {
660+
unsafe {
661+
if cs_disasm_iter(
662+
self.csh as csh,
663+
&mut self.code,
664+
&mut self.size,
665+
&mut self.addr,
666+
self.insn,
667+
) {
668+
return Some(Insn::from_raw(self.insn));
669+
}
670+
}
671+
672+
None
673+
}
674+
}
675+
676+
impl<'cs, 'buf> DisasmIter<'cs, 'buf> {
677+
/// Get the slice of the code yet to be disassembled
678+
///
679+
/// ```
680+
/// # use capstone::prelude::*;
681+
/// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
682+
/// let code = b"\x90";
683+
/// let mut iter = cs.disasm_iter(code, 0x1000).unwrap();
684+
/// assert_eq!(iter.code(), code);
685+
/// iter.next();
686+
/// assert_eq!(iter.code(), b"");
687+
/// ```
688+
pub fn code(&self) -> &[u8] {
689+
unsafe { core::slice::from_raw_parts(self.code, self.size) }
690+
}
691+
692+
/// Get the address of the next instruction to be disassembled
693+
///
694+
/// ```
695+
/// # use capstone::prelude::*;
696+
/// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
697+
/// let code = b"\x90";
698+
/// let mut iter = cs.disasm_iter(code, 0x1000).unwrap();
699+
/// assert_eq!(iter.addr(), 0x1000);
700+
/// iter.next();
701+
/// assert_eq!(iter.addr(), 0x1001);
702+
/// ```
703+
pub fn addr(&self) -> u64 {
704+
self.addr
705+
}
706+
707+
/// Reset the iterator to disassemble in the specified code buffer
708+
///
709+
/// ```
710+
/// # use capstone::prelude::*;
711+
/// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
712+
/// let code = b"\x90";
713+
/// let mut iter = cs.disasm_iter(code, 0x1000).unwrap();
714+
/// assert_eq!(iter.addr(), 0x1000);
715+
/// assert_eq!(iter.code(), code);
716+
/// iter.next();
717+
/// assert_eq!(iter.addr(), 0x1001);
718+
/// assert_eq!(iter.code(), b"");
719+
/// let new_code = b"\xc3";
720+
/// iter.reset(new_code, 0x2000);
721+
/// assert_eq!(iter.addr(), 0x2000);
722+
/// assert_eq!(iter.code(), new_code);
723+
/// ```
724+
pub fn reset(&mut self, code: &'buf [u8], addr: u64) {
725+
self.code = code.as_ptr();
726+
self.size = code.len();
727+
self.addr = addr;
728+
}
729+
}

0 commit comments

Comments
 (0)