| /* |
| * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| package sun.jvm.hotspot.debugger.posix.elf; |
| |
| import java.io.*; |
| import java.util.*; |
| import sun.jvm.hotspot.utilities.memo.*; |
| import sun.jvm.hotspot.debugger.DataSource; |
| import sun.jvm.hotspot.debugger.RandomAccessFileDataSource; |
| |
| public class ELFFileParser { |
| private static ELFFileParser elfParser; |
| private static final String US_ASCII = "US-ASCII"; |
| |
| public static ELFFileParser getParser() { |
| if (elfParser == null) { |
| elfParser = new ELFFileParser(); |
| } |
| return elfParser; |
| } |
| |
| /** |
| * Parses the data in filename and returns the ELFFile representation. |
| */ |
| public ELFFile parse(String filename) throws ELFException { |
| try { |
| RandomAccessFile file = new RandomAccessFile(filename, "r"); |
| return parse(new RandomAccessFileDataSource(file)); |
| } catch (FileNotFoundException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| /** |
| * Parses the data source and returns the ELFFile representation. |
| */ |
| public ELFFile parse(DataSource source) throws ELFException { |
| return new ELFFileImpl(source); |
| } |
| |
| /** |
| * Implementation of the ELFFile interface. |
| */ |
| class ELFFileImpl implements ELFFile { |
| private DataSource file; |
| private ELFHeader header; |
| private byte ident[] = new byte[16]; |
| |
| ELFFileImpl(DataSource file) throws ELFException { |
| this.file = file; |
| int bytesRead = readBytes(ident); |
| if (bytesRead != ident.length) { |
| throw new ELFException("Error reading elf header (read " + |
| bytesRead + "bytes, expected to " + |
| "read " + ident.length + "bytes)."); |
| } |
| |
| // Check the magic number before we continue reading the file. |
| if (!Arrays.equals(getMagicNumber(), ELF_MAGIC_NUMBER)) { |
| throw new ELFException("Bad magic number for file."); |
| } |
| |
| header = new ELFHeaderImpl(); |
| } |
| |
| public ELFHeader getHeader() { return header; } |
| |
| public byte[] getMagicNumber() { |
| byte magicNumber[] = new byte[4]; |
| magicNumber[0] = ident[NDX_MAGIC_0]; |
| magicNumber[1] = ident[NDX_MAGIC_1]; |
| magicNumber[2] = ident[NDX_MAGIC_2]; |
| magicNumber[3] = ident[NDX_MAGIC_3]; |
| return magicNumber; |
| } |
| |
| public byte getObjectSize() { return ident[NDX_OBJECT_SIZE]; } |
| public byte getEncoding() { return ident[NDX_ENCODING]; } |
| public byte getVersion() { return ident[NDX_VERSION]; } |
| |
| |
| /** |
| * Implementation of the ELFHeader interface. |
| */ |
| class ELFHeaderImpl implements ELFHeader { |
| /** Marks the file as an object file and provide machine-independent |
| * data so the contents may be decoded and interpreted. */ |
| private byte ident[] = new byte[16]; // unsigned char |
| /** Identifies the object file type. */ |
| private short file_type; // Elf32_Half |
| /** The required architecture. */ |
| private short arch; // Elf32_Half |
| /** Version */ |
| private int version; // Elf32_Word |
| /** Virtual address to which the system first transfers control. |
| * If there is no entry point for the file the value is 0. */ |
| private int entry_point; // Elf32_Addr |
| /** Program header table offset in bytes. If there is no program |
| * header table the value is 0. */ |
| private int ph_offset; // Elf32_Off |
| /** Section header table offset in bytes. If there is no section |
| * header table the value is 0. */ |
| private int sh_offset; // Elf32_Off |
| /** Processor specific flags. */ |
| private int flags; // Elf32_Word |
| /** ELF header size in bytes. */ |
| private short eh_size; // Elf32_Half |
| /** Size of one entry in the file's program header table in bytes. |
| * All entries are the same size. */ |
| private short ph_entry_size; // Elf32_Half |
| /** Number of entries in the program header table, 0 if no |
| * entries. */ |
| private short num_ph; // Elf32_Half |
| /** Section header entry size in bytes. */ |
| private short sh_entry_size; // Elf32_Half |
| /** Number of entries in the section header table, 0 if no |
| * entries. */ |
| private short num_sh; // Elf32_Half |
| /** Index into the section header table associated with the section |
| * name string table. SH_UNDEF if there is no section name string |
| * table. */ |
| private short sh_string_ndx; // Elf32_Half |
| |
| /** MemoizedObject array of section headers associated with this |
| * ELF file. */ |
| private MemoizedObject[] sectionHeaders; |
| /** MemoizedObject array of program headers associated with this |
| * ELF file. */ |
| private MemoizedObject[] programHeaders; |
| |
| /** Used to cache symbol table lookup. */ |
| private ELFSectionHeader symbolTableSection; |
| /** Used to cache dynamic symbol table lookup. */ |
| private ELFSectionHeader dynamicSymbolTableSection; |
| /** Used to cache hash table lookup. */ |
| private ELFHashTable hashTable; |
| |
| /** |
| * Reads the ELF header and sets up the section and program headers |
| * in memoized arrays. |
| */ |
| ELFHeaderImpl() throws ELFException { |
| file_type = readShort(); |
| arch = readShort(); |
| version = readInt(); |
| entry_point = readInt(); |
| ph_offset = readInt(); |
| sh_offset = readInt(); |
| flags = readInt(); |
| eh_size = readShort(); |
| ph_entry_size = readShort(); |
| num_ph = readShort(); |
| sh_entry_size = readShort(); |
| num_sh = readShort(); |
| sh_string_ndx = readShort(); |
| |
| // Set up the section headers |
| sectionHeaders = new MemoizedObject[num_sh]; |
| for (int i = 0; i < num_sh; i++) { |
| final long sectionHeaderOffset = |
| (long)(sh_offset + (i * sh_entry_size)); |
| sectionHeaders[i] = new MemoizedObject() { |
| public Object computeValue() { |
| return new ELFSectionHeaderImpl(sectionHeaderOffset); |
| } |
| }; |
| } |
| |
| // // Set up the program headers |
| // programHeaders = new MemoizedObject[num_sh]; |
| // for (int i = 0; i < num_sh; i++) { |
| // final long programHeaderOffset = |
| // (long)(ph_offset + (i * ph_entry_size)); |
| // programHeaders[i] = new MemoizedObject() { |
| // public Object computeValue() { |
| // return new ProgramHeaderImpl(programHeaderOffset); |
| // } |
| // }; |
| // } |
| } |
| |
| public short getFileType() { return file_type; } |
| public short getArch() { return arch; } |
| public short getSectionHeaderSize() { return sh_entry_size; } |
| public short getNumberOfSectionHeaders() { return num_sh; } |
| |
| // public short getProgramHeaderSize() { return ph_entry_size; } |
| // public short getNumberOfProgramHeaders() { return num_ph; } |
| |
| |
| /** |
| * Returns the section header at the specified index. The section |
| * header at index 0 is defined as being a undefined section. */ |
| public ELFSectionHeader getSectionHeader(int index) { |
| return (ELFSectionHeader)sectionHeaders[index].getValue(); |
| } |
| |
| public ELFStringTable getSectionHeaderStringTable() { |
| return getSectionHeader(sh_string_ndx).getStringTable(); |
| } |
| |
| public ELFStringTable getStringTable() { |
| return findStringTableWithName(ELFSectionHeader.STRING_TABLE_NAME); |
| } |
| |
| public ELFStringTable getDynamicStringTable() { |
| return findStringTableWithName( |
| ELFSectionHeader.DYNAMIC_STRING_TABLE_NAME); |
| } |
| |
| private ELFStringTable findStringTableWithName(String tableName) { |
| // 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. |
| ELFSectionHeader sh = null; |
| for (int i = 1; i < getNumberOfSectionHeaders(); i++) { |
| sh = getSectionHeader(i); |
| if (tableName.equals(sh.getName())) { |
| return sh.getStringTable(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * The ELFHashTable does not currently work. This method will |
| * always return null. */ |
| public ELFHashTable getHashTable() { |
| // if (hashTable != null) { |
| // return hashTable; |
| // } |
| // |
| // ELFHashTable ht = null; |
| // for (int i = 1; i < getNumberOfSectionHeaders(); i++) { |
| // if ((ht = getSectionHeader(i).getHashTable()) != null) { |
| // hashTable = ht; |
| // return hashTable; |
| // } |
| // } |
| return null; |
| } |
| |
| public ELFSectionHeader getSymbolTableSection() { |
| if (symbolTableSection != null) { |
| return symbolTableSection; |
| } |
| |
| symbolTableSection = |
| getSymbolTableSection(ELFSectionHeader.TYPE_SYMTBL); |
| return symbolTableSection; |
| } |
| |
| public ELFSectionHeader getDynamicSymbolTableSection() { |
| if (dynamicSymbolTableSection != null) { |
| return dynamicSymbolTableSection; |
| } |
| |
| dynamicSymbolTableSection = |
| getSymbolTableSection(ELFSectionHeader.TYPE_DYNSYM); |
| return dynamicSymbolTableSection; |
| } |
| |
| private ELFSectionHeader getSymbolTableSection(int type) { |
| ELFSectionHeader sh = null; |
| for (int i = 1; i < getNumberOfSectionHeaders(); i++) { |
| sh = getSectionHeader(i); |
| if (sh.getType() == type) { |
| dynamicSymbolTableSection = sh; |
| return sh; |
| } |
| } |
| return null; |
| } |
| |
| public ELFSymbol getELFSymbol(String symbolName) { |
| if (symbolName == null) { |
| return null; |
| } |
| |
| // Check dynamic symbol table for symbol name. |
| ELFSymbol symbol = null; |
| int numSymbols = 0; |
| ELFSectionHeader sh = getDynamicSymbolTableSection(); |
| if (sh != null) { |
| numSymbols = sh.getNumberOfSymbols(); |
| for (int i = 0; i < Math.ceil(numSymbols / 2); i++) { |
| if (symbolName.equals( |
| (symbol = sh.getELFSymbol(i)).getName())) { |
| return symbol; |
| } else if (symbolName.equals( |
| (symbol = sh.getELFSymbol( |
| numSymbols - 1 - i)).getName())) { |
| return symbol; |
| } |
| } |
| } |
| |
| // Check symbol table for symbol name. |
| sh = getSymbolTableSection(); |
| if (sh != null) { |
| numSymbols = sh.getNumberOfSymbols(); |
| for (int i = 0; i < Math.ceil(numSymbols / 2); i++) { |
| if (symbolName.equals( |
| (symbol = sh.getELFSymbol(i)).getName())) { |
| return symbol; |
| } else if (symbolName.equals( |
| (symbol = sh.getELFSymbol( |
| numSymbols - 1 - i)).getName())) { |
| return symbol; |
| } |
| } |
| } |
| return null; |
| } |
| |
| public ELFSymbol getELFSymbol(long address) { |
| // Check dynamic symbol table for address. |
| ELFSymbol symbol = null; |
| int numSymbols = 0; |
| long value = 0L; |
| |
| ELFSectionHeader sh = getDynamicSymbolTableSection(); |
| if (sh != null) { |
| numSymbols = sh.getNumberOfSymbols(); |
| for (int i = 0; i < numSymbols; i++) { |
| symbol = sh.getELFSymbol(i); |
| value = symbol.getValue(); |
| if (address >= value && address < value + symbol.getSize()) { |
| return symbol; |
| } |
| } |
| } |
| |
| // Check symbol table for symbol name. |
| sh = getSymbolTableSection(); |
| if (sh != null) { |
| numSymbols = sh.getNumberOfSymbols(); |
| for (int i = 0; i < numSymbols; i++) { |
| symbol = sh.getELFSymbol(i); |
| value = symbol.getValue(); |
| if (address >= value && address < value + symbol.getSize()) { |
| return symbol; |
| } |
| } |
| } |
| return null; |
| } |
| |
| // public ProgramHeader getProgramHeader(int index) { |
| // return (ProgramHeader)programHeaders[index].getValue(); |
| // } |
| } |
| |
| |
| /** |
| * Implementation of the ELFSectionHeader interface. |
| */ |
| class ELFSectionHeaderImpl implements ELFSectionHeader { |
| /** Index into the section header string table which gives the |
| * name of the section. */ |
| private int name_ndx; // Elf32_Word |
| /** Section content and semantics. */ |
| private int type; // Elf32_Word |
| /** Flags. */ |
| private int flags; // Elf32_Word |
| /** If the section will be in the memory image of a process this |
| * will be the address at which the first byte of section will be |
| * loaded. Otherwise, this value is 0. */ |
| private int address; // Elf32_Addr |
| /** Offset from beginning of file to first byte of the section. */ |
| private int section_offset; // Elf32_Off |
| /** Size in bytes of the section. TYPE_NOBITS is a special case. */ |
| private int size; // Elf32_Word |
| /** Section header table index link. */ |
| private int link; // Elf32_Word |
| /** Extra information determined by the section type. */ |
| private int info; // Elf32_Word |
| /** Address alignment constraints for the section. */ |
| private int address_alignment; // Elf32_Word |
| /** Size of a fixed-size entry, 0 if none. */ |
| private int entry_size; // Elf32_Word |
| |
| /** Memoized symbol table. */ |
| private MemoizedObject[] symbols; |
| /** Memoized string table. */ |
| private MemoizedObject stringTable; |
| /** Memoized hash table. */ |
| private MemoizedObject hashTable; |
| |
| /** |
| * Reads the section header information located at offset. |
| */ |
| ELFSectionHeaderImpl(long offset) throws ELFException { |
| seek(offset); |
| name_ndx = readInt(); |
| type = readInt(); |
| flags = readInt(); |
| address = readInt(); |
| section_offset = readInt(); |
| size = readInt(); |
| link = readInt(); |
| info = readInt(); |
| address_alignment = readInt(); |
| entry_size = readInt(); |
| |
| switch (type) { |
| case ELFSectionHeader.TYPE_NULL: |
| break; |
| case ELFSectionHeader.TYPE_PROGBITS: |
| break; |
| case ELFSectionHeader.TYPE_SYMTBL: |
| case ELFSectionHeader.TYPE_DYNSYM: |
| // Setup the symbol table. |
| int num_entries = size / entry_size; |
| symbols = new MemoizedObject[num_entries]; |
| for (int i = 0; i < num_entries; i++) { |
| final int symbolOffset = section_offset + |
| (i * entry_size); |
| symbols[i] = new MemoizedObject() { |
| public Object computeValue() { |
| return new ELFSymbolImpl(symbolOffset,type); |
| } |
| }; |
| } |
| break; |
| case ELFSectionHeader.TYPE_STRTBL: |
| // Setup the string table. |
| final int strTableOffset = section_offset; |
| final int strTableSize = size; |
| stringTable = new MemoizedObject() { |
| public Object computeValue() { |
| return new ELFStringTableImpl(strTableOffset, |
| strTableSize); |
| } |
| }; |
| break; |
| case ELFSectionHeader.TYPE_RELO_EXPLICIT: |
| break; |
| case ELFSectionHeader.TYPE_HASH: |
| final int hashTableOffset = section_offset; |
| final int hashTableSize = size; |
| hashTable = new MemoizedObject() { |
| public Object computeValue() { |
| return new ELFHashTableImpl(hashTableOffset, |
| hashTableSize); |
| } |
| }; |
| break; |
| case ELFSectionHeader.TYPE_DYNAMIC: |
| break; |
| case ELFSectionHeader.TYPE_NOTE: |
| break; |
| case ELFSectionHeader.TYPE_NOBITS: |
| break; |
| case ELFSectionHeader.TYPE_RELO: |
| break; |
| case ELFSectionHeader.TYPE_SHLIB: |
| break; |
| default: |
| break; |
| } |
| } |
| |
| public int getType() { |
| return type; |
| } |
| |
| public int getNumberOfSymbols() { |
| if (symbols != null) { |
| return symbols.length; |
| } |
| return 0; |
| } |
| |
| /** |
| * Returns the ELFSymbol at the specified index. Index 0 is |
| * reserved for the undefined ELF symbol. */ |
| public ELFSymbol getELFSymbol(int index) { |
| return (ELFSymbol)symbols[index].getValue(); |
| } |
| |
| public ELFStringTable getStringTable() { |
| if (stringTable != null) { |
| return (ELFStringTable)stringTable.getValue(); |
| } |
| return null; |
| } |
| |
| /** |
| * The ELFHashTable does not currently work. This method will |
| * always return null. */ |
| public ELFHashTable getHashTable() { |
| if (hashTable != null) { |
| return (ELFHashTable)hashTable.getValue(); |
| } |
| return null; |
| } |
| |
| public String getName() { |
| if (name_ndx == 0) { |
| return null; |
| } |
| |
| ELFStringTable tbl = getHeader().getSectionHeaderStringTable(); |
| return tbl.get(name_ndx); |
| } |
| |
| public int getLink() { |
| return link; |
| } |
| |
| public int getOffset() { |
| return section_offset; |
| } |
| } |
| |
| |
| // class ProgramHeaderImpl implements ProgramHeader { |
| // /** Defines the kind of segment this element describes. */ |
| // private int type; // Elf32_Word |
| // /** Offset from the beginning of the file. */ |
| // private int offset; // Elf32_Off |
| // /** Virtual address at which the first byte of the segment |
| // * resides in memory. */ |
| // private int virtual_address; // Elf32_Addr |
| // /** Reserved for the physical address of the segment on systems |
| // * where physical addressinf is relevant. */ |
| // private int physical_address; // Elf32_addr |
| // /** File image size of segment in bytes, may be 0. */ |
| // private int file_size; // Elf32_Word |
| // /** Memory image size of segment in bytes, may be 0. */ |
| // private int mem_size; // Elf32_Word |
| // /** Flags relevant to this segment. Values for flags are defined |
| // * in ELFSectionHeader. */ |
| // private int flags; // Elf32_Word |
| // private int alignment; // Elf32_Word |
| // |
| // private MemoizedObject[] symbols; |
| // |
| // ProgramHeaderImpl(long offset) throws ELFException { |
| // seek(offset); |
| // type = readInt(); |
| // this.offset = readInt(); |
| // virtual_address = readInt(); |
| // physical_address = readInt(); |
| // file_size = readInt(); |
| // mem_size = readInt(); |
| // flags = readInt(); |
| // alignment = readInt(); |
| // |
| // switch (type) { |
| // case ELFSectionHeader.TYPE_NULL: |
| // break; |
| // case ELFSectionHeader.TYPE_PROGBITS: |
| // break; |
| // case ELFSectionHeader.TYPE_SYMTBL: |
| // case ELFSectionHeader.TYPE_DYNSYM: |
| // break; |
| // case ELFSectionHeader.TYPE_STRTBL: |
| // // Setup the string table. |
| // final int strTableOffset = section_offset; |
| // final int strTableSize = size; |
| // stringTable = new MemoizedObject() { |
| // public Object computeValue() { |
| // return new ELFStringTableImpl(strTableOffset, |
| // strTableSize); |
| // } |
| // }; |
| // new ELFStringTableImpl(offset, file_size); |
| // break; |
| // case ELFSectionHeader.TYPE_RELO_EXPLICIT: |
| // break; |
| // case ELFSectionHeader.TYPE_HASH: |
| // break; |
| // case ELFSectionHeader.TYPE_DYNAMIC: |
| // break; |
| // case ELFSectionHeader.TYPE_NOTE: |
| // break; |
| // case ELFSectionHeader.TYPE_NOBITS: |
| // break; |
| // case ELFSectionHeader.TYPE_RELO: |
| // break; |
| // case ELFSectionHeader.TYPE_SHLIB: |
| // break; |
| // default: |
| // break; |
| // } |
| // } |
| // |
| // public int getType() { |
| // return type; |
| // } |
| // } |
| |
| |
| /** |
| * Implementation of the ELFSymbol interface. |
| */ |
| class ELFSymbolImpl implements ELFSymbol { |
| /** Index into the symbol string table that holds the character |
| * representation of the symbols. 0 means the symbol has no |
| * character name. */ |
| private int name_ndx; // Elf32_Word |
| /** Value of the associated symbol. This may be an address or |
| * an absolute value. */ |
| private int value; // Elf32_Addr |
| /** Size of the symbol. 0 if the symbol has no size or the size |
| * is unknown. */ |
| private int size; // Elf32_Word |
| /** Specifies the symbol type and beinding attributes. */ |
| private byte info; // unsigned char |
| /** Currently holds the value of 0 and has no meaning. */ |
| private byte 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. */ |
| private short section_header_ndx; // Elf32_Half |
| |
| private int section_type; |
| |
| /** Offset from the beginning of the file to this symbol. */ |
| private long offset; |
| |
| ELFSymbolImpl(long offset, int section_type) throws ELFException { |
| seek(offset); |
| this.offset = offset; |
| name_ndx = readInt(); |
| value = readInt(); |
| size = readInt(); |
| info = readByte(); |
| other = readByte(); |
| section_header_ndx = readShort(); |
| |
| this.section_type = section_type; |
| |
| switch (getType()) { |
| case TYPE_NOOBJECT: |
| break; |
| case TYPE_OBJECT: |
| break; |
| case TYPE_FUNCTION: |
| break; |
| case TYPE_SECTION: |
| break; |
| case TYPE_FILE: |
| break; |
| case TYPE_LOPROC: |
| break; |
| case TYPE_HIPROC: |
| break; |
| default: |
| break; |
| } |
| } |
| |
| public int getBinding() { return info >> 4; } |
| public int getType() { return info & 0x0F; } |
| public long getOffset() { return offset; } |
| |
| public String getName() { |
| // Check to make sure this symbol has a name. |
| if (name_ndx == 0) { |
| return null; |
| } |
| |
| // Retrieve the name of the symbol from the correct string |
| // table. |
| String symbol_name = null; |
| if (section_type == ELFSectionHeader.TYPE_SYMTBL) { |
| symbol_name = getHeader().getStringTable().get(name_ndx); |
| } else if (section_type == ELFSectionHeader.TYPE_DYNSYM) { |
| symbol_name = |
| getHeader().getDynamicStringTable().get(name_ndx); |
| } |
| return symbol_name; |
| } |
| |
| public long getValue() { |
| return value; |
| } |
| |
| public int getSize() { |
| return size; |
| } |
| } |
| |
| /** |
| * Implementation of the ELFStringTable interface. |
| */ |
| class ELFStringTableImpl implements ELFStringTable { |
| /** The string table data. */ |
| private byte data[]; |
| private int numStrings; |
| |
| /** |
| * Reads all the strings from [offset, length]. |
| */ |
| ELFStringTableImpl(long offset, int length) throws ELFException { |
| seek(offset); |
| data = new byte[length]; |
| int bytesRead = readBytes(data); |
| if (bytesRead != length) { |
| throw new ELFException("Error reading string table (read " + |
| bytesRead + "bytes, expected to " + |
| "read " + data.length + "bytes)."); |
| } |
| |
| // Count the strings. |
| numStrings = 0; |
| for (int ptr = 0; ptr < data.length; ptr++) { |
| if (data[ptr] == '\0') { |
| numStrings++; |
| } |
| } |
| } |
| |
| public String get(int index) { |
| int startPtr = index; |
| int endPtr = index; |
| while (data[endPtr] != '\0') { |
| endPtr++; |
| } |
| return new String(data, startPtr, endPtr - startPtr); |
| } |
| |
| public int getNumStrings() { |
| return numStrings; |
| } |
| } |
| |
| |
| /** Implementation of the ELFHashTable. */ |
| class ELFHashTableImpl implements ELFHashTable { |
| private int num_buckets; |
| private int num_chains; |
| |
| // These could probably be memoized. |
| private int buckets[]; |
| private int chains[]; |
| |
| ELFHashTableImpl(long offset, int length) throws ELFException { |
| seek(offset); |
| num_buckets = readInt(); |
| num_chains = readInt(); |
| |
| buckets = new int[num_buckets]; |
| chains = new int[num_chains]; |
| // Read the bucket data. |
| for (int i = 0; i < num_buckets; i++) { |
| buckets[i] = readInt(); |
| } |
| |
| // Read the chain data. |
| for (int i = 0; i < num_chains; i++) { |
| chains[i] = readInt(); |
| } |
| |
| // Make sure that the amount of bytes we were supposed to read |
| // was what we actually read. |
| int actual = num_buckets * 4 + num_chains * 4 + 8; |
| if (length != actual) { |
| throw new ELFException("Error reading string table (read " + |
| actual + "bytes, expected to " + |
| "read " + length + "bytes)."); |
| } |
| } |
| |
| /** |
| * This method doesn't work every time and is unreliable. Use |
| * ELFSection.getELFSymbol(String) to retrieve symbols by name. |
| * NOTE: since this method is currently broken it will always |
| * return null. */ |
| public ELFSymbol getSymbol(String symbolName) { |
| // if (symbolName == null) { |
| // return null; |
| // } |
| // |
| // long hash = 0; |
| // long g = 0; |
| // |
| // for (int i = 0; i < symbolName.length(); i++) { |
| // hash = (hash << 4) + symbolName.charAt(i); |
| // if ((g = hash & 0xf0000000) != 0) { |
| // hash ^= g >>> 24; |
| // } |
| // hash &= ~g; |
| // } |
| // |
| // ELFSymbol symbol = null; |
| // ELFSectionHeader dyn_sh = |
| // getHeader().getDynamicSymbolTableSection(); |
| // int index = (int)hash % num_buckets; |
| // while(index != 0) { |
| // symbol = dyn_sh.getELFSymbol(index); |
| // if (symbolName.equals(symbol.getName())) { |
| // break; |
| // } |
| // symbol = null; |
| // index = chains[index]; |
| // } |
| // return symbol; |
| return null; |
| } |
| } |
| |
| |
| public void close() throws ELFException { |
| try { |
| file.close(); |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| void seek(long offset) throws ELFException { |
| try { |
| file.seek(offset); |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| long getFilePointer() throws ELFException { |
| try { |
| return file.getFilePointer(); |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| byte readByte() throws ELFException { |
| try { |
| return file.readByte(); |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| int readBytes(byte[] b) throws ELFException { |
| try { |
| return file.read(b); |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| short readShort() throws ELFException { |
| try { |
| short val; |
| switch (ident[NDX_ENCODING]) { |
| case DATA_LSB: |
| val = byteSwap(file.readShort()); |
| break; |
| case DATA_MSB: |
| val = file.readShort(); |
| break; |
| default: |
| throw new ELFException("Invalid encoding."); |
| } |
| return val; |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| int readInt() throws ELFException { |
| try { |
| int val; |
| switch (ident[NDX_ENCODING]) { |
| case DATA_LSB: |
| val = byteSwap(file.readInt()); |
| break; |
| case DATA_MSB: |
| val = file.readInt(); |
| break; |
| default: |
| throw new ELFException("Invalid encoding."); |
| } |
| return val; |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| long readLong() throws ELFException { |
| try { |
| long val; |
| switch (ident[NDX_ENCODING]) { |
| case DATA_LSB: |
| val = byteSwap(file.readLong()); |
| break; |
| case DATA_MSB: |
| val = file.readLong(); |
| break; |
| default: |
| throw new ELFException("Invalid encoding."); |
| } |
| return val; |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| /** Signed byte utility functions used for converting from big-endian |
| * (MSB) to little-endian (LSB). */ |
| short byteSwap(short arg) { |
| return (short) ((arg << 8) | ((arg >>> 8) & 0xFF)); |
| } |
| |
| int byteSwap(int arg) { |
| return (((int) byteSwap((short) arg)) << 16) | |
| (((int) (byteSwap((short) (arg >>> 16)))) & 0xFFFF); |
| } |
| |
| long byteSwap(long arg) { |
| return ((((long) byteSwap((int) arg)) << 32) | |
| (((long) byteSwap((int) (arg >>> 32))) & 0xFFFFFFFF)); |
| } |
| |
| |
| /* Unsigned byte utility functions. Since java does not have unsigned |
| * data types we must convert values manually and we must return |
| * unsigned values in a larger data type. Therefore we can only have |
| * unsigned values for byte, short, and int. */ |
| short readUnsignedByte() throws ELFException { |
| try { |
| return unsignedByte(file.readByte()); |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| int readUnsignedShort() throws ELFException { |
| try { |
| int val; |
| switch (ident[NDX_ENCODING]) { |
| case DATA_LSB: |
| val = unsignedByteSwap(file.readShort()); |
| break; |
| case DATA_MSB: |
| val = unsignedByte(file.readShort()); |
| break; |
| default: |
| throw new ELFException("Invalid encoding."); |
| } |
| return val; |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| long readUnsignedInt() throws ELFException { |
| try { |
| long val; |
| switch (ident[NDX_ENCODING]) { |
| case DATA_LSB: |
| val = unsignedByteSwap(file.readInt()); |
| break; |
| case DATA_MSB: |
| val = unsignedByte(file.readInt()); |
| break; |
| default: |
| throw new ELFException("Invalid encoding."); |
| } |
| return val; |
| } catch (IOException e) { |
| throw new ELFException(e); |
| } |
| } |
| |
| /** Returns the unsigned value of the byte. */ |
| short unsignedByte(byte arg) { |
| return (short)(arg & 0x00FF); |
| } |
| |
| /** Returns a big-endian unsigned representation of the short. */ |
| int unsignedByte(short arg) { |
| int val; |
| if (arg >= 0) { |
| val = arg; |
| } else { |
| val = (int)(((int)unsignedByte((byte)(arg >>> 8)) << 8) | |
| ((byte)arg)); |
| } |
| return val; |
| } |
| |
| /** Returns a big-endian unsigned representation of the int. */ |
| long unsignedByte(int arg) { |
| long val; |
| if (arg >= 0) { |
| val = arg; |
| } else { |
| val = (long)(((long)unsignedByte((short)(arg >>> 16)) << 16) | |
| ((short)arg)); |
| } |
| return val; |
| } |
| |
| /** Unsigned byte utility functions used for converting from big-endian |
| * (MSB) to little-endian (LSB). */ |
| int unsignedByteSwap(short arg) { |
| return (int)(((int)unsignedByte((byte)arg)) << 8) | |
| ((int)unsignedByte((byte)(arg >>> 8))); |
| } |
| |
| long unsignedByteSwap(int arg) { |
| return (long)(((long)unsignedByteSwap((short)arg)) << 16) | |
| ((long)unsignedByteSwap((short)(arg >>> 16))); |
| } |
| } |
| |
| public static void main(String args[]) { |
| if (args.length != 1) { |
| System.out.println("Usage: java ELFFileParser <elf file>"); |
| System.exit(0); |
| } |
| |
| // Parse the file. |
| ELFFile elfFile = ELFFileParser.getParser().parse(args[0]); |
| |
| ELFHeader elfHeader = elfFile.getHeader(); |
| System.out.println("ELF File: " + args[0]); |
| |
| System.out.println("ELF object size: " + |
| ((elfFile.getObjectSize() == 0) ? "Invalid Object Size" : |
| (elfFile.getObjectSize() == 1) ? "32-bit" : "64-bit")); |
| System.out.println("ELF data encoding: " + |
| ((elfFile.getEncoding() == 0) ? "Invalid Data Encoding" : |
| (elfFile.getEncoding() == 1) ? "LSB" : "MSB")); |
| |
| int h = elfHeader.getNumberOfSectionHeaders(); |
| System.out.println("--> Start: reading " + h + " section headers."); |
| for (int i = 0; i < elfHeader.getNumberOfSectionHeaders(); i++) { |
| ELFSectionHeader sh = elfHeader.getSectionHeader(i); |
| String str = sh.getName(); |
| System.out.println("----> Start: Section (" + i + ") " + str); |
| |
| int num = 0; |
| if ((num = sh.getNumberOfSymbols()) != 0) { |
| System.out.println("------> Start: reading " + num + " symbols."); |
| for (int j = 0; j < num ; j++) { |
| ELFSymbol sym = sh.getELFSymbol(j); |
| //String name = sym.getName(); |
| //if (name != null) { |
| // System.out.println(name); |
| //} |
| } |
| System.out.println("<------ End: reading " + num + " symbols."); |
| } |
| ELFStringTable st; |
| if (sh.getType() == ELFSectionHeader.TYPE_STRTBL) { |
| System.out.println("------> Start: reading string table."); |
| st = sh.getStringTable(); |
| System.out.println("<------ End: reading string table."); |
| } |
| if (sh.getType() == ELFSectionHeader.TYPE_HASH) { |
| System.out.println("------> Start: reading hash table."); |
| sh.getHashTable(); |
| System.out.println("<------ End: reading hash table."); |
| } |
| System.out.println("<---- End: Section (" + i + ") " + str); |
| } |
| System.out.println("<-- End: reading " + h + " section headers."); |
| /* |
| h = elfHeader.getNumberOfProgramHeaders(); |
| System.out.println("--> Start: reading " + h + " program headers."); |
| for (int i = 0; i < elfHeader.getNumberOfProgramHeaders(); i++) { |
| elfHeader.getProgramHeader(i); |
| } |
| System.out.println("<-- End: reading " + h + " program headers."); |
| */ |
| elfFile.close(); |
| } |
| } |