fromReader static method
Creates an Elf from the data pointed to by reader
.
After succesful completion, the endian
and wordSize
fields of the
reader are set to match the values read from the ELF header. The position
of the reader will be unchanged.
Returns null if the file does not start with the ELF magic number.
Implementation
static Elf? fromReader(Reader elfReader) {
// ELF files contain absolute offsets from the start of the file, so
// make sure we have a reader that a) makes no assumptions about the
// endianness or word size, since we'll read those in the header and b)
// has an internal offset of 0 so absolute offsets can be used directly.
final reader = Reader.fromTypedData(
ByteData.sublistView(elfReader.bdata, elfReader.offset));
final header = ElfHeader.fromReader(reader);
// Only happens if the file didn't start with the expected magic number.
if (header == null) return null;
// At this point, the endianness and wordSize should have been set
// during ElfHeader.fromReader.
final programHeader = ProgramHeader.fromReader(reader, header);
final sectionHeader = SectionHeader.fromReader(reader, header);
final sections = <SectionHeaderEntry, Section>{};
for (var i = 0; i < sectionHeader.entries.length; i++) {
final entry = sectionHeader.entries[i];
sections[entry] = Section.fromReader(reader, entry);
}
// Now set up the by-name section table and cache the names in the section
// header entries.
if (header.sectionHeaderStringsIndex < 0 ||
header.sectionHeaderStringsIndex >= sectionHeader.entries.length) {
throw FormatException('Section header string table index invalid');
}
final sectionHeaderStringTableEntry =
sectionHeader.entries[header.sectionHeaderStringsIndex];
final sectionHeaderStringTable =
sections[sectionHeaderStringTableEntry] as StringTable?;
if (sectionHeaderStringTable == null) {
throw FormatException(
'No section for entry $sectionHeaderStringTableEntry');
}
final sectionsByName = <String, Set<Section>>{};
for (final entry in sectionHeader.entries) {
final section = sections[entry];
if (section == null) {
throw FormatException('No section found for entry $entry');
}
entry.setName(sectionHeaderStringTable);
sectionsByName.putIfAbsent(entry.name, () => {}).add(section);
}
void cacheSymbolNames(String stringTableTag, String symbolTableTag) {
final stringTables = sectionsByName[stringTableTag]?.cast<StringTable>();
if (stringTables == null) {
return;
}
final stringTableMap =
Map.fromEntries(stringTables.map((s) => MapEntry(s.headerEntry, s)));
final symbolTables = sectionsByName[symbolTableTag]?.cast<SymbolTable>();
if (symbolTables == null) {
return;
}
for (final symbolTable in symbolTables) {
final link = symbolTable.headerEntry.link;
final entry = sectionHeader.entries[link];
final stringTable = stringTableMap[entry];
if (stringTable == null) {
throw FormatException(
'String table not found at section header entry $link');
}
symbolTable._cacheNames(stringTable);
}
}
cacheSymbolNames('.strtab', '.symtab');
cacheSymbolNames('.dynstr', '.dynsym');
StringTable? debugStringTable;
if (sectionsByName.containsKey('.debug_str')) {
// Stored as PROGBITS, so need to explicitly parse as a string table.
debugStringTable = StringTable.fromReader(
reader, sectionsByName['.debug_str']!.single.headerEntry);
}
StringTable? debugLineStringTable;
if (sectionsByName.containsKey('.debug_line_str')) {
// Stored as PROGBITS, so need to explicitly parse as a string table.
debugLineStringTable = StringTable.fromReader(
reader, sectionsByName['.debug_line_str']!.single.headerEntry);
}
// Set the wordSize and endian of the original reader before returning.
elfReader.wordSize = reader.wordSize;
elfReader.endian = reader.endian;
return Elf._(header, programHeader, sectionHeader, sections, sectionsByName,
debugStringTable, debugLineStringTable);
}