diff options
author | Sven Gothel <[email protected]> | 2013-02-08 05:12:39 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-02-08 05:12:39 +0100 |
commit | 2432dbef17c1dc4164f055cf434073bdabf8a6a9 (patch) | |
tree | 348a46b246ead8bb508152a96847a62089b72d0c /src | |
parent | 1118cb7182611d0a77764a3c781a1148849b3022 (diff) |
Bug 681: Add Basic ELF Header + ARM EABI Section Parsing, allowing to distinguish ARM soft-float/hard-float (part-1)
https://jogamp.org/bugzilla/show_bug.cgi?id=681
+ * References:
+ * <ul>
+ * <li>http://linux.die.net/man/5/elf</li>
+ * <li>http://www.sco.com/developers/gabi/latest/contents.html</li>
+ * <li>http://infocenter.arm.com/
+ * <ul>
+ * <li>ARM IHI 0044E, current through ABI release 2.09</li>
+ * <li>ARM IHI 0045D, current through ABI release 2.09</li>
+ * </ul></li>
Added self contained jogamp.common.os.elf package w/ entry point class ElfHeader
to read a RandomAccessFile and parse it as an ELF file.
ELF Parsing completness:
- Header: OK
- SectionHeader: OK
- Section Type SHT_ARM_ATTRIBUTES: OK
- Will be read into SectionArmAttributes
- Used to distinguisgh soft/hard VFP float
Tested manually on:
- Linux intel 32bit / 64bit, arm soft-float and hard-float
Diffstat (limited to 'src')
-rw-r--r-- | src/java/jogamp/common/os/elf/Ehdr.java | 179 | ||||
-rw-r--r-- | src/java/jogamp/common/os/elf/ElfHeader.java | 574 | ||||
-rw-r--r-- | src/java/jogamp/common/os/elf/IOUtils.java | 148 | ||||
-rw-r--r-- | src/java/jogamp/common/os/elf/Section.java | 50 | ||||
-rw-r--r-- | src/java/jogamp/common/os/elf/SectionArmAttributes.java | 317 | ||||
-rw-r--r-- | src/java/jogamp/common/os/elf/SectionHeader.java | 274 | ||||
-rw-r--r-- | src/java/jogamp/common/os/elf/Shdr.java | 141 | ||||
-rw-r--r-- | src/junit/com/jogamp/common/nio/TestStructAccessorEndian.java | 10 | ||||
-rw-r--r-- | src/junit/com/jogamp/common/os/TestElfReader01.java | 119 |
9 files changed, 1807 insertions, 5 deletions
diff --git a/src/java/jogamp/common/os/elf/Ehdr.java b/src/java/jogamp/common/os/elf/Ehdr.java new file mode 100644 index 0000000..d787f67 --- /dev/null +++ b/src/java/jogamp/common/os/elf/Ehdr.java @@ -0,0 +1,179 @@ +/* !---- DO NOT EDIT: This file autogenerated by com/jogamp/gluegen/JavaEmitter.java on Thu Feb 07 17:54:18 CET 2013 ----! */ + + +package jogamp.common.os.elf; + +import java.nio.*; + +import com.jogamp.gluegen.runtime.*; +import com.jogamp.common.os.*; +import com.jogamp.common.nio.*; +import jogamp.common.os.MachineDescriptionRuntime; + + +public class Ehdr { + + StructAccessor accessor; + + private static final int mdIdx = MachineDescriptionRuntime.getStatic().ordinal(); + + private static final int[] Ehdr_size = new int[] { 52 /* ARMle_EABI */, 52 /* X86_32_UNIX */, 64 /* X86_64_UNIX */, 52 /* X86_32_MACOS */, 52 /* X86_32_WINDOWS */, 64 /* X86_64_WINDOWS */ }; + private static final int[] e_ident_offset = new int[] { 0 /* ARMle_EABI */, 0 /* X86_32_UNIX */, 0 /* X86_64_UNIX */, 0 /* X86_32_MACOS */, 0 /* X86_32_WINDOWS */, 0 /* X86_64_WINDOWS */ }; + private static final int[] e_type_offset = new int[] { 16 /* ARMle_EABI */, 16 /* X86_32_UNIX */, 16 /* X86_64_UNIX */, 16 /* X86_32_MACOS */, 16 /* X86_32_WINDOWS */, 16 /* X86_64_WINDOWS */ }; + private static final int[] e_machine_offset = new int[] { 18 /* ARMle_EABI */, 18 /* X86_32_UNIX */, 18 /* X86_64_UNIX */, 18 /* X86_32_MACOS */, 18 /* X86_32_WINDOWS */, 18 /* X86_64_WINDOWS */ }; + private static final int[] e_version_offset = new int[] { 20 /* ARMle_EABI */, 20 /* X86_32_UNIX */, 20 /* X86_64_UNIX */, 20 /* X86_32_MACOS */, 20 /* X86_32_WINDOWS */, 20 /* X86_64_WINDOWS */ }; + private static final int[] e_entry_offset = new int[] { 24 /* ARMle_EABI */, 24 /* X86_32_UNIX */, 24 /* X86_64_UNIX */, 24 /* X86_32_MACOS */, 24 /* X86_32_WINDOWS */, 24 /* X86_64_WINDOWS */ }; + private static final int[] e_phoff_offset = new int[] { 28 /* ARMle_EABI */, 28 /* X86_32_UNIX */, 32 /* X86_64_UNIX */, 28 /* X86_32_MACOS */, 28 /* X86_32_WINDOWS */, 32 /* X86_64_WINDOWS */ }; + private static final int[] e_shoff_offset = new int[] { 32 /* ARMle_EABI */, 32 /* X86_32_UNIX */, 40 /* X86_64_UNIX */, 32 /* X86_32_MACOS */, 32 /* X86_32_WINDOWS */, 40 /* X86_64_WINDOWS */ }; + private static final int[] e_flags_offset = new int[] { 36 /* ARMle_EABI */, 36 /* X86_32_UNIX */, 48 /* X86_64_UNIX */, 36 /* X86_32_MACOS */, 36 /* X86_32_WINDOWS */, 48 /* X86_64_WINDOWS */ }; + private static final int[] e_ehsize_offset = new int[] { 40 /* ARMle_EABI */, 40 /* X86_32_UNIX */, 52 /* X86_64_UNIX */, 40 /* X86_32_MACOS */, 40 /* X86_32_WINDOWS */, 52 /* X86_64_WINDOWS */ }; + private static final int[] e_phentsize_offset = new int[] { 42 /* ARMle_EABI */, 42 /* X86_32_UNIX */, 54 /* X86_64_UNIX */, 42 /* X86_32_MACOS */, 42 /* X86_32_WINDOWS */, 54 /* X86_64_WINDOWS */ }; + private static final int[] e_phnum_offset = new int[] { 44 /* ARMle_EABI */, 44 /* X86_32_UNIX */, 56 /* X86_64_UNIX */, 44 /* X86_32_MACOS */, 44 /* X86_32_WINDOWS */, 56 /* X86_64_WINDOWS */ }; + private static final int[] e_shentsize_offset = new int[] { 46 /* ARMle_EABI */, 46 /* X86_32_UNIX */, 58 /* X86_64_UNIX */, 46 /* X86_32_MACOS */, 46 /* X86_32_WINDOWS */, 58 /* X86_64_WINDOWS */ }; + private static final int[] e_shnum_offset = new int[] { 48 /* ARMle_EABI */, 48 /* X86_32_UNIX */, 60 /* X86_64_UNIX */, 48 /* X86_32_MACOS */, 48 /* X86_32_WINDOWS */, 60 /* X86_64_WINDOWS */ }; + private static final int[] e_shstrndx_offset = new int[] { 50 /* ARMle_EABI */, 50 /* X86_32_UNIX */, 62 /* X86_64_UNIX */, 50 /* X86_32_MACOS */, 50 /* X86_32_WINDOWS */, 62 /* X86_64_WINDOWS */ }; + + public static int size() { + return Ehdr_size[mdIdx]; + } + + public static Ehdr create() { + return create(Buffers.newDirectByteBuffer(size())); + } + + public static Ehdr create(java.nio.ByteBuffer buf) { + return new Ehdr(buf); + } + + Ehdr(java.nio.ByteBuffer buf) { + accessor = new StructAccessor(buf); + } + + public java.nio.ByteBuffer getBuffer() { + return accessor.getBuffer(); + } + + public Ehdr setE_ident(byte[] val) { + accessor.setBytesAt(e_ident_offset[mdIdx], val); return this; + } + + public byte[] getE_ident() { + return accessor.getBytesAt(e_ident_offset[mdIdx], new byte[16]); } + + public Ehdr setE_type(short val) { + accessor.setShortAt(e_type_offset[mdIdx], val); + return this; + } + + public short getE_type() { + return accessor.getShortAt(e_type_offset[mdIdx]); + } + + public Ehdr setE_machine(short val) { + accessor.setShortAt(e_machine_offset[mdIdx], val); + return this; + } + + public short getE_machine() { + return accessor.getShortAt(e_machine_offset[mdIdx]); + } + + public Ehdr setE_version(int val) { + accessor.setIntAt(e_version_offset[mdIdx], val); + return this; + } + + public int getE_version() { + return accessor.getIntAt(e_version_offset[mdIdx]); + } + + public Ehdr setE_entry(long val) { + accessor.setLongAt(e_entry_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + return this; + } + + public long getE_entry() { + return accessor.getLongAt(e_entry_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + } + + public Ehdr setE_phoff(long val) { + accessor.setLongAt(e_phoff_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + return this; + } + + public long getE_phoff() { + return accessor.getLongAt(e_phoff_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + } + + public Ehdr setE_shoff(long val) { + accessor.setLongAt(e_shoff_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + return this; + } + + public long getE_shoff() { + return accessor.getLongAt(e_shoff_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + } + + public Ehdr setE_flags(int val) { + accessor.setIntAt(e_flags_offset[mdIdx], val); + return this; + } + + public int getE_flags() { + return accessor.getIntAt(e_flags_offset[mdIdx]); + } + + public Ehdr setE_ehsize(short val) { + accessor.setShortAt(e_ehsize_offset[mdIdx], val); + return this; + } + + public short getE_ehsize() { + return accessor.getShortAt(e_ehsize_offset[mdIdx]); + } + + public Ehdr setE_phentsize(short val) { + accessor.setShortAt(e_phentsize_offset[mdIdx], val); + return this; + } + + public short getE_phentsize() { + return accessor.getShortAt(e_phentsize_offset[mdIdx]); + } + + public Ehdr setE_phnum(short val) { + accessor.setShortAt(e_phnum_offset[mdIdx], val); + return this; + } + + public short getE_phnum() { + return accessor.getShortAt(e_phnum_offset[mdIdx]); + } + + public Ehdr setE_shentsize(short val) { + accessor.setShortAt(e_shentsize_offset[mdIdx], val); + return this; + } + + public short getE_shentsize() { + return accessor.getShortAt(e_shentsize_offset[mdIdx]); + } + + public Ehdr setE_shnum(short val) { + accessor.setShortAt(e_shnum_offset[mdIdx], val); + return this; + } + + public short getE_shnum() { + return accessor.getShortAt(e_shnum_offset[mdIdx]); + } + + public Ehdr setE_shstrndx(short val) { + accessor.setShortAt(e_shstrndx_offset[mdIdx], val); + return this; + } + + public short getE_shstrndx() { + return accessor.getShortAt(e_shstrndx_offset[mdIdx]); + } +} diff --git a/src/java/jogamp/common/os/elf/ElfHeader.java b/src/java/jogamp/common/os/elf/ElfHeader.java new file mode 100644 index 0000000..85bdcf0 --- /dev/null +++ b/src/java/jogamp/common/os/elf/ElfHeader.java @@ -0,0 +1,574 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.common.os.elf; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; + +import static jogamp.common.os.elf.IOUtils.readBytes; +import static jogamp.common.os.elf.IOUtils.seek; +import static jogamp.common.os.elf.IOUtils.shortToInt; + +/** + * ELF ABI Header + * <p> + * References: + * <ul> + * <li>http://linux.die.net/man/5/elf</li> + * <li>http://www.sco.com/developers/gabi/latest/contents.html</li> + * <li>http://infocenter.arm.com/ + * <ul> + * <li>ARM IHI 0044E, current through ABI release 2.09</li> + * </ul></li> + * </ul> + * </p> + */ +public class ElfHeader { + /** Size of e_ident array - {@value} */ + public static int EI_NIDENT = 16; + + /** ident byte #0 - {@value} */ + public static final byte ELFMAG0 = 0x7f; + /** ident byte #1 - {@value} */ + public static final byte ELFMAG1 = 'E'; + /** ident byte #2 - {@value} */ + public static final byte ELFMAG2 = 'L'; + /** ident byte #3 - {@value} */ + public static final byte ELFMAG3 = 'F'; + + /** ident byte #4 */ + public static final int EI_CLASS = 4; + public static final byte ELFCLASSNONE = 0; + public static final byte ELFCLASS32 = 1; + public static final byte ELFCLASS64 = 2; + + /** ident byte #5 */ + public static final int EI_DATA = 5; + public static final byte ELFDATANONE = 0; + public static final byte ELFDATA2LSB = 1; + public static final byte ELFDATA2MSB = 2; + + /** ident byte #6 */ + public static final int EI_VERSION = 6; + public static final byte EV_NONE = 0; + public static final byte EV_CURRENT = 1; + + /** ident byte #7 */ + public static final int EI_OSABI = 7; + /** Unix System V ABI - {@value} */ + public static final byte ELFOSABI_SYSV = 0; + public static final byte ELFOSABI_NONE = ELFOSABI_SYSV; + /** HP-UX ABI - {@value} */ + public static final byte ELFOSABI_HPUX = 1; + /** NetBSD ABI - {@value} **/ + public static final byte ELFOSABI_NETBSD = 2; + /** Linux ABI - {@value} **/ + public static final byte ELFOSABI_LINUX = 3; + /** Solaris ABI - {@value} **/ + public static final byte ELFOSABI_SOLARIS = 6; + /** IRIX ABI - {@value} **/ + public static final byte ELFOSABI_IRIX = 7; + /** FreeBSD ABI - {@value} **/ + public static final byte ELFOSABI_FREEBSD = 8; + /** ARM architecture ABI - {@value} **/ + public static final byte ELFOSABI_ARM = 8; // FIXME + /** Stand-alone (embedded) ABI - {@value} **/ + public static final byte ELFOSABI_STANDALONE = 9; // FIXME + /** TRU64 UNIX ABI - {@value} **/ + public static final byte ELFOSABI_TRU64 = 10; + /** Novell Modesto ABI - {@value} **/ + public static final byte ELFOSABI_MODESTO = 11; + /** Open BSD ABI - {@value} **/ + public static final byte ELFOSABI_OPENBSD = 12; + /** Open VMS ABI - {@value} **/ + public static final byte ELFOSABI_OPENVMS = 13; + /** Hewlett-Packard Non-Stop Kernel ABI - {@value} **/ + public static final byte ELFOSABI_NSK = 14; + /** Amiga Research OS ABI - {@value} **/ + public static final byte ELFOSABI_AROS = 15; + /** The FenixOS highly scalable multi-core OS 64-255 Architecture-specific value range - {@value} */ + public static final byte ELFOSABI_FENIXOS = 16; + + /** ident byte #8 + * <p> + * This byte identifies the version of the ABI to which the object is targeted. + * This field is used to distinguish among incompatible versions of an ABI. + * The interpretation of this version number is dependent on the ABI identified by the EI_OSABI field. + * Applications conforming to this specification use the value 0. + * </p> + */ + public static final int EI_ABIVERSION = 8; + + /** + * ident byte #9 .. ? + * <p> + * Start of padding. + * These bytes are reserved and set to zero. + * Programs which read them should ignore them. + * The value for EI_PAD will change in the future if currently unused bytes are given meanings. + * </p> + */ + public static final int EI_PAD = 9; + + /** + * This masks an 8-bit version number, the version of the ABI to which this + * ELF file conforms. This ABI is version 5. A value of 0 denotes unknown conformance. + * {@value} + */ + public static final int EF_ARM_ABIMASK = 0xFF000000; + public static final int EF_ARM_ABISHIFT = 24; + + /** + * ARM ABI version 5. + * {@value} + */ + public static final int EF_ARM_ABI5 = 0x05000000; + + /** + * The ELF file contains BE-8 code, suitable for execution on an ARM + * Architecture v6 processor. This flag must only be set on an executable file. + * {@value} + */ + public static final int EF_ARM_BE8 = 0x00800000; + + /** + * Legacy code (ABI version 4 and earlier) generated by gcc-arm-xxx might + * use these bits. + * {@value} + */ + public static final int EF_ARM_GCCMASK = 0x00400FFF; + + /** + * Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note that + * the executable file was built to conform to the hardware floating-point + * procedure-call standard. + * <p> + * Compatible with legacy (pre version 5) gcc use as EF_ARM_VFP_FLOAT. + * </p> + * <p> + * Note: This is not used (anymore) + * </p> + * {@value} + */ + public static final int EF_ARM_ABI_FLOAT_HARD = 0x00000400; + + /** + * Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note + * explicitly that the executable file was built to conform to the software + * floating-point procedure-call standard (the base standard). If both + * {@link #EF_ARM_ABI_FLOAT_HARD} and {@link #EF_ARM_ABI_FLOAT_SOFT} are clear, + * conformance to the base procedure-call standard is implied. + * <p> + * Compatible with legacy (pre version 5) gcc use as EF_ARM_SOFT_FLOAT. + * </p> + * <p> + * Note: This is not used (anymore) + * </p> + * {@value} + */ + public static final int EF_ARM_ABI_FLOAT_SOFT = 0x00000200; + + /** An unknown type - {@value} */ + public static final short ET_NONE = 0; + /** A relocatable file - {@value} */ + public static final short ET_REL = 1; + /** An executable file - {@value} */ + public static final short ET_EXEC = 2; + /** A shared object - {@value} */ + public static final short ET_DYN = 3; + /** A core file - {@value} */ + public static final short ET_CORE = 4; + + public static final short EM_NONE = 0; + public static final short EM_M32 = 1; + public static final short EM_SPARC = 2; + public static final short EM_386 = 3; + public static final short EM_68K = 4; + public static final short EM_88K = 5; + public static final short EM_486 = 6; + public static final short EM_860 = 7; + public static final short EM_MIPS = 8; + public static final short EM_S370 = 9; + public static final short EM_MIPS_RS3_LE = 10; + public static final short EM_PARISC = 15; + public static final short EM_res016 = 16; + public static final short EM_VPP550 = 17; + public static final short EM_SPARC32PLUS = 18; + public static final short EM_960 = 19; + public static final short EM_PPC = 20; + public static final short EM_PPC64 = 21; + public static final short EM_S390 = 22; + public static final short EM_SPU = 23; + public static final short EM_V800 = 36; + public static final short EM_FR20 = 37; + public static final short EM_RH32 = 38; + public static final short EM_MCORE = 39; + public static final short EM_RCE = 39; + public static final short EM_ARM = 40; + public static final short EM_OLD_ALPHA = 41; + public static final short EM_SH = 42; + public static final short EM_SPARCV9 = 43; + public static final short EM_TRICORE = 44; + public static final short EM_ARC = 45; + public static final short EM_H8_300 = 46; + public static final short EM_H8_300H = 47; + public static final short EM_H8S = 48; + public static final short EM_H8_500 = 49; + public static final short EM_IA_64 = 50; + public static final short EM_MIPS_X = 51; + public static final short EM_COLDFIRE = 52; + public static final short EM_68HC12 = 53; + public static final short EM_MMA = 54; + public static final short EM_PCP = 55; + public static final short EM_NCPU = 56; + public static final short EM_NDR1 = 57; + public static final short EM_STARCORE = 58; + public static final short EM_ME16 = 59; + public static final short EM_ST100 = 60; + public static final short EM_TINYJ = 61; + public static final short EM_X86_64 = 62; + public static final short EM_PDSP = 63; + public static final short EM_PDP10 = 64; + public static final short EM_PDP11 = 65; + public static final short EM_FX66 = 66; + public static final short EM_ST9PLUS = 67; + public static final short EM_ST7 = 68; + public static final short EM_68HC16 = 69; + public static final short EM_68HC11 = 70; + public static final short EM_68HC08 = 71; + public static final short EM_68HC05 = 72; + public static final short EM_SVX = 73; + public static final short EM_ST19 = 74; + public static final short EM_VAX = 75; + public static final short EM_CRIS = 76; + public static final short EM_JAVELIN = 77; + public static final short EM_FIREPATH = 78; + public static final short EM_ZSP = 79; + public static final short EM_MMIX = 80; + public static final short EM_HUANY = 81; + public static final short EM_PRISM = 82; + public static final short EM_AVR = 83; + public static final short EM_FR30 = 84; + public static final short EM_D10V = 85; + public static final short EM_D30V = 86; + public static final short EM_V850 = 87; + public static final short EM_M32R = 88; + public static final short EM_MN10300 = 89; + public static final short EM_MN10200 = 90; + public static final short EM_PJ = 91; + public static final short EM_OPENRISC = 92; + public static final short EM_ARC_A5 = 93; + public static final short EM_XTENSA = 94; + public static final short EM_VIDEOCORE = 95; + public static final short EM_TMM_GPP = 96; + public static final short EM_NS32K = 97; + public static final short EM_TPC = 98; + public static final short EM_SNP1K = 99; + public static final short EM_ST200 = 100; + public static final short EM_IP2K = 101; + public static final short EM_MAX = 102; + public static final short EM_CR = 103; + public static final short EM_F2MC16 = 104; + public static final short EM_MSP430 = 105; + public static final short EM_BLACKFIN = 106; + public static final short EM_SE_C33 = 107; + public static final short EM_SEP = 108; + public static final short EM_ARCA = 109; + public static final short EM_UNICORE = 110; + public static final short EM_EXCESS = 111; + public static final short EM_DXP = 112; + public static final short EM_ALTERA_NIOS2 = 113; + public static final short EM_CRX = 114; + public static final short EM_XGATE = 115; + public static final short EM_C166 = 116; + public static final short EM_M16C = 117; + public static final short EM_DSPIC30F = 118; + public static final short EM_CE = 119; + public static final short EM_M32C = 120; + public static final short EM_TSK3000 = 131; + public static final short EM_RS08 = 132; + public static final short EM_res133 = 133; + public static final short EM_ECOG2 = 134; + public static final short EM_SCORE = 135; + public static final short EM_SCORE7 = 135; + public static final short EM_DSP24 = 136; + public static final short EM_VIDEOCORE3 = 137; + public static final short EM_LATTICEMICO32 = 138; + public static final short EM_SE_C17 = 139; + public static final short EM_TI_C6000 = 140; + public static final short EM_TI_C2000 = 141; + public static final short EM_TI_C5500 = 142; + public static final short EM_MMDSP_PLUS = 160; + public static final short EM_CYPRESS_M8C = 161; + public static final short EM_R32C = 162; + public static final short EM_TRIMEDIA = 163; + public static final short EM_QDSP6 = 164; + public static final short EM_8051 = 165; + public static final short EM_STXP7X = 166; + public static final short EM_NDS32 = 167; + public static final short EM_ECOG1 = 168; + public static final short EM_ECOG1X = 168; + public static final short EM_MAXQ30 = 169; + public static final short EM_XIMO16 = 170; + public static final short EM_MANIK = 171; + public static final short EM_CRAYNV2 = 172; + public static final short EM_RX = 173; + public static final short EM_METAG = 174; + public static final short EM_MCST_ELBRUS = 175; + public static final short EM_ECOG16 = 176; + public static final short EM_CR16 = 177; + public static final short EM_ETPU = 178; + public static final short EM_SLE9X = 179; + public static final short EM_L1OM = 180; + public static final short EM_INTEL181 = 181; + public static final short EM_INTEL182 = 182; + public static final short EM_res183 = 183; + public static final short EM_res184 = 184; + public static final short EM_AVR32 = 185; + public static final short EM_STM8 = 186; + public static final short EM_TILE64 = 187; + public static final short EM_TILEPRO = 188; + public static final short EM_MICROBLAZE = 189; + public static final short EM_CUDA = 190; + + public static final boolean isIdentityValid(byte[] ident) { + return ELFMAG0 == ident[0] && + ELFMAG1 == ident[1] && + ELFMAG2 == ident[2] && + ELFMAG3 == ident[3] ; + } + + /** Public access to the raw elf header */ + public final Ehdr d; + + /** Public access to the {@link SectionHeader} */ + public final SectionHeader[] sht; + + /** + * Note: The input stream shall stay untouch to be able to read sections! + * + * @param in input stream of a binary file at position zero + * @return + * @throws IOException if reading from the given input stream fails or less then ELF Header size bytes + * @throws IllegalArgumentException if the given input stream does not represent an ELF Header + */ + public static ElfHeader read(RandomAccessFile in) throws IOException, IllegalArgumentException { + final int eh_sz = Ehdr.size(); + final byte[] buf = new byte[eh_sz]; + readBytes (in, buf, 0, eh_sz); + final ElfHeader eh = new ElfHeader(ByteBuffer.wrap(buf, 0, buf.length), in); + return eh; + } + + /** + * @param buf ELF Header bytes + * @throws IllegalArgumentException if the given buffer does not represent an ELF Header + * @throws IOException + */ + ElfHeader(java.nio.ByteBuffer buf, RandomAccessFile in) throws IllegalArgumentException, IOException { + d = Ehdr.create(buf); + if( !isIdentityValid(d.getE_ident()) ) { + throw new IllegalArgumentException("Buffer is not an ELF Header"); + } + sht = readSectionHeaderTable(in); + } + + public final short getSize() { return d.getE_ehsize(); } + + /** + * Returns the architecture class in bits, + * 32 for {@link #ELFCLASS32}, 64 for {@link #ELFCLASS64} + * and 0 for {@link #ELFCLASSNONE}. + */ + public final int getArchClassBits() { + switch( d.getE_ident()[EI_CLASS] ) { + case ELFCLASS32: return 32; + case ELFCLASS64: return 64; + default: return 0; + } + } + + /** + * Returns the processor's data encoding, + * 1 for {@link #ELFDATA2LSB}, 2 for for {@link #ELFDATA2MSB} + * and 0 for for {@link #ELFDATANONE} + */ + public final int getDataEncodingMode() { + switch( d.getE_ident()[EI_DATA] ) { + case ELFDATA2LSB: return 1; + case ELFDATA2MSB: return 2; + default: return 0; + } + } + + /** 3 == Linux */ + public final byte getOSABI() { + return d.getE_ident()[EI_OSABI]; + } + + /** Returns the object file type */ + public final short getType() { + return d.getE_type(); + } + + /** Returns the required architecture for the file */ + public final short getMachine() { + return d.getE_machine(); + } + + /** + * Returns true if {@link #getMachine() machine} is a 32 or 64 bit ARM CPU + * of type {@link #EM_ARM}. */ + public final boolean isArm() { + return getMachine() == EM_ARM; + } + + /** + * Returns true if {@link #getMachine() machine} is a 32 or 64 bit Intel CPU + * of type {@link #EM_386}, {@link #EM_486} or {@link #EM_X86_64}. */ + public final boolean isIntel() { + final short m = getMachine(); + return EM_386 == m || + EM_486 == m || + EM_X86_64 == m; + } + + /** Retruns the processor-specific flags associated with the file. */ + public final int getFlags() { + return d.getE_flags(); + } + + /** Returns the ARM EABI version from {@link #getFlags() flags}, maybe 0 if not an ARM EABI. */ + public byte getArmABI() { + return (byte) ( ( ( EF_ARM_ABIMASK & d.getE_flags() ) >> EF_ARM_ABISHIFT ) & 0xff ); + } + + /** Returns the ARM EABI legacy GCC {@link #getFlags() flags}, maybe 0 if not an ARM EABI or not having legacy GCC flags. */ + public int getArmLegacyGCCFlags() { + final int f = d.getE_flags(); + return 0 != ( EF_ARM_ABIMASK & f ) ? ( EF_ARM_GCCMASK & f ) : 0; + } + + /** + * Returns the ARM EABI float mode from {@link #getFlags() flags}, + * i.e. 1 for {@link #EF_ARM_ABI_FLOAT_SOFT}, 2 for {@link #EF_ARM_ABI_FLOAT_HARD} + * or 0 for none. + * <p> + * Note: This is not used (anymore) + * </p> + */ + public byte getArmFloatMode() { + final int f = d.getE_flags(); + if( 0 != ( EF_ARM_ABIMASK & f ) ) { + if( ( EF_ARM_ABI_FLOAT_HARD & f ) != 0 ) { + return 2; + } + if( ( EF_ARM_ABI_FLOAT_SOFT & f ) != 0 ) { + return 1; + } + } + return 0; + } + + /** Returns the 1st occurence of matching SectionHeader {@link SectionHeader#getType() type}, or null if not exists. */ + public final SectionHeader getSectionHeader(int type) { + for(int i=0; i<sht.length; i++) { + final SectionHeader sh = sht[i]; + if( sh.getType() == type ) { + return sh; + } + } + return null; + } + + /** Returns the 1st occurence of matching SectionHeader {@link SectionHeader#getName() name}, or null if not exists. */ + public final SectionHeader getSectionHeader(String name) { + for(int i=0; i<sht.length; i++) { + final SectionHeader sh = sht[i]; + if( sh.getName().equals(name) ) { + return sh; + } + } + return null; + } + + final SectionHeader[] readSectionHeaderTable(RandomAccessFile in) throws IOException, IllegalArgumentException { + // positioning + { + final long off = d.getE_shoff(); // absolute offset + if( 0 == off ) { + return new SectionHeader[0]; + } + seek(in, off); + } + final SectionHeader[] sht; + final int strndx = d.getE_shstrndx(); + final int size = d.getE_shentsize(); + final int num; + int i; + if( 0 == d.getE_shnum() ) { + // Read 1st table 1st and use it's sh_size + final byte[] buf0 = new byte[size]; + readBytes(in, buf0, 0, size); + SectionHeader sh0 = new SectionHeader(buf0, 0, size, 0); + num = (int) sh0.d.getSh_size(); + if( 0 >= num ) { + throw new IllegalArgumentException("EHdr sh_num == 0 and 1st SHdr size == 0"); + } + sht = new SectionHeader[num]; + sht[0] = sh0; + i=1; + } else { + num = d.getE_shnum(); + sht = new SectionHeader[num]; + i=0; + } + for(; i<num; i++) { + final byte[] buf = new byte[size]; + readBytes(in, buf, 0, size); + sht[i] = new SectionHeader(buf, 0, size, i); + } + if( SectionHeader.SHN_UNDEF != strndx ) { + // has section name string table + if( shortToInt(SectionHeader.SHN_LORESERVE) <= strndx ) { + throw new InternalError("TODO strndx: "+SectionHeader.SHN_LORESERVE+" < "+strndx); + } + final SectionHeader strShdr = sht[strndx]; + if( SectionHeader.SHT_STRTAB != strShdr.getType() ) { + throw new IllegalArgumentException("Ref. string Shdr["+strndx+"] is of type "+strShdr.d.getSh_type()); + } + final Section strS = strShdr.readSection(in); + for(i=0; i<num; i++) { + sht[i].initName(strS, sht[i].d.getSh_name()); + } + } + + return sht; + } +} diff --git a/src/java/jogamp/common/os/elf/IOUtils.java b/src/java/jogamp/common/os/elf/IOUtils.java new file mode 100644 index 0000000..8308463 --- /dev/null +++ b/src/java/jogamp/common/os/elf/IOUtils.java @@ -0,0 +1,148 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.common.os.elf; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +class IOUtils { + static final long MAX_INT_VALUE = ( (long) Integer.MAX_VALUE & 0xffffffffL ) ; + + static String toHexString(int i) { return "0x"+Integer.toHexString(i); } + + static String toHexString(long i) { return "0x"+Long.toHexString(i); } + + static int shortToInt(short s) { + return (int)s & 0x0000ffff; + } + + static int long2Int(final long v) { + if( MAX_INT_VALUE < v ) { + throw new IllegalArgumentException("Read uint32 value "+toHexString(v)+" > int32-max "+toHexString(MAX_INT_VALUE)); + } + return (int)v; + } + + static void checkBounds(final byte[] sb, final int offset, final int remaining) { + if( offset + remaining > sb.length ) { + throw new IndexOutOfBoundsException("Buffer of size "+sb.length+" cannot hold offset "+offset+" + remaining "+remaining); + } + } + + static void readBytes(final RandomAccessFile in, final byte[] out, final int offset, final int len) + throws IOException, IllegalArgumentException + { + in.readFully(out, offset, len); + } + + static void seek(final RandomAccessFile in, long newPos) throws IOException { + in.seek(newPos); + } + + static int readUInt32(final byte[] in, final int offset) { + final int v = readInt32(in, offset); + if( 0 > v ) { + throw new IllegalArgumentException("Read uint32 value "+toHexString(v)+" > int32-max "+toHexString(MAX_INT_VALUE)); + } + return v; + /** Need to fix endian for below path .. + checkBounds(in, offset, 4); + final byte[] uint = new byte[] { 0, 0, 0, 0, in[offset+0], in[offset+1], in[offset+2], in[offset+3] }; + final ByteBuffer b = ByteBuffer.wrap(uint, 0, 8).order(ByteOrder.nativeOrder()); + return b.asLongBuffer().get(0); */ + } + + static int readInt32(final byte[] in, final int offset) { + checkBounds(in, offset, 4); + final ByteBuffer b = ByteBuffer.wrap(in, offset, 4).order(ByteOrder.nativeOrder()); + return b.asIntBuffer().get(0); + } + + /** + * @param sb byte source buffer to parse + * @param offset offset within byte source buffer to start parsing + * @param remaining remaining numbers of bytes to parse beginning w/ <code>sb_off</code>, + * which shall not exceed <code>sb.length - offset</code>. + * @param offset_post optional integer array holding offset post parsing + * @return the parsed string + * @throws IndexOutOfBoundsException if <code>offset + remaining > sb.length</code>. + */ + static String getString(final byte[] sb, final int offset, final int remaining, int[] offset_post) throws IndexOutOfBoundsException { + checkBounds(sb, offset, remaining); + int strlen = 0; + for(; strlen < remaining && sb[strlen + offset] != 0; strlen++) { } + final String s = 0 < strlen ? new String(sb, offset, strlen) : "" ; + if( null != offset_post ) { + offset_post[0] = offset + strlen + 1; // incl. EOS + } + return s; + } + + /** + * @param sb byte source buffer to parse + * @param offset offset within byte source buffer to start parsing + * @param remaining remaining numbers of bytes to parse beginning w/ <code>sb_off</code>, + * which shall not exceed <code>sb.length - offset</code>. + * @return the number of parsed strings + * @throws IndexOutOfBoundsException if <code>offset + remaining > sb.length</code>. + */ + static int getStringCount(final byte[] sb, int offset, final int remaining) throws IndexOutOfBoundsException { + checkBounds(sb, offset, remaining); + int strnum=0; + for(int i=0; i < remaining; i++) { + for(; i < remaining && sb[i + offset] != 0; i++) { } + strnum++; + } + return strnum; + } + + /** + * @param sb byte source buffer to parse + * @param offset offset within byte source buffer to start parsing + * @param remaining remaining numbers of bytes to parse beginning w/ <code>sb_off</code>, + * which shall not exceed <code>sb.length - offset</code>. + * @return the parsed strings + * @throws IndexOutOfBoundsException if <code>offset + remaining > sb.length</code>. + */ + public static String[] getStrings(final byte[] sb, int offset, final int remaining) throws IndexOutOfBoundsException { + final int strnum = getStringCount(sb, offset, remaining); + // System.err.println("XXX: strnum "+strnum+", sb_off "+sb_off+", sb_len "+sb_len); + + final String[] sa = new String[strnum]; + final int[] io_off = new int[] { offset }; + for(int i=0; i < strnum; i++) { + // System.err.print("XXX: str["+i+"] ["+io_off[0]); + sa[i] = getString(sb, io_off[0], remaining - io_off[0], io_off); + // System.err.println(".. "+io_off[0]+"[ "+sa[i]); + } + return sa; + } + +} diff --git a/src/java/jogamp/common/os/elf/Section.java b/src/java/jogamp/common/os/elf/Section.java new file mode 100644 index 0000000..99c762c --- /dev/null +++ b/src/java/jogamp/common/os/elf/Section.java @@ -0,0 +1,50 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.common.os.elf; + +public class Section { + public SectionHeader sh; + public byte[] data; + public int offset; + public int length; + + Section(SectionHeader sh, byte[] data, int offset, int length) { + this.sh = sh; + this.data = data; + this.offset = offset; + this.length = length; + } + + public String toString() { + return "Section["+toSubString()+"]"; + } + String toSubString() { + return sh+", data[off "+offset+", len "+length+"/"+data.length+"]"; + } + +} diff --git a/src/java/jogamp/common/os/elf/SectionArmAttributes.java b/src/java/jogamp/common/os/elf/SectionArmAttributes.java new file mode 100644 index 0000000..7b85bb9 --- /dev/null +++ b/src/java/jogamp/common/os/elf/SectionArmAttributes.java @@ -0,0 +1,317 @@ +package jogamp.common.os.elf; + +import static jogamp.common.os.elf.IOUtils.toHexString; +import static jogamp.common.os.elf.IOUtils.checkBounds; +import static jogamp.common.os.elf.IOUtils.readUInt32; +import static jogamp.common.os.elf.IOUtils.getString; + +import java.util.ArrayList; +import java.util.List; + +/** + * ARM EABI attributes within section header {@link SectionHeader#SHT_ARM_ATTRIBUTES}. + * <p> + * References: + * <ul> + * <li>http://infocenter.arm.com/ + * <ul> + * <li>ARM IHI 0044E, current through ABI release 2.09</li> + * <li>ARM IHI 0045D, current through ABI release 2.09</li> + * </ul></li> + * </ul> + * </p> + */ +public class SectionArmAttributes extends Section { + public static final byte FORMAT_VERSION_A = 0x41; // 'A'; + + public static enum Type { + /** No Value */ + None, + /** A Sub-Section - following the 4 byte sub section total size (tag + size + content) - byte order of the ELF file */ + SubSection, + /** Null Terminated Byte-String */ + NTBS, + ULEB128, + } + + /** ULEB128 Value for {@link Tag#ABI_VFP_args}: FP parameter/result passing conforms to AAPCS, BASE variant. */ + public static final byte ABI_VFP_ARGS_IS_BASE_VARIANT = 0; + /** ULEB128 Value for {@link Tag#ABI_VFP_args}: FP parameter/result passing conforms to AAPCS, VFP variant. */ + public static final byte ABI_VFP_ARGS_IS_VFP_VARIANT = 1; + /** ULEB128 Value for {@link Tag#ABI_VFP_args}: FP parameter/result passing conforms to custom toolchain. */ + public static final byte ABI_VFP_ARGS_IS_CUSTOM_VARIANT = 2; + /** ULEB128 Value for {@link Tag#ABI_VFP_args}: FP parameter/result passing conforms to both , BASE and VFP variant. */ + public static final byte ABI_VFP_ARGS_IS_BOTH_BASE_AND_VFP_VARIANT = 3; + + /** + * Returns true if value is either {@link #ABI_VFP_ARGS_IS_VFP_VARIANT} or {@link #ABI_VFP_ARGS_IS_BOTH_BASE_AND_VFP_VARIANT} + * @param v ULEB128 Value from {@link Tag#ABI_VFP_args} attribute + */ + public static final boolean abiVFPArgsAcceptsVFPVariant(byte v) { + return ABI_VFP_ARGS_IS_VFP_VARIANT == v || ABI_VFP_ARGS_IS_BOTH_BASE_AND_VFP_VARIANT == v; + } + + public static enum Tag { + None(0, Type.None), + File(1, Type.SubSection), Section(2, Type.SubSection), Symbol(3, Type.SubSection), + CPU_raw_name( 4, Type.NTBS ), + CPU_name( 5, Type.NTBS ), + CPU_arch( 6, Type.ULEB128 ), + CPU_arch_profile( 7, Type.ULEB128 ), + ARM_ISA_use( 8, Type.ULEB128 ), + THUMB_ISA_use( 9, Type.ULEB128 ), + FP_arch( 10, Type.ULEB128 ), + WMMX_arch( 11, Type.ULEB128 ), + Advanced_SIMD_arch( 12, Type.ULEB128 ), + PCS_config( 13, Type.ULEB128 ), + ABI_PCS_R9_use ( 14, Type.ULEB128 ), + ABI_PCS_RW_data( 15, Type.ULEB128 ), + ABI_PCS_RO_data( 16, Type.ULEB128 ), + ABI_PCS_GOT_use( 17, Type.ULEB128 ), + ABI_PCS_wchar_t( 18, Type.ULEB128 ), + ABI_FP_rounding( 19, Type.ULEB128 ), + ABI_FP_denormal( 20, Type.ULEB128 ), + ABI_FP_exceptions( 21, Type.ULEB128 ), + ABI_FP_user_exceptions( 22, Type.ULEB128 ), + ABI_FP_number_model( 23, Type.ULEB128 ), + ABI_align_needed( 24, Type.ULEB128 ), + ABI_align_preserved( 25, Type.ULEB128 ), + ABI_enum_size( 26, Type.ULEB128 ), + ABI_HardFP_use( 27, Type.ULEB128 ), + ABI_VFP_args( 28, Type.ULEB128 ), + ABI_WMMX_args( 29, Type.ULEB128 ), + ABI_optimization_goals( 30, Type.ULEB128 ), + ABI_FP_optimization_goals( 31, Type.ULEB128 ), + compatibility ( 32, Type.NTBS ), /** with each byte interpreted as an ULEB128 with closing EOS */ + CPU_unaligned_access( 34, Type.ULEB128 ), + FP_HP_extension( 36, Type.ULEB128 ), + ABI_FP_16bit_format( 38, Type.ULEB128 ), + MPextension_use( 42, Type.ULEB128 ), + DIV_use( 44, Type.ULEB128 ), + nodefaults( 64, Type.ULEB128 ), /* value ignored */ + also_compatible_with( 65, Type.ULEB128 ), + T2EE_use( 66, Type.ULEB128 ), + conformance( 67, Type.NTBS ), + Virtualization_use( 68, Type.ULEB128 ), + undefined69( 69, Type.None ), + MPextension_use_legacy( 70, Type.ULEB128 ) + ; + + public final int id; + public final Type type; + + /** Slow O(n) transition of a native tag value to a Tag. */ + public static Tag get(final int id) { + final Tag[] tags = Tag.values(); + final int tag_count = tags.length; + for(int i=0; i < tag_count; i++) { + if( tags[i].id == id ) { + return tags[i]; + } + } + return null; + } + + Tag(int id, Type type){ + this.id = id; + this.type = type; + } + } + + public static class Attribute { + public final Tag tag; + private final Object value; + + Attribute(Tag tag, Object value) { + this.tag = tag; + this.value = value; + } + + public final boolean isNTBS() { + return Type.NTBS == tag.type; + } + public final String getNTBS() { + if( Type.NTBS == tag.type ) { + return (String) value; + } + throw new IllegalArgumentException("Not NTBS but "+tag.type); + } + + public final boolean isULEB128() { + return Type.ULEB128 == tag.type; + } + public final byte getULEB128() { + if( Type.ULEB128== tag.type ) { + return ((Byte) value).byteValue(); + } + throw new IllegalArgumentException("Not ULEB128 but "+tag.type); + } + + public String toString() { + return tag+" = "+value; + } + } + + public static class VendorAttributes { + public final String vendor; + public final List<Attribute> attributes; + + VendorAttributes(String vendor, List<Attribute> attributes) { + this.vendor = vendor; + this.attributes = attributes; + } + + public String toString() { + return vendor + attributes.toString(); + } + } + public final List<VendorAttributes> vendorAttributesList; + + SectionArmAttributes(SectionHeader sh, byte[] data, int offset, int length) throws IndexOutOfBoundsException, IllegalArgumentException { + super(sh, data, offset, length); + this.vendorAttributesList = parse(data, offset, length); + } + + public String toString() { + return "SectionArmAttributes["+super.toSubString()+", "+vendorAttributesList.toString()+"]"; + } + + public final Attribute get(Tag tag) { + for(int i=0; i<vendorAttributesList.size(); i++) { + final List<Attribute> attributes = vendorAttributesList.get(i).attributes; + for(int j=0; j<attributes.size(); j++) { + final Attribute a = attributes.get(j); + if( a.tag == tag ) { + return a; + } + } + } + return null; + } + + public final List<Attribute> get(String vendor) { + return get(vendorAttributesList, vendor); + } + + static final List<Attribute> get(final List<VendorAttributes> vendorAttributesList, String vendor) { + for(int i=0; i<vendorAttributesList.size(); i++) { + final VendorAttributes vas = vendorAttributesList.get(i); + if( vas.vendor.equals(vendor) ) { + return vas.attributes; + } + } + return null; + } + + /** + * @param in byte source buffer to parse + * @param offset offset within byte source buffer to start parsing + * @param remaining remaining numbers of bytes to parse beginning w/ <code>sb_off</code>, + * which shall not exceed <code>sb.length - offset</code>. + * @throws IndexOutOfBoundsException if <code>offset + remaining > sb.length</code>. + * @throws IllegalArgumentException if section parsing failed, i.e. incompatible version or data. + */ + static List<VendorAttributes> parse(final byte[] in, final int offset, final int remaining) throws IndexOutOfBoundsException, IllegalArgumentException { + checkBounds(in, offset, remaining); + int i = offset; + if( FORMAT_VERSION_A != in[ i ] ) { + throw new IllegalArgumentException("ShArmAttr: Not version A, but: "+toHexString(in[i])); + } + i++; + + final List<VendorAttributes> vendorAttributesList = new ArrayList<VendorAttributes>(); + + while(i < remaining) { + final int i_pre = i; + final int secLen = readUInt32(in, i); /* total section size: 4 + string + content, i.e. offset to next section */ + i+=4; + + final String vendor; + { + int[] i_post = new int[] { 0 }; + vendor = getString(in, i, secLen - 4, i_post); + i = i_post[0]; + } + + final List<Attribute> attributes = new ArrayList<Attribute>(); + + while(i < secLen) { + int[] i_post = new int[] { 0 }; + parseSub(in, i, secLen - i, i_post, attributes); + i = i_post[0]; + } + + if( i_pre + secLen != i ) { + throw new IllegalArgumentException("ShArmAttr: Section length count mismatch, expected "+(i_pre + secLen)+", has "+i); + } + + final List<Attribute> mergeAttribs = get(vendorAttributesList, vendor); + if( null != mergeAttribs ) { + mergeAttribs.addAll(attributes); + } else { + vendorAttributesList.add(new VendorAttributes(vendor, attributes)); + } + } + + return vendorAttributesList; + } + + /** + * @param in byte source buffer to parse + * @param offset offset within byte source buffer to start parsing + * @param remaining remaining numbers of bytes to parse beginning w/ <code>sb_off</code>, + * which shall not exceed <code>sb.length - offset</code>. + * @throws IndexOutOfBoundsException if <code>offset + remaining > sb.length</code>. + * @throws IllegalArgumentException if section parsing failed, i.e. incompatible version or data. + */ + static void parseSub(final byte[] in, final int offset, final int remaining, int[] offset_post, List<Attribute> attributes) throws IndexOutOfBoundsException, IllegalArgumentException { + checkBounds(in, offset, remaining); + + // Starts w/ sub-section Tag + int i = offset; + final int i_sTag = in[i++]; + final Tag sTag = Tag.get(i_sTag); + if( null == sTag ) { + throw new IllegalArgumentException("ShArmAttr: Invalid Sub-Section tag (NaT): "+i_sTag); + } + final int subSecLen; // sub section total size (tag + size + content) + switch(sTag) { + case File: + case Section: + case Symbol: + subSecLen = readUInt32(in, i); + i+=4; + break; + default: + throw new IllegalArgumentException("ShArmAttr: Invalid Sub-Section tag: "+sTag); + } + if( Tag.File == sTag ) { + while( i < offset + subSecLen ) { + final int i_tag = in[i++]; + final Tag tag = Tag.get(i_tag); + if( null == tag ) { + throw new IllegalArgumentException("ShArmAttr: Invalid Attribute tag (NaT): "+i_tag); + } + switch(tag.type) { + case NTBS: + { + int[] i_post = new int[] { 0 }; + final String value = getString(in, i, subSecLen + offset - i, i_post); + attributes.add(new Attribute(tag, value)); + i = i_post[0]; + } + break; + case ULEB128: + { + final byte value = in[i++]; + attributes.add(new Attribute(tag, new Byte(value))); + } + break; + default: + throw new IllegalArgumentException("ShArmAttr: Invalid Attribute tag: "+tag); + } + } + } + offset_post[0] = offset + subSecLen; + } +} diff --git a/src/java/jogamp/common/os/elf/SectionHeader.java b/src/java/jogamp/common/os/elf/SectionHeader.java new file mode 100644 index 0000000..18a3293 --- /dev/null +++ b/src/java/jogamp/common/os/elf/SectionHeader.java @@ -0,0 +1,274 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.common.os.elf; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; + +import static jogamp.common.os.elf.IOUtils.long2Int; +import static jogamp.common.os.elf.IOUtils.readBytes; +import static jogamp.common.os.elf.IOUtils.seek; +import static jogamp.common.os.elf.IOUtils.getString; +import static jogamp.common.os.elf.IOUtils.toHexString; + +/** + * ELF ABI Section Header + * <p> + * References: + * <ul> + * <li>http://linux.die.net/man/5/elf</li> + * <li>http://www.sco.com/developers/gabi/latest/contents.html</li> + * <li>http://infocenter.arm.com/ + * <ul> + * <li>ARM IHI 0044E, current through ABI release 2.09</li> + * </ul></li> + * </ul> + * </p> + */ +public class SectionHeader { + /** + * {@value} + */ + public static final int SHT_NULL = 0; + /** + * {@value} + */ + public static final int SHT_PROGBITS = 1; + /** + * {@value} + */ + public static final int SHT_SYMTAB = 2; + /** + * {@value} + */ + public static final int SHT_STRTAB = 3; + /** + * {@value} + */ + public static final int SHT_RELA = 4; + /** + * {@value} + */ + public static final int SHT_HASH = 5; + /** + * {@value} + */ + public static final int SHT_DYNAMIC = 6; + /** + * {@value} + */ + public static final int SHT_NOTE = 7; + /** + * {@value} + */ + public static final int SHT_NOBITS = 8; + /** + * {@value} + */ + public static final int SHT_REL = 9; + /** + * {@value} + */ + public static final int SHT_SHLIB = 10; + /** + * {@value} + */ + public static final int SHT_DYNSYM = 11; + /** + * {@value} + */ + public static final int SHT_NUM = 12; + /** + * {@value} + */ + public static final int SHT_LOPROC = 0x70000000; + /** + * {@value} + */ + public static final int SHT_HIPROC = 0x7fffffff; + /** + * {@value} + */ + public static final int SHT_LOUSER = 0x80000000; + /** + * {@value} + */ + public static final int SHT_HIUSER = 0xffffffff; + + /** + * {@value} + */ + public static final int SHT_ARM_EXIDX = 0x70000001; + /** + * {@value} + */ + public static final int SHT_ARM_PREEMPTMAP = 0x70000002; + /** + * {@value} + */ + public static final int SHT_ARM_ATTRIBUTES = 0x70000003; + /** + * {@value} + */ + public static final int SHT_ARM_DEBUGOVERLAY = 0x70000004; + /** + * {@value} + */ + public static final int SHT_ARM_OVERLAYSECTION = 0x70000005; + + /** + * {@value} + */ + public static final short SHN_UNDEF = (short)0; + /** + * {@value} + */ + public static final short SHN_LORESERVE = (short)0xff00; + /** + * {@value} + */ + public static final short SHN_LOPROC = (short)0xff00; + /** + * {@value} + */ + public static final short SHN_HIPROC = (short)0xff1f; + /** + * {@value} + */ + public static final short SHN_ABS = (short)0xfff1; + /** + * {@value} + */ + public static final short SHN_COMMON = (short)0xfff2; + /** + * {@value} + */ + public static final short SHN_HIRESERVE = (short)0xffff; + + /** Public access to the raw elf section header */ + public final Shdr d; + + private int idx; + private String name; + + SectionHeader(byte[] buf, int offset, int length, int sectionIdx) { + this( ByteBuffer.wrap(buf, 0, buf.length), sectionIdx ); + } + SectionHeader(java.nio.ByteBuffer buf, int idx) { + d = Shdr.create(buf); + this.idx = idx; + name = null; + } + + public String toString() { + return "SectionHeader[idx "+idx+", name "+name+", type "+toHexString(getType())+", link "+d.getSh_link()+", info "+toHexString(d.getSh_info())+", flags "+toHexString(getFlags())+"]"; + } + + /** + * @param strS the {@link SectionHeader#SHT_STRTAB} section containing all strings + * @param nameOffset name offset within strS + */ + void initName(final Section strS, final int nameOffset) throws IndexOutOfBoundsException { + name = getString(strS.data, strS.offset + nameOffset, strS.length - nameOffset, null); + } + + /** Returns the index of this section within the Elf section header table. */ + public int getIndex() { + return idx; + } + + /** Returns the type of this section. */ + public int getType() { + return d.getSh_type(); + } + + /** Returns the flags of this section. */ + public long getFlags() { + return d.getSh_flags(); + } + + /** Returns the size of this section. */ + public long getSize() { + return d.getSh_size(); + } + + /** Returns this section name, maybe <code>null</code> if not read. */ + public String getName() { + return name; + } + + /** + * Returns the Section referenced w/ this section header + * + * @param in file owning the section + * @throws IOException if read error occurs + * @throws IllegalArgumentException if section offset or size mismatch including size > {@link Integer#MAX_VALUE} + */ + public Section readSection(RandomAccessFile in) throws IOException, IllegalArgumentException { + final int s_size = long2Int(d.getSh_size()); + if( 0 == s_size || 0 > s_size ) { + throw new IllegalArgumentException("Shdr["+idx+"] has invalid int size: "+d.getSh_size()+" -> "+s_size); + } + final byte[] s_buf = new byte[s_size]; + return readSectionImpl(in, s_buf, 0, s_size); + } + + /** + * Returns the Section referenced w/ this section header using given byte array. + * + * @param in file owning the section + * @param b destination buffer + * @param b_off offset in destination buffer + * @param r_len requested read length in bytes, which shall be ≤ than this section size + * @throws IOException if read error occurs + * @throws IllegalArgumentException if section offset or size mismatch including size > {@link Integer#MAX_VALUE} + * @throws IllegalArgumentException if requested read length is > section size + */ + public Section readSection(RandomAccessFile in, byte[] b, int b_off, int r_len) throws IOException, IllegalArgumentException { + final int s_size = long2Int(d.getSh_size()); + if( 0 == s_size || 0 > s_size ) { + throw new IllegalArgumentException("Shdr["+idx+"] has invalid int size: "+d.getSh_size()+" -> "+s_size); + } + if( r_len > s_size ) { + throw new IllegalArgumentException("Shdr["+idx+"] has only "+s_size+" bytes, while read request is of "+r_len+" bytes"); + } + return readSectionImpl(in, b, b_off, r_len); + } + + Section readSectionImpl(RandomAccessFile in, byte[] b, int b_off, int r_len) throws IOException, IllegalArgumentException { + final long s_off = d.getSh_offset(); + seek(in, s_off); + readBytes(in, b, b_off, r_len); + if( SectionHeader.SHT_ARM_ATTRIBUTES == getType() ) { + return new SectionArmAttributes(this, b, b_off, r_len); + } else { + return new Section(this, b, b_off, r_len); + } + } +} diff --git a/src/java/jogamp/common/os/elf/Shdr.java b/src/java/jogamp/common/os/elf/Shdr.java new file mode 100644 index 0000000..5465b3d --- /dev/null +++ b/src/java/jogamp/common/os/elf/Shdr.java @@ -0,0 +1,141 @@ +/* !---- DO NOT EDIT: This file autogenerated by com/jogamp/gluegen/JavaEmitter.java on Thu Feb 07 17:54:18 CET 2013 ----! */ + + +package jogamp.common.os.elf; + +import java.nio.*; + +import com.jogamp.gluegen.runtime.*; +import com.jogamp.common.os.*; +import com.jogamp.common.nio.*; +import jogamp.common.os.MachineDescriptionRuntime; + + +public class Shdr { + + StructAccessor accessor; + + private static final int mdIdx = MachineDescriptionRuntime.getStatic().ordinal(); + + private static final int[] Shdr_size = new int[] { 40 /* ARMle_EABI */, 40 /* X86_32_UNIX */, 64 /* X86_64_UNIX */, 40 /* X86_32_MACOS */, 40 /* X86_32_WINDOWS */, 64 /* X86_64_WINDOWS */ }; + private static final int[] sh_name_offset = new int[] { 0 /* ARMle_EABI */, 0 /* X86_32_UNIX */, 0 /* X86_64_UNIX */, 0 /* X86_32_MACOS */, 0 /* X86_32_WINDOWS */, 0 /* X86_64_WINDOWS */ }; + private static final int[] sh_type_offset = new int[] { 4 /* ARMle_EABI */, 4 /* X86_32_UNIX */, 4 /* X86_64_UNIX */, 4 /* X86_32_MACOS */, 4 /* X86_32_WINDOWS */, 4 /* X86_64_WINDOWS */ }; + private static final int[] sh_flags_offset = new int[] { 8 /* ARMle_EABI */, 8 /* X86_32_UNIX */, 8 /* X86_64_UNIX */, 8 /* X86_32_MACOS */, 8 /* X86_32_WINDOWS */, 8 /* X86_64_WINDOWS */ }; + private static final int[] sh_addr_offset = new int[] { 12 /* ARMle_EABI */, 12 /* X86_32_UNIX */, 16 /* X86_64_UNIX */, 12 /* X86_32_MACOS */, 12 /* X86_32_WINDOWS */, 16 /* X86_64_WINDOWS */ }; + private static final int[] sh_offset_offset = new int[] { 16 /* ARMle_EABI */, 16 /* X86_32_UNIX */, 24 /* X86_64_UNIX */, 16 /* X86_32_MACOS */, 16 /* X86_32_WINDOWS */, 24 /* X86_64_WINDOWS */ }; + private static final int[] sh_size_offset = new int[] { 20 /* ARMle_EABI */, 20 /* X86_32_UNIX */, 32 /* X86_64_UNIX */, 20 /* X86_32_MACOS */, 20 /* X86_32_WINDOWS */, 32 /* X86_64_WINDOWS */ }; + private static final int[] sh_link_offset = new int[] { 24 /* ARMle_EABI */, 24 /* X86_32_UNIX */, 40 /* X86_64_UNIX */, 24 /* X86_32_MACOS */, 24 /* X86_32_WINDOWS */, 40 /* X86_64_WINDOWS */ }; + private static final int[] sh_info_offset = new int[] { 28 /* ARMle_EABI */, 28 /* X86_32_UNIX */, 44 /* X86_64_UNIX */, 28 /* X86_32_MACOS */, 28 /* X86_32_WINDOWS */, 44 /* X86_64_WINDOWS */ }; + private static final int[] sh_addralign_offset = new int[] { 32 /* ARMle_EABI */, 32 /* X86_32_UNIX */, 48 /* X86_64_UNIX */, 32 /* X86_32_MACOS */, 32 /* X86_32_WINDOWS */, 48 /* X86_64_WINDOWS */ }; + private static final int[] sh_entsize_offset = new int[] { 36 /* ARMle_EABI */, 36 /* X86_32_UNIX */, 56 /* X86_64_UNIX */, 36 /* X86_32_MACOS */, 36 /* X86_32_WINDOWS */, 56 /* X86_64_WINDOWS */ }; + + public static int size() { + return Shdr_size[mdIdx]; + } + + public static Shdr create() { + return create(Buffers.newDirectByteBuffer(size())); + } + + public static Shdr create(java.nio.ByteBuffer buf) { + return new Shdr(buf); + } + + Shdr(java.nio.ByteBuffer buf) { + accessor = new StructAccessor(buf); + } + + public java.nio.ByteBuffer getBuffer() { + return accessor.getBuffer(); + } + + public Shdr setSh_name(int val) { + accessor.setIntAt(sh_name_offset[mdIdx], val); + return this; + } + + public int getSh_name() { + return accessor.getIntAt(sh_name_offset[mdIdx]); + } + + public Shdr setSh_type(int val) { + accessor.setIntAt(sh_type_offset[mdIdx], val); + return this; + } + + public int getSh_type() { + return accessor.getIntAt(sh_type_offset[mdIdx]); + } + + public Shdr setSh_flags(long val) { + accessor.setLongAt(sh_flags_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + return this; + } + + public long getSh_flags() { + return accessor.getLongAt(sh_flags_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + } + + public Shdr setSh_addr(long val) { + accessor.setLongAt(sh_addr_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + return this; + } + + public long getSh_addr() { + return accessor.getLongAt(sh_addr_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + } + + public Shdr setSh_offset(long val) { + accessor.setLongAt(sh_offset_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + return this; + } + + public long getSh_offset() { + return accessor.getLongAt(sh_offset_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + } + + public Shdr setSh_size(long val) { + accessor.setLongAt(sh_size_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + return this; + } + + public long getSh_size() { + return accessor.getLongAt(sh_size_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + } + + public Shdr setSh_link(int val) { + accessor.setIntAt(sh_link_offset[mdIdx], val); + return this; + } + + public int getSh_link() { + return accessor.getIntAt(sh_link_offset[mdIdx]); + } + + public Shdr setSh_info(int val) { + accessor.setIntAt(sh_info_offset[mdIdx], val); + return this; + } + + public int getSh_info() { + return accessor.getIntAt(sh_info_offset[mdIdx]); + } + + public Shdr setSh_addralign(long val) { + accessor.setLongAt(sh_addralign_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + return this; + } + + public long getSh_addralign() { + return accessor.getLongAt(sh_addralign_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + } + + public Shdr setSh_entsize(long val) { + accessor.setLongAt(sh_entsize_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + return this; + } + + public long getSh_entsize() { + return accessor.getLongAt(sh_entsize_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes()); + } +} diff --git a/src/junit/com/jogamp/common/nio/TestStructAccessorEndian.java b/src/junit/com/jogamp/common/nio/TestStructAccessorEndian.java index c1d946e..6d8ed88 100644 --- a/src/junit/com/jogamp/common/nio/TestStructAccessorEndian.java +++ b/src/junit/com/jogamp/common/nio/TestStructAccessorEndian.java @@ -1,16 +1,16 @@ package com.jogamp.common.nio; -import com.jogamp.common.os.*; -import com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter; -import com.jogamp.junit.util.JunitTracer; +import static java.lang.System.out; import java.io.IOException; -import java.nio.*; +import java.nio.ByteBuffer; import org.junit.Assert; import org.junit.Test; -import static java.lang.System.*; +import com.jogamp.common.os.MachineDescription; +import com.jogamp.common.os.Platform; +import com.jogamp.junit.util.JunitTracer; public class TestStructAccessorEndian extends JunitTracer { diff --git a/src/junit/com/jogamp/common/os/TestElfReader01.java b/src/junit/com/jogamp/common/os/TestElfReader01.java new file mode 100644 index 0000000..fe6adc2 --- /dev/null +++ b/src/junit/com/jogamp/common/os/TestElfReader01.java @@ -0,0 +1,119 @@ +package com.jogamp.common.os; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.RandomAccessFile; + +import jogamp.common.os.elf.ElfHeader; +import jogamp.common.os.elf.Section; +import jogamp.common.os.elf.SectionArmAttributes; +import jogamp.common.os.elf.SectionHeader; + +import org.junit.Test; + +import com.jogamp.junit.util.JunitTracer; + +public class TestElfReader01 extends JunitTracer { + public static String GNU_LINUX_SELF_EXE = "/proc/self/exe"; + public static String ARM_HF_EXE = "tst-exe-armhf"; + public static String ARM_SF_EXE = "tst-exe-arm"; + + @Test + public void testGNULinuxSelfExe () throws IOException { + testElfHeaderImpl(GNU_LINUX_SELF_EXE, false); + } + + // @Test + public void testArmHFExe () throws IOException { + testElfHeaderImpl(ARM_HF_EXE, false); + } + + // @Test + public void testArmSFExe () throws IOException { + testElfHeaderImpl(ARM_SF_EXE, false); + } + + void testElfHeaderImpl(String file, boolean fileOutSections) throws IOException { + RandomAccessFile in = new RandomAccessFile(file, "r"); + try { + ElfHeader eh = ElfHeader.read(in); + byte[] e_ident = eh.d.getE_ident(); + int i=0; + System.err.print("[0..4]: 0x"+toHexString(e_ident[i++])); + System.err.print(", 0x"+toHexString(e_ident[i++])); + System.err.print(", 0x"+toHexString(e_ident[i++])); + System.err.println(", 0x"+toHexString(e_ident[i++])); + System.err.println("e_class "+e_ident[ElfHeader.EI_CLASS]+", "+eh.getArchClassBits()+" bits"); + System.err.println("e_data "+e_ident[ElfHeader.EI_DATA]+", "+eh.getDataEncodingMode()); + System.err.println("e_flags "+toHexString(eh.getFlags())); + System.err.println(" ARM ABI "+eh.getArmABI()); + System.err.println(" ARM lGCC "+eh.getArmLegacyGCCFlags()); + System.err.println(" ARM FLOAT "+eh.getArmFloatMode()+", is hard-float "+(2 == eh.getArmFloatMode())); + System.err.println("e_version "+e_ident[ElfHeader.EI_VERSION]); + System.err.println("e_osabi "+eh.getOSABI()+", Linux "+ElfHeader.ELFOSABI_LINUX); + System.err.println("e_abiversion "+e_ident[ElfHeader.EI_ABIVERSION]); + System.err.println("e_machine "+eh.getMachine()+", isARM "+eh.isArm()+", isIntel "+eh.isIntel()); + System.err.println("e_version "+eh.d.getE_version()); + System.err.println("e_type "+eh.getType()); + System.err.println("EH Size "+eh.d.getE_ehsize()); + System.err.println("SH num "+eh.d.getE_shnum()); + System.err.println("SH entsz "+eh.d.getE_shentsize()); + System.err.println("SH off "+toHexString(eh.d.getE_shoff())); + System.err.println("SH strndx "+eh.d.getE_shstrndx()); + System.err.println("SH num "+eh.sht.length); + if( 0 < eh.sht.length ) { + System.err.println("SH size "+eh.sht[0].d.getBuffer().limit()); + } + { + SectionHeader sh = eh.getSectionHeader(SectionHeader.SHT_ARM_ATTRIBUTES); + boolean abiVFPArgsAcceptsVFPVariant = false; + if( null != sh ) { + final SectionArmAttributes sArmAttrs = (SectionArmAttributes) sh.readSection(in); + final SectionArmAttributes.Attribute abiVFPArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.ABI_VFP_args); + if( null != abiVFPArgsAttr ) { + abiVFPArgsAcceptsVFPVariant = SectionArmAttributes.abiVFPArgsAcceptsVFPVariant(abiVFPArgsAttr.getULEB128()); + } + } + System.err.println("abiVFPArgsAcceptsVFPVariant "+abiVFPArgsAcceptsVFPVariant); + } + for(i=0; i<eh.sht.length; i++) { + final SectionHeader sh = eh.sht[i]; + System.err.println(sh); + final int type = sh.getType(); + if( SectionHeader.SHT_STRTAB == type ) { + dumpSection(in, sh, "SHT_STRTAB", fileOutSections); + } else if( SectionHeader.SHT_ARM_ATTRIBUTES == type ) { + dumpSection(in, sh, "SHT_ARM_ATTRIBUTES", fileOutSections); + } + } + } finally { + in.close(); + } + } + + static void dumpSection(RandomAccessFile in, SectionHeader sh, String name, boolean fileOut) throws IllegalArgumentException, IOException { + final Section s = sh.readSection(in); + if(fileOut) { + File outFile = new File("ElfSection-"+sh.getIndex()+"-"+name); + OutputStream out = new BufferedOutputStream(new FileOutputStream(outFile)); + try { + out.write(s.data, s.offset, s.length); + } finally { + out.close(); + } + } + System.err.println(name+": read "+s.length+", "+s); + } + + public static void main(String args[]) throws IOException { + String tstname = TestElfReader01.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + + static String toHexString(int i) { return "0x"+Integer.toHexString(i); } + static String toHexString(long i) { return "0x"+Long.toHexString(i); } + +} |