package jogamp.common.os.elf; import static jogamp.common.os.elf.IOUtils.toHexString; import static jogamp.common.os.elf.IOUtils.readUInt32; import static jogamp.common.os.elf.IOUtils.getString; import java.util.ArrayList; import java.util.List; import com.jogamp.common.util.Bitstream; /** * ARM EABI attributes within section header {@link SectionHeader#SHT_ARM_ATTRIBUTES}. *

* References: *

*

*/ 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); } @Override public String toString() { return tag+" = "+value; } } public static class VendorAttributes { public final String vendor; public final List attributes; VendorAttributes(String vendor, List attributes) { this.vendor = vendor; this.attributes = attributes; } @Override public String toString() { return vendor + attributes.toString(); } } public final List vendorAttributesList; SectionArmAttributes(SectionHeader sh, byte[] data, int offset, int length) throws IndexOutOfBoundsException, IllegalArgumentException { super(sh, data, offset, length); this.vendorAttributesList = parse(data, offset, length); } @Override public String toString() { return "SectionArmAttributes["+super.toSubString()+", "+vendorAttributesList.toString()+"]"; } public final Attribute get(Tag tag) { for(int i=0; i attributes = vendorAttributesList.get(i).attributes; for(int j=0; j get(String vendor) { return get(vendorAttributesList, vendor); } static final List get(final List vendorAttributesList, String vendor) { for(int i=0; isb_off, * which shall not exceed sb.length - offset. * @throws IndexOutOfBoundsException if offset + remaining > sb.length. * @throws IllegalArgumentException if section parsing failed, i.e. incompatible version or data. */ static List parse(final byte[] in, final int offset, final int remaining) throws IndexOutOfBoundsException, IllegalArgumentException { Bitstream.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 vendorAttributesList = new ArrayList(); 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 attributes = new ArrayList(); 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 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/ sb_off, * which shall not exceed sb.length - offset. * @throws IndexOutOfBoundsException if offset + remaining > sb.length. * @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 attributes) throws IndexOutOfBoundsException, IllegalArgumentException { Bitstream.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; } }