aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/jogamp/common/os/elf/SectionArmAttributes.java
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-02-08 05:12:39 +0100
committerSven Gothel <[email protected]>2013-02-08 05:12:39 +0100
commit2432dbef17c1dc4164f055cf434073bdabf8a6a9 (patch)
tree348a46b246ead8bb508152a96847a62089b72d0c /src/java/jogamp/common/os/elf/SectionArmAttributes.java
parent1118cb7182611d0a77764a3c781a1148849b3022 (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.java317
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;
+ }
+}