11use std:: { borrow:: Cow , collections:: BTreeMap } ;
22
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+ } ;
59use ppc750cl:: { Argument , InsIter , GPR } ;
610
711use crate :: {
812 arch:: { ObjArch , ProcessCodeResult } ,
913 diff:: DiffObjConfig ,
10- obj:: { ObjIns , ObjInsArg , ObjInsArgValue , ObjReloc , ObjSection } ,
14+ obj:: { ObjIns , ObjInsArg , ObjInsArgValue , ObjReloc , ObjSection , ObjSymbol } ,
1115} ;
1216
1317// Relative relocation, can be Simm, Offset or BranchDest
@@ -22,10 +26,13 @@ fn is_rel_abs_arg(arg: &Argument) -> bool {
2226
2327fn is_offset_arg ( arg : & Argument ) -> bool { matches ! ( arg, Argument :: Offset ( _) ) }
2428
25- pub struct ObjArchPpc { }
29+ pub struct ObjArchPpc {
30+ /// Exception info
31+ pub extab : Option < BTreeMap < usize , ExceptionInfo > > ,
32+ }
2633
2734impl 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 ) ? } ) }
2936}
3037
3138impl ObjArch for ObjArchPpc {
@@ -178,6 +185,14 @@ impl ObjArch for ObjArchPpc {
178185 _ => Cow :: Owned ( format ! ( "<{flags:?}>" ) ) ,
179186 }
180187 }
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+ }
181196}
182197
183198fn push_reloc ( args : & mut Vec < ObjInsArg > , reloc : & ObjReloc ) -> Result < ( ) > {
@@ -208,3 +223,128 @@ fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
208223 } ;
209224 Ok ( ( ) )
210225}
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