summaryrefslogtreecommitdiffstats
path: root/src/java/jogamp/common/os/elf/ElfHeaderPart2.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/jogamp/common/os/elf/ElfHeaderPart2.java')
-rw-r--r--src/java/jogamp/common/os/elf/ElfHeaderPart2.java374
1 files changed, 374 insertions, 0 deletions
diff --git a/src/java/jogamp/common/os/elf/ElfHeaderPart2.java b/src/java/jogamp/common/os/elf/ElfHeaderPart2.java
new file mode 100644
index 0000000..320b8b4
--- /dev/null
+++ b/src/java/jogamp/common/os/elf/ElfHeaderPart2.java
@@ -0,0 +1,374 @@
+/**
+ * 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 com.jogamp.common.os.Platform.ABIType;
+import com.jogamp.common.os.Platform.CPUFamily;
+import com.jogamp.common.os.Platform.CPUType;
+
+import static jogamp.common.os.elf.IOUtils.readBytes;
+import static jogamp.common.os.elf.IOUtils.seek;
+import static jogamp.common.os.elf.IOUtils.shortToInt;
+import static jogamp.common.os.elf.IOUtils.toHexString;
+
+/**
+ * ELF ABI Header Part-2
+ * <p>
+ * Part-2 can only be read w/ knowledge of CPUType!
+ * </p>
+ * <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>
+ * <li>ARM IHI 0056B: Elf for ARM 64-bit Architecture</li>
+ * </ul></li>
+ * </ul>
+ * </p>
+ */
+public class ElfHeaderPart2 {
+ /**
+ * 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;
+
+ /** Public access to the elf header part-1 (CPU/ABI independent read) */
+ public final ElfHeaderPart1 eh1;
+
+ /** Public access to the raw elf header part-2 (CPU/ABI dependent read) */
+ public final Ehdr_p2 raw;
+
+ /** Lower case CPUType name */
+ public final String cpuName;
+ public final CPUType cpuType;
+ public final ABIType abiType;
+
+ /** 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 ElfHeaderPart2 read(final ElfHeaderPart1 eh1, final RandomAccessFile in) throws IOException, IllegalArgumentException {
+ return new ElfHeaderPart2(eh1, in);
+ }
+
+ /**
+ * @param buf ELF Header bytes
+ * @throws IllegalArgumentException if the given buffer does not represent an ELF Header
+ * @throws IOException
+ */
+ ElfHeaderPart2(final ElfHeaderPart1 eh1, final RandomAccessFile in) throws IllegalArgumentException, IOException {
+ this.eh1 = eh1;
+ //
+ // Part-2
+ //
+ {
+ final byte[] buf = new byte[Ehdr_p2.size(eh1.machDesc.ordinal())];
+ readBytes (in, buf, 0, buf.length);
+ final ByteBuffer eh2Bytes = ByteBuffer.wrap(buf, 0, buf.length);
+ raw = Ehdr_p2.create(eh1.machDesc.ordinal(), eh2Bytes);
+ }
+ sht = readSectionHeaderTable(in);
+
+ if( CPUFamily.ARM == eh1.cpuType.family && eh1.cpuType.is32Bit ) {
+ // AArch64, has no SHT_ARM_ATTRIBUTES or SHT_AARCH64_ATTRIBUTES SectionHeader defined in our builds!
+ String armCpuName = null;
+ String armCpuRawName = null;
+ boolean abiVFPArgsAcceptsVFPVariant = false;
+ final SectionHeader sh = getSectionHeader(SectionHeader.SHT_ARM_ATTRIBUTES);
+ if(ElfHeaderPart1.DEBUG) {
+ System.err.println("ELF-2: Got ARM Attribs Section Header: "+sh);
+ }
+ if( null != sh ) {
+ final SectionArmAttributes sArmAttrs = (SectionArmAttributes) sh.readSection(in);
+ if(ElfHeaderPart1.DEBUG) {
+ System.err.println("ELF-2: Got ARM Attribs Section Block : "+sArmAttrs);
+ }
+ final SectionArmAttributes.Attribute cpuNameArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.CPU_name);
+ if( null != cpuNameArgsAttr && cpuNameArgsAttr.isNTBS() ) {
+ armCpuName = cpuNameArgsAttr.getNTBS();
+ }
+ final SectionArmAttributes.Attribute cpuRawNameArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.CPU_raw_name);
+ if( null != cpuRawNameArgsAttr && cpuRawNameArgsAttr.isNTBS() ) {
+ armCpuRawName = cpuRawNameArgsAttr.getNTBS();
+ }
+ final SectionArmAttributes.Attribute abiVFPArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.ABI_VFP_args);
+ if( null != abiVFPArgsAttr ) {
+ abiVFPArgsAcceptsVFPVariant = SectionArmAttributes.abiVFPArgsAcceptsVFPVariant(abiVFPArgsAttr.getULEB128());
+ }
+ }
+ {
+ String _cpuName;
+ if( null != armCpuName && armCpuName.length() > 0 ) {
+ _cpuName = armCpuName.toLowerCase().replace(' ', '-');
+ } else if( null != armCpuRawName && armCpuRawName.length() > 0 ) {
+ _cpuName = armCpuRawName.toLowerCase().replace(' ', '-');
+ } else {
+ _cpuName = eh1.cpuName;
+ }
+
+ // 1st-try: native name
+ CPUType _cpuType = queryCPUTypeSafe(_cpuName);
+ if( null == _cpuType ) {
+ // 2nd-try: "arm-" + native name
+ _cpuName = "arm-"+_cpuName;
+ _cpuType = queryCPUTypeSafe(_cpuName);
+ if( null == _cpuType ) {
+ // finally: Use ELF-1
+ _cpuName = eh1.cpuName;
+ _cpuType = queryCPUTypeSafe(_cpuName);
+ if( null == _cpuType ) {
+ throw new InternalError("XXX: "+_cpuName+", "+eh1); // shall not happen
+ }
+ }
+ }
+ cpuName = _cpuName;
+ cpuType = _cpuType;
+ if(ElfHeaderPart1.DEBUG) {
+ System.err.println("ELF-2: abiARM cpuName "+_cpuName+"[armCpuName "+armCpuName+", armCpuRawName "+armCpuRawName+"] -> "+cpuName+" -> "+cpuType+", abiVFPArgsAcceptsVFPVariant "+abiVFPArgsAcceptsVFPVariant);
+ }
+ }
+ if( cpuType.is32Bit ) { // always true, see above!
+ abiType = abiVFPArgsAcceptsVFPVariant ? ABIType.EABI_GNU_ARMHF : ABIType.EABI_GNU_ARMEL;
+ } else {
+ abiType = eh1.abiType;
+ }
+ } else {
+ cpuName = eh1.cpuName;
+ cpuType = eh1.cpuType;
+ abiType = eh1.abiType;
+ }
+ if(ElfHeaderPart1.DEBUG) {
+ System.err.println("ELF-2: cpuName "+cpuName+" -> "+cpuType+", "+abiType);
+ }
+ }
+ private static CPUType queryCPUTypeSafe(final String cpuName) {
+ CPUType res = null;
+ try {
+ res = CPUType.query(cpuName);
+ } catch (final Throwable t) {
+ if(ElfHeaderPart1.DEBUG) {
+ System.err.println("ELF-2: queryCPUTypeSafe("+cpuName+"): "+t.getMessage());
+ }
+ }
+ return res;
+ }
+
+ public final short getSize() { return raw.getE_ehsize(); }
+
+ /** Returns the processor-specific flags associated with the file. */
+ public final int getFlags() {
+ return raw.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 & raw.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 = raw.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 = raw.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(final 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(final String name) {
+ for(int i=0; i<sht.length; i++) {
+ final SectionHeader sh = sht[i];
+ if( sh.getName().equals(name) ) {
+ return sh;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public final String toString() {
+ final int armABI = getArmABI();
+ final String armFlagsS;
+ if( 0 != armABI ) {
+ armFlagsS=", arm[abi "+armABI+", lGCC "+getArmLegacyGCCFlags()+", float "+getArmFloatMode()+"]";
+ } else {
+ armFlagsS="";
+ }
+ return "ELF-2["+cpuType+", "+abiType+", flags["+toHexString(getFlags())+armFlagsS+"], sh-num "+sht.length+"]";
+ }
+
+ final SectionHeader[] readSectionHeaderTable(final RandomAccessFile in) throws IOException, IllegalArgumentException {
+ // positioning
+ {
+ final long off = raw.getE_shoff(); // absolute offset
+ if( 0 == off ) {
+ return new SectionHeader[0];
+ }
+ seek(in, off);
+ }
+ final SectionHeader[] sht;
+ final int strndx = raw.getE_shstrndx();
+ final int size = raw.getE_shentsize();
+ final int num;
+ int i;
+ if( 0 == raw.getE_shnum() ) {
+ // Read 1st table 1st and use it's sh_size
+ final byte[] buf0 = new byte[size];
+ readBytes(in, buf0, 0, size);
+ final SectionHeader sh0 = new SectionHeader(this, buf0, 0, size, 0);
+ num = (int) sh0.raw.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 = raw.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(this, 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.raw.getSh_type());
+ }
+ final Section strS = strShdr.readSection(in);
+ for(i=0; i<num; i++) {
+ sht[i].initName(strS, sht[i].raw.getSh_name());
+ }
+ }
+
+ return sht;
+ }
+}