diff agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFFileParser.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/posix/elf/ELFFileParser.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,1097 @@
+/*
+ * Copyright 2001-2004 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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();
+    }
+}