11use alloc:: { boxed:: Box , string:: String , vec:: Vec } ;
22
3- use anyhow:: { Result , anyhow, bail} ;
3+ use anyhow:: { Context , Result , anyhow, bail} ;
44use iced_x86:: {
55 Decoder , DecoderOptions , DecoratorKind , FormatterOutput , FormatterTextKind , GasFormatter ,
66 Instruction , IntelFormatter , MasmFormatter , NasmFormatter , NumberKind , OpKind , Register ,
@@ -10,7 +10,9 @@ use object::{Endian as _, Object as _, ObjectSection as _, pe};
1010use crate :: {
1111 arch:: Arch ,
1212 diff:: { DiffObjConfig , X86Formatter , display:: InstructionPart } ,
13- obj:: { InstructionRef , RelocationFlags , ResolvedInstructionRef , ScannedInstruction } ,
13+ obj:: {
14+ InstructionRef , Relocation , RelocationFlags , ResolvedInstructionRef , ScannedInstruction ,
15+ } ,
1416} ;
1517
1618#[ derive( Debug ) ]
@@ -80,18 +82,48 @@ impl ArchX86 {
8082 }
8183}
8284
85+ const DATA_OPCODE : u16 = u16:: MAX - 1 ;
86+
8387impl Arch for ArchX86 {
8488 fn scan_instructions (
8589 & self ,
8690 address : u64 ,
8791 code : & [ u8 ] ,
8892 _section_index : usize ,
93+ relocations : & [ Relocation ] ,
8994 _diff_config : & DiffObjConfig ,
9095 ) -> Result < Vec < ScannedInstruction > > {
9196 let mut out = Vec :: with_capacity ( code. len ( ) / 2 ) ;
9297 let mut decoder = self . decoder ( code, address) ;
9398 let mut instruction = Instruction :: default ( ) ;
94- while decoder. can_decode ( ) {
99+ let mut reloc_iter = relocations. iter ( ) . peekable ( ) ;
100+ ' outer: while decoder. can_decode ( ) {
101+ let address = decoder. ip ( ) ;
102+ while let Some ( reloc) = reloc_iter. peek ( ) {
103+ if reloc. address < address {
104+ reloc_iter. next ( ) ;
105+ } else if reloc. address == address {
106+ // If the instruction starts at a relocation, it's inline data
107+ let size = self . reloc_size ( reloc. flags ) . with_context ( || {
108+ format ! ( "Unsupported inline x86 relocation {:?}" , reloc. flags)
109+ } ) ?;
110+ if decoder. set_position ( decoder. position ( ) + size) . is_ok ( ) {
111+ decoder. set_ip ( address + size as u64 ) ;
112+ out. push ( ScannedInstruction {
113+ ins_ref : InstructionRef {
114+ address,
115+ size : size as u8 ,
116+ opcode : DATA_OPCODE ,
117+ } ,
118+ branch_dest : None ,
119+ } ) ;
120+ reloc_iter. next ( ) ;
121+ continue ' outer;
122+ }
123+ } else {
124+ break ;
125+ }
126+ }
95127 decoder. decode_out ( & mut instruction) ;
96128 let branch_dest = match instruction. op0_kind ( ) {
97129 OpKind :: NearBranch16 => Some ( instruction. near_branch16 ( ) as u64 ) ,
@@ -101,7 +133,7 @@ impl Arch for ArchX86 {
101133 } ;
102134 out. push ( ScannedInstruction {
103135 ins_ref : InstructionRef {
104- address : instruction . ip ( ) ,
136+ address,
105137 size : instruction. len ( ) as u8 ,
106138 opcode : instruction. mnemonic ( ) as u16 ,
107139 } ,
@@ -117,6 +149,21 @@ impl Arch for ArchX86 {
117149 diff_config : & DiffObjConfig ,
118150 cb : & mut dyn FnMut ( InstructionPart ) -> Result < ( ) > ,
119151 ) -> Result < ( ) > {
152+ if resolved. ins_ref . opcode == DATA_OPCODE {
153+ let ( mnemonic, imm) = match resolved. ins_ref . size {
154+ 2 => ( ".word" , self . endianness . read_u16_bytes ( resolved. code . try_into ( ) ?) as u64 ) ,
155+ 4 => ( ".dword" , self . endianness . read_u32_bytes ( resolved. code . try_into ( ) ?) as u64 ) ,
156+ _ => bail ! ( "Unsupported x86 inline data size {}" , resolved. ins_ref. size) ,
157+ } ;
158+ cb ( InstructionPart :: opcode ( mnemonic, DATA_OPCODE ) ) ?;
159+ if resolved. relocation . is_some ( ) {
160+ cb ( InstructionPart :: reloc ( ) ) ?;
161+ } else {
162+ cb ( InstructionPart :: unsigned ( imm) ) ?;
163+ }
164+ return Ok ( ( ) ) ;
165+ }
166+
120167 let mut decoder = self . decoder ( resolved. code , resolved. ins_ref . address ) ;
121168 let mut formatter = self . formatter ( diff_config) ;
122169 let mut instruction = Instruction :: default ( ) ;
@@ -406,7 +453,7 @@ mod test {
406453 0xc7 , 0x85 , 0x68 , 0xff , 0xff , 0xff , 0x00 , 0x00 , 0x00 , 0x00 , 0x8b , 0x04 , 0x85 , 0x00 ,
407454 0x00 , 0x00 , 0x00 ,
408455 ] ;
409- let scanned = arch. scan_instructions ( 0 , & code, 0 , & DiffObjConfig :: default ( ) ) . unwrap ( ) ;
456+ let scanned = arch. scan_instructions ( 0 , & code, 0 , & [ ] , & DiffObjConfig :: default ( ) ) . unwrap ( ) ;
410457 assert_eq ! ( scanned. len( ) , 2 ) ;
411458 assert_eq ! ( scanned[ 0 ] . ins_ref. address, 0 ) ;
412459 assert_eq ! ( scanned[ 0 ] . ins_ref. size, 10 ) ;
0 commit comments