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}.
*
* References:
*
* - http://infocenter.arm.com/
*
* - ARM IHI 0044E, current through ABI release 2.09
* - ARM IHI 0045D, current through ABI release 2.09
*
*
*
*/
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 {
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 {
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;
}
}