1
+ use alloc:: boxed:: Box ;
1
2
use alloc:: string:: String ;
2
3
use core:: convert:: From ;
3
4
use core:: marker:: PhantomData ;
@@ -10,11 +11,24 @@ use capstone_sys::*;
10
11
11
12
use crate :: arch:: CapstoneBuilder ;
12
13
use crate :: constants:: { Arch , Endian , ExtraMode , Mode , OptValue , Syntax } ;
13
- use crate :: error:: * ;
14
14
use crate :: instruction:: { Insn , InsnDetail , InsnGroupId , InsnId , Instructions , RegId } ;
15
+ use crate :: { error:: * , PartialInitRegsAccess } ;
15
16
16
17
use { crate :: ffi:: str_from_cstr_ptr, alloc:: string:: ToString , libc:: c_uint} ;
17
18
19
+ /// Length of `cs_regs`
20
+ pub ( crate ) const REGS_ACCESS_BUF_LEN : usize = 64 ;
21
+
22
+ // todo(tmfink) When MSRV is 1.75 or later, can use:
23
+ //pub(crate) const REGS_ACCESS_BUF_LEN: usize = unsafe { core::mem::zeroed::<cs_regs>() }.len();
24
+
25
+ /// Equivalent to `MaybeUninit<cs_regs>`
26
+ pub ( crate ) type RegsAccessBuf = [ MaybeUninit < RegId > ; REGS_ACCESS_BUF_LEN ] ;
27
+
28
+ static_assertions:: assert_eq_size!( RegId , u16 ) ;
29
+ static_assertions:: assert_eq_size!( RegsAccessBuf , cs_regs) ;
30
+ static_assertions:: assert_type_eq_all!( [ u16 ; REGS_ACCESS_BUF_LEN ] , cs_regs) ;
31
+
18
32
/// An instance of the capstone disassembler
19
33
///
20
34
/// Create with an instance with [`.new()`](Self::new) and disassemble bytes with [`.disasm_all()`](Self::disasm_all).
@@ -101,17 +115,19 @@ impl Iterator for EmptyExtraModeIter {
101
115
}
102
116
}
103
117
104
- #[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
105
- pub struct RegAccess {
106
- pub read : Vec < RegId > ,
107
- pub write : Vec < RegId > ,
118
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
119
+ pub struct RegAccessRef < ' a > {
120
+ pub ( crate ) read : & ' a [ RegId ] ,
121
+ pub ( crate ) write : & ' a [ RegId ] ,
108
122
}
109
123
110
- impl RegAccess {
111
- /// Sort read and write fields
112
- pub fn sort ( & mut self ) {
113
- self . read . sort_unstable ( ) ;
114
- self . write . sort_unstable ( ) ;
124
+ impl RegAccessRef < ' _ > {
125
+ pub fn read ( & self ) -> & [ RegId ] {
126
+ self . read
127
+ }
128
+
129
+ pub fn write ( & self ) -> & [ RegId ] {
130
+ self . write
115
131
}
116
132
}
117
133
@@ -380,39 +396,24 @@ impl Capstone {
380
396
}
381
397
}
382
398
383
- // todo(tmfink): integrate into regs_read()/regs_write() methods to avoid the need to call
384
- /// Get the registers which are read and written
385
- pub fn regs_access ( & self , insn : & Insn ) -> CsResult < RegAccess > {
386
- let mut read = Vec :: new ( ) ;
387
- let mut write = Vec :: new ( ) ;
388
-
389
- self . regs_access_buf ( insn, & mut read, & mut write) ?;
390
-
391
- Ok ( RegAccess { read, write } )
392
- }
393
-
394
- /// Get the registers are which are read and written.
395
- /// The registers are pushed to the back of the provided buffers
396
- pub ( crate ) fn regs_access_buf (
399
+ /// Get the registers are which are read and written
400
+ pub ( crate ) fn regs_access < ' buf > (
397
401
& self ,
398
402
insn : & Insn ,
399
- read : & mut Vec < RegId > ,
400
- write : & mut Vec < RegId > ,
401
- ) -> CsResult < ( ) > {
403
+ regs_read : & ' buf mut RegsAccessBuf ,
404
+ regs_write : & ' buf mut RegsAccessBuf ,
405
+ ) -> CsResult < RegAccessRef < ' buf > > {
402
406
if cfg ! ( feature = "full" ) {
403
407
let mut regs_read_count: u8 = 0 ;
404
408
let mut regs_write_count: u8 = 0 ;
405
409
406
- let mut regs_write: MaybeUninit < cs_regs > = MaybeUninit :: uninit ( ) ;
407
- let mut regs_read: MaybeUninit < cs_regs > = MaybeUninit :: uninit ( ) ;
408
-
409
410
let err = unsafe {
410
411
cs_regs_access (
411
412
self . csh ( ) ,
412
413
& insn. insn as * const cs_insn ,
413
- regs_read. as_mut_ptr ( ) ,
414
+ regs_read. as_mut_ptr ( ) as * mut cs_regs ,
414
415
& mut regs_read_count as * mut _ ,
415
- regs_write. as_mut_ptr ( ) ,
416
+ regs_write. as_mut_ptr ( ) as * mut cs_regs ,
416
417
& mut regs_write_count as * mut _ ,
417
418
)
418
419
} ;
@@ -423,23 +424,24 @@ impl Capstone {
423
424
424
425
// SAFETY: count indicates how many elements are initialized;
425
426
let regs_read_slice: & [ RegId ] = unsafe {
426
- std :: slice:: from_raw_parts (
427
+ core :: slice:: from_raw_parts (
427
428
regs_read. as_mut_ptr ( ) as * mut RegId ,
428
429
regs_read_count as usize ,
429
430
)
430
431
} ;
431
- read. extend_from_slice ( regs_read_slice) ;
432
432
433
433
// SAFETY: count indicates how many elements are initialized
434
434
let regs_write_slice: & [ RegId ] = unsafe {
435
- std :: slice:: from_raw_parts (
435
+ core :: slice:: from_raw_parts (
436
436
regs_write. as_mut_ptr ( ) as * mut RegId ,
437
437
regs_write_count as usize ,
438
438
)
439
439
} ;
440
- write. extend_from_slice ( regs_write_slice) ;
441
440
442
- Ok ( ( ) )
441
+ Ok ( RegAccessRef {
442
+ read : regs_read_slice,
443
+ write : regs_write_slice,
444
+ } )
443
445
} else {
444
446
Err ( Error :: DetailOff )
445
447
}
@@ -472,7 +474,30 @@ impl Capstone {
472
474
} else if insn. id ( ) . 0 == 0 {
473
475
Err ( Error :: IrrelevantDataInSkipData )
474
476
} else {
475
- Ok ( unsafe { insn. detail ( self . arch ) } )
477
+ // Call regs_access to get "extra" read/write registers for the instruction.
478
+ // Capstone only supports this for some architectures, so ignore errors if there are
479
+ // any.
480
+ //
481
+ // This *could* results in wasted effort if the read/write regs are not checked. As
482
+ // an optimization, we could call regs_access() lazily (i.e. only if InsnDetail
483
+ // regs_read()/regs_write() are called).
484
+ let partial_init_regs_access = {
485
+ let mut regs_buf = Box :: new ( crate :: RWRegsAccessBuf :: new ( ) ) ;
486
+ match self . regs_access ( insn, & mut regs_buf. read_buf , & mut regs_buf. write_buf ) {
487
+ Ok ( regs_access) => {
488
+ let read_len = regs_access. read . len ( ) as u16 ;
489
+ let write_len = regs_access. write . len ( ) as u16 ;
490
+ Some ( PartialInitRegsAccess {
491
+ regs_buf,
492
+ read_len,
493
+ write_len,
494
+ } )
495
+ }
496
+ Err ( _) => None ,
497
+ }
498
+ } ;
499
+
500
+ Ok ( unsafe { insn. detail ( self . arch , partial_init_regs_access) } )
476
501
}
477
502
}
478
503
0 commit comments