Skip to content

Commit

Permalink
Add firstSectionByType() and firstSectionByName()
Browse files Browse the repository at this point in the history
  • Loading branch information
fornwall committed Sep 8, 2019
1 parent 1a9e7b0 commit 53a9821
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 52 deletions.
41 changes: 23 additions & 18 deletions src/main/java/net/fornwall/jelf/ElfFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,50 +137,55 @@ public ElfStringTable getSectionNameStringTable() throws ElfException, IOExcepti

/** Returns the string table associated with this ELF file. */
public ElfStringTable getStringTable() throws ElfException, IOException {
return findStringTableWithName(ElfSection.STRING_TABLE_NAME);
return findStringTableWithName(ElfSection.NAME_STRTAB);
}

/**
* Returns the dynamic symbol table associated with this ELF file, or null if one does not exist.
*/
public ElfStringTable getDynamicStringTable() throws ElfException, IOException {
return findStringTableWithName(ElfSection.DYNAMIC_STRING_TABLE_NAME);
return findStringTableWithName(ElfSection.NAME_DYNSTR);
}

private ElfStringTable findStringTableWithName(String tableName) throws ElfException, IOException {
// Loop through the section header and look for a section
// header with the name "tableName". We can ignore entry 0
// since it is defined as being undefined.
for (int i = 1; i < num_sh; i++) {
ElfSection sh = getSection(i);
if (tableName.equals(sh.getName())) return sh.getStringTable();
}
return null;
ElfSection section = firstSectionByName(tableName);
return section == null ? null : section.getStringTable();
}

/** The {@link ElfSection#SHT_SYMTAB} section (of which there may be only one), if any. */
public ElfSection getSymbolTableSection() throws ElfException, IOException {
return (symbolTableSection != null) ? symbolTableSection : (symbolTableSection = getSymbolTableSection(ElfSection.SHT_SYMTAB));
public ElfSection firstSectionByType() throws ElfException, IOException {
return (symbolTableSection != null) ? symbolTableSection : (symbolTableSection = firstSectionByType(ElfSection.SHT_SYMTAB));
}

/** The {@link ElfSection#SHT_DYNSYM} section (of which there may be only one), if any. */
public ElfSection getDynamicSymbolTableSection() throws ElfException, IOException {
return (dynamicSymbolTableSection != null) ? dynamicSymbolTableSection : (dynamicSymbolTableSection = getSymbolTableSection(ElfSection.SHT_DYNSYM));
return (dynamicSymbolTableSection != null) ? dynamicSymbolTableSection : (dynamicSymbolTableSection = firstSectionByType(ElfSection.SHT_DYNSYM));
}

/** The {@link ElfSection#SHT_DYNAMIC} section (of which there may be only one). Named ".dynamic". */
public ElfSection getDynamicLinkSection() throws IOException {
return (dynamicLinkSection != null) ? dynamicLinkSection : (dynamicLinkSection = getSymbolTableSection(ElfSection.SHT_DYNAMIC));
return (dynamicLinkSection != null) ? dynamicLinkSection : (dynamicLinkSection = firstSectionByType(ElfSection.SHT_DYNAMIC));
}

private ElfSection getSymbolTableSection(int type) throws ElfException, IOException {
public ElfSection firstSectionByType(int type) throws ElfException, IOException {
for (int i = 1; i < num_sh; i++) {
ElfSection sh = getSection(i);
if (sh.type == type) return sh;
}
return null;
}

public ElfSection firstSectionByName(String sectionName) throws ElfException, IOException {
for (int i = 1; i < num_sh; i++) {
ElfSection sh = getSection(i);
if (sectionName.equals(sh.getName())) return sh;
}
return null;
}

/** Returns the elf symbol with the specified name or null if one is not found. */
public ElfSymbol getELFSymbol(String symbolName) throws ElfException, IOException {
if (symbolName == null) return null;
Expand All @@ -200,7 +205,7 @@ public ElfSymbol getELFSymbol(String symbolName) throws ElfException, IOExceptio
}

// Check symbol table for symbol name.
sh = getSymbolTableSection();
sh = firstSectionByType();
if (sh != null) {
int numSymbols = sh.getNumberOfSymbols();
for (int i = 0; i < Math.ceil(numSymbols / 2); i++) {
Expand Down Expand Up @@ -229,19 +234,19 @@ public ElfSymbol getELFSymbol(long address) throws ElfException, IOException {
int numSymbols = sh.getNumberOfSymbols();
for (int i = 0; i < numSymbols; i++) {
symbol = sh.getELFSymbol(i);
value = symbol.value;
if (address >= value && address < value + symbol.size) return symbol;
value = symbol.st_value;
if (address >= value && address < value + symbol.st_size) return symbol;
}
}

// Check symbol table for symbol name.
sh = getSymbolTableSection();
sh = firstSectionByType();
if (sh != null) {
int numSymbols = sh.getNumberOfSymbols();
for (int i = 0; i < numSymbols; i++) {
symbol = sh.getELFSymbol(i);
value = symbol.value;
if (address >= value && address < value + symbol.size) return symbol;
value = symbol.st_value;
if (address >= value && address < value + symbol.st_size) return symbol;
}
}
return null;
Expand Down
25 changes: 18 additions & 7 deletions src/main/java/net/fornwall/jelf/ElfSection.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@

/**
* Class corresponding to the Elf32_Shdr/Elf64_Shdr struct.
*
*
* <p>
* An object file's section header table lets one locate all the file's sections. The section header table is an array
* of Elf32_Shdr or Elf64_Shdr structures. A section header table index is a subscript into this array. The ELF header's
* {@link ElfFile#sh_offset e_shoff member} gives the byte offset from the beginning of the file to the section header
* table with each section header entry being {@link ElfFile#sh_entry_size e_shentsize} bytes big.
*
*
* <p>
* {@link ElfFile#num_sh e_shnum} normally tells how many entries the section header table contains, but if the number
* of sections is greater than or equal to SHN_LORESERVE (0xff00), e_shnum has the value SHN_UNDEF (0) and the actual
* number of section header table entries is contained in the sh_size field of the section header at index 0 (otherwise,
* the sh_size member of the initial entry contains 0).
*
*
* <p>
* Some section header table indexes are reserved in contexts where index size is restricted, for example, the st_shndx
* member of a symbol table entry and the e_shnum and e_shstrndx members of the ELF header. In such contexts, the
Expand Down Expand Up @@ -91,10 +91,21 @@ public final class ElfSection {
/** Flag informing that all the bits in the mask are reserved for processor specific semantics. */
public static final int FLAG_MASK = 0xf0000000;

/** Section header name identifying the section as a string table. */
public static final String STRING_TABLE_NAME = ".strtab";
/** Section header name identifying the section as a dynamic string table. */
public static final String DYNAMIC_STRING_TABLE_NAME = ".dynstr";
/**
* Name for the section containing the string table.
* <p>
* This section contains a string table which contains names for symbol structures
* by being indexed by the {@link ElfSymbol#st_name} field.
*/
public static final String NAME_STRTAB = ".strtab";
/**
* Name for the section containing the dynamic string table.
*/
public static final String NAME_DYNSTR = ".dynstr";
/**
* Name for the section containing read-only initialized data.
*/
public static final String NAME_RODATA = ".rodata";

/** Index into the section header string table which gives the name of the section. */
public final int name_ndx; // Elf32_Word or Elf64_Word - 4 bytes in both.
Expand Down
76 changes: 49 additions & 27 deletions src/main/java/net/fornwall/jelf/ElfSymbol.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,29 @@
import java.io.IOException;

/**
* Class corresponding to the Elf32_Sym/Elf64_Sym struct.
* An entry in the symbol table, which holds information needed to locate and relocate a program's symbolic definitions and references.
* <p>
* In the elf.h header file the struct definitions are:
*
* <pre>
* typedef struct {
* uint32_t st_name;
* Elf32_Addr st_value;
* uint32_t st_size;
* unsigned char st_info;
* unsigned char st_other;
* uint16_t st_shndx;
* } Elf32_Sym;
*
* typedef struct {
* uint32_t st_name;
* unsigned char st_info;
* unsigned char st_other;
* uint16_t st_shndx;
* Elf64_Addr st_value;
* uint64_t st_size;
* } Elf64_Sym;
* </pre>
*/
public final class ElfSymbol {

Expand Down Expand Up @@ -49,22 +71,22 @@ public final class ElfSymbol {
* Index into the symbol string table that holds the character representation of the symbols. 0 means the symbol has
* no character name.
*/
private final int name_ndx; // Elf32_Word
/** Value of the associated symbol. This may be a relativa address for .so or absolute address for other ELFs. */
public final long value; // Elf32_Addr
public final int st_name; // Elf32_Word
/** Value of the associated symbol. This may be a relative address for .so or absolute address for other ELFs. */
public final long st_value; // Elf32_Addr
/** Size of the symbol. 0 if the symbol has no size or the size is unknown. */
public final long size; // Elf32_Word
public final long st_size; // Elf32_Word
/** Specifies the symbol type and binding attributes. */
private final short info; // unsigned char
public final short st_info; // unsigned char
/** Currently holds the value of 0 and has no meaning. */
public final short other; // unsigned char
public final short st_other; // unsigned char
/**
* Index to the associated section header. This value will need to be read as an unsigned short if we compare it to
* ELFSectionHeader.NDX_LORESERVE and ELFSectionHeader.NDX_HIRESERVE.
*/
public final short section_header_ndx; // Elf32_Half
public final short st_shndx; // Elf32_Half

private final int section_type;
public final int section_type;

/** Offset from the beginning of the file to this symbol. */
public final long offset;
Expand All @@ -76,19 +98,19 @@ public final class ElfSymbol {
parser.seek(offset);
this.offset = offset;
if (parser.elfFile.objectSize == ElfFile.CLASS_32) {
name_ndx = parser.readInt();
value = parser.readInt();
size = parser.readInt();
info = parser.readUnsignedByte();
other = parser.readUnsignedByte();
section_header_ndx = parser.readShort();
st_name = parser.readInt();
st_value = parser.readInt();
st_size = parser.readInt();
st_info = parser.readUnsignedByte();
st_other = parser.readUnsignedByte();
st_shndx = parser.readShort();
} else {
name_ndx = parser.readInt();
info = parser.readUnsignedByte();
other = parser.readUnsignedByte();
section_header_ndx = parser.readShort();
value = parser.readLong();
size = parser.readLong();
st_name = parser.readInt();
st_info = parser.readUnsignedByte();
st_other = parser.readUnsignedByte();
st_shndx = parser.readShort();
st_value = parser.readLong();
st_size = parser.readLong();
}

this.section_type = section_type;
Expand All @@ -115,25 +137,25 @@ public final class ElfSymbol {

/** Returns the binding for this symbol. */
public int getBinding() {
return info >> 4;
return st_info >> 4;
}

/** Returns the symbol type. */
public int getType() {
return info & 0x0F;
return st_info & 0x0F;
}

/** Returns the name of the symbol or null if the symbol has no name. */
public String getName() throws ElfException, IOException {
// Check to make sure this symbol has a name.
if (name_ndx == 0) return null;
if (st_name == 0) return null;

// Retrieve the name of the symbol from the correct string table.
String symbol_name = null;
if (section_type == ElfSection.SHT_SYMTAB) {
symbol_name = elfHeader.getStringTable().get(name_ndx);
symbol_name = elfHeader.getStringTable().get(st_name);
} else if (section_type == ElfSection.SHT_DYNSYM) {
symbol_name = elfHeader.getDynamicStringTable().get(name_ndx);
symbol_name = elfHeader.getDynamicStringTable().get(st_name);
}
return symbol_name;
}
Expand Down Expand Up @@ -169,7 +191,7 @@ public String toString() {
}

try {
return "ElfSymbol[name=" + getName() + ", type=" + typeString + ", size=" + size + "]";
return "ElfSymbol[name=" + getName() + ", type=" + typeString + ", size=" + st_size + "]";
} catch (IOException e) {
throw new RuntimeException(e);
}
Expand Down
4 changes: 4 additions & 0 deletions src/test/java/net/fornwall/jelf/BasicTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ public void testLinxAmd64BinDash() throws ElfException, FileNotFoundException, I
Assert.assertEquals(Collections.singletonList("libc.so.6"), ds.getNeededLibraries());

Assert.assertEquals("/lib64/ld-linux-x86-64.so.2", file.getInterpreter());

ElfSection rodata = file.firstSectionByName(ElfSection.NAME_RODATA);
Assert.assertNotNull(rodata);
Assert.assertEquals(ElfSection.SHT_PROGBITS, rodata.type);
}

}

0 comments on commit 53a9821

Please sign in to comment.