From a3f2d08801c5a54048faca52f422bcededf81b2a Mon Sep 17 00:00:00 2001
From: Sven Gothel
+ * Part-2 can only be read w/ knowledge of CPUType!
+ *
+ * References:
+ *
+ *
+ *
+ *
+ * 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