@@ -214,7 +214,10 @@ class ElfHeader {
214214 static const _ELFDATA2MSB = 0x02 ;
215215
216216 void writeToStringBuffer (StringBuffer buffer) {
217- buffer..write ('Format is ' )..write (wordSize * 8 )..write (' bits' );
217+ buffer
218+ ..write ('Format is ' )
219+ ..write (wordSize * 8 )
220+ ..write (' bits' );
218221 switch (endian) {
219222 case Endian .little:
220223 buffer..writeln (' and little-endian' );
@@ -342,6 +345,15 @@ class ProgramHeader {
342345 int get length => _entries.length;
343346 ProgramHeaderEntry operator [](int index) => _entries[index];
344347
348+ ProgramHeaderEntry ? loadSegmentFor (int address) {
349+ for (final entry in _entries) {
350+ if (entry.vaddr <= address && address <= entry.vaddr + entry.memsz) {
351+ return entry;
352+ }
353+ }
354+ return null ;
355+ }
356+
345357 static ProgramHeader fromReader (Reader reader, ElfHeader header) {
346358 final programReader = reader.refocusedCopy (
347359 header.programHeaderOffset, header.programHeaderSize);
@@ -352,7 +364,10 @@ class ProgramHeader {
352364
353365 void writeToStringBuffer (StringBuffer buffer) {
354366 for (var i = 0 ; i < length; i++ ) {
355- if (i != 0 ) buffer..writeln ()..writeln ();
367+ if (i != 0 )
368+ buffer
369+ ..writeln ()
370+ ..writeln ();
356371 buffer
357372 ..write ('Entry ' )
358373 ..write (i)
@@ -422,6 +437,17 @@ class SectionHeaderEntry {
422437 static const _SHT_NOBITS = 8 ;
423438 static const _SHT_DYNSYM = 11 ;
424439
440+ // sh_flags constants from ELF specification.
441+ static const _SHF_WRITE = 0x1 ;
442+ static const _SHF_ALLOC = 0x2 ;
443+ static const _SHF_EXECINSTR = 0x4 ;
444+
445+ bool get isWritable => flags & _SHF_WRITE != 0 ;
446+ bool get isAllocated => flags & _SHF_ALLOC != 0 ;
447+ bool get isExecutable => flags & _SHF_EXECINSTR != 0 ;
448+
449+ bool get hasBits => type != _SHT_NOBITS ;
450+
425451 void setName (StringTable nameTable) {
426452 name = nameTable[nameIndex]! ;
427453 }
@@ -495,7 +521,10 @@ class SectionHeader {
495521
496522 void writeToStringBuffer (StringBuffer buffer) {
497523 for (var i = 0 ; i < entries.length; i++ ) {
498- if (i != 0 ) buffer..writeln ()..writeln ();
524+ if (i != 0 )
525+ buffer
526+ ..writeln ()
527+ ..writeln ();
499528 buffer
500529 ..write ('Entry ' )
501530 ..write (i)
@@ -536,6 +565,8 @@ class Section {
536565 return SymbolTable .fromReader (reader, entry);
537566 case SectionHeaderEntry ._SHT_NOTE :
538567 return Note .fromReader (reader, entry);
568+ case SectionHeaderEntry ._SHT_DYNAMIC :
569+ return DynamicTable .fromReader (reader, entry);
539570 default :
540571 return Section ._(entry);
541572 }
@@ -713,7 +744,10 @@ class Symbol {
713744 SymbolVisibility get visibility => SymbolVisibility .values[other & 0x03 ];
714745
715746 void writeToStringBuffer (StringBuffer buffer) {
716- buffer..write ('"' )..write (name)..write ('" =>' );
747+ buffer
748+ ..write ('"' )
749+ ..write (name)
750+ ..write ('" =>' );
717751 switch (bind) {
718752 case SymbolBinding .STB_GLOBAL :
719753 buffer..write (' a global' );
@@ -794,6 +828,109 @@ class SymbolTable extends Section {
794828 }
795829}
796830
831+ /// Represents d_tag constants from ELF specification.
832+ enum DynamicTableTag {
833+ DT_NULL ,
834+ DT_NEEDED ,
835+ DT_PLTRELSZ ,
836+ DT_PLTGOT ,
837+ DT_HASH ,
838+ DT_STRTAB ,
839+ DT_SYMTAB ,
840+ DT_RELA ,
841+ DT_RELASZ ,
842+ DT_RELAENT ,
843+ DT_STRSZ ,
844+ DT_SYMENT ,
845+ // Later d_tag values are not currently used in Dart ELF files.
846+ }
847+
848+ /// The dynamic table, which contains entries pointing to various relocated
849+ /// addresses.
850+ class DynamicTable extends Section {
851+ // We don't use DynamicTableTag for the key so that we can handle ELF files
852+ // that may use unknown (to us) tags.
853+ final Map <int , int > _entries;
854+ final _wordSize;
855+
856+ DynamicTable ._(SectionHeaderEntry entry, this ._entries, this ._wordSize)
857+ : super ._(entry);
858+
859+ static DynamicTable fromReader (Reader reader, SectionHeaderEntry entry) {
860+ final sectionReader = reader.refocusedCopy (entry.offset, entry.size);
861+ final entries = < int , int > {};
862+ while (true ) {
863+ // Each entry is a tag and a value, both native word sized.
864+ final tag = _readElfNative (sectionReader);
865+ final value = _readElfNative (sectionReader);
866+ // A DT_NULL entry signfies the end of entries.
867+ if (tag == DynamicTableTag .DT_NULL .index) break ;
868+ entries[tag] = value;
869+ }
870+ return DynamicTable ._(entry, entries, sectionReader.wordSize);
871+ }
872+
873+ int ? operator [](DynamicTableTag tag) => _entries[tag.index];
874+ bool containsKey (DynamicTableTag tag) => _entries.containsKey (tag.index);
875+
876+ // To avoid depending on EnumName.name from 2.15.
877+ static const _tagStrings = {
878+ DynamicTableTag .DT_NULL : 'DT_NULL' ,
879+ DynamicTableTag .DT_NEEDED : 'DT_NEEDED' ,
880+ DynamicTableTag .DT_PLTRELSZ : 'DT_PLTRELSZ' ,
881+ DynamicTableTag .DT_PLTGOT : 'DT_PLTGOT' ,
882+ DynamicTableTag .DT_HASH : 'DT_HASH' ,
883+ DynamicTableTag .DT_STRTAB : 'DT_STRTAB' ,
884+ DynamicTableTag .DT_SYMTAB : 'DT_SYMTAB' ,
885+ DynamicTableTag .DT_RELA : 'DT_RELA' ,
886+ DynamicTableTag .DT_RELASZ : 'DT_RELASZ' ,
887+ DynamicTableTag .DT_STRSZ : 'DT_STRSZ' ,
888+ DynamicTableTag .DT_SYMENT : 'DT_SYMENT' ,
889+ };
890+ static final _maxTagStringLength = (_tagStrings.values.toList ()
891+ ..sort ((s1, s2) => s2.length - s1.length))
892+ .first
893+ .length;
894+
895+ @override
896+ void writeToStringBuffer (StringBuffer buffer) {
897+ buffer
898+ ..write ('Section "' )
899+ ..write (headerEntry.name)
900+ ..writeln ('" is a dynamic table:' );
901+ for (var kv in _entries.entries) {
902+ buffer.write (' ' );
903+ if (kv.key < DynamicTableTag .values.length) {
904+ final tag = DynamicTableTag .values[kv.key];
905+ buffer
906+ ..write (_tagStrings[tag]? .padRight (_maxTagStringLength))
907+ ..write (' => ' );
908+ switch (tag) {
909+ // These are relocated addresses.
910+ case DynamicTableTag .DT_HASH :
911+ case DynamicTableTag .DT_PLTGOT :
912+ case DynamicTableTag .DT_SYMTAB :
913+ case DynamicTableTag .DT_STRTAB :
914+ case DynamicTableTag .DT_RELA :
915+ buffer
916+ ..write ('0x' )
917+ ..writeln (paddedHex (kv.value, _wordSize));
918+ break ;
919+ // Other entries are just values or offsets.
920+ default :
921+ buffer.writeln (kv.value);
922+ }
923+ } else {
924+ buffer
925+ ..write ("Unknown tag " )
926+ ..write (kv.key)
927+ ..write (' => ' )
928+ ..writeln (kv.value);
929+ }
930+ }
931+ }
932+ }
933+
797934/// Information parsed from an Executable and Linking Format (ELF) file.
798935class Elf {
799936 final ElfHeader _header;
@@ -819,6 +956,21 @@ class Elf {
819956 Iterable <Section > namedSections (String name) =>
820957 _sectionsByName[name] ?? < Section > [];
821958
959+ /// Checks that the contents of a given section have valid addresses when the
960+ /// file contents for the corresponding segment is loaded into memory.
961+ ///
962+ /// Returns false for sections that are not allocated or where the address
963+ /// does not correspond to file contents (i.e., NOBITS sections).
964+ bool sectionHasValidSegmentAddresses (Section section) {
965+ final headerEntry = section.headerEntry;
966+ if (! headerEntry.isAllocated || ! headerEntry.hasBits) return false ;
967+ final segment = _programHeader.loadSegmentFor (headerEntry.addr);
968+ if (segment == null ) return false ;
969+ return (headerEntry.addr < (segment.vaddr + segment.filesz)) &&
970+ (headerEntry.addr + headerEntry.size) <=
971+ (segment.vaddr + segment.filesz);
972+ }
973+
822974 /// Lookup of a dynamic symbol by name.
823975 ///
824976 /// Returns -1 if there is no dynamic symbol that matches [name] .
0 commit comments