1
1
use std:: { borrow:: Cow , collections:: BTreeMap } ;
2
2
3
- use anyhow:: { bail, Result } ;
4
- use object:: { elf, File , Relocation , RelocationFlags } ;
3
+ use anyhow:: { bail, ensure, Result } ;
4
+ use cwextab:: { decode_extab, ExceptionTableData } ;
5
+ use object:: {
6
+ elf, File , Object , ObjectSection , ObjectSymbol , Relocation , RelocationFlags , RelocationTarget ,
7
+ Symbol , SymbolKind ,
8
+ } ;
5
9
use ppc750cl:: { Argument , InsIter , GPR } ;
6
10
7
11
use crate :: {
8
12
arch:: { ObjArch , ProcessCodeResult } ,
9
13
diff:: DiffObjConfig ,
10
- obj:: { ObjIns , ObjInsArg , ObjInsArgValue , ObjReloc , ObjSection } ,
14
+ obj:: { ObjIns , ObjInsArg , ObjInsArgValue , ObjReloc , ObjSection , ObjSymbol } ,
11
15
} ;
12
16
13
17
// Relative relocation, can be Simm, Offset or BranchDest
@@ -22,10 +26,13 @@ fn is_rel_abs_arg(arg: &Argument) -> bool {
22
26
23
27
fn is_offset_arg ( arg : & Argument ) -> bool { matches ! ( arg, Argument :: Offset ( _) ) }
24
28
25
- pub struct ObjArchPpc { }
29
+ pub struct ObjArchPpc {
30
+ /// Exception info
31
+ pub extab : Option < BTreeMap < usize , ExceptionInfo > > ,
32
+ }
26
33
27
34
impl ObjArchPpc {
28
- pub fn new ( _file : & File ) -> Result < Self > { Ok ( Self { } ) }
35
+ pub fn new ( file : & File ) -> Result < Self > { Ok ( Self { extab : decode_exception_info ( file ) ? } ) }
29
36
}
30
37
31
38
impl ObjArch for ObjArchPpc {
@@ -178,6 +185,14 @@ impl ObjArch for ObjArchPpc {
178
185
_ => Cow :: Owned ( format ! ( "<{flags:?}>" ) ) ,
179
186
}
180
187
}
188
+
189
+ fn ppc ( & self ) -> Option < & ObjArchPpc > { Some ( self ) }
190
+ }
191
+
192
+ impl ObjArchPpc {
193
+ pub fn extab_for_symbol ( & self , symbol : & ObjSymbol ) -> Option < & ExceptionInfo > {
194
+ symbol. original_index . and_then ( |i| self . extab . as_ref ( ) ?. get ( & i) )
195
+ }
181
196
}
182
197
183
198
fn push_reloc ( args : & mut Vec < ObjInsArg > , reloc : & ObjReloc ) -> Result < ( ) > {
@@ -208,3 +223,128 @@ fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
208
223
} ;
209
224
Ok ( ( ) )
210
225
}
226
+
227
+ #[ derive( Debug , Clone ) ]
228
+ pub struct ExtabSymbolRef {
229
+ pub original_index : usize ,
230
+ pub name : String ,
231
+ pub demangled_name : Option < String > ,
232
+ }
233
+
234
+ #[ derive( Debug , Clone ) ]
235
+ pub struct ExceptionInfo {
236
+ pub eti_symbol : ExtabSymbolRef ,
237
+ pub etb_symbol : ExtabSymbolRef ,
238
+ pub data : ExceptionTableData ,
239
+ pub dtors : Vec < ExtabSymbolRef > ,
240
+ }
241
+
242
+ fn decode_exception_info ( file : & File < ' _ > ) -> Result < Option < BTreeMap < usize , ExceptionInfo > > > {
243
+ let Some ( extab_section) = file. section_by_name ( "extab" ) else {
244
+ return Ok ( None ) ;
245
+ } ;
246
+ let Some ( extabindex_section) = file. section_by_name ( "extabindex" ) else {
247
+ return Ok ( None ) ;
248
+ } ;
249
+
250
+ let mut result = BTreeMap :: new ( ) ;
251
+ let extab_relocations = extab_section. relocations ( ) . collect :: < BTreeMap < u64 , Relocation > > ( ) ;
252
+ let extabindex_relocations =
253
+ extabindex_section. relocations ( ) . collect :: < BTreeMap < u64 , Relocation > > ( ) ;
254
+
255
+ for extabindex in file. symbols ( ) . filter ( |symbol| {
256
+ symbol. section_index ( ) == Some ( extabindex_section. index ( ) )
257
+ && symbol. kind ( ) == SymbolKind :: Data
258
+ } ) {
259
+ if extabindex. size ( ) != 12 {
260
+ log:: warn!( "Invalid extabindex entry size {}" , extabindex. size( ) ) ;
261
+ continue ;
262
+ }
263
+
264
+ // Each extabindex entry has two relocations:
265
+ // - 0x0: The function that the exception table is for
266
+ // - 0x8: The relevant entry in extab section
267
+ let Some ( extab_func_reloc) = extabindex_relocations. get ( & extabindex. address ( ) ) else {
268
+ log:: warn!( "Failed to find function relocation for extabindex entry" ) ;
269
+ continue ;
270
+ } ;
271
+ let Some ( extab_reloc) = extabindex_relocations. get ( & ( extabindex. address ( ) + 8 ) ) else {
272
+ log:: warn!( "Failed to find extab relocation for extabindex entry" ) ;
273
+ continue ;
274
+ } ;
275
+
276
+ // Resolve the function and extab symbols
277
+ let Some ( extab_func) = relocation_symbol ( file, extab_func_reloc) ? else {
278
+ log:: warn!( "Failed to find function symbol for extabindex entry" ) ;
279
+ continue ;
280
+ } ;
281
+ let extab_func_name = extab_func. name ( ) ?;
282
+ let Some ( extab) = relocation_symbol ( file, extab_reloc) ? else {
283
+ log:: warn!( "Failed to find extab symbol for extabindex entry" ) ;
284
+ continue ;
285
+ } ;
286
+
287
+ let extab_start_addr = extab. address ( ) - extab_section. address ( ) ;
288
+ let extab_end_addr = extab_start_addr + extab. size ( ) ;
289
+
290
+ // All relocations in the extab section are dtors
291
+ let mut dtors: Vec < ExtabSymbolRef > = vec ! [ ] ;
292
+ for ( _, reloc) in extab_relocations. range ( extab_start_addr..extab_end_addr) {
293
+ let Some ( symbol) = relocation_symbol ( file, reloc) ? else {
294
+ log:: warn!( "Failed to find symbol for extab relocation" ) ;
295
+ continue ;
296
+ } ;
297
+ dtors. push ( make_symbol_ref ( & symbol) ?) ;
298
+ }
299
+
300
+ // Decode the extab data
301
+ let Some ( extab_data) = extab_section. data_range ( extab_start_addr, extab. size ( ) ) ? else {
302
+ log:: warn!( "Failed to get extab data for function {}" , extab_func_name) ;
303
+ continue ;
304
+ } ;
305
+ let data = match decode_extab ( extab_data) {
306
+ Some ( decoded_data) => decoded_data,
307
+ None => {
308
+ log:: warn!( "Exception table decoding failed for function {}" , extab_func_name) ;
309
+ return Ok ( None ) ;
310
+ }
311
+ } ;
312
+
313
+ //Add the new entry to the list
314
+ result. insert ( extab_func. index ( ) . 0 , ExceptionInfo {
315
+ eti_symbol : make_symbol_ref ( & extabindex) ?,
316
+ etb_symbol : make_symbol_ref ( & extab) ?,
317
+ data,
318
+ dtors,
319
+ } ) ;
320
+ }
321
+
322
+ Ok ( Some ( result) )
323
+ }
324
+
325
+ fn relocation_symbol < ' data , ' file > (
326
+ file : & ' file File < ' data > ,
327
+ relocation : & Relocation ,
328
+ ) -> Result < Option < Symbol < ' data , ' file > > > {
329
+ let addend = relocation. addend ( ) ;
330
+ match relocation. target ( ) {
331
+ RelocationTarget :: Symbol ( idx) => {
332
+ ensure ! ( addend == 0 , "Symbol relocations must have zero addend" ) ;
333
+ Ok ( Some ( file. symbol_by_index ( idx) ?) )
334
+ }
335
+ RelocationTarget :: Section ( idx) => {
336
+ ensure ! ( addend >= 0 , "Section relocations must have non-negative addend" ) ;
337
+ let addend = addend as u64 ;
338
+ Ok ( file
339
+ . symbols ( )
340
+ . find ( |symbol| symbol. section_index ( ) == Some ( idx) && symbol. address ( ) == addend) )
341
+ }
342
+ target => bail ! ( "Unsupported relocation target: {target:?}" ) ,
343
+ }
344
+ }
345
+
346
+ fn make_symbol_ref ( symbol : & Symbol ) -> Result < ExtabSymbolRef > {
347
+ let name = symbol. name ( ) ?. to_string ( ) ;
348
+ let demangled_name = cwdemangle:: demangle ( & name, & cwdemangle:: DemangleOptions :: default ( ) ) ;
349
+ Ok ( ExtabSymbolRef { original_index : symbol. index ( ) . 0 , name, demangled_name } )
350
+ }
0 commit comments