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,23 @@ 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 = const {
21
+ // SAFETY: integers can have 0 value; in const context
22
+ let regs: cs_regs = unsafe { core:: mem:: zeroed ( ) } ;
23
+ regs. len ( )
24
+ } ;
25
+
26
+ /// Equivalent to `MaybeUninit<cs_regs>`
27
+ pub ( crate ) type RegsAccessBuf = [ MaybeUninit < RegId > ; REGS_ACCESS_BUF_LEN ] ;
28
+
29
+ static_assertions:: assert_eq_size!( RegsAccessBuf , cs_regs) ;
30
+
18
31
/// An instance of the capstone disassembler
19
32
///
20
33
/// Create with an instance with [`.new()`](Self::new) and disassemble bytes with [`.disasm_all()`](Self::disasm_all).
@@ -101,17 +114,19 @@ impl Iterator for EmptyExtraModeIter {
101
114
}
102
115
}
103
116
104
- #[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
105
- pub struct RegAccess {
106
- pub read : Vec < RegId > ,
107
- pub write : Vec < RegId > ,
117
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
118
+ pub struct RegAccessRef < ' a > {
119
+ pub ( crate ) read : & ' a [ RegId ] ,
120
+ pub ( crate ) write : & ' a [ RegId ] ,
108
121
}
109
122
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 ( ) ;
123
+ impl RegAccessRef < ' _ > {
124
+ pub fn read ( & self ) -> & [ RegId ] {
125
+ self . read
126
+ }
127
+
128
+ pub fn write ( & self ) -> & [ RegId ] {
129
+ self . write
115
130
}
116
131
}
117
132
@@ -380,39 +395,24 @@ impl Capstone {
380
395
}
381
396
}
382
397
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 (
398
+ /// Get the registers are which are read and written
399
+ pub ( crate ) fn regs_access < ' buf > (
397
400
& self ,
398
401
insn : & Insn ,
399
- read : & mut Vec < RegId > ,
400
- write : & mut Vec < RegId > ,
401
- ) -> CsResult < ( ) > {
402
+ regs_read : & ' buf mut RegsAccessBuf ,
403
+ regs_write : & ' buf mut RegsAccessBuf ,
404
+ ) -> CsResult < RegAccessRef < ' buf > > {
402
405
if cfg ! ( feature = "full" ) {
403
406
let mut regs_read_count: u8 = 0 ;
404
407
let mut regs_write_count: u8 = 0 ;
405
408
406
- let mut regs_write: MaybeUninit < cs_regs > = MaybeUninit :: uninit ( ) ;
407
- let mut regs_read: MaybeUninit < cs_regs > = MaybeUninit :: uninit ( ) ;
408
-
409
409
let err = unsafe {
410
410
cs_regs_access (
411
411
self . csh ( ) ,
412
412
& insn. insn as * const cs_insn ,
413
- regs_read. as_mut_ptr ( ) ,
413
+ regs_read. as_mut_ptr ( ) as * mut cs_regs ,
414
414
& mut regs_read_count as * mut _ ,
415
- regs_write. as_mut_ptr ( ) ,
415
+ regs_write. as_mut_ptr ( ) as * mut cs_regs ,
416
416
& mut regs_write_count as * mut _ ,
417
417
)
418
418
} ;
@@ -423,23 +423,24 @@ impl Capstone {
423
423
424
424
// SAFETY: count indicates how many elements are initialized;
425
425
let regs_read_slice: & [ RegId ] = unsafe {
426
- std :: slice:: from_raw_parts (
426
+ core :: slice:: from_raw_parts (
427
427
regs_read. as_mut_ptr ( ) as * mut RegId ,
428
428
regs_read_count as usize ,
429
429
)
430
430
} ;
431
- read. extend_from_slice ( regs_read_slice) ;
432
431
433
432
// SAFETY: count indicates how many elements are initialized
434
433
let regs_write_slice: & [ RegId ] = unsafe {
435
- std :: slice:: from_raw_parts (
434
+ core :: slice:: from_raw_parts (
436
435
regs_write. as_mut_ptr ( ) as * mut RegId ,
437
436
regs_write_count as usize ,
438
437
)
439
438
} ;
440
- write. extend_from_slice ( regs_write_slice) ;
441
439
442
- Ok ( ( ) )
440
+ Ok ( RegAccessRef {
441
+ read : regs_read_slice,
442
+ write : regs_write_slice,
443
+ } )
443
444
} else {
444
445
Err ( Error :: DetailOff )
445
446
}
@@ -472,7 +473,30 @@ impl Capstone {
472
473
} else if insn. id ( ) . 0 == 0 {
473
474
Err ( Error :: IrrelevantDataInSkipData )
474
475
} else {
475
- Ok ( unsafe { insn. detail ( self . arch ) } )
476
+ // Call regs_access to get "extra" read/write registers for the instruction.
477
+ // Capstone only supports this for some architectures, so ignore errors if there are
478
+ // any.
479
+ //
480
+ // This *could* results in wasted effort if the read/write regs are not checked. As
481
+ // an optimization, we could call regs_access() lazily (i.e. only if InsnDetail
482
+ // regs_read()/regs_write() are called).
483
+ let partial_init_regs_access = {
484
+ let mut regs_buf = Box :: new ( crate :: RWRegsAccessBuf :: new ( ) ) ;
485
+ match self . regs_access ( insn, & mut regs_buf. read_buf , & mut regs_buf. write_buf ) {
486
+ Ok ( regs_access) => {
487
+ let read_len = regs_access. read . len ( ) as u16 ;
488
+ let write_len = regs_access. write . len ( ) as u16 ;
489
+ Some ( PartialInitRegsAccess {
490
+ regs_buf,
491
+ read_len,
492
+ write_len,
493
+ } )
494
+ }
495
+ Err ( _) => None ,
496
+ }
497
+ } ;
498
+
499
+ Ok ( unsafe { insn. detail ( self . arch , partial_init_regs_access) } )
476
500
}
477
501
}
478
502
0 commit comments