@@ -214,7 +214,10 @@ class ElfHeader {
214
214
static const _ELFDATA2MSB = 0x02 ;
215
215
216
216
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' );
218
221
switch (endian) {
219
222
case Endian .little:
220
223
buffer..writeln (' and little-endian' );
@@ -342,6 +345,15 @@ class ProgramHeader {
342
345
int get length => _entries.length;
343
346
ProgramHeaderEntry operator [](int index) => _entries[index];
344
347
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
+
345
357
static ProgramHeader fromReader (Reader reader, ElfHeader header) {
346
358
final programReader = reader.refocusedCopy (
347
359
header.programHeaderOffset, header.programHeaderSize);
@@ -352,7 +364,10 @@ class ProgramHeader {
352
364
353
365
void writeToStringBuffer (StringBuffer buffer) {
354
366
for (var i = 0 ; i < length; i++ ) {
355
- if (i != 0 ) buffer..writeln ()..writeln ();
367
+ if (i != 0 )
368
+ buffer
369
+ ..writeln ()
370
+ ..writeln ();
356
371
buffer
357
372
..write ('Entry ' )
358
373
..write (i)
@@ -422,6 +437,17 @@ class SectionHeaderEntry {
422
437
static const _SHT_NOBITS = 8 ;
423
438
static const _SHT_DYNSYM = 11 ;
424
439
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
+
425
451
void setName (StringTable nameTable) {
426
452
name = nameTable[nameIndex]! ;
427
453
}
@@ -495,7 +521,10 @@ class SectionHeader {
495
521
496
522
void writeToStringBuffer (StringBuffer buffer) {
497
523
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 ();
499
528
buffer
500
529
..write ('Entry ' )
501
530
..write (i)
@@ -536,6 +565,8 @@ class Section {
536
565
return SymbolTable .fromReader (reader, entry);
537
566
case SectionHeaderEntry ._SHT_NOTE :
538
567
return Note .fromReader (reader, entry);
568
+ case SectionHeaderEntry ._SHT_DYNAMIC :
569
+ return DynamicTable .fromReader (reader, entry);
539
570
default :
540
571
return Section ._(entry);
541
572
}
@@ -713,7 +744,10 @@ class Symbol {
713
744
SymbolVisibility get visibility => SymbolVisibility .values[other & 0x03 ];
714
745
715
746
void writeToStringBuffer (StringBuffer buffer) {
716
- buffer..write ('"' )..write (name)..write ('" =>' );
747
+ buffer
748
+ ..write ('"' )
749
+ ..write (name)
750
+ ..write ('" =>' );
717
751
switch (bind) {
718
752
case SymbolBinding .STB_GLOBAL :
719
753
buffer..write (' a global' );
@@ -794,6 +828,109 @@ class SymbolTable extends Section {
794
828
}
795
829
}
796
830
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
+
797
934
/// Information parsed from an Executable and Linking Format (ELF) file.
798
935
class Elf {
799
936
final ElfHeader _header;
@@ -819,6 +956,21 @@ class Elf {
819
956
Iterable <Section > namedSections (String name) =>
820
957
_sectionsByName[name] ?? < Section > [];
821
958
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
+
822
974
/// Lookup of a dynamic symbol by name.
823
975
///
824
976
/// Returns -1 if there is no dynamic symbol that matches [name] .
0 commit comments