1 /** 2 * Copyright 2013 JogAmp Community. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, are 5 * permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, this list of 8 * conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 * of conditions and the following disclaimer in the documentation and/or other materials 12 * provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * The views and conclusions contained in the software and documentation are those of the 25 * authors and should not be interpreted as representing official policies, either expressed 26 * or implied, of JogAmp Community. 27 */ 28 package jogamp.common.os.elf; 29 30 import static jogamp.common.os.elf.IOUtils.toHexString; 31 import static jogamp.common.os.elf.IOUtils.readUInt32; 32 import static jogamp.common.os.elf.IOUtils.getString; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 37 import com.jogamp.common.util.Bitstream; 38 39 /** 40 * ARM EABI attributes within section header {@link SectionHeader#SHT_ARM_ATTRIBUTES}. 41 * <p> 42 * References: 43 * <ul> 44 * <li>http://infocenter.arm.com/ 45 * <ul> 46 * <li>ARM IHI 0044E, current through ABI release 2.09</li> 47 * <li>ARM IHI 0045D, current through ABI release 2.09</li> 48 * </ul></li> 49 * </ul> 50 * </p> 51 */ 52 public class SectionArmAttributes extends Section { 53 public static final byte FORMAT_VERSION_A = 0x41; // 'A'; 54 55 public static enum Type { 56 /** No Value */ 57 None, 58 /** A Sub-Section - following the 4 byte sub section total size (tag + size + content) - byte order of the ELF file */ 59 SubSection, 60 /** Null Terminated Byte-String */ 61 NTBS, 62 ULEB128, 63 } 64 65 /** ULEB128 Value for {@link Tag#ABI_VFP_args}: FP parameter/result passing conforms to AAPCS, BASE variant. */ 66 public static final byte ABI_VFP_ARGS_IS_BASE_VARIANT = 0; 67 /** ULEB128 Value for {@link Tag#ABI_VFP_args}: FP parameter/result passing conforms to AAPCS, VFP variant. */ 68 public static final byte ABI_VFP_ARGS_IS_VFP_VARIANT = 1; 69 /** ULEB128 Value for {@link Tag#ABI_VFP_args}: FP parameter/result passing conforms to custom toolchain. */ 70 public static final byte ABI_VFP_ARGS_IS_CUSTOM_VARIANT = 2; 71 /** ULEB128 Value for {@link Tag#ABI_VFP_args}: FP parameter/result passing conforms to both , BASE and VFP variant. */ 72 public static final byte ABI_VFP_ARGS_IS_BOTH_BASE_AND_VFP_VARIANT = 3; 73 74 /** 75 * Returns true if value is either {@link #ABI_VFP_ARGS_IS_VFP_VARIANT} or {@link #ABI_VFP_ARGS_IS_BOTH_BASE_AND_VFP_VARIANT} 76 * @param v ULEB128 Value from {@link Tag#ABI_VFP_args} attribute 77 */ abiVFPArgsAcceptsVFPVariant(final byte v)78 public static final boolean abiVFPArgsAcceptsVFPVariant(final byte v) { 79 return ABI_VFP_ARGS_IS_VFP_VARIANT == v || ABI_VFP_ARGS_IS_BOTH_BASE_AND_VFP_VARIANT == v; 80 } 81 82 public static enum Tag { 83 None(0, Type.None), 84 File(1, Type.SubSection), Section(2, Type.SubSection), Symbol(3, Type.SubSection), 85 CPU_raw_name( 4, Type.NTBS ), 86 CPU_name( 5, Type.NTBS ), 87 CPU_arch( 6, Type.ULEB128 ), 88 CPU_arch_profile( 7, Type.ULEB128 ), 89 ARM_ISA_use( 8, Type.ULEB128 ), 90 THUMB_ISA_use( 9, Type.ULEB128 ), 91 FP_arch( 10, Type.ULEB128 ), 92 WMMX_arch( 11, Type.ULEB128 ), 93 Advanced_SIMD_arch( 12, Type.ULEB128 ), 94 PCS_config( 13, Type.ULEB128 ), 95 ABI_PCS_R9_use ( 14, Type.ULEB128 ), 96 ABI_PCS_RW_data( 15, Type.ULEB128 ), 97 ABI_PCS_RO_data( 16, Type.ULEB128 ), 98 ABI_PCS_GOT_use( 17, Type.ULEB128 ), 99 ABI_PCS_wchar_t( 18, Type.ULEB128 ), 100 ABI_FP_rounding( 19, Type.ULEB128 ), 101 ABI_FP_denormal( 20, Type.ULEB128 ), 102 ABI_FP_exceptions( 21, Type.ULEB128 ), 103 ABI_FP_user_exceptions( 22, Type.ULEB128 ), 104 ABI_FP_number_model( 23, Type.ULEB128 ), 105 ABI_align_needed( 24, Type.ULEB128 ), 106 ABI_align_preserved( 25, Type.ULEB128 ), 107 ABI_enum_size( 26, Type.ULEB128 ), 108 ABI_HardFP_use( 27, Type.ULEB128 ), 109 ABI_VFP_args( 28, Type.ULEB128 ), 110 ABI_WMMX_args( 29, Type.ULEB128 ), 111 ABI_optimization_goals( 30, Type.ULEB128 ), 112 ABI_FP_optimization_goals( 31, Type.ULEB128 ), 113 compatibility ( 32, Type.NTBS ), /** with each byte interpreted as an ULEB128 with closing EOS */ 114 CPU_unaligned_access( 34, Type.ULEB128 ), 115 FP_HP_extension( 36, Type.ULEB128 ), 116 ABI_FP_16bit_format( 38, Type.ULEB128 ), 117 MPextension_use( 42, Type.ULEB128 ), 118 DIV_use( 44, Type.ULEB128 ), 119 nodefaults( 64, Type.ULEB128 ), /* value ignored */ 120 also_compatible_with( 65, Type.ULEB128 ), 121 T2EE_use( 66, Type.ULEB128 ), 122 conformance( 67, Type.NTBS ), 123 Virtualization_use( 68, Type.ULEB128 ), 124 undefined69( 69, Type.None ), 125 MPextension_use_legacy( 70, Type.ULEB128 ) 126 ; 127 128 public final int id; 129 public final Type type; 130 131 /** Slow O(n) transition of a native tag value to a Tag. */ get(final int id)132 public static Tag get(final int id) { 133 final Tag[] tags = Tag.values(); 134 final int tag_count = tags.length; 135 for(int i=0; i < tag_count; i++) { 136 if( tags[i].id == id ) { 137 return tags[i]; 138 } 139 } 140 return null; 141 } 142 Tag(final int id, final Type type)143 Tag(final int id, final Type type){ 144 this.id = id; 145 this.type = type; 146 } 147 } 148 149 public static class Attribute { 150 public final Tag tag; 151 private final Object value; 152 Attribute(final Tag tag, final Object value)153 Attribute(final Tag tag, final Object value) { 154 this.tag = tag; 155 this.value = value; 156 } 157 isNTBS()158 public final boolean isNTBS() { 159 return Type.NTBS == tag.type; 160 } getNTBS()161 public final String getNTBS() { 162 if( Type.NTBS == tag.type ) { 163 return (String) value; 164 } 165 throw new IllegalArgumentException("Not NTBS but "+tag.type); 166 } 167 isULEB128()168 public final boolean isULEB128() { 169 return Type.ULEB128 == tag.type; 170 } getULEB128()171 public final byte getULEB128() { 172 if( Type.ULEB128== tag.type ) { 173 return ((Byte) value).byteValue(); 174 } 175 throw new IllegalArgumentException("Not ULEB128 but "+tag.type); 176 } 177 178 @Override toString()179 public String toString() { 180 return tag+" = "+value; 181 } 182 } 183 184 public static class VendorAttributes { 185 public final String vendor; 186 public final List<Attribute> attributes; 187 VendorAttributes(final String vendor, final List<Attribute> attributes)188 VendorAttributes(final String vendor, final List<Attribute> attributes) { 189 this.vendor = vendor; 190 this.attributes = attributes; 191 } 192 193 @Override toString()194 public String toString() { 195 return vendor + attributes.toString(); 196 } 197 } 198 public final List<VendorAttributes> vendorAttributesList; 199 SectionArmAttributes(final SectionHeader sh, final byte[] data, final int offset, final int length)200 SectionArmAttributes(final SectionHeader sh, final byte[] data, final int offset, final int length) throws IndexOutOfBoundsException, IllegalArgumentException { 201 super(sh, data, offset, length); 202 this.vendorAttributesList = parse(sh, data, offset, length); 203 } 204 205 @Override toString()206 public String toString() { 207 return "SectionArmAttributes["+super.toSubString()+", "+vendorAttributesList.toString()+"]"; 208 } 209 get(final Tag tag)210 public final Attribute get(final Tag tag) { 211 for(int i=0; i<vendorAttributesList.size(); i++) { 212 final List<Attribute> attributes = vendorAttributesList.get(i).attributes; 213 for(int j=0; j<attributes.size(); j++) { 214 final Attribute a = attributes.get(j); 215 if( a.tag == tag ) { 216 return a; 217 } 218 } 219 } 220 return null; 221 } 222 get(final String vendor)223 public final List<Attribute> get(final String vendor) { 224 return get(vendorAttributesList, vendor); 225 } 226 get(final List<VendorAttributes> vendorAttributesList, final String vendor)227 static final List<Attribute> get(final List<VendorAttributes> vendorAttributesList, final String vendor) { 228 for(int i=0; i<vendorAttributesList.size(); i++) { 229 final VendorAttributes vas = vendorAttributesList.get(i); 230 if( vas.vendor.equals(vendor) ) { 231 return vas.attributes; 232 } 233 } 234 return null; 235 } 236 237 /** 238 * @param sh TODO 239 * @param in byte source buffer to parse 240 * @param offset offset within byte source buffer to start parsing 241 * @param remaining remaining numbers of bytes to parse beginning w/ <code>sb_off</code>, 242 * which shall not exceed <code>sb.length - offset</code>. 243 * @throws IndexOutOfBoundsException if <code>offset + remaining > sb.length</code>. 244 * @throws IllegalArgumentException if section parsing failed, i.e. incompatible version or data. 245 */ parse(final SectionHeader sh, final byte[] in, final int offset, final int remaining)246 static List<VendorAttributes> parse(final SectionHeader sh, final byte[] in, final int offset, final int remaining) throws IndexOutOfBoundsException, IllegalArgumentException { 247 Bitstream.checkBounds(in, offset, remaining); 248 int i = offset; 249 if( FORMAT_VERSION_A != in[ i ] ) { 250 throw new IllegalArgumentException("ShArmAttr: Not version A, but: "+toHexString(in[i])); 251 } 252 i++; 253 254 final List<VendorAttributes> vendorAttributesList = new ArrayList<VendorAttributes>(); 255 final boolean isBigEndian = sh.eh2.eh1.isBigEndian(); 256 257 while(i < remaining) { 258 final int i_pre = i; 259 final int secLen = readUInt32(isBigEndian, in, i); /* total section size: 4 + string + content, i.e. offset to next section */ 260 i+=4; 261 262 final String vendor; 263 { 264 final int[] i_post = new int[] { 0 }; 265 vendor = getString(in, i, secLen - 4, i_post); 266 i = i_post[0]; 267 } 268 269 final List<Attribute> attributes = new ArrayList<Attribute>(); 270 271 while(i < secLen) { 272 final int[] i_post = new int[] { 0 }; 273 parseSub(isBigEndian, in, i, secLen - i, i_post, attributes); 274 i = i_post[0]; 275 } 276 277 if( i_pre + secLen != i ) { 278 throw new IllegalArgumentException("ShArmAttr: Section length count mismatch, expected "+(i_pre + secLen)+", has "+i); 279 } 280 281 final List<Attribute> mergeAttribs = get(vendorAttributesList, vendor); 282 if( null != mergeAttribs ) { 283 mergeAttribs.addAll(attributes); 284 } else { 285 vendorAttributesList.add(new VendorAttributes(vendor, attributes)); 286 } 287 } 288 289 return vendorAttributesList; 290 } 291 292 /** 293 * @param isBigEndian TODO 294 * @param in byte source buffer to parse 295 * @param offset offset within byte source buffer to start parsing 296 * @param remaining remaining numbers of bytes to parse beginning w/ <code>sb_off</code>, 297 * which shall not exceed <code>sb.length - offset</code>. 298 * @throws IndexOutOfBoundsException if <code>offset + remaining > sb.length</code>. 299 * @throws IllegalArgumentException if section parsing failed, i.e. incompatible version or data. 300 */ parseSub(final boolean isBigEndian, final byte[] in, final int offset, final int remaining, final int[] offset_post, final List<Attribute> attributes)301 private static void parseSub(final boolean isBigEndian, final byte[] in, final int offset, final int remaining, 302 final int[] offset_post, final List<Attribute> attributes) 303 throws IndexOutOfBoundsException, IllegalArgumentException 304 { 305 Bitstream.checkBounds(in, offset, remaining); 306 307 // Starts w/ sub-section Tag 308 int i = offset; 309 final int i_sTag = in[i++]; 310 final Tag sTag = Tag.get(i_sTag); 311 if( null == sTag ) { 312 throw new IllegalArgumentException("ShArmAttr: Invalid Sub-Section tag (NaT): "+i_sTag); 313 } 314 final int subSecLen; // sub section total size (tag + size + content) 315 switch(sTag) { 316 case File: 317 case Section: 318 case Symbol: 319 subSecLen = readUInt32(isBigEndian, in, i); 320 i+=4; 321 break; 322 default: 323 throw new IllegalArgumentException("ShArmAttr: Invalid Sub-Section tag: "+sTag); 324 } 325 if( Tag.File == sTag ) { 326 while( i < offset + subSecLen ) { 327 final int i_tag = in[i++]; 328 final Tag tag = Tag.get(i_tag); 329 if( null == tag ) { 330 throw new IllegalArgumentException("ShArmAttr: Invalid Attribute tag (NaT): "+i_tag); 331 } 332 switch(tag.type) { 333 case NTBS: 334 { 335 final int[] i_post = new int[] { 0 }; 336 final String value = getString(in, i, subSecLen + offset - i, i_post); 337 attributes.add(new Attribute(tag, value)); 338 i = i_post[0]; 339 } 340 break; 341 case ULEB128: 342 { 343 final byte value = in[i++]; 344 attributes.add(new Attribute(tag, new Byte(value))); 345 } 346 break; 347 default: 348 throw new IllegalArgumentException("ShArmAttr: Invalid Attribute tag: "+tag); 349 } 350 } 351 } 352 offset_post[0] = offset + subSecLen; 353 } 354 } 355