@@ -205,6 +205,43 @@ impl Capstone {
205
205
}
206
206
}
207
207
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
+
208
245
/// Disassemble all instructions in buffer
209
246
///
210
247
/// ```
@@ -590,3 +627,103 @@ impl Drop for Capstone {
590
627
unsafe { cs_close ( & mut self . csh ( ) ) } ;
591
628
}
592
629
}
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