GP-2334 improve support for extended ELF section indexing when number of

sections exceed SHN_LORESERVE (0xff00).
This commit is contained in:
ghidra1
2022-07-18 18:22:03 -04:00
parent 88570bf43e
commit 5908e79022
10 changed files with 228 additions and 108 deletions
@@ -212,8 +212,8 @@ public class DWARFAnalyzer extends AbstractAnalyzer {
"Manually re-run the DWARF analyzer after adjusting the options or start it via Dwarf_ExtractorScript"); "Manually re-run the DWARF analyzer after adjusting the options or start it via Dwarf_ExtractorScript");
} }
catch (DWARFException | IOException e) { catch (DWARFException | IOException e) {
log.appendMsg("Error during DWARFAnalyzer import"); log.appendMsg("Error during DWARFAnalyzer import: " + e.getMessage());
log.appendException(e); Msg.error(this, "Error during DWARFAnalyzer import: " + e.getMessage(), e);
} }
return false; return false;
} }
@@ -141,10 +141,8 @@ public class DWARFCompilationUnit {
debugInfoBR.setPointerIndex(debugInfoBR.length()); debugInfoBR.setPointerIndex(debugInfoBR.length());
return null; return null;
} }
else { throw new DWARFException(
throw new DWARFException( "Invalid DWARF length 0 at 0x" + Long.toHexString(startOffset));
"Invalid DWARF length 0 at 0x" + Long.toHexString(startOffset));
}
} }
long endOffset = debugInfoBR.getPointerIndex() + lengthInfo.length; long endOffset = debugInfoBR.getPointerIndex() + lengthInfo.length;
@@ -155,7 +153,8 @@ public class DWARFCompilationUnit {
if (version < 2 || version > 4) { if (version < 2 || version > 4) {
throw new DWARFException( throw new DWARFException(
"Only DWARF version 2, 3, or 4 information is currently supported."); "Only DWARF version 2, 3, or 4 information is currently supported (detected " +
version + ").");
} }
if (firstDIEOffset > endOffset) { if (firstDIEOffset > endOffset) {
throw new IOException("Invalid length " + (endOffset - startOffset) + throw new IOException("Invalid length " + (endOffset - startOffset) +
@@ -68,10 +68,10 @@ public class ElfHeader implements StructConverter, Writeable {
private int e_flags; //processor-specific flags private int e_flags; //processor-specific flags
private short e_ehsize; //elf header size private short e_ehsize; //elf header size
private short e_phentsize; //size of entries in the program header table private short e_phentsize; //size of entries in the program header table
private int e_phnum; //number of enties in the program header table (may not be preserved) private int e_phnum; //number of enties in the program header table (may be extended and may not be preserved)
private short e_shentsize; //size of entries in the section header table private short e_shentsize; //size of entries in the section header table
private int e_shnum; //number of enties in the section header table (may not be preserved) private int e_shnum; //number of enties in the section header table (may be extended and may not be preserved)
private short e_shstrndx; //section index of the section name string table private int e_shstrndx; //section index of the section name string table (may be extended and may not be preserved)
private Structure headerStructure; private Structure headerStructure;
@@ -88,6 +88,7 @@ public class ElfHeader implements StructConverter, Writeable {
private ElfStringTable dynamicStringTable; private ElfStringTable dynamicStringTable;
private ElfSymbolTable dynamicSymbolTable; private ElfSymbolTable dynamicSymbolTable;
private boolean hasExtendedSymbolSectionIndexTable; // if SHT_SYMTAB_SHNDX sections exist
private String[] dynamicLibraryNames; private String[] dynamicLibraryNames;
@@ -186,15 +187,23 @@ public class ElfHeader implements StructConverter, Writeable {
e_shentsize = reader.readNextShort(); e_shentsize = reader.readNextShort();
e_shnum = reader.readNextUnsignedShort(); e_shnum = reader.readNextUnsignedShort();
e_shstrndx = reader.readNextShort(); e_shstrndx = Short.toUnsignedInt(reader.readNextShort());
if (e_shnum >= Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_LORESERVE)) { if (e_shnum == 0 ||
e_shnum >= Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_LORESERVE)) {
e_shnum = readExtendedSectionHeaderCount(); // use extended stored section header count e_shnum = readExtendedSectionHeaderCount(); // use extended stored section header count
} }
if (e_phnum == Short.toUnsignedInt(ElfConstants.PN_XNUM)) { if (e_phnum == Short.toUnsignedInt(ElfConstants.PN_XNUM)) {
e_phnum = readExtendedProgramHeaderCount(); // use extended stored program header count e_phnum = readExtendedProgramHeaderCount(); // use extended stored program header count
} }
if (e_shnum == 0) {
e_shstrndx = 0;
}
else if (e_shstrndx == Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_XINDEX)) {
e_shstrndx = readExtendedSectionHeaderStringTableIndex();
}
} }
catch (IOException e) { catch (IOException e) {
throw new ElfException(e); throw new ElfException(e);
@@ -202,35 +211,36 @@ public class ElfHeader implements StructConverter, Writeable {
} }
private ElfSectionHeader getSection0() throws IOException { private ElfSectionHeader getSection0() throws IOException {
if (section0 == null && e_shnum != 0) { if (section0 == null && e_shoff != 0) {
long index = e_shoff; if (!providerContainsRegion(e_shoff, e_shentsize)) {
if (!providerContainsRegion(index, e_shentsize)) {
return null; return null;
} }
reader.setPointerIndex(index); reader.setPointerIndex(e_shoff);
section0 = new ElfSectionHeader(reader, this); section0 = new ElfSectionHeader(reader, this);
} }
return section0; return section0;
} }
/** /**
* Read extended program header count stored in first section header (ST_NULL) sh_info field value. * Read extended program header count (e_phnum) stored in first section header (ST_NULL)
* Returned value is restricted to the range 0..0x7fffffff. * sh_info field value. This is done to overcome the short value limitation of the
* e_phnum header field. Returned value is restricted to the range 0..0x7fffffff.
* @return extended program header count or 0 if not found or out of range * @return extended program header count or 0 if not found or out of range
* @throws IOException if file IO error occurs * @throws IOException if file IO error occurs
*/ */
private int readExtendedProgramHeaderCount() throws IOException { private int readExtendedProgramHeaderCount() throws IOException {
ElfSectionHeader s = getSection0(); ElfSectionHeader s = getSection0();
if (s != null && s.getType() == ElfSectionHeaderConstants.SHT_NULL) { if (s != null && s.getType() == ElfSectionHeaderConstants.SHT_NULL) {
long val = s.getInfo(); int val = s.getInfo();
return (val < 0 || val > Integer.MAX_VALUE) ? 0 : (int) val; return val < 0 ? 0 : val;
} }
return 0; return 0;
} }
/** /**
* Read extended section header count stored in first section header (ST_NULL) sh_size field value. * Read extended section header count (e_shnum) stored in first section header (ST_NULL)
* Returned value is restricted to the range 0..0x7fffffff. * sh_size field value. This is done to overcome the short value limitation of the
* e_shnum header field. Returned value is restricted to the range 0..0x7fffffff.
* @return extended section header count or 0 if not found or out of range * @return extended section header count or 0 if not found or out of range
* @throws IOException if file IO error occurs * @throws IOException if file IO error occurs
*/ */
@@ -243,6 +253,22 @@ public class ElfHeader implements StructConverter, Writeable {
return 0; return 0;
} }
/**
* Read extended section header string table index (e_shstrndx) stored in first section header
* (ST_NULL) sh_size field value. This is done to overcome the short value limitation of the
* e_shstrndx header field. Returned value is restricted to the range 0..0x7fffffff.
* @return extended section header count or 0 if not found or out of range
* @throws IOException if file IO error occurs
*/
private int readExtendedSectionHeaderStringTableIndex() throws IOException {
ElfSectionHeader s = getSection0();
if (s != null && s.getType() == ElfSectionHeaderConstants.SHT_NULL) {
int val = s.getLink();
return val < 0 ? 0 : val;
}
return 0;
}
private void initElfLoadAdapter() { private void initElfLoadAdapter() {
programHeaderTypeMap = new HashMap<>(); programHeaderTypeMap = new HashMap<>();
@@ -733,9 +759,9 @@ public class ElfHeader implements StructConverter, Writeable {
ArrayList<ElfStringTable> stringTableList = new ArrayList<>(); ArrayList<ElfStringTable> stringTableList = new ArrayList<>();
for (ElfSectionHeader stringTableSectionHeader : sectionHeaders) { for (ElfSectionHeader stringTableSectionHeader : sectionHeaders) {
if (stringTableSectionHeader.getType() == ElfSectionHeaderConstants.SHT_STRTAB) { if (stringTableSectionHeader.getType() == ElfSectionHeaderConstants.SHT_STRTAB) {
ElfStringTable stringTable = new ElfStringTable(reader, this, ElfStringTable stringTable = new ElfStringTable(this, stringTableSectionHeader,
stringTableSectionHeader, stringTableSectionHeader.getOffset(), stringTableSectionHeader.getOffset(), stringTableSectionHeader.getAddress(),
stringTableSectionHeader.getAddress(), stringTableSectionHeader.getSize()); stringTableSectionHeader.getSize());
stringTableList.add(stringTable); stringTableList.add(stringTable);
if (stringTable.getAddressOffset() == dynamicStringTableAddr) { if (stringTable.getAddressOffset() == dynamicStringTableAddr) {
dynamicStringTable = stringTable; dynamicStringTable = stringTable;
@@ -778,7 +804,7 @@ public class ElfHeader implements StructConverter, Writeable {
return null; return null;
} }
return new ElfStringTable(reader, this, null, return new ElfStringTable(this, null,
stringTableLoadHeader.getOffset(dynamicStringTableAddr), dynamicStringTableAddr, stringTableLoadHeader.getOffset(dynamicStringTableAddr), dynamicStringTableAddr,
stringTableSize); stringTableSize);
} }
@@ -787,6 +813,54 @@ public class ElfHeader implements StructConverter, Writeable {
} }
} }
private int[] getExtendedSymbolSectionIndexTable(ElfSectionHeader symbolTableSectionHeader) {
if (!hasExtendedSymbolSectionIndexTable) {
return null;
}
// Find SHT_SYMTAB_SHNDX section linked to specified symbol table section
ElfSectionHeader symbolSectionIndexHeader = null;
for (ElfSectionHeader section : sectionHeaders) {
if (section.getType() != ElfSectionHeaderConstants.SHT_SYMTAB_SHNDX) {
continue;
}
int linkIndex = section.getLink();
if (linkIndex <= 0 || linkIndex >= sectionHeaders.length) {
continue;
}
if (sectionHeaders[linkIndex] == symbolTableSectionHeader) {
symbolSectionIndexHeader = section;
break;
}
}
if (symbolSectionIndexHeader == null) {
return null;
}
// determine number of 32-bit index elements for int[]
int count = (int) (symbolSectionIndexHeader.getSize() / 4);
int[] indexTable = new int[count];
long ptr = reader.getPointerIndex();
try {
reader.setPointerIndex(symbolSectionIndexHeader.getOffset());
for (int i = 0; i < count; i++) {
indexTable[i] = reader.readNextInt();
}
}
catch (IOException e) {
errorConsumer.accept("Failed to read symbol section index table at 0x" +
Long.toHexString(symbolSectionIndexHeader.getOffset()) + ": " +
symbolSectionIndexHeader.getNameAsString());
}
finally {
reader.setPointerIndex(ptr); // restore reader position
}
return indexTable;
}
private void parseSymbolTables() throws IOException { private void parseSymbolTables() throws IOException {
// identify dynamic symbol table address // identify dynamic symbol table address
@@ -822,10 +896,15 @@ public class ElfHeader implements StructConverter, Writeable {
boolean isDyanmic = ElfSectionHeaderConstants.dot_dynsym boolean isDyanmic = ElfSectionHeaderConstants.dot_dynsym
.equals(symbolTableSectionHeader.getNameAsString()); .equals(symbolTableSectionHeader.getNameAsString());
// get extended symbol section index table if present
int[] symbolSectionIndexTable =
getExtendedSymbolSectionIndexTable(symbolTableSectionHeader);
ElfSymbolTable symbolTable = new ElfSymbolTable(reader, this, ElfSymbolTable symbolTable = new ElfSymbolTable(reader, this,
symbolTableSectionHeader, symbolTableSectionHeader.getOffset(), symbolTableSectionHeader, symbolTableSectionHeader.getOffset(),
symbolTableSectionHeader.getAddress(), symbolTableSectionHeader.getSize(), symbolTableSectionHeader.getAddress(), symbolTableSectionHeader.getSize(),
symbolTableSectionHeader.getEntrySize(), stringTable, isDyanmic); symbolTableSectionHeader.getEntrySize(), stringTable, symbolSectionIndexTable,
isDyanmic);
symbolTableList.add(symbolTable); symbolTableList.add(symbolTable);
if (symbolTable.getAddressOffset() == dynamicSymbolTableAddr) { if (symbolTable.getAddressOffset() == dynamicSymbolTableAddr) {
dynamicSymbolTable = symbolTable; // remember dynamic symbol table dynamicSymbolTable = symbolTable; // remember dynamic symbol table
@@ -910,8 +989,12 @@ public class ElfHeader implements StructConverter, Writeable {
symCount = reader.readInt(symbolHashTableOffset + 4); // nchain from DT_HASH symCount = reader.readInt(symbolHashTableOffset + 4); // nchain from DT_HASH
} }
// NOTE: When parsed from dynamic table and not found via section header parse
// it is assumed that the extended symbol section table is not used.
return new ElfSymbolTable(reader, this, null, symbolTableOffset, return new ElfSymbolTable(reader, this, null, symbolTableOffset,
tableAddr, tableEntrySize * symCount, tableEntrySize, dynamicStringTable, true); tableAddr, tableEntrySize * symCount, tableEntrySize, dynamicStringTable, null,
true);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
throw new AssertException(e); throw new AssertException(e);
@@ -997,6 +1080,9 @@ public class ElfHeader implements StructConverter, Writeable {
} }
reader.setPointerIndex(index); reader.setPointerIndex(index);
sectionHeaders[i] = new ElfSectionHeader(reader, this); sectionHeaders[i] = new ElfSectionHeader(reader, this);
if (sectionHeaders[i].getType() == ElfSectionHeaderConstants.SHT_SYMTAB_SHNDX) {
hasExtendedSymbolSectionIndexTable = true;
}
} }
if (sectionHeaders.length != 0) { if (sectionHeaders.length != 0) {
@@ -1388,7 +1474,7 @@ public class ElfHeader implements StructConverter, Writeable {
* the value SHN_UNDEF. * the value SHN_UNDEF.
* @return the section header table index of the entry associated with the section name string table * @return the section header table index of the entry associated with the section name string table
*/ */
public short e_shstrndx() { public int e_shstrndx() {
return e_shstrndx; return e_shstrndx;
} }
@@ -333,10 +333,10 @@ public class ElfSectionHeader implements StructConverter, Writeable, MemoryLoada
} }
ElfSectionHeader[] sections = header.getSections(); ElfSectionHeader[] sections = header.getSections();
short e_shstrndx = header.e_shstrndx(); int e_shstrndx = header.e_shstrndx();
name = null; name = null;
try { try {
if (sh_name >= 0 && e_shstrndx >= 0 && e_shstrndx < sections.length) { if (sh_name >= 0 && e_shstrndx > 0 && e_shstrndx < sections.length) {
// read section name from string table // read section name from string table
long stringTableOffset = sections[e_shstrndx].getOffset(); long stringTableOffset = sections[e_shstrndx].getOffset();
if (stringTableOffset >= 0) { if (stringTableOffset >= 0) {
@@ -20,56 +20,32 @@ public class ElfSectionHeaderConstants {
private ElfSectionHeaderConstants() { private ElfSectionHeaderConstants() {
} }
/**RESERVED SECTION NAME*/ // Frequently used section names
public static final String dot_bss = ".bss";
/**RESERVED SECTION NAME*/
public static final String dot_comment = ".comment";
/**RESERVED SECTION NAME*/
public static final String dot_data = ".data";
/**RESERVED SECTION NAME*/
public static final String dot_data1 = ".data1";
/**RESERVED SECTION NAME*/
public static final String dot_debug = ".debug";
/**RESERVED SECTION NAME*/
public static final String dot_dynamic = ".dynamic";
/**RESERVED SECTION NAME*/
public static final String dot_dynstr = ".dynstr";
/**RESERVED SECTION NAME*/
public static final String dot_dynsym = ".dynsym";
/**RESERVED SECTION NAME*/
public static final String dot_fini = ".fini";
/**RESERVED SECTION NAME*/
public static final String dot_got = ".got";
/**RESERVED SECTION NAME*/
public static final String dot_hash = ".hash";
/**RESERVED SECTION NAME*/
public static final String dot_init = ".init";
/**RESERVED SECTION NAME*/
public static final String dot_interp = ".interp";
/**RESERVED SECTION NAME*/
public static final String dot_line = ".line";
/**RESERVED SECTION NAME*/
public static final String dot_note = ".note";
/**RESERVED SECTION NAME*/
public static final String dot_plt = ".plt";
/**RESERVED SECTION NAME*/
public static final String dot_rodata = ".rodata";
/**RESERVED SECTION NAME*/
public static final String dot_rodata1 = ".rodata1";
/**RESERVED SECTION NAME*/
public static final String dot_shstrtab = ".shstrtab";
/**RESERVED SECTION NAME*/
public static final String dot_strtab = ".strtab";
/**RESERVED SECTION NAME*/
public static final String dot_symtab = ".symtab";
/**RESERVED SECTION NAME*/
public static final String dot_text = ".text";
/**RESERVED SECTION NAME*/ public static final String dot_bss = ".bss";
public static final String dot_comment = ".comment";
public static final String dot_data = ".data";
public static final String dot_data1 = ".data1";
public static final String dot_debug = ".debug";
public static final String dot_dynamic = ".dynamic";
public static final String dot_dynstr = ".dynstr";
public static final String dot_dynsym = ".dynsym";
public static final String dot_fini = ".fini";
public static final String dot_got = ".got";
public static final String dot_hash = ".hash";
public static final String dot_init = ".init";
public static final String dot_interp = ".interp";
public static final String dot_line = ".line";
public static final String dot_note = ".note";
public static final String dot_plt = ".plt";
public static final String dot_rodata = ".rodata";
public static final String dot_rodata1 = ".rodata1";
public static final String dot_shstrtab = ".shstrtab";
public static final String dot_strtab = ".strtab";
public static final String dot_symtab = ".symtab";
public static final String dot_text = ".text";
public static final String dot_tbss = ".tbss"; public static final String dot_tbss = ".tbss";
/**RESERVED SECTION NAME*/
public static final String dot_tdata = ".tdata"; public static final String dot_tdata = ".tdata";
/**RESERVED SECTION NAME*/
public static final String dot_tdata1 = ".tdata1"; public static final String dot_tdata1 = ".tdata1";
// Section Header Types // Section Header Types
@@ -106,9 +82,12 @@ public class ElfSectionHeaderConstants {
public static final int SHT_PREINIT_ARRAY = 16; public static final int SHT_PREINIT_ARRAY = 16;
/**Section group*/ /**Section group*/
public static final int SHT_GROUP = 17; public static final int SHT_GROUP = 17;
/**Extended section indeces*/ /**Extended section index table for linked symbol table */
public static final int SHT_SYMTAB_SHNDX = 18; public static final int SHT_SYMTAB_SHNDX = 18;
/**Experimental support - see proposal at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg */ /**
* Relative relocation table section
* (see proposal at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
*/
public static final int SHT_RELR = 19; public static final int SHT_RELR = 19;
// OS Specific Section Types // OS Specific Section Types
@@ -192,13 +171,4 @@ public class ElfSectionHeaderConstants {
/**upper bound on range of reserved indexes*/ /**upper bound on range of reserved indexes*/
public static final short SHN_HIRESERVE = (short) 0xffff; public static final short SHN_HIRESERVE = (short) 0xffff;
/**
* @param symbolSectionIndex symbol section index (st_shndx)
* @return true if specified symbol section index corresponds to a processor
* specific value in the range SHN_LOPROC..SHN_HIPROC, else false
*/
public static boolean isProcessorSpecificSymbolSectionIndex(short symbolSectionIndex) {
return (Short.compareUnsigned(symbolSectionIndex, SHN_LOPROC) >= 0) &&
(Short.compareUnsigned(symbolSectionIndex, SHN_HIPROC) <= 0);
}
} }
@@ -32,15 +32,14 @@ public class ElfStringTable implements ElfFileSection {
/** /**
* Construct and parse an Elf string table * Construct and parse an Elf string table
* @param reader the binary reader containing the elf string table
* @param header elf header * @param header elf header
* @param stringTableSection string table section header or null if associated with a dynamic table entry * @param stringTableSection string table section header or null if associated with a dynamic table entry
* @param fileOffset symbol table file offset * @param fileOffset symbol table file offset
* @param addrOffset memory address of symbol table (should already be adjusted for prelink) * @param addrOffset memory address of symbol table (should already be adjusted for prelink)
* @param length length of symbol table in bytes of -1 if unknown * @param length length of symbol table in bytes of -1 if unknown
*/ */
public ElfStringTable(BinaryReader reader, ElfHeader header, public ElfStringTable(ElfHeader header, ElfSectionHeader stringTableSection, long fileOffset,
ElfSectionHeader stringTableSection, long fileOffset, long addrOffset, long length) { long addrOffset, long length) {
this.header = header; this.header = header;
this.stringTableSection = stringTableSection; this.stringTableSection = stringTableSection;
this.fileOffset = fileOffset; this.fileOffset = fileOffset;
@@ -469,15 +469,36 @@ public class ElfSymbol implements ByteArrayConverter {
} }
/** /**
* Every symbol table entry is "defined" in relation to some section; * Get the raw section index value (<code>st_shndx</code>) for this symbol.
* this member holds the relevant section header table index. * Special values (SHN_LORESERVE and higher) must be treated properly. The value SHN_XINDEX
* NOTE: This value reflects the raw st_shndx value and not the extended section index value * indicates that the extended value must be used to obtained the actual section index
* @return the relevant section header table index * (see {@link #getExtendedSectionHeaderIndex()}).
* @return the <code>st_shndx</code> section index value
*/ */
public short getSectionHeaderIndex() { public short getSectionHeaderIndex() {
return st_shndx; return st_shndx;
} }
/**
* Get the extended symbol section index value when <code>st_shndx</code>
* ({@link #getSectionHeaderIndex()}) has a value of SHN_XINDEX. This requires a lookup
* into a table defined by an associated SHT_SYMTAB_SHNDX section.
* @return extended symbol section index value
*/
public int getExtendedSectionHeaderIndex() {
return symbolTable.getExtendedSectionIndex(this);
}
/**
* Determine if st_shndx is within the reserved processor-specific index range
* @return true if specified symbol section index corresponds to a processor
* specific value in the range SHN_LOPROC..SHN_HIPROC, else false
*/
public boolean hasProcessorSpecificSymbolSectionIndex() {
return (Short.compareUnsigned(st_shndx, ElfSectionHeaderConstants.SHN_LOPROC) >= 0) &&
(Short.compareUnsigned(st_shndx, ElfSectionHeaderConstants.SHN_HIPROC) <= 0);
}
/** /**
* Many symbols have associated sizes. For example, a data object's size is the number of * Many symbols have associated sizes. For example, a data object's size is the number of
* bytes contained in the object. This member holds 0 if the symbol has no size or an * bytes contained in the object. This member holds 0 if the symbol has no size or an
@@ -32,8 +32,8 @@ import ghidra.util.exception.DuplicateNameException;
public class ElfSymbolTable implements ElfFileSection, ByteArrayConverter { public class ElfSymbolTable implements ElfFileSection, ByteArrayConverter {
private ElfStringTable stringTable; private ElfStringTable stringTable;
private ElfSectionHeader symbolTableSection; // may be null private ElfSectionHeader symbolTableSection; // may be null
private int[] symbolSectionIndexTable;
private long fileOffset; private long fileOffset;
private long addrOffset; private long addrOffset;
private long length; private long length;
@@ -55,12 +55,16 @@ public class ElfSymbolTable implements ElfFileSection, ByteArrayConverter {
* @param length length of symbol table in bytes of -1 if unknown * @param length length of symbol table in bytes of -1 if unknown
* @param entrySize size of each symbol entry in bytes * @param entrySize size of each symbol entry in bytes
* @param stringTable associated string table * @param stringTable associated string table
* @param symbolSectionIndexTable extended symbol section index table (may be null, used when
* symbol <code>st_shndx == SHN_XINDEX</code>). See
* {@link ElfSymbol#getExtendedSectionHeaderIndex()}).
* @param isDynamic true if symbol table is the dynamic symbol table * @param isDynamic true if symbol table is the dynamic symbol table
* @throws IOException if an IO or parse error occurs * @throws IOException if an IO or parse error occurs
*/ */
public ElfSymbolTable(BinaryReader reader, ElfHeader header, public ElfSymbolTable(BinaryReader reader, ElfHeader header,
ElfSectionHeader symbolTableSection, long fileOffset, long addrOffset, long length, ElfSectionHeader symbolTableSection, long fileOffset, long addrOffset, long length,
long entrySize, ElfStringTable stringTable, boolean isDynamic) throws IOException { long entrySize, ElfStringTable stringTable, int[] symbolSectionIndexTable,
boolean isDynamic) throws IOException {
this.symbolTableSection = symbolTableSection; this.symbolTableSection = symbolTableSection;
this.fileOffset = fileOffset; this.fileOffset = fileOffset;
@@ -69,6 +73,7 @@ public class ElfSymbolTable implements ElfFileSection, ByteArrayConverter {
this.entrySize = entrySize; this.entrySize = entrySize;
this.stringTable = stringTable; this.stringTable = stringTable;
this.is32bit = header.is32Bit(); this.is32bit = header.is32Bit();
this.symbolSectionIndexTable = symbolSectionIndexTable;
this.isDynamic = isDynamic; this.isDynamic = isDynamic;
long ptr = reader.getPointerIndex(); long ptr = reader.getPointerIndex();
@@ -136,6 +141,24 @@ public class ElfSymbolTable implements ElfFileSection, ByteArrayConverter {
return symbols; return symbols;
} }
/**
* Get the extended symbol section index value for the specified ELF symbol which originated
* from this symbol table. This section index is provided by an associated SHT_SYMTAB_SHNDX
* section when the symbols st_shndx == SHN_XINDEX.
* @param sym ELF symbol from this symbol table
* @return associated extended section index value or 0 if not defined.
*/
public int getExtendedSectionIndex(ElfSymbol sym) {
if (sym.getSectionHeaderIndex() == ElfSectionHeaderConstants.SHN_XINDEX &&
symbolSectionIndexTable != null) {
int symbolTableIndex = sym.getSymbolTableIndex();
if (symbolTableIndex < symbolSectionIndexTable.length) {
return symbolSectionIndexTable[symbolTableIndex];
}
}
return 0;
}
/** /**
* Returns the index of the specified symbol in this * Returns the index of the specified symbol in this
* symbol table. * symbol table.
@@ -1162,6 +1162,10 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
component.addOperandReference(0, sectionAddr, RefType.DATA, component.addOperandReference(0, sectionAddr, RefType.DATA,
SourceType.IMPORTED); SourceType.IMPORTED);
} }
if (sections[i].getType() == ElfSectionHeaderConstants.SHT_SYMTAB_SHNDX) {
markupSymbolSectionHeaderIndex(sections[i]);
}
} }
} }
catch (Exception e) { catch (Exception e) {
@@ -1169,6 +1173,17 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
} }
} }
private void markupSymbolSectionHeaderIndex(ElfSectionHeader section) {
Address sectionAddr = findLoadAddress(section, 0);
if (sectionAddr == null) {
return;
}
// determine number of 32-bit index elements for DWORD[]
int count = (int) (section.getSize() / 4);
DataType dt = new ArrayDataType(DWordDataType.dataType, count, -1);
createData(sectionAddr, dt);
}
private void markupRelocationTable(Address relocTableAddr, ElfRelocationTable relocTable, private void markupRelocationTable(Address relocTableAddr, ElfRelocationTable relocTable,
TaskMonitor monitor) { TaskMonitor monitor) {
try { try {
@@ -1583,7 +1598,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
boolean isAllocatedToSection = false; boolean isAllocatedToSection = false;
if (sectionIndex == ElfSectionHeaderConstants.SHN_UNDEF) { // Not section relative 0x0000 (e.g., no sections defined) if (sectionIndex == ElfSectionHeaderConstants.SHN_UNDEF) { // Not section relative 0x0000 (e.g., no sections defined)
Address regAddr = findMemoryRegister(elfSymbol); Address regAddr = findMemoryRegister(elfSymbol);
if (regAddr != null) { if (regAddr != null) {
return regAddr; return regAddr;
@@ -1595,9 +1609,22 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
symOffset = loadAdapter.getAdjustedMemoryOffset(symOffset, defaultSpace); symOffset = loadAdapter.getAdjustedMemoryOffset(symOffset, defaultSpace);
symOffset += getImageBaseWordAdjustmentOffset(); symOffset += getImageBaseWordAdjustmentOffset();
} }
else if (Short.compareUnsigned(sectionIndex, ElfSectionHeaderConstants.SHN_LORESERVE) < 0) { else if (Short.compareUnsigned(sectionIndex, ElfSectionHeaderConstants.SHN_LORESERVE) < 0 ||
sectionIndex == ElfSectionHeaderConstants.SHN_XINDEX) {
isAllocatedToSection = true; isAllocatedToSection = true;
int uSectionIndex = Short.toUnsignedInt(sectionIndex); int uSectionIndex = Short.toUnsignedInt(sectionIndex);
if (sectionIndex == ElfSectionHeaderConstants.SHN_XINDEX) {
uSectionIndex = elfSymbol.getExtendedSectionHeaderIndex();
if (uSectionIndex == 0) {
log("Failed to read extended symbol section index: " +
elfSymbol.getNameAsString() + " - value=0x" +
Long.toHexString(elfSymbol.getValue()));
return null;
}
}
if (uSectionIndex < elfSections.length) { if (uSectionIndex < elfSections.length) {
ElfSectionHeader symSection = elf.getSections()[uSectionIndex]; ElfSectionHeader symSection = elf.getSections()[uSectionIndex];
@@ -1641,11 +1668,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
} }
else if (sectionIndex == ElfSectionHeaderConstants.SHN_ABS) { // Absolute value/address - 0xfff1 else if (sectionIndex == ElfSectionHeaderConstants.SHN_ABS) { // Absolute value/address - 0xfff1
byte type = elfSymbol.getType();
if (type == ElfSymbol.STT_FILE) {
return null; // ignore file symbol
}
// Absolute symbols will be pinned to associated address // Absolute symbols will be pinned to associated address
symbolSpace = defaultDataSpace; symbolSpace = defaultDataSpace;
if (elfSymbol.isFunction()) { if (elfSymbol.isFunction()) {
@@ -336,11 +336,11 @@ public class MIPS_ElfExtension extends ElfExtension {
public Address calculateSymbolAddress(ElfLoadHelper elfLoadHelper, ElfSymbol elfSymbol) public Address calculateSymbolAddress(ElfLoadHelper elfLoadHelper, ElfSymbol elfSymbol)
throws NoValueException { throws NoValueException {
short sectionIndex = elfSymbol.getSectionHeaderIndex(); if (!elfSymbol.hasProcessorSpecificSymbolSectionIndex()) {
if (!ElfSectionHeaderConstants.isProcessorSpecificSymbolSectionIndex(sectionIndex)) {
return null; return null;
} }
short sectionIndex = elfSymbol.getSectionHeaderIndex();
if (sectionIndex == SHN_MIPS_ACOMMON || sectionIndex == SHN_MIPS_TEXT || sectionIndex == SHN_MIPS_DATA) { if (sectionIndex == SHN_MIPS_ACOMMON || sectionIndex == SHN_MIPS_TEXT || sectionIndex == SHN_MIPS_DATA) {
// NOTE: logic assumes no memory conflict occured during section loading // NOTE: logic assumes no memory conflict occured during section loading
AddressSpace defaultSpace = elfLoadHelper.getProgram().getAddressFactory().getDefaultAddressSpace(); AddressSpace defaultSpace = elfLoadHelper.getProgram().getAddressFactory().getDefaultAddressSpace();