diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSymbol.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSymbol.java index 297dedfd3b..170c317d97 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSymbol.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSymbol.java @@ -103,11 +103,24 @@ public class ElfSymbol implements ByteArrayConverter { private String nameAsString; + /** + * create an ElfSymbol() + * Warning! the routine initSymbolName() must be called on the symbol later + * to initialize the string name. This is a performance enhancement. + * + * @param reader to read symbol from + * @param symbolIndex index of the symbol to read + * @param symbolTable symbol table to associate the symbol to + * @param stringTable string table to read symbols from + * @param header else header + * @return newly created ElfSymbol + * + * @throws IOException if an issue with reading occurs + */ public static ElfSymbol createElfSymbol(FactoryBundledWithBinaryReader reader, int symbolIndex, - ElfSymbolTable symbolTable, ElfStringTable stringTable, ElfHeader header) - throws IOException { + ElfSymbolTable symbolTable, ElfHeader header) throws IOException { ElfSymbol elfSymbol = (ElfSymbol) reader.getFactory().create(ElfSymbol.class); - elfSymbol.initElfSymbol(reader, symbolIndex, symbolTable, stringTable, header); + elfSymbol.initElfSymbol(reader, symbolIndex, symbolTable, header); return elfSymbol; } @@ -117,49 +130,6 @@ public class ElfSymbol implements ByteArrayConverter { public ElfSymbol() { } - private void initElfSymbol(FactoryBundledWithBinaryReader reader, int symbolIndex, - ElfSymbolTable symbolTable, ElfStringTable stringTable, ElfHeader header) - throws IOException { - this.header = header; - this.symbolTable = symbolTable; - this.symbolTableIndex = symbolIndex; - - if (header.is32Bit()) { - st_name = reader.readNextInt(); - st_value = reader.readNextInt() & Conv.INT_MASK; - st_size = reader.readNextInt() & Conv.INT_MASK; - st_info = reader.readNextByte(); - st_other = reader.readNextByte(); - st_shndx = reader.readNextShort(); - } - else { - st_name = reader.readNextInt(); - st_info = reader.readNextByte(); - st_other = reader.readNextByte(); - st_shndx = reader.readNextShort(); - st_value = reader.readNextLong(); - st_size = reader.readNextLong(); - } - - if (st_name == 0) { - if (getType() == STT_SECTION) { - ElfSectionHeader[] sections = header.getSections(); - if (st_shndx < 0 || st_shndx >= sections.length) { - //invalid section reference... - //this is a bug in objcopy, whereby sections are removed - //but the corresponding section symbols are left behind. - } - else { - ElfSectionHeader section = sections[st_shndx]; - nameAsString = section.getNameAsString(); - } - } - } - else { - nameAsString = stringTable.readString(reader, st_name); - } - } - /** * Creates a new section symbol. * @param header the corresponding ELF header @@ -209,6 +179,69 @@ public class ElfSymbol implements ByteArrayConverter { this.symbolTableIndex = symbolIndex; } + private void initElfSymbol(FactoryBundledWithBinaryReader reader, int symbolIndex, + ElfSymbolTable symbolTable, ElfHeader header) throws IOException { + this.header = header; + this.symbolTable = symbolTable; + this.symbolTableIndex = symbolIndex; + + if (header.is32Bit()) { + st_name = reader.readNextInt(); + st_value = reader.readNextInt() & Conv.INT_MASK; + st_size = reader.readNextInt() & Conv.INT_MASK; + st_info = reader.readNextByte(); + st_other = reader.readNextByte(); + st_shndx = reader.readNextShort(); + } + else { + st_name = reader.readNextInt(); + st_info = reader.readNextByte(); + st_other = reader.readNextByte(); + st_shndx = reader.readNextShort(); + st_value = reader.readNextLong(); + st_size = reader.readNextLong(); + } + + if (st_name == 0) { + if (getType() == STT_SECTION) { + ElfSectionHeader[] sections = header.getSections(); + if (st_shndx < 0 || st_shndx >= sections.length) { + //invalid section reference... + //this is a bug in objcopy, whereby sections are removed + //but the corresponding section symbols are left behind. + } + else { + ElfSectionHeader section = sections[st_shndx]; + nameAsString = section.getNameAsString(); + } + } + } + else { + // The string name will be initialized later + // in a call to initSymbolName() + } + } + + /** + * Initialize the string name of the symbol. + * + * NOTE: This routine MUST be called for each + * ELFSymbol after the elf symbols have been created. + * + * This is done separately from the initial symbol entry read because + * the string names are in a separate location. If they are read + * at the same time the reading buffer will jump around and significantly + * degrade reading performance. + * + * @param reader to read from + * @param stringTable stringTable to initialize symbol name + */ + public void initSymbolName(FactoryBundledWithBinaryReader reader, ElfStringTable stringTable) { + if (nameAsString == null) { + nameAsString = stringTable.readString(reader, st_name); + } + } + /** * Get the symbol table containing this symbol * @return symbol table @@ -249,27 +282,37 @@ public class ElfSymbol implements ByteArrayConverter { @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } ElfSymbol other = (ElfSymbol) obj; - if (st_info != other.st_info) + if (st_info != other.st_info) { return false; - if (st_name != other.st_name) + } + if (st_name != other.st_name) { return false; - if (st_other != other.st_other) + } + if (st_other != other.st_other) { return false; - if (st_shndx != other.st_shndx) + } + if (st_shndx != other.st_shndx) { return false; - if (st_size != other.st_size) + } + if (st_size != other.st_size) { return false; - if (st_value != other.st_value) + } + if (st_value != other.st_value) { return false; - if (symbolTableIndex != other.symbolTableIndex) + } + if (symbolTableIndex != other.symbolTableIndex) { return false; + } return true; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSymbolTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSymbolTable.java index 09eea496c9..fcb4631af9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSymbolTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSymbolTable.java @@ -18,6 +18,7 @@ package ghidra.app.util.bin.format.elf; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import ghidra.app.util.bin.ByteArrayConverter; import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; @@ -96,15 +97,26 @@ public class ElfSymbolTable implements ElfFileSection, ByteArrayConverter { long entryPos = reader.getPointerIndex(); + // load the all the symbol entries first, don't initialize the string name + // that will be done later to help localize memory access for (int i = 0; i < symbolCount; i++) { // Reposition reader to start of symbol element since ElfSymbol object // may not consume all symbol element data reader.setPointerIndex(entryPos); - ElfSymbol sym = ElfSymbol.createElfSymbol(reader, i, this, stringTable, header); + ElfSymbol sym = ElfSymbol.createElfSymbol(reader, i, this, header); symbolList.add(sym); entryPos += entrySize; } + // sort the entries by the index in the string table, so don't jump around reading + List sortedList = symbolList.stream().sorted( + (o1, o2) -> Integer.compare(o1.getName(), o2.getName())).collect(Collectors.toList()); + + // initialize the Symbol string names from string table + for (ElfSymbol sym : sortedList) { + sym.initSymbolName(reader, stringTable); + } + reader.setPointerIndex(ptr); symbols = new ElfSymbol[symbolList.size()]; @@ -163,9 +175,9 @@ public class ElfSymbolTable implements ElfFileSection, ByteArrayConverter { * @return the symbol at the specified address */ public ElfSymbol getSymbolAt(long addr) { - for (int i = 0; i < symbols.length; i++) { - if (symbols[i].getValue() == addr) { - return symbols[i]; + for (ElfSymbol symbol : symbols) { + if (symbol.getValue() == addr) { + return symbol; } } return null; @@ -177,9 +189,9 @@ public class ElfSymbolTable implements ElfFileSection, ByteArrayConverter { */ public ElfSymbol[] getGlobalSymbols() { List list = new ArrayList<>(); - for (int i = 0; i < symbols.length; i++) { - if (symbols[i].getBind() == ElfSymbol.STB_GLOBAL) { - list.add(symbols[i]); + for (ElfSymbol symbol : symbols) { + if (symbol.getBind() == ElfSymbol.STB_GLOBAL) { + list.add(symbol); } } ElfSymbol[] array = new ElfSymbol[list.size()]; @@ -193,11 +205,11 @@ public class ElfSymbolTable implements ElfFileSection, ByteArrayConverter { */ public String[] getSourceFiles() { List list = new ArrayList<>(); - for (int j = 0; j < symbols.length; j++) { - if (symbols[j].getType() == ElfSymbol.STT_FILE) { - String name = symbols[j].getNameAsString(); + for (ElfSymbol symbol : symbols) { + if (symbol.getType() == ElfSymbol.STT_FILE) { + String name = symbol.getNameAsString(); if (name != null) { - list.add(symbols[j].getNameAsString()); + list.add(symbol.getNameAsString()); } } }