GP-697_emteere delayed reading of symbol names to improve memory read performance

This commit is contained in:
emteere 2021-02-22 13:55:34 +00:00 committed by ghidra1
parent efa065ac4d
commit 01b6027c77
2 changed files with 122 additions and 67 deletions

View file

@ -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;
}

View file

@ -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<ElfSymbol> 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<ElfSymbol> 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<String> 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());
}
}
}