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/java/jogamp/common/os/elf/SectionArmAttributes.java | |
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/java/jogamp/common/os/elf/SectionArmAttributes.java')
-rw-r--r-- | src/java/jogamp/common/os/elf/SectionArmAttributes.java | 317 |
1 files changed, 317 insertions, 0 deletions
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; + } +} |