Skip to content

Commit

Permalink
Merge pull request #3 from Buglife/master
Browse files Browse the repository at this point in the history
Parse note sections, MapByteBuffer option for file reading
  • Loading branch information
fornwall authored Apr 3, 2019
2 parents c5b4b61 + b2552ba commit 9ea17cb
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 9 deletions.
4 changes: 2 additions & 2 deletions src/main/java/net/fornwall/jelf/ElfDynamicStructure.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public String toString() {
}
}

public ElfDynamicStructure(ElfParser parser, long offset, int size) {
public ElfDynamicStructure(final ElfParser parser, long offset, int size) {
parser.seek(offset);
int numEntries = size / 8;

Expand All @@ -150,7 +150,7 @@ public ElfDynamicStructure(ElfParser parser, long offset, int size) {
// necessary DT_STRSZ is read.
loop: for (int i = 0; i < numEntries; i++) {
long d_tag = parser.readIntOrLong();
long d_val_or_ptr = parser.readIntOrLong();
final long d_val_or_ptr = parser.readIntOrLong();
entries.add(new ElfDynamicSectionEntry(d_tag, d_val_or_ptr));
switch ((int) d_tag) {
case DT_NULL:
Expand Down
70 changes: 69 additions & 1 deletion src/main/java/net/fornwall/jelf/ElfFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.MappedByteBuffer;

/**
* An ELF (Executable and Linkable Format) file can be a relocatable, executable, shared or core file.
Expand Down Expand Up @@ -290,11 +291,78 @@ public static ElfFile fromFile(File file) throws ElfException, IOException {
public static ElfFile fromBytes(byte[] buffer) throws ElfException, IOException {
return new ElfFile(new ByteArrayInputStream(buffer));
}
public ElfFile(MappedByteBuffer buffer, long startPosition) throws ElfException, IOException {
final ElfParser parser = new ElfParser(this, buffer, startPosition);

//Parsing is a shitty thing to do in constructors.
byte[] ident = new byte[16];
int bytesRead = parser.read(ident);
if (bytesRead != ident.length)
throw new ElfException("Error reading elf header (read " + bytesRead + "bytes - expected to read " + ident.length + "bytes)");

if (!(0x7f == ident[0] && 'E' == ident[1] && 'L' == ident[2] && 'F' == ident[3])) throw new ElfException("Bad magic number for file");

objectSize = ident[4];
if (!(objectSize == CLASS_32 || objectSize == CLASS_64)) throw new ElfException("Invalid object size class: " + objectSize);
encoding = ident[5];
if (!(encoding == DATA_LSB || encoding == DATA_MSB)) throw new ElfException("Invalid encoding: " + encoding);
int elfVersion = ident[6];
if (elfVersion != 1) throw new ElfException("Invalid elf version: " + elfVersion);
// ident[7]; // EI_OSABI, target operating system ABI
// ident[8]; // EI_ABIVERSION, ABI version. Linux kernel (after at least 2.6) has no definition of it.
// ident[9-15] // EI_PAD, currently unused.

file_type = parser.readShort();
arch = parser.readShort();
version = parser.readInt();
entry_point = parser.readIntOrLong();
ph_offset = parser.readIntOrLong();
sh_offset = parser.readIntOrLong();
flags = parser.readInt();
eh_size = parser.readShort();
ph_entry_size = parser.readShort();
num_ph = parser.readShort();
sh_entry_size = parser.readShort();
num_sh = parser.readShort();
if (num_sh == 0) {
throw new ElfException("e_shnum is SHN_UNDEF(0), which is not supported yet"
+ " (the actual number of section header table entries is contained in the sh_size field of the section header at index 0)");
}
sh_string_ndx = parser.readShort();
if (sh_string_ndx == /* SHN_XINDEX= */0xffff) {
throw new ElfException("e_shstrndx is SHN_XINDEX(0xffff), which is not supported yet"
+ " (the actual index of the section name string table section is contained in the sh_link field of the section header at index 0)");
}

sectionHeaders = MemoizedObject.uncheckedArray(num_sh);
for (int i = 0; i < num_sh; i++) {
final long sectionHeaderOffset = sh_offset + (i * sh_entry_size);
sectionHeaders[i] = new MemoizedObject<ElfSection>() {
@Override
public ElfSection computeValue() throws ElfException, IOException {
return new ElfSection(parser, sectionHeaderOffset);
}
};
}

programHeaders = MemoizedObject.uncheckedArray(num_ph);
for (int i = 0; i < num_ph; i++) {
final long programHeaderOffset = ph_offset + (i * ph_entry_size);
programHeaders[i] = new MemoizedObject<ElfSegment>() {
@Override
public ElfSegment computeValue() throws IOException {
return new ElfSegment(parser, programHeaderOffset);
}
};
}

}


public ElfFile(ByteArrayInputStream baos) throws ElfException, IOException {
byte[] ident = new byte[16];
final ElfParser parser = new ElfParser(this, baos);

byte[] ident = new byte[16];
int bytesRead = parser.read(ident);
if (bytesRead != ident.length)
throw new ElfException("Error reading elf header (read " + bytesRead + "bytes - expected to read " + ident.length + "bytes)");
Expand Down
54 changes: 54 additions & 0 deletions src/main/java/net/fornwall/jelf/ElfNote.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.fornwall.jelf;

import java.io.IOException;

class ElfNote {
private int nameSize;
private int descSize;
private int type;
private String name;
private String desc;
private byte[] descBytes;
ElfNote(ElfParser parser, long offset, int size) throws ElfException, IOException {
parser.seek(offset);
nameSize = parser.readInt();
descSize = parser.readInt();
type = parser.readInt();
byte nameBytes[] = new byte[nameSize];
descBytes = new byte[descSize];
int bytesRead = parser.read(nameBytes);
if (bytesRead != nameSize) {
throw new ElfException("Error reading note (read " + bytesRead + "bytes - expected to " + "read " + nameSize + "bytes)");
}
while (bytesRead % 4 != 0) { // finish reading the padding to the nearest 4 bytes
parser.readUnsignedByte();
bytesRead += 1;
}
bytesRead = parser.read(descBytes);
if (bytesRead != descSize) {
throw new ElfException("Error reading note (read " + bytesRead + "bytes - expected to " + "read " + descSize + "bytes)");
}
while (bytesRead % 4 != 0) { // finish reading the padding to the nearest 4 bytes
parser.readUnsignedByte();
bytesRead += 1;
}
name = new String(nameBytes, 0, nameSize-1); // unnecessary trailing 0
desc = new String(descBytes, 0, descSize); // There's no trailing 0 on desc
}

String getName() {
return name;
}

int getType() {
return type;
}

String getDesc() {
return desc;
}

byte[] getDescBytes() {
return descBytes;
}
}
41 changes: 37 additions & 4 deletions src/main/java/net/fornwall/jelf/ElfParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,41 @@

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;

/** Package internal class used for parsing ELF files. */
class ElfParser {

final ElfFile elfFile;
private final ByteArrayInputStream fsFile;

private final MappedByteBuffer mappedByteBuffer;
private final long mbbStartPosition;


ElfParser(ElfFile elfFile, ByteArrayInputStream fsFile) {
this.elfFile = elfFile;
this.fsFile = fsFile;
mappedByteBuffer = null;
mbbStartPosition = -1;
}

ElfParser(ElfFile elfFile, MappedByteBuffer byteBuffer, long mbbStartPos) {
this.elfFile = elfFile;
mappedByteBuffer = byteBuffer;
mbbStartPosition = mbbStartPos;
mappedByteBuffer.position((int)mbbStartPosition);
fsFile = null;
}

public void seek(long offset) {
fsFile.reset();
if (fsFile.skip(offset) != offset) throw new ElfException("seeking outside file");
if (fsFile != null) {
fsFile.reset();
if (fsFile.skip(offset) != offset) throw new ElfException("seeking outside file");
}
else if (mappedByteBuffer != null) {
mappedByteBuffer.position((int)(mbbStartPosition + offset)); // we may be limited to sub-4GB mapped filess
}
}

/**
Expand All @@ -35,7 +55,14 @@ long byteSwap(long arg) {
}

short readUnsignedByte() {
int val = fsFile.read();
int val = -1;
if (fsFile != null) {
val = fsFile.read();
} else if (mappedByteBuffer != null) {
byte temp = mappedByteBuffer.get();
val = temp & 0xFF; // bytes are signed in Java =_= so assigning them to a longer type risks sign extension.
}

if (val < 0) throw new ElfException("Trying to read outside file");
return (short) val;
}
Expand Down Expand Up @@ -111,7 +138,13 @@ long virtualMemoryAddrToFileOffset(long address) throws IOException {
}

public int read(byte[] data) throws IOException {
return fsFile.read(data);
if (fsFile != null) {
return fsFile.read(data);
} else if (mappedByteBuffer != null) {
mappedByteBuffer.get(data);
return data.length;
}
throw new IOException("No way to read from file or buffer");
}

}
12 changes: 11 additions & 1 deletion src/main/java/net/fornwall/jelf/ElfSection.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,12 @@ public final class ElfSection {
private MemoizedObject<ElfHashTable> hashTable;
/** For the {@link #SHT_DYNAMIC} ".dynamic" structure. */
private MemoizedObject<ElfDynamicStructure> dynamicStructure;
private MemoizedObject<ElfNote> note;

private final ElfFile elfHeader;

/** Reads the section header information located at offset. */
ElfSection(ElfParser parser, long offset) {
ElfSection(final ElfParser parser, long offset) {
this.elfHeader = parser.elfFile;
parser.seek(offset);

Expand Down Expand Up @@ -190,6 +191,12 @@ protected ElfDynamicStructure computeValue() throws ElfException, IOException {
};
break;
case ElfSection.SHT_NOTE:
note = new MemoizedObject<ElfNote>() {
@Override
protected ElfNote computeValue() throws ElfException, IOException {
return new ElfNote(parser, section_offset, (int)size);
}
};
break;
case ElfSection.SHT_NOBITS:
break;
Expand Down Expand Up @@ -220,6 +227,9 @@ public ElfStringTable getStringTable() throws IOException {
public ElfDynamicStructure getDynamicSection() throws IOException {
return (dynamicStructure != null) ? dynamicStructure.getValue() : null;
}
public ElfNote getNote() throws IOException {
return (note != null) ? note.getValue() : null;
}

/**
* Returns the hash table for this section or null if one does not exist. NOTE: currently the ELFHashTable does not
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/net/fornwall/jelf/ElfSegment.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public class ElfSegment {

private MemoizedObject<String> ptInterpreter;

ElfSegment(ElfParser parser, long offset) {
ElfSegment(final ElfParser parser, long offset) {
parser.seek(offset);
if (parser.elfFile.objectSize == ElfFile.CLASS_32) {
// typedef struct {
Expand Down

0 comments on commit 9ea17cb

Please sign in to comment.