88
99namespace ApplicationUtility ;
1010
11- class SharedLibrary : IAspect , IDisposable
11+ public class SharedLibrary : IAspect , IDisposable
1212{
1313 const uint ELF_MAGIC = 0x464c457f ;
1414 const string DebugLinkSectionName = ".gnu_debuglink" ;
1515 const string PayloadSectionName = "payload" ;
1616
17- readonly IELF elf ;
18- readonly NativeArchitecture nativeArch = NativeArchitecture . Unknown ;
19- readonly Stream libraryStream ;
20- readonly bool hasDebugInfo ;
21- readonly bool is64Bit ;
22- readonly string libraryName ;
2317 readonly string ? androidIdent ;
2418 readonly string ? buildId ;
2519 readonly string ? debugLink ;
20+ readonly IELF elf ;
21+ readonly bool hasDebugInfo ;
22+ readonly bool is64Bit ;
2623 readonly ulong libraryAlignment ;
24+ readonly string libraryName ;
25+ readonly Stream libraryStream ;
26+ readonly NativeArchitecture nativeArch = NativeArchitecture . Unknown ;
2727 readonly ulong payloadOffset ;
2828 readonly ulong payloadSize ;
29+ readonly string ? soname ;
2930
3031 bool disposed ;
3132
3233 public static string AspectName { get ; } = "Native shared library" ;
3334
34- public NativeArchitecture TargetArchitecture => nativeArch ;
35+ public ulong Alignment => libraryAlignment ;
36+ public bool AlignmentCompatibleWith16k => libraryAlignment >= 0x4000 && ( libraryAlignment % 0x4000 == 0 ) ;
37+ public string ? AndroidIdent => androidIdent ;
38+ public string ? BuildID => buildId ;
39+ public string ? DebugLink => debugLink ;
3540 public bool HasAndroidIdent => ! String . IsNullOrEmpty ( androidIdent ) ;
3641 public bool HasAndroidPayload => payloadSize > 0 ;
3742 public bool HasBuildID => ! String . IsNullOrEmpty ( buildId ) ;
3843 public bool HasDebugInfo => hasDebugInfo ;
3944 public bool HasDebugLink => ! String . IsNullOrEmpty ( debugLink ) ;
45+ public bool HasSoname => ! String . IsNullOrEmpty ( soname ) ;
4046 public bool Is64Bit => is64Bit ;
4147 public string Name => libraryName ;
42- public string ? AndroidIdent => androidIdent ;
43- public string ? BuildID => buildId ;
44- public string ? DebugLink => debugLink ;
45- public ulong Alignment => libraryAlignment ;
48+ public string ? Soname => soname ;
49+ public NativeArchitecture TargetArchitecture => nativeArch ;
4650
4751 protected IELF ELF => elf ;
4852
@@ -56,6 +60,7 @@ protected SharedLibrary (Stream stream, string libraryName)
5660 ( hasDebugInfo , debugLink ) = DetectDebugInfo ( elf , libraryName ) ;
5761 buildId = GetBuildID ( elf , is64Bit ) ;
5862 androidIdent = GetAndroidIdent ( elf , is64Bit ) ;
63+ soname = GetSoname ( elf , is64Bit ) ;
5964 }
6065
6166 public static IAspect LoadAspect ( Stream stream , IAspectState ? state , string ? description )
@@ -291,23 +296,73 @@ static ulong DetectAlignment (IELF elf, bool is64Bit)
291296 return 0 ;
292297 }
293298
299+ static string ? GetSoname ( IELF elf , bool is64Bit )
300+ {
301+ IDynamicEntry ? sonameEntry = null ;
302+
303+ foreach ( IDynamicSection section in elf . GetSections < IDynamicSection > ( ) ) {
304+ foreach ( IDynamicEntry dyne in section . Entries ) {
305+ if ( dyne . Tag != DynamicTag . SoName ) {
306+ continue ;
307+ }
308+ sonameEntry = dyne ;
309+ break ;
310+ }
311+
312+ if ( sonameEntry != null ) {
313+ break ;
314+ }
315+ }
316+
317+ if ( sonameEntry == null ) {
318+ return null ;
319+ }
320+
321+ ulong stringIndex = is64Bit switch {
322+ true => ( ( DynamicEntry < ulong > ) sonameEntry ) . Value ,
323+ false => ( ( DynamicEntry < uint > ) sonameEntry ) . Value
324+ } ;
325+
326+ // Offset is into the .dynstr section
327+ if ( ! elf . TryGetSection ( ".dynstr" , out ISection ? strtabSection ) || strtabSection == null || strtabSection . Type != SectionType . StringTable ) {
328+ return null ;
329+ }
330+
331+ var strtab = ( IStringTable ) strtabSection ;
332+ try {
333+ return strtab [ ( long ) stringIndex ] ;
334+ } catch ( Exception ex ) {
335+ Log . Debug ( $ "Failed to obtain soname from the string table (asked for index { stringIndex } )", ex ) ;
336+ return null ;
337+ }
338+ }
339+
294340 static string ? GetBuildID ( IELF elf , bool is64Bit )
295341 {
296- byte [ ] ? contents = GetNoteSectionContents ( elf , is64Bit , ".note.gnu.build-id" ) ;
342+ // From elf_common.h
343+ //
344+ // #define NT_GNU_BUILD_ID 3
345+ //
346+ const ulong NT_GNU_BUILD_ID = 0 ;
347+ byte [ ] ? contents = GetNoteSectionContents ( elf , is64Bit , ".note.gnu.build-id" , NT_GNU_BUILD_ID ) ;
297348 if ( contents == null ) {
298349 return null ;
299350 }
300351
301- // TODO: decode
302- return "decoding not implemented yet" ;
352+ var sb = new StringBuilder ( ) ;
353+ foreach ( byte b in contents ) {
354+ sb . Append ( $ "{ b : x02} ") ;
355+ }
356+
357+ return sb . ToString ( ) ;
303358 }
304359
305360 static string ? GetAndroidIdent ( IELF elf , bool is64Bit )
306361 {
307362 return GetNoteSectionContentsAsString ( elf , is64Bit , ".note.android.ident" ) ; ;
308363 }
309364
310- static string ? GetNoteSectionContentsAsString ( IELF elf , bool is64Bit , string sectionName )
365+ static string ? GetNoteSectionContentsAsString ( IELF elf , bool is64Bit , string sectionName , ulong noteType = 0 )
311366 {
312367 byte [ ] ? contents = GetNoteSectionContents ( elf , is64Bit , sectionName ) ;
313368 if ( contents == null ) {
@@ -317,13 +372,27 @@ static ulong DetectAlignment (IELF elf, bool is64Bit)
317372 return Encoding . UTF8 . GetString ( contents ) ;
318373 }
319374
320- static byte [ ] ? GetNoteSectionContents ( IELF elf , bool is64Bit , string sectionName )
375+ static byte [ ] ? GetNoteSectionContents ( IELF elf , bool is64Bit , string sectionName , ulong noteType = 0 )
321376 {
322377 if ( ! elf . TryGetSection ( sectionName , out ISection ? section ) || section == null || section . Type != SectionType . Note ) {
323378 return null ;
324379 }
325380
326- return ( ( INoteSection ) section ) . Description ;
381+ var note = ( INoteSection ) section ;
382+ if ( noteType == 0 ) {
383+ return note . Description ;
384+ }
385+
386+ ulong type = is64Bit switch {
387+ true => ( ( NoteSection < ulong > ) note ) . NoteType ,
388+ false => ( ( NoteSection < uint > ) note ) . NoteType
389+ } ;
390+
391+ if ( type != noteType ) {
392+ return null ;
393+ }
394+
395+ return note . Description ;
327396 }
328397
329398 public bool HasSection ( string name , SectionType type = SectionType . Null )
0 commit comments