/** * 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 *

* Part-2 can only be read w/ knowledge of CPUType! *

*

* References: *

*

*/ 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. *

* Compatible with legacy (pre version 5) gcc use as EF_ARM_VFP_FLOAT. *

*

* Note: This is not used (anymore) *

* {@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. *

* Compatible with legacy (pre version 5) gcc use as EF_ARM_SOFT_FLOAT. *

*

* Note: This is not used (anymore) *

* {@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. *

* Note: This is not used (anymore) *

*/ 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= 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