@@ -4,9 +4,11 @@ use std::{
4
4
} ;
5
5
6
6
use anyhow:: { bail, Result } ;
7
+ use arm_attr:: { enums:: CpuArch , tag:: Tag , BuildAttrs } ;
7
8
use object:: {
8
- elf, File , Object , ObjectSection , ObjectSymbol , Relocation , RelocationFlags , SectionIndex ,
9
- SectionKind , Symbol ,
9
+ elf:: { self , SHT_ARM_ATTRIBUTES } ,
10
+ Endian , File , Object , ObjectSection , ObjectSymbol , Relocation , RelocationFlags , SectionIndex ,
11
+ SectionKind , Symbol , SymbolKind ,
10
12
} ;
11
13
use unarm:: {
12
14
args:: { Argument , OffsetImm , OffsetReg , Register } ,
@@ -16,41 +18,93 @@ use unarm::{
16
18
17
19
use crate :: {
18
20
arch:: { ObjArch , ProcessCodeResult } ,
19
- diff:: DiffObjConfig ,
21
+ diff:: { ArmArchVersion , DiffObjConfig } ,
20
22
obj:: { ObjIns , ObjInsArg , ObjInsArgValue , ObjReloc , ObjSection } ,
21
23
} ;
22
24
23
25
pub struct ObjArchArm {
24
26
/// Maps section index, to list of disasm modes (arm, thumb or data) sorted by address
25
27
disasm_modes : HashMap < SectionIndex , Vec < DisasmMode > > ,
28
+ detected_version : Option < ArmVersion > ,
29
+ endianness : object:: Endianness ,
26
30
}
27
31
28
32
impl ObjArchArm {
29
33
pub fn new ( file : & File ) -> Result < Self > {
34
+ let endianness = file. endianness ( ) ;
30
35
match file {
31
36
File :: Elf32 ( _) => {
32
- let disasm_modes: HashMap < _ , _ > = file
33
- . sections ( )
34
- . filter ( |s| s. kind ( ) == SectionKind :: Text )
35
- . map ( |s| {
36
- let index = s. index ( ) ;
37
- let mut mapping_symbols: Vec < _ > = file
38
- . symbols ( )
39
- . filter ( |s| s. section_index ( ) . map ( |i| i == index) . unwrap_or ( false ) )
40
- . filter_map ( |s| DisasmMode :: from_symbol ( & s) )
41
- . collect ( ) ;
42
- mapping_symbols. sort_unstable_by_key ( |x| x. address ) ;
43
- ( s. index ( ) , mapping_symbols)
44
- } )
45
- . collect ( ) ;
46
- Ok ( Self { disasm_modes } )
37
+ let disasm_modes = Self :: elf_get_mapping_symbols ( file) ;
38
+ let detected_version = Self :: elf_detect_arm_version ( file) ?;
39
+ Ok ( Self { disasm_modes, detected_version, endianness } )
47
40
}
48
41
_ => bail ! ( "Unsupported file format {:?}" , file. format( ) ) ,
49
42
}
50
43
}
44
+
45
+ fn elf_detect_arm_version ( file : & File ) -> Result < Option < ArmVersion > > {
46
+ // Check ARM attributes
47
+ if let Some ( arm_attrs) = file. sections ( ) . find ( |s| {
48
+ s. kind ( ) == SectionKind :: Elf ( SHT_ARM_ATTRIBUTES ) && s. name ( ) == Ok ( ".ARM.attributes" )
49
+ } ) {
50
+ let attr_data = arm_attrs. uncompressed_data ( ) ?;
51
+ let build_attrs = BuildAttrs :: new ( & attr_data, match file. endianness ( ) {
52
+ object:: Endianness :: Little => arm_attr:: Endian :: Little ,
53
+ object:: Endianness :: Big => arm_attr:: Endian :: Big ,
54
+ } ) ?;
55
+ for subsection in build_attrs. subsections ( ) {
56
+ let subsection = subsection?;
57
+ if !subsection. is_aeabi ( ) {
58
+ continue ;
59
+ }
60
+ // Only checking first CpuArch tag. Others may exist, but that's very unlikely.
61
+ let cpu_arch = subsection. into_public_tag_iter ( ) ?. find_map ( |( _, tag) | {
62
+ if let Tag :: CpuArch ( cpu_arch) = tag {
63
+ Some ( cpu_arch)
64
+ } else {
65
+ None
66
+ }
67
+ } ) ;
68
+ match cpu_arch {
69
+ Some ( CpuArch :: V4T ) => return Ok ( Some ( ArmVersion :: V4T ) ) ,
70
+ Some ( CpuArch :: V5TE ) => return Ok ( Some ( ArmVersion :: V5Te ) ) ,
71
+ Some ( CpuArch :: V6K ) => return Ok ( Some ( ArmVersion :: V6K ) ) ,
72
+ Some ( arch) => bail ! ( "ARM arch {} not supported" , arch) ,
73
+ None => { }
74
+ } ;
75
+ }
76
+ }
77
+
78
+ Ok ( None )
79
+ }
80
+
81
+ fn elf_get_mapping_symbols ( file : & File ) -> HashMap < SectionIndex , Vec < DisasmMode > > {
82
+ file. sections ( )
83
+ . filter ( |s| s. kind ( ) == SectionKind :: Text )
84
+ . map ( |s| {
85
+ let index = s. index ( ) ;
86
+ let mut mapping_symbols: Vec < _ > = file
87
+ . symbols ( )
88
+ . filter ( |s| s. section_index ( ) . map ( |i| i == index) . unwrap_or ( false ) )
89
+ . filter_map ( |s| DisasmMode :: from_symbol ( & s) )
90
+ . collect ( ) ;
91
+ mapping_symbols. sort_unstable_by_key ( |x| x. address ) ;
92
+ ( s. index ( ) , mapping_symbols)
93
+ } )
94
+ . collect ( )
95
+ }
51
96
}
52
97
53
98
impl ObjArch for ObjArchArm {
99
+ fn symbol_address ( & self , symbol : & Symbol ) -> u64 {
100
+ let address = symbol. address ( ) ;
101
+ if symbol. kind ( ) == SymbolKind :: Text {
102
+ address & !1
103
+ } else {
104
+ address
105
+ }
106
+ }
107
+
54
108
fn process_code (
55
109
& self ,
56
110
address : u64 ,
@@ -81,10 +135,21 @@ impl ObjArch for ObjArchArm {
81
135
mapping_symbols. iter ( ) . skip ( first_mapping_idx + 1 ) . take_while ( |x| x. address < end_addr) ;
82
136
let mut next_mapping = mappings_iter. next ( ) ;
83
137
84
- let ins_count = code. len ( ) / first_mapping. instruction_size ( ) ;
138
+ let ins_count = code. len ( ) / first_mapping. instruction_size ( start_addr ) ;
85
139
let mut ops = Vec :: < u16 > :: with_capacity ( ins_count) ;
86
140
let mut insts = Vec :: < ObjIns > :: with_capacity ( ins_count) ;
87
- let mut parser = Parser :: new ( ArmVersion :: V5Te , first_mapping, start_addr, code) ;
141
+
142
+ let version = match config. arm_arch_version {
143
+ ArmArchVersion :: Auto => self . detected_version . unwrap_or ( ArmVersion :: V5Te ) ,
144
+ ArmArchVersion :: V4T => ArmVersion :: V4T ,
145
+ ArmArchVersion :: V5TE => ArmVersion :: V5Te ,
146
+ ArmArchVersion :: V6K => ArmVersion :: V6K ,
147
+ } ;
148
+ let endian = match self . endianness {
149
+ object:: Endianness :: Little => unarm:: Endian :: Little ,
150
+ object:: Endianness :: Big => unarm:: Endian :: Big ,
151
+ } ;
152
+ let mut parser = Parser :: new ( version, first_mapping, start_addr, endian, code) ;
88
153
89
154
while let Some ( ( address, op, ins) ) = parser. next ( ) {
90
155
if let Some ( next) = next_mapping {
@@ -95,19 +160,26 @@ impl ObjArch for ObjArchArm {
95
160
next_mapping = mappings_iter. next ( ) ;
96
161
}
97
162
}
98
-
99
163
let line = line_info. range ( ..=address as u64 ) . last ( ) . map ( |( _, & b) | b) ;
100
164
101
165
let reloc = relocations. iter ( ) . find ( |r| ( r. address as u32 & !1 ) == address) . cloned ( ) ;
102
166
103
167
let mut reloc_arg = None ;
104
168
if let Some ( reloc) = & reloc {
105
169
match reloc. flags {
170
+ // Calls
106
171
RelocationFlags :: Elf { r_type : elf:: R_ARM_THM_XPC22 }
107
- | RelocationFlags :: Elf { r_type : elf:: R_ARM_PC24 } => {
172
+ | RelocationFlags :: Elf { r_type : elf:: R_ARM_THM_PC22 }
173
+ | RelocationFlags :: Elf { r_type : elf:: R_ARM_PC24 }
174
+ | RelocationFlags :: Elf { r_type : elf:: R_ARM_XPC25 }
175
+ | RelocationFlags :: Elf { r_type : elf:: R_ARM_CALL } => {
108
176
reloc_arg =
109
177
ins. args . iter ( ) . rposition ( |a| matches ! ( a, Argument :: BranchDest ( _) ) ) ;
110
178
}
179
+ // Data
180
+ RelocationFlags :: Elf { r_type : elf:: R_ARM_ABS32 } => {
181
+ reloc_arg = ins. args . iter ( ) . rposition ( |a| matches ! ( a, Argument :: UImm ( _) ) ) ;
182
+ }
111
183
_ => ( ) ,
112
184
}
113
185
} ;
@@ -138,11 +210,42 @@ impl ObjArch for ObjArchArm {
138
210
139
211
fn implcit_addend (
140
212
& self ,
141
- _section : & ObjSection ,
213
+ section : & ObjSection ,
142
214
address : u64 ,
143
215
reloc : & Relocation ,
144
216
) -> anyhow:: Result < i64 > {
145
- bail ! ( "Unsupported ARM implicit relocation {:#x}{:?}" , address, reloc. flags( ) )
217
+ let address = address as usize ;
218
+ Ok ( match reloc. flags ( ) {
219
+ // ARM calls
220
+ RelocationFlags :: Elf { r_type : elf:: R_ARM_PC24 }
221
+ | RelocationFlags :: Elf { r_type : elf:: R_ARM_XPC25 }
222
+ | RelocationFlags :: Elf { r_type : elf:: R_ARM_CALL } => {
223
+ let data = section. data [ address..address + 4 ] . try_into ( ) ?;
224
+ let addend = self . endianness . read_i32_bytes ( data) ;
225
+ let imm24 = addend & 0xffffff ;
226
+ ( imm24 << 2 ) << 8 >> 8
227
+ }
228
+
229
+ // Thumb calls
230
+ RelocationFlags :: Elf { r_type : elf:: R_ARM_THM_PC22 }
231
+ | RelocationFlags :: Elf { r_type : elf:: R_ARM_THM_XPC22 } => {
232
+ let data = section. data [ address..address + 2 ] . try_into ( ) ?;
233
+ let high = self . endianness . read_i16_bytes ( data) as i32 ;
234
+ let data = section. data [ address + 2 ..address + 4 ] . try_into ( ) ?;
235
+ let low = self . endianness . read_i16_bytes ( data) as i32 ;
236
+
237
+ let imm22 = ( ( high & 0x7ff ) << 11 ) | ( low & 0x7ff ) ;
238
+ ( imm22 << 1 ) << 9 >> 9
239
+ }
240
+
241
+ // Data
242
+ RelocationFlags :: Elf { r_type : elf:: R_ARM_ABS32 } => {
243
+ let data = section. data [ address..address + 4 ] . try_into ( ) ?;
244
+ self . endianness . read_i32_bytes ( data)
245
+ }
246
+
247
+ flags => bail ! ( "Unsupported ARM implicit relocation {flags:?}" ) ,
248
+ } as i64 )
146
249
}
147
250
148
251
fn demangle ( & self , name : & str ) -> Option < String > {
@@ -209,6 +312,7 @@ fn push_args(
209
312
args. push ( ObjInsArg :: Reloc ) ;
210
313
} else {
211
314
match arg {
315
+ Argument :: None => { }
212
316
Argument :: Reg ( reg) => {
213
317
if reg. deref {
214
318
deref = true ;
@@ -242,7 +346,7 @@ fn push_args(
242
346
args. push ( ObjInsArg :: Arg ( ObjInsArgValue :: Opaque ( "^" . to_string ( ) . into ( ) ) ) ) ;
243
347
}
244
348
}
245
- Argument :: UImm ( value) | Argument :: CoOpcode ( value) => {
349
+ Argument :: UImm ( value) | Argument :: CoOpcode ( value) | Argument :: SatImm ( value ) => {
246
350
args. push ( ObjInsArg :: PlainText ( "#" . into ( ) ) ) ;
247
351
args. push ( ObjInsArg :: Arg ( ObjInsArgValue :: Unsigned ( * value as u64 ) ) ) ;
248
352
}
@@ -282,7 +386,21 @@ fn push_args(
282
386
offset. reg . to_string ( ) . into ( ) ,
283
387
) ) ) ;
284
388
}
285
- _ => args. push ( ObjInsArg :: Arg ( ObjInsArgValue :: Opaque ( arg. to_string ( ) . into ( ) ) ) ) ,
389
+ Argument :: CpsrMode ( mode) => {
390
+ args. push ( ObjInsArg :: PlainText ( "#" . into ( ) ) ) ;
391
+ args. push ( ObjInsArg :: Arg ( ObjInsArgValue :: Unsigned ( mode. mode as u64 ) ) ) ;
392
+ if mode. writeback {
393
+ args. push ( ObjInsArg :: Arg ( ObjInsArgValue :: Opaque ( "!" . into ( ) ) ) ) ;
394
+ }
395
+ }
396
+ Argument :: CoReg ( _)
397
+ | Argument :: StatusReg ( _)
398
+ | Argument :: StatusMask ( _)
399
+ | Argument :: Shift ( _)
400
+ | Argument :: CpsrFlags ( _)
401
+ | Argument :: Endian ( _) => {
402
+ args. push ( ObjInsArg :: Arg ( ObjInsArgValue :: Opaque ( arg. to_string ( ) . into ( ) ) ) )
403
+ }
286
404
}
287
405
}
288
406
}
0 commit comments