@@ -227,18 +227,72 @@ impl Capstone {
227227 code : & ' b [ u8 ] ,
228228 addr : u64 ,
229229 ) -> CsResult < DisasmIter < ' a , ' b > > {
230+ let buffer = self . create_buffer ( ) ?;
231+ Ok ( self . disasm_iter_with_buffer ( code, addr, buffer) )
232+ }
233+
234+ /// Disassemble and iterate instructions from user-provided buffer `code` using `cs_disasm_iter`.
235+ /// The disassembled address of the buffer is assumed to be `addr`.
236+ /// The provided `buffer` is used to store the disassembled instruction.
237+ ///
238+ /// # Examples
239+ ///
240+ /// ```
241+ /// # use capstone::prelude::*;
242+ /// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
243+ /// let buffer = cs.create_buffer().unwrap();
244+ /// let mut iter = cs.disasm_iter_with_buffer(b"\x90", 0x1000, buffer);
245+ /// assert_eq!(iter.next().unwrap().mnemonic(), Some("nop"));
246+ /// assert!(iter.next().is_none());
247+ /// ```
248+ pub fn disasm_iter_with_buffer < ' cs , ' buf > (
249+ & ' cs self ,
250+ code : & ' buf [ u8 ] ,
251+ addr : u64 ,
252+ buffer : DisasmBuffer < ' cs > ,
253+ ) -> DisasmIter < ' cs , ' buf > {
254+ DisasmIter {
255+ buffer,
256+ code : code. as_ptr ( ) ,
257+ size : code. len ( ) ,
258+ addr,
259+ _data : PhantomData ,
260+ }
261+ }
262+
263+ /// Create a `DisasmBuffer`[DisasmBuffer] instance for future
264+ /// [`disasm_iter_with_buffer`](Capstone::disasm_iter_with_buffer)
265+ /// to reduce memory allocations.
266+ ///
267+ /// # Examples
268+ ///
269+ /// ```
270+ /// # use capstone::prelude::*;
271+ /// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
272+ /// let buffer = cs.create_buffer().unwrap();
273+ /// let mut iter = cs.disasm_iter_with_buffer(b"\x90", 0x1000, buffer);
274+ /// assert_eq!(iter.next().unwrap().mnemonic(), Some("nop"));
275+ /// assert!(iter.next().is_none());
276+ /// // Reuse the undelying buffer
277+ /// let buffer2 = iter.into_buffer();
278+ /// let mut iter2 = cs.disasm_iter_with_buffer(b"\xc3", 0x1000, buffer2);
279+ /// assert_eq!(iter2.next().unwrap().mnemonic(), Some("ret"));
280+ /// assert!(iter2.next().is_none());
281+ /// ```
282+ ///
283+ /// # Errors
284+ ///
285+ /// If `cs_malloc` failed due to OOM, [`Err(Error::OutOfMemory)`](Error::OutOfMemory) is returned.
286+ ///
287+ pub fn create_buffer < ' cs > ( & ' cs self ) -> CsResult < DisasmBuffer < ' cs > > {
230288 let insn = unsafe { cs_malloc ( self . csh ( ) ) } ;
231289 if insn. is_null ( ) {
232290 return Err ( Error :: OutOfMemory ) ;
233291 }
234- Ok ( DisasmIter {
292+ Ok ( DisasmBuffer {
235293 insn,
236294 csh : self . csh ,
237- code : code. as_ptr ( ) ,
238- size : code. len ( ) ,
239- addr,
240- _data1 : PhantomData ,
241- _data2 : PhantomData ,
295+ _data : PhantomData ,
242296 } )
243297 }
244298
@@ -628,31 +682,43 @@ impl Drop for Capstone {
628682 }
629683}
630684
631- /// Structure to handle iterative disassembly .
685+ /// Structure to hold the memory buffer for a disassembled instruction .
632686///
633- /// Create with a [`Capstone`](Capstone) instance: [`Capstone::disasm_iter()`](Capstone::disasm_iter).
687+ /// Create with a [`Capstone`](Capstone) instance: [`Capstone::create_buffer()`](Capstone::create_buffer).
688+ ///
689+ /// It deallocates memory via `cs_free` when dropped.
634690///
635691/// # Lifetimes
636692///
637693/// `'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
694+ pub struct DisasmBuffer < ' cs > {
695+ insn : * mut cs_insn , // space for disassembled instruction
696+ csh : * mut c_void , // reference to the the capstone handle
697+ _data : PhantomData < & ' cs ( ) > , // used to make sure DisasmBuffer lifetime doesn't exceed Capstone's lifetime
648698}
649699
650- impl < ' cs , ' buf > Drop for DisasmIter < ' cs , ' buf > {
700+ impl < ' cs > Drop for DisasmBuffer < ' cs > {
651701 fn drop ( & mut self ) {
652702 unsafe { cs_free ( self . insn , 1 ) } ;
653703 }
654704}
655705
706+ /// Structure to handle iterative disassembly.
707+ ///
708+ /// Create with a [`Capstone`](Capstone) instance: [`Capstone::disasm_iter()`](Capstone::disasm_iter).
709+ ///
710+ /// # Lifetimes
711+ ///
712+ /// `'cs` is the lifetime of the [`Capstone`](Capstone) instance.
713+ /// `'buf` is the lifetime of the user provided code buffer in [`Capstone::disasm_iter()`](Capstone::disasm_iter).
714+ pub struct DisasmIter < ' cs , ' buf > {
715+ buffer : DisasmBuffer < ' cs > , // buffer for current instruction to be processed
716+ code : * const u8 , // pointer to the code buffer
717+ size : usize , // size of the code buffer
718+ addr : u64 , // current address
719+ _data : PhantomData < & ' buf ( ) > , // used to make sure code lifetime doesn't exceed user provided array
720+ }
721+
656722impl < ' cs , ' buf > DisasmIter < ' cs , ' buf > {
657723 /// Get next instruction if available.
658724 ///
@@ -685,13 +751,13 @@ impl<'cs, 'buf> DisasmIter<'cs, 'buf> {
685751 pub fn next < ' iter > ( & ' iter mut self ) -> Option < Insn < ' iter > > {
686752 unsafe {
687753 if cs_disasm_iter (
688- self . csh as csh ,
754+ self . buffer . csh as csh ,
689755 & mut self . code ,
690756 & mut self . size ,
691757 & mut self . addr ,
692- self . insn ,
758+ self . buffer . insn ,
693759 ) {
694- return Some ( Insn :: from_raw ( self . insn ) ) ;
760+ return Some ( Insn :: from_raw ( self . buffer . insn ) ) ;
695761 }
696762 }
697763
@@ -750,4 +816,20 @@ impl<'cs, 'buf> DisasmIter<'cs, 'buf> {
750816 self . size = code. len ( ) ;
751817 self . addr = addr;
752818 }
819+
820+ /// Extract the underlying buffer for reuse.
821+ /// ```
822+ /// # use capstone::prelude::*;
823+ /// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
824+ /// let code = b"\x90";
825+ /// let mut iter = cs.disasm_iter(code, 0x1000).unwrap();
826+ /// assert!(iter.next().is_some());
827+ /// // reuse buffer
828+ /// let buffer = iter.into_buffer();
829+ /// let mut iter2 = cs.disasm_iter_with_buffer(code, 0x2000, buffer);
830+ /// assert!(iter2.next().is_some());
831+ /// ```
832+ pub fn into_buffer ( self ) -> DisasmBuffer < ' cs > {
833+ self . buffer
834+ }
753835}
0 commit comments