jogamp.common.os.elf.ElfHeaderPart2 Maven / Gradle / Ivy
/**
* 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:
*
* - http://www.sco.com/developers/gabi/latest/contents.html
* - https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
* - http://linux.die.net/man/5/elf
* - http://infocenter.arm.com/
*
* - ARM IHI 0044E, current through ABI release 2.09
* - ARM IHI 0056B: Elf for ARM 64-bit Architecture
*
*
*
*/
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