ARM build attributes section parsing (#160)
authortyb0807 <sontuan.vu119@gmail.com>
Tue, 21 Nov 2017 05:00:08 +0000 (06:00 +0100)
committerEli Bendersky <eliben@users.noreply.github.com>
Tue, 21 Nov 2017 05:00:08 +0000 (21:00 -0800)
elftools/common/construct_utils.py
elftools/dwarf/structs.py
elftools/elf/descriptions.py
elftools/elf/elffile.py
elftools/elf/enums.py
elftools/elf/sections.py
elftools/elf/structs.py
scripts/readelf.py
test/test_arm_support.py

index 8ace30efd9eab4a4dd9f4c2e8ee87357499bbf15..36332497a306a79b084447bb6b98daddce910416 100644 (file)
@@ -6,7 +6,10 @@
 # Eli Bendersky (eliben@gmail.com)
 # This code is in the public domain
 #-------------------------------------------------------------------------------
-from ..construct import Subconstruct, ConstructError, ArrayError
+from ..construct import (
+    Subconstruct, ConstructError, ArrayError, Adapter, Field, RepeatUntil,
+    Rename
+    )
 
 
 class RepeatUntilExcluding(Subconstruct):
@@ -42,3 +45,47 @@ class RepeatUntilExcluding(Subconstruct):
         raise NotImplementedError('no building')
     def _sizeof(self, context):
         raise SizeofError("can't calculate size")
+
+
+def _LEB128_reader():
+    """ Read LEB128 variable-length data from the stream. The data is terminated
+        by a byte with 0 in its highest bit.
+    """
+    return RepeatUntil(
+                lambda obj, ctx: ord(obj) < 0x80,
+                Field(None, 1))
+
+
+class _ULEB128Adapter(Adapter):
+    """ An adapter for ULEB128, given a sequence of bytes in a sub-construct.
+    """
+    def _decode(self, obj, context):
+        value = 0
+        for b in reversed(obj):
+            value = (value << 7) + (ord(b) & 0x7F)
+        return value
+
+
+class _SLEB128Adapter(Adapter):
+    """ An adapter for SLEB128, given a sequence of bytes in a sub-construct.
+    """
+    def _decode(self, obj, context):
+        value = 0
+        for b in reversed(obj):
+            value = (value << 7) + (ord(b) & 0x7F)
+        if ord(obj[-1]) & 0x40:
+            # negative -> sign extend
+            value |= - (1 << (7 * len(obj)))
+        return value
+
+
+def ULEB128(name):
+    """ A construct creator for ULEB128 encoding.
+    """
+    return Rename(name, _ULEB128Adapter(_LEB128_reader()))
+
+
+def SLEB128(name):
+    """ A construct creator for SLEB128 encoding.
+    """
+    return Rename(name, _SLEB128Adapter(_LEB128_reader()))
index 9234cf82b809b5ab0e041b75a1626fa8dd9aa0d3..f3b6ef3b673fd0e47c26a64417c691d0c84bf293 100644 (file)
 from ..construct import (
     UBInt8, UBInt16, UBInt32, UBInt64, ULInt8, ULInt16, ULInt32, ULInt64,
     SBInt8, SBInt16, SBInt32, SBInt64, SLInt8, SLInt16, SLInt32, SLInt64,
-    Adapter, Struct, ConstructError, If, RepeatUntil, Field, Rename, Enum,
-    Array, PrefixedArray, CString, Embed, StaticField
+    Adapter, Struct, ConstructError, If, Enum, Array, PrefixedArray,
+    CString, Embed, StaticField
     )
-from ..common.construct_utils import RepeatUntilExcluding
-
+from ..common.construct_utils import RepeatUntilExcluding, ULEB128, SLEB128
 from .enums import *
 
 
@@ -148,8 +147,8 @@ class DWARFStructs(object):
         self.Dwarf_initial_length = _InitialLength
 
     def _create_leb128(self):
-        self.Dwarf_uleb128 = _ULEB128
-        self.Dwarf_sleb128 = _SLEB128
+        self.Dwarf_uleb128 = ULEB128
+        self.Dwarf_sleb128 = SLEB128
 
     def _create_cu_header(self):
         self.Dwarf_CU_header = Struct('Dwarf_CU_header',
@@ -303,47 +302,3 @@ class _InitialLengthAdapter(Adapter):
             else:
                 raise ConstructError("Failed decoding initial length for %X" % (
                     obj.first))
-
-
-def _LEB128_reader():
-    """ Read LEB128 variable-length data from the stream. The data is terminated
-        by a byte with 0 in its highest bit.
-    """
-    return RepeatUntil(
-                lambda obj, ctx: ord(obj) < 0x80,
-                Field(None, 1))
-
-
-class _ULEB128Adapter(Adapter):
-    """ An adapter for ULEB128, given a sequence of bytes in a sub-construct.
-    """
-    def _decode(self, obj, context):
-        value = 0
-        for b in reversed(obj):
-            value = (value << 7) + (ord(b) & 0x7F)
-        return value
-
-
-class _SLEB128Adapter(Adapter):
-    """ An adapter for SLEB128, given a sequence of bytes in a sub-construct.
-    """
-    def _decode(self, obj, context):
-        value = 0
-        for b in reversed(obj):
-            value = (value << 7) + (ord(b) & 0x7F)
-        if ord(obj[-1]) & 0x40:
-            # negative -> sign extend
-            value |= - (1 << (7 * len(obj)))
-        return value
-
-
-def _ULEB128(name):
-    """ A construct creator for ULEB128 encoding.
-    """
-    return Rename(name, _ULEB128Adapter(_LEB128_reader()))
-
-
-def _SLEB128(name):
-    """ A construct creator for SLEB128 encoding.
-    """
-    return Rename(name, _SLEB128Adapter(_LEB128_reader()))
index 7e394f2677678486090d30fd52eaa5772e6ad192..4d92730ce78bc7d84e5fc57355ff164cb60f82b3 100644 (file)
@@ -9,7 +9,8 @@
 from .enums import (
     ENUM_D_TAG, ENUM_E_VERSION, ENUM_P_TYPE, ENUM_SH_TYPE,
     ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64,
-    ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_MIPS)
+    ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_MIPS,
+    ENUM_ATTR_TAG_ARM)
 from .constants import P_FLAGS, SH_FLAGS, SUNW_SYMINFO_FLAGS, VER_FLAGS
 from ..common.py3compat import iteritems
 
@@ -17,27 +18,34 @@ from ..common.py3compat import iteritems
 def describe_ei_class(x):
     return _DESCR_EI_CLASS.get(x, _unknown)
 
+
 def describe_ei_data(x):
     return _DESCR_EI_DATA.get(x, _unknown)
 
+
 def describe_ei_version(x):
     s = '%d' % ENUM_E_VERSION[x]
     if x == 'EV_CURRENT':
         s += ' (current)'
     return s
 
+
 def describe_ei_osabi(x):
     return _DESCR_EI_OSABI.get(x, _unknown)
 
+
 def describe_e_type(x):
     return _DESCR_E_TYPE.get(x, _unknown)
 
+
 def describe_e_machine(x):
     return _DESCR_E_MACHINE.get(x, _unknown)
 
+
 def describe_e_version_numeric(x):
     return '0x%x' % ENUM_E_VERSION[x]
 
+
 def describe_p_type(x):
     if x in _DESCR_P_TYPE:
         return _DESCR_P_TYPE.get(x)
@@ -46,12 +54,14 @@ def describe_p_type(x):
     else:
         return _unknown
 
+
 def describe_p_flags(x):
     s = ''
     for flag in (P_FLAGS.PF_R, P_FLAGS.PF_W, P_FLAGS.PF_X):
         s += _DESCR_P_FLAGS[flag] if (x & flag) else ' '
     return s
 
+
 def describe_sh_type(x):
     if x in _DESCR_SH_TYPE:
         return _DESCR_SH_TYPE.get(x)
@@ -60,6 +70,7 @@ def describe_sh_type(x):
     else:
         return _unknown
 
+
 def describe_sh_flags(x):
     s = ''
     for flag in (
@@ -70,18 +81,23 @@ def describe_sh_flags(x):
         s += _DESCR_SH_FLAGS[flag] if (x & flag) else ''
     return s
 
+
 def describe_symbol_type(x):
     return _DESCR_ST_INFO_TYPE.get(x, _unknown)
 
+
 def describe_symbol_bind(x):
     return _DESCR_ST_INFO_BIND.get(x, _unknown)
 
+
 def describe_symbol_visibility(x):
     return _DESCR_ST_VISIBILITY.get(x, _unknown)
 
+
 def describe_symbol_shndx(x):
     return _DESCR_ST_SHNDX.get(x, '%3s' % x)
 
+
 def describe_reloc_type(x, elffile):
     arch = elffile.get_machine_arch()
     if arch == 'x86':
@@ -97,6 +113,7 @@ def describe_reloc_type(x, elffile):
     else:
         return 'unrecognized: %-7x' % (x & 0xFFFFFFFF)
 
+
 def describe_dyn_tag(x):
     return _DESCR_D_TAG.get(x, _unknown)
 
@@ -114,15 +131,18 @@ def describe_syminfo_flags(x):
         SUNW_SYMINFO_FLAGS.SYMINFO_FLG_INTERPOSE,
         SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DEFERRED) if x & flag)
 
+
 def describe_symbol_boundto(x):
     return _DESCR_SYMINFO_BOUNDTO.get(x, '%3s' % x)
 
+
 def describe_ver_flags(x):
     return ' | '.join(_DESCR_VER_FLAGS[flag] for flag in (
         VER_FLAGS.VER_FLG_WEAK,
         VER_FLAGS.VER_FLG_BASE,
         VER_FLAGS.VER_FLG_INFO) if x & flag)
 
+
 def describe_note(x):
     n_desc = x['n_desc']
     desc = ''
@@ -144,6 +164,34 @@ def describe_note(x):
                       _DESCR_NOTE_N_TYPE.get(x['n_type'], _unknown))
     return '%s (%s)%s' % (note_type, note_type_desc, desc)
 
+
+def describe_attr_tag_arm(tag, val, extra):
+    idx = ENUM_ATTR_TAG_ARM[tag] - 1
+    d_entry = _DESCR_ATTR_VAL_ARM[idx]
+
+    if d_entry is None:
+        if tag == 'TAG_COMPATIBILITY':
+            return (_DESCR_ATTR_TAG_ARM[tag]
+                    + 'flag = %d, vendor = %s' % (val, extra))
+
+        elif tag == 'TAG_ALSO_COMPATIBLE_WITH':
+            if val.tag == 'TAG_CPU_ARCH':
+                return _DESCR_ATTR_TAG_ARM[tag] + d_entry[val]
+
+            else:
+                return _DESCR_ATTR_TAG_ARM[tag] + '??? (%d)' % val.tag
+
+        elif tag == 'TAG_NODEFAULTS':
+            return _DESCR_ATTR_TAG_ARM[tag] + 'True'
+            
+        s = _DESCR_ATTR_TAG_ARM[tag]
+        s += '"%s"' % val if val else ''
+        return s
+
+    else:
+        return _DESCR_ATTR_TAG_ARM[tag] + d_entry[val]
+
+
 #-------------------------------------------------------------------------------
 _unknown = '<unknown>'
 
@@ -154,12 +202,14 @@ _DESCR_EI_CLASS = dict(
     ELFCLASS64='ELF64',
 )
 
+
 _DESCR_EI_DATA = dict(
     ELFDATANONE='none',
     ELFDATA2LSB="2's complement, little endian",
     ELFDATA2MSB="2's complement, big endian",
 )
 
+
 _DESCR_EI_OSABI = dict(
     ELFOSABI_SYSV='UNIX - System V',
     ELFOSABI_HPUX='UNIX - HP-UX',
@@ -184,6 +234,7 @@ _DESCR_EI_OSABI = dict(
     ELFOSABI_STANDALONE='Standalone App',
 )
 
+
 _DESCR_E_TYPE = dict(
     ET_NONE='NONE (None)',
     ET_REL='REL (Relocatable file)',
@@ -193,6 +244,7 @@ _DESCR_E_TYPE = dict(
     PROC_SPECIFIC='Processor Specific',
 )
 
+
 _DESCR_E_MACHINE = dict(
     EM_NONE='None',
     EM_M32='WE32100',
@@ -213,6 +265,7 @@ _DESCR_E_MACHINE = dict(
     RESERVED='RESERVED',
 )
 
+
 _DESCR_P_TYPE = dict(
     PT_NULL='NULL',
     PT_LOAD='LOAD',
@@ -230,12 +283,14 @@ _DESCR_P_TYPE = dict(
     PT_AARCH64_UNWIND='AARCH64_UNWIND',
 )
 
+
 _DESCR_P_FLAGS = {
     P_FLAGS.PF_X: 'E',
     P_FLAGS.PF_R: 'R',
     P_FLAGS.PF_W: 'W',
 }
 
+
 _DESCR_SH_TYPE = dict(
     SHT_NULL='NULL',
     SHT_PROGBITS='PROGBITS',
@@ -301,6 +356,7 @@ _DESCR_SH_TYPE = dict(
     SHT_MIPS_PDR_EXCEPTION='MIPS_PDR_EXCEPTION',
 )
 
+
 _DESCR_SH_FLAGS = {
     SH_FLAGS.SHF_WRITE: 'W',
     SH_FLAGS.SHF_ALLOC: 'A',
@@ -315,6 +371,7 @@ _DESCR_SH_FLAGS = {
     SH_FLAGS.SHF_EXCLUDE: 'E',
 }
 
+
 _DESCR_ST_INFO_TYPE = dict(
     STT_NOTYPE='NOTYPE',
     STT_OBJECT='OBJECT',
@@ -328,12 +385,14 @@ _DESCR_ST_INFO_TYPE = dict(
     STT_SRELC='SRELC',
 )
 
+
 _DESCR_ST_INFO_BIND = dict(
     STB_LOCAL='LOCAL',
     STB_GLOBAL='GLOBAL',
     STB_WEAK='WEAK',
 )
 
+
 _DESCR_ST_VISIBILITY = dict(
     STV_DEFAULT='DEFAULT',
     STV_INTERNAL='INTERNAL',
@@ -344,12 +403,14 @@ _DESCR_ST_VISIBILITY = dict(
     STV_ELIMINATE='ELIMINATE',
 )
 
+
 _DESCR_ST_SHNDX = dict(
     SHN_UNDEF='UND',
     SHN_ABS='ABS',
     SHN_COMMON='COM',
 )
 
+
 _DESCR_SYMINFO_FLAGS = {
     SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECT: 'D',
     SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECTBIND: 'B',
@@ -363,6 +424,7 @@ _DESCR_SYMINFO_FLAGS = {
     SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DEFERRED: 'P',
 }
 
+
 _DESCR_SYMINFO_BOUNDTO = dict(
     SYMINFO_BT_SELF='<self>',
     SYMINFO_BT_PARENT='<parent>',
@@ -370,6 +432,7 @@ _DESCR_SYMINFO_BOUNDTO = dict(
     SYMINFO_BT_EXTERN='<extern>',
 )
 
+
 _DESCR_VER_FLAGS = {
     0: '',
     VER_FLAGS.VER_FLG_BASE: 'BASE',
@@ -377,6 +440,7 @@ _DESCR_VER_FLAGS = {
     VER_FLAGS.VER_FLG_INFO: 'INFO',
 }
 
+
 # PT_NOTE section types
 _DESCR_NOTE_N_TYPE = dict(
     NT_GNU_ABI_TAG='ABI version tag',
@@ -385,6 +449,7 @@ _DESCR_NOTE_N_TYPE = dict(
     NT_GNU_GOLD_VERSION='gold version',
 )
 
+
 # Values in GNU .note.ABI-tag notes (n_type=='NT_GNU_ABI_TAG')
 _DESCR_NOTE_ABI_TAG_OS = dict(
     ELF_NOTE_OS_LINUX='Linux',
@@ -395,20 +460,327 @@ _DESCR_NOTE_ABI_TAG_OS = dict(
     ELF_NOTE_OS_SYLLABLE='Syllable',
 )
 
+
 _DESCR_RELOC_TYPE_i386 = dict(
         (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_i386))
 
+
 _DESCR_RELOC_TYPE_x64 = dict(
         (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_x64))
 
+
 _DESCR_RELOC_TYPE_ARM = dict(
         (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_ARM))
 
+
 _DESCR_RELOC_TYPE_AARCH64 = dict(
         (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_AARCH64))
 
+
 _DESCR_RELOC_TYPE_MIPS = dict(
         (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_MIPS))
 
+
 _DESCR_D_TAG = dict(
         (v, k) for k, v in iteritems(ENUM_D_TAG))
+
+
+_DESCR_ATTR_TAG_ARM = dict(
+    TAG_FILE='File Attributes',
+    TAG_SECTION='Section Attributes:',
+    TAG_SYMBOL='Symbol Attributes:',
+    TAG_CPU_RAW_NAME='Tag_CPU_raw_name: ',
+    TAG_CPU_NAME='Tag_CPU_name: ',
+    TAG_CPU_ARCH='Tag_CPU_arch: ',
+    TAG_CPU_ARCH_PROFILE='Tag_CPU_arch_profile: ',
+    TAG_ARM_ISA_USE='Tag_ARM_ISA_use: ',
+    TAG_THUMB_ISA_USE='Tag_Thumb_ISA_use: ',
+    TAG_FP_ARCH='Tag_FP_arch: ',
+    TAG_WMMX_ARCH='Tag_WMMX_arch: ',
+    TAG_ADVANCED_SIMD_ARCH='Tag_Advanced_SIMD_arch: ',
+    TAG_PCS_CONFIG='Tag_PCS_config: ',
+    TAG_ABI_PCS_R9_USE='Tag_ABI_PCS_R9_use: ',
+    TAG_ABI_PCS_RW_DATA='Tag_ABI_PCS_RW_use: ',
+    TAG_ABI_PCS_RO_DATA='Tag_ABI_PCS_RO_use: ',
+    TAG_ABI_PCS_GOT_USE='Tag_ABI_PCS_GOT_use: ',
+    TAG_ABI_PCS_WCHAR_T='Tag_ABI_PCS_wchar_t: ',
+    TAG_ABI_FP_ROUNDING='Tag_ABI_FP_rounding: ',
+    TAG_ABI_FP_DENORMAL='Tag_ABI_FP_denormal: ',
+    TAG_ABI_FP_EXCEPTIONS='Tag_ABI_FP_exceptions: ',
+    TAG_ABI_FP_USER_EXCEPTIONS='Tag_ABI_FP_user_exceptions: ',
+    TAG_ABI_FP_NUMBER_MODEL='Tag_ABI_FP_number_model: ',
+    TAG_ABI_ALIGN_NEEDED='Tag_ABI_align_needed: ',
+    TAG_ABI_ALIGN_PRESERVED='Tag_ABI_align_preserved: ',
+    TAG_ABI_ENUM_SIZE='Tag_ABI_enum_size: ',
+    TAG_ABI_HARDFP_USE='Tag_ABI_HardFP_use: ',
+    TAG_ABI_VFP_ARGS='Tag_ABI_VFP_args: ',
+    TAG_ABI_WMMX_ARGS='Tag_ABI_WMMX_args: ',
+    TAG_ABI_OPTIMIZATION_GOALS='Tag_ABI_optimization_goals: ',
+    TAG_ABI_FP_OPTIMIZATION_GOALS='Tag_ABI_FP_optimization_goals: ',
+    TAG_COMPATIBILITY='Tag_compatibility: ',
+    TAG_CPU_UNALIGNED_ACCESS='Tag_CPU_unaligned_access: ',
+    TAG_FP_HP_EXTENSION='Tag_FP_HP_extension: ',
+    TAG_ABI_FP_16BIT_FORMAT='Tag_ABI_FP_16bit_format: ',
+    TAG_MPEXTENSION_USE='Tag_MPextension_use: ',
+    TAG_DIV_USE='Tag_DIV_use: ',
+    TAG_NODEFAULTS='Tag_nodefaults: ',
+    TAG_ALSO_COMPATIBLE_WITH='Tag_also_compatible_with: ',
+    TAG_T2EE_USE='Tag_T2EE_use: ',
+    TAG_CONFORMANCE='Tag_conformance: ',
+    TAG_VIRTUALIZATION_USE='Tag_Virtualization_use: ',
+    TAG_MPEXTENSION_USE_OLD='Tag_MPextension_use_old: ',
+)
+
+
+_DESCR_ATTR_VAL_ARM = [
+    None, #1
+    None, #2
+    None, #3
+    None, #4
+    None, #5
+    { #6 TAG_CPU_ARCH
+        0 : 'Pre-v4',
+        1 : 'v4',
+        2 : 'v4T',
+        3 : 'v5T',
+        4 : 'v5TE',
+        5 : 'v5TEJ',
+        6 : 'v6',
+        7 : 'v6KZ',
+        8 : 'v6T2',
+        9 : 'v6K',
+        10: 'v7',
+        11: 'v6-M',
+        12: 'v6S-M',
+        13: 'v7E-M',
+        14: 'v8',
+        15: 'v8-R',
+        16: 'v8-M.baseline',
+        17: 'v8-M.mainline',
+    },
+    { #7 TAG_CPU_ARCH_PROFILE
+        0x00: 'None',
+        0x41: 'Application',
+        0x52: 'Realtime',
+        0x4D: 'Microcontroller',
+        0x53: 'Application or Realtime',
+    },
+    { #8 TAG_ARM_ISA
+        0: 'No',
+        1: 'Yes',
+    },
+    { #9 TAG_THUMB_ISA
+        0: 'No',
+        1: 'Thumb-1',
+        2: 'Thumb-2',
+        3: 'Yes',
+    },
+    { #10 TAG_FP_ARCH
+        0: 'No',
+        1: 'VFPv1',
+        2: 'VFPv2 ',
+        3: 'VFPv3',
+        4: 'VFPv3-D16',
+        5: 'VFPv4',
+        6: 'VFPv4-D16',
+        7: 'FP ARM v8',
+        8: 'FPv5/FP-D16 for ARMv8',
+    },
+    { #11 TAG_WMMX_ARCH
+        0: 'No',
+        1: 'WMMXv1',
+        2: 'WMMXv2',
+    },
+    { #12 TAG_ADVANCED_SIMD_ARCH
+        0: 'No',
+        1: 'NEONv1',
+        2: 'NEONv1 with Fused-MAC',
+        3: 'NEON for ARMv8',
+        4: 'NEON for ARMv8.1',
+    },
+    { #13 TAG_PCS_CONFIG
+        0: 'None',
+        1: 'Bare platform',
+        2: 'Linux application',
+        3: 'Linux DSO',
+        4: 'PalmOS 2004',
+        5: 'PalmOS (reserved)',
+        6: 'SymbianOS 2004',
+        7: 'SymbianOS (reserved)',
+    },
+    { #14 TAG_ABI_PCS_R9_USE
+        0: 'v6',
+        1: 'SB',
+        2: 'TLS',
+        3: 'Unused',
+    },
+    { #15 TAG_ABI_PCS_RW_DATA
+        0: 'Absolute',
+        1: 'PC-relative',
+        2: 'SB-relative',
+        3: 'None',
+    },
+    { #16 TAG_ABI_PCS_RO_DATA
+        0: 'Absolute',
+        1: 'PC-relative',
+        2: 'None',
+    },
+    { #17 TAG_ABI_PCS_GOT_USE
+        0: 'None',
+        1: 'direct',
+        2: 'GOT-indirect',
+    },
+    { #18 TAG_ABI_PCS_WCHAR_T
+        0: 'None',
+        1: '??? 1',
+        2: '2',
+        3: '??? 3',
+        4: '4',
+    },
+    { #19 TAG_ABI_FP_ROUNDING
+        0: 'Unused',
+        1: 'Needed',
+    },
+    { #20 TAG_ABI_FP_DENORMAL
+        0: 'Unused',
+        1: 'Needed',
+        2: 'Sign only',
+    },
+    { #21 TAG_ABI_FP_EXCEPTIONS
+        0: 'Unused',
+        1: 'Needed',
+    },
+    { #22 TAG_ABI_FP_USER_EXCEPTIONS
+        0: 'Unused',
+        1: 'Needed',
+    },
+    { #23 TAG_ABI_FP_NUMBER_MODEL
+        0: 'Unused',
+        1: 'Finite',
+        2: 'RTABI',
+        3: 'IEEE 754',
+    },
+    { #24 TAG_ABI_ALIGN_NEEDED
+        0: 'None',
+        1: '8-byte',
+        2: '4-byte',
+        3: '??? 3',
+    },
+    { #25 TAG_ABI_ALIGN_PRESERVED
+        0: 'None',
+        1: '8-byte, except leaf SP',
+        2: '8-byte',
+        3: '??? 3',
+    },
+    { #26 TAG_ABI_ENUM_SIZE
+        0: 'Unused',
+        1: 'small',
+        2: 'int',
+        3: 'forced to int',
+    },
+    { #27 TAG_ABI_HARDFP_USE
+        0: 'As Tag_FP_arch',
+        1: 'SP only',
+        2: 'Reserved',
+        3: 'Deprecated',
+    },
+    { #28 TAG_ABI_VFP_ARGS
+        0: 'AAPCS',
+        1: 'VFP registers',
+        2: 'custom',
+        3: 'compatible',
+    },
+    { #29 TAG_ABI_WMMX_ARGS
+        0: 'AAPCS',
+        1: 'WMMX registers',
+        2: 'custom',
+    },
+    { #30 TAG_ABI_OPTIMIZATION_GOALS
+        0: 'None',
+        1: 'Prefer Speed',
+        2: 'Aggressive Speed',
+        3: 'Prefer Size',
+        4: 'Aggressive Size',
+        5: 'Prefer Debug',
+        6: 'Aggressive Debug',
+    },
+    { #31 TAG_ABI_FP_OPTIMIZATION_GOALS
+        0: 'None',
+        1: 'Prefer Speed',
+        2: 'Aggressive Speed',
+        3: 'Prefer Size',
+        4: 'Aggressive Size',
+        5: 'Prefer Accuracy',
+        6: 'Aggressive Accuracy',
+    },
+    { #32 TAG_COMPATIBILITY
+        0: 'No',
+        1: 'Yes',
+    },
+    None, #33
+    { #34 TAG_CPU_UNALIGNED_ACCESS
+        0: 'None',
+        1: 'v6',
+    },
+    None, #35
+    { #36 TAG_FP_HP_EXTENSION
+        0: 'Not Allowed',
+        1: 'Allowed',
+    },
+    None, #37
+    { #38 TAG_ABI_FP_16BIT_FORMAT
+        0: 'None',
+        1: 'IEEE 754',
+        2: 'Alternative Format',
+    },
+    None, #39
+    None, #40
+    None, #41
+    { #42 TAG_MPEXTENSION_USE
+        0: 'Not Allowed',
+        1: 'Allowed',
+    },
+    None, #43
+    { #44 TAG_DIV_USE
+        0: 'Allowed in Thumb-ISA, v7-R or v7-M',
+        1: 'Not allowed',
+        2: 'Allowed in v7-A with integer division extension',
+    },
+    None, #45
+    None, #46
+    None, #47
+    None, #48
+    None, #49
+    None, #50
+    None, #51
+    None, #52
+    None, #53
+    None, #54
+    None, #55
+    None, #56
+    None, #57
+    None, #58
+    None, #59
+    None, #60
+    None, #61
+    None, #62
+    None, #63
+    None, #64
+    None, #65
+    { #66 TAG_FP_HP_EXTENSION
+        0: 'Not Allowed',
+        1: 'Allowed',
+    },
+    None, #67
+    { #68 TAG_VIRTUALIZATION_USE
+        0: 'Not Allowed',
+        1: 'TrustZone',
+        2: 'Virtualization Extensions',
+        3: 'TrustZone and Virtualization Extensions',
+    },
+    None, #69
+    { #70 TAG_MPEXTENSION_USE_OLD
+        0: 'Not Allowed',
+        1: 'Allowed',
+    },
+]
index 584e016b3384d5e590949c37af1bc49224b0f76c..815e941ab7f56806668eb28ff4363c822433fb63 100644 (file)
@@ -25,7 +25,7 @@ from .structs import ELFStructs
 from .sections import (
         Section, StringTableSection, SymbolTableSection,
         SUNWSyminfoTableSection, NullSection, NoteSection,
-        StabSection)
+        StabSection, ARMAttributesSection)
 from .dynamic import DynamicSection, DynamicSegment
 from .relocation import RelocationSection, RelocationHandler
 from .gnuversions import (
@@ -324,6 +324,8 @@ class ELFFile(object):
             return NoteSection(section_header, name, self)
         elif sectype == 'SHT_PROGBITS' and name == '.stab':
             return StabSection(section_header, name, self)
+        elif sectype == 'SHT_ARM_ATTRIBUTES':
+            return ARMAttributesSection(section_header, name, self)
         else:
             return Section(section_header, name, self)
 
index 81798acdd4719dbb400a7391be193f7cfd2ff062..dede76241c498f2c34b4a593ff8ba9b7fce3f2dc 100644 (file)
@@ -700,6 +700,7 @@ ENUM_VERSYM = dict(
     VER_NDX_ELIMINATE=0xff01,
     _default_=Pass,
 )
+
 # Sunw Syminfo Bound To special values
 ENUM_SUNW_SYMINFO_BOUNDTO = dict(
     SYMINFO_BT_SELF=0xffff,
@@ -983,3 +984,49 @@ ENUM_RELOC_TYPE_AARCH64 = dict(
     R_AARCH64_TLS_DTPMOD32=1032,
     R_AARCH64_TLS_TPREL32=1033,
 )
+
+ENUM_ATTR_TAG_ARM = dict(
+    TAG_FILE=1,
+    TAG_SECTION=2,
+    TAG_SYMBOL=3,
+    TAG_CPU_RAW_NAME=4,
+    TAG_CPU_NAME=5,
+    TAG_CPU_ARCH=6,
+    TAG_CPU_ARCH_PROFILE=7,
+    TAG_ARM_ISA_USE=8,
+    TAG_THUMB_ISA_USE=9,
+    TAG_FP_ARCH=10,
+    TAG_WMMX_ARCH=11,
+    TAG_ADVANCED_SIMD_ARCH=12,
+    TAG_PCS_CONFIG=13,
+    TAG_ABI_PCS_R9_USE=14,
+    TAG_ABI_PCS_RW_DATA=15,
+    TAG_ABI_PCS_RO_DATA=16,
+    TAG_ABI_PCS_GOT_USE=17,
+    TAG_ABI_PCS_WCHAR_T=18,
+    TAG_ABI_FP_ROUNDING=19,
+    TAG_ABI_FP_DENORMAL=20,
+    TAG_ABI_FP_EXCEPTIONS=21,
+    TAG_ABI_FP_USER_EXCEPTIONS=22,
+    TAG_ABI_FP_NUMBER_MODEL=23,
+    TAG_ABI_ALIGN_NEEDED=24,
+    TAG_ABI_ALIGN_PRESERVED=25,
+    TAG_ABI_ENUM_SIZE=26,
+    TAG_ABI_HARDFP_USE=27,
+    TAG_ABI_VFP_ARGS=28,
+    TAG_ABI_WMMX_ARGS=29,
+    TAG_ABI_OPTIMIZATION_GOALS=30,
+    TAG_ABI_FP_OPTIMIZATION_GOALS=31,
+    TAG_COMPATIBILITY=32,
+    TAG_CPU_UNALIGNED_ACCESS=34,
+    TAG_FP_HP_EXTENSION=36,
+    TAG_ABI_FP_16BIT_FORMAT=38,
+    TAG_MPEXTENSION_USE=42,
+    TAG_DIV_USE=44,
+    TAG_NODEFAULTS=64,
+    TAG_ALSO_COMPATIBLE_WITH=65,
+    TAG_T2EE_USE=66,
+    TAG_CONFORMANCE=67,
+    TAG_VIRTUALIZATION_USE=68,
+    TAG_MPEXTENSION_USE_OLD=70,
+)
index eb4d40a3a587b3b879bbc2b32bd11f11b6de8f56..c2d92208d87980984743b87163844473af49b4fb 100644 (file)
@@ -11,6 +11,7 @@ from ..common.utils import struct_parse, elf_assert, parse_cstring_from_stream
 from collections import defaultdict
 from .constants import SH_FLAGS
 from .notes import iter_notes
+
 import zlib
 
 
@@ -253,6 +254,7 @@ class NoteSection(Section):
         """
         return iter_notes(self.elffile, self['sh_offset'], self['sh_size'])
 
+
 class StabSection(Section):
     """ ELF stab section.
     """
@@ -272,3 +274,212 @@ class StabSection(Section):
             self.stream.seek(offset)
             yield stabs
 
+
+class ARMAttribute(object):
+    """ ARM attribute object - representing a build attribute of ARM ELF files.
+    """
+    def __init__(self, structs, stream):
+        self._tag = struct_parse(structs.Elf_Attribute_Tag, stream)
+        self.extra = None
+
+        if self.tag in ('TAG_FILE', 'TAG_SECTION', 'TAG_SYMBOL'):
+            self.value = struct_parse(structs.Elf_word('value'), stream)
+
+            if self.tag != 'TAG_FILE':
+                self.extra = []
+                s_number = struct_parse(self.structs.Elf_uleb128('s_number'),
+                                        self.stream
+                           )
+
+                while s_number != 0:
+                    self.extra.append(s_number)
+                    s_number = struct_parse(self.structs.Elf_uleb128('s_number'),
+                                            self.stream
+                               )
+
+        elif self.tag in ('TAG_CPU_RAW_NAME', 'TAG_CPU_NAME', 'TAG_CONFORMANCE'):
+            self.value = struct_parse(structs.Elf_ntbs('value',
+                                                       encoding='ascii'),
+                                      stream)
+
+        elif self.tag == 'TAG_COMPATIBILITY':
+            self.value = struct_parse(structs.Elf_uleb128('value'), stream)
+            self.extra = struct_parse(structs.Elf_ntbs('vendor_name',
+                                                       encoding='ascii'),
+                                      stream)
+
+        elif self.tag == 'TAG_ALSO_COMPATIBLE_WITH':
+            self.value = ARMAttribute(structs, stream)
+
+            if type(self.value.value) is not str:
+                nul = struct_parse(structs.Elf_byte('nul'), stream)
+                elf_assert(null_byte == 0, 
+                           "Invalid terminating byte %r, expecting NUL." % nul)
+
+        else:
+            self.value = struct_parse(structs.Elf_uleb128('value'), stream)
+
+    @property
+    def tag(self):
+        return self._tag['tag']
+
+    def __repr__(self):
+        s = '<ARMAttribute (%s): %r>' % (self.tag, self.value) 
+        s += ' %s' % self.extra if self.extra is not None else ''
+        return s
+
+
+class ARMAttributesSubsubsection(object):
+    """ Subsubsection of an ELF .ARM.attributes section's subsection.
+    """
+    def __init__(self, stream, structs, offset):
+        self.stream = stream
+        self.offset = offset
+        self.structs = structs
+
+        self.header = ARMAttribute(self.structs, self.stream)
+
+        self.attr_start = self.stream.tell()
+
+    def iter_attributes(self, tag=None):
+        """ Yield all attributes (limit to |tag| if specified).
+        """
+        for attribute in self._make_attributes():
+            if tag is None or attribute.tag == tag:
+                yield attribute
+
+    @property
+    def num_attributes(self):
+        """ Number of attributes in the subsubsection.
+        """
+        return sum(1 for _ in self.iter_attributes()) + 1
+
+    @property
+    def attributes(self):
+        """ List of all attributes in the subsubsection.
+        """
+        return [self.header] + list(self.iter_attributes())
+
+    def _make_attributes(self):
+        """ Create all attributes for this subsubsection except the first one
+            which is the header.
+        """
+        end = self.offset + self.header.value
+
+        self.stream.seek(self.attr_start)
+
+        while self.stream.tell() != end:
+            yield ARMAttribute(self.structs, self.stream)
+
+    def __repr__(self):
+        s = "<ARMAttributesSubsubsection (%s): %d bytes>" 
+        return s % (self.header.tag[4:], self.header.value)
+
+
+class ARMAttributesSubsection(object):
+    """ Subsection of an ELF .ARM.attributes section.
+    """
+    def __init__(self, stream, structs, offset):
+        self.stream = stream
+        self.offset = offset
+        self.structs = structs
+
+        self.header = struct_parse(self.structs.Elf_Attr_Subsection_Header,
+                                   self.stream,
+                                   self.offset
+                      )
+
+        self.subsubsec_start = self.stream.tell()
+
+    def iter_subsubsections(self, scope=None):
+        """ Yield all subsubsections (limit to |scope| if specified).
+        """
+        for subsubsec in self._make_subsubsections():
+            if scope is None or subsubsec.header.tag == scope:
+                yield subsubsec
+
+    @property
+    def num_subsubsections(self):
+        """ Number of subsubsections in the subsection.
+        """
+        return sum(1 for _ in self.iter_subsubsections())
+
+    @property
+    def subsubsections(self):
+        """ List of all subsubsections in the subsection.
+        """
+        return list(self.iter_subsubsections())
+
+    def _make_subsubsections(self):
+        """ Create all subsubsections for this subsection.
+        """
+        end = self.offset + self['length']
+
+        self.stream.seek(self.subsubsec_start)
+
+        while self.stream.tell() != end:
+            subsubsec = ARMAttributesSubsubsection(self.stream,
+                                                   self.structs,
+                                                   self.stream.tell())
+            self.stream.seek(self.subsubsec_start + subsubsec.header.value)
+            yield subsubsec
+
+    def __getitem__(self, name):
+        """ Implement dict-like access to header entries.
+        """
+        return self.header[name]
+
+    def __repr__(self):
+        s = "<ARMAttributesSubsection (%s): %d bytes>"
+        return s  % (self.header['vendor_name'], self.header['length'])
+
+
+class ARMAttributesSection(Section):
+    """ ELF .ARM.attributes section.
+    """
+    def __init__(self, header, name, elffile):
+        super(ARMAttributesSection, self).__init__(header, name, elffile)
+
+        fv = struct_parse(self.structs.Elf_byte('format_version'),
+                          self.stream,
+                          self['sh_offset']
+             )
+
+        elf_assert(chr(fv) == 'A',
+                   "Unknown attributes version %s, expecting 'A'." % chr(fv)
+        )
+
+        self.subsec_start = self.stream.tell()
+
+    def iter_subsections(self, vendor_name=None):
+        """ Yield all subsections (limit to |vendor_name| if specified).
+        """
+        for subsec in self._make_subsections():
+            if vendor_name is None or subsec['vendor_name'] == vendor_name:
+                yield subsec
+
+    @property
+    def num_subsections(self):
+        """ Number of subsections in the section.
+        """
+        return sum(1 for _ in self.iter_subsections())
+
+    @property
+    def subsections(self):
+        """ List of all subsections in the section.
+        """
+        return list(self.iter_subsections())
+
+    def _make_subsections(self):
+        """ Create all subsections for this section.
+        """
+        end = self['sh_offset'] + self.data_size
+
+        self.stream.seek(self.subsec_start)
+
+        while self.stream.tell() != end:
+            subsec = ARMAttributesSubsection(self.stream,
+                                             self.structs,
+                                             self.stream.tell())
+            self.stream.seek(self.subsec_start + subsec['length'])
+            yield subsec
index 8cc87d2d07d6954b7ecd45dfe462057e2a406f8a..4fb665ed60fa38a5e2c698dd063120657a7bb333 100644 (file)
@@ -11,9 +11,9 @@ from ..construct import (
     UBInt8, UBInt16, UBInt32, UBInt64,
     ULInt8, ULInt16, ULInt32, ULInt64,
     SBInt32, SLInt32, SBInt64, SLInt64,
-    Struct, Array, Enum, Padding, BitStruct, BitField, Value, String, CString,
+    Struct, Array, Enum, Padding, BitStruct, BitField, Value, String, CString
     )
-
+from ..common.construct_utils import ULEB128
 from .enums import *
 
 
@@ -69,6 +69,8 @@ class ELFStructs(object):
             self.Elf_xword = UBInt32 if self.elfclass == 32 else UBInt64
             self.Elf_sxword = SBInt32 if self.elfclass == 32 else SBInt64
         self._create_ehdr()
+        self._create_leb128()
+        self._create_ntbs()
 
     def create_advanced_structs(self, elftype=None):
         """ Create all ELF structs except the ehdr. They may possibly depend
@@ -87,6 +89,7 @@ class ELFStructs(object):
         self._create_gnu_abi()
         self._create_note(elftype)
         self._create_stabs()
+        self._create_arm_attributes()
 
     #-------------------------------- PRIVATE --------------------------------#
 
@@ -116,6 +119,12 @@ class ELFStructs(object):
             self.Elf_half('e_shstrndx'),
         )
 
+    def _create_leb128(self):
+        self.Elf_uleb128 = ULEB128
+
+    def _create_ntbs(self):
+        self.Elf_ntbs = CString
+
     def _create_phdr(self):
         if self.elfclass == 32:
             self.Elf_Phdr = Struct('Elf_Phdr',
@@ -347,3 +356,19 @@ class ELFStructs(object):
             self.Elf_half('n_desc'),
             self.Elf_word('n_value'),
         )
+
+    def _create_arm_attributes(self):
+        # Structure of a build attributes subsection header. A subsection is
+        # either public to all tools that process the ELF file or private to
+        # the vendor's tools.
+        self.Elf_Attr_Subsection_Header = Struct('Elf_Attr_Subsection',
+                                                 self.Elf_word('length'),
+                                                 self.Elf_ntbs('vendor_name',
+                                                               encoding='ascii')
+        )
+
+        # Structure of a build attribute tag.
+        self.Elf_Attribute_Tag = Struct('Elf_Attribute_Tag',
+                                        Enum(self.Elf_uleb128('tag'),
+                                             **ENUM_ATTR_TAG_ARM)
+        )
index 915d93bf6a1b2e719e85e8b7ef47736bf932329e..a09ba7dd2c504da8af5769d22f8e2e74211acbe6 100755 (executable)
@@ -37,7 +37,7 @@ from elftools.elf.descriptions import (
     describe_sh_type, describe_sh_flags,
     describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
     describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
-    describe_ver_flags, describe_note
+    describe_ver_flags, describe_note, describe_attr_tag_arm
     )
 from elftools.elf.constants import E_FLAGS
 from elftools.dwarf.dwarfinfo import DWARFInfo
@@ -589,6 +589,12 @@ class ReadElf(object):
 
                     offset += verneed['vn_next']
 
+    def display_arch_specific(self):
+        """ Display the architecture-specific info contained in the file.
+        """
+        if self.elffile['e_machine'] == 'EM_ARM':
+            self._display_arch_specific_arm()
+
     def display_hex_dump(self, section_spec):
         """ Display a hex dump of a section. section_spec is either a section
             number or a name.
@@ -1192,6 +1198,23 @@ class ReadElf(object):
                     self._dwarfinfo.debug_frame_sec,
                     self._dwarfinfo.CFI_entries())
 
+    def _display_arch_specific_arm(self):
+        """ Display the ARM architecture-specific info contained in the file.
+        """
+        attr_sec = self.elffile.get_section_by_name('.ARM.attributes')
+
+        for s in attr_sec.iter_subsections():
+            self._emitline("Attribute Section: %s" % s.header['vendor_name'])
+            for ss in s.iter_subsubsections():
+                h_val = "" if ss.header.extra is None else " ".join("%d" % x for x in ss.header.extra)
+                self._emitline(describe_attr_tag_arm(ss.header.tag, h_val, None))
+
+                for attr in ss.iter_attributes():
+                    self._emit('  ')
+                    self._emitline(describe_attr_tag_arm(attr.tag,
+                                                         attr.value,
+                                                         attr.extra))
+
     def _emit(self, s=''):
         """ Emit an object to output
         """
@@ -1251,6 +1274,9 @@ def main(stream=None):
     optparser.add_option('-V', '--version-info',
             action='store_true', dest='show_version_info',
             help='Display the version sections (if present)')
+    optparser.add_option('-A', '--arch-specific',
+            action='store_true', dest='show_arch_specific',
+            help='Display the architecture-specific information (if present)')
     optparser.add_option('--debug-dump',
             action='store', dest='debug_dump_what', metavar='<what>',
             help=(
@@ -1291,6 +1317,8 @@ def main(stream=None):
                 readelf.display_relocations()
             if options.show_version_info:
                 readelf.display_version_info()
+            if options.show_arch_specific:
+                readelf.display_arch_specific()
             if options.show_hex_dump:
                 readelf.display_hex_dump(options.show_hex_dump)
             if options.show_string_dump:
index 87b18054de24608789a07bf012b65cd8bcfbc292..6b94f7c278d662dfec202f94449ec979ea1612e9 100644 (file)
@@ -22,6 +22,28 @@ class TestARMSupport(unittest.TestCase):
             self.assertEqual(elf.num_sections(), 14)
             self.assertEqual(elf.num_segments(), 2)
 
+    def test_build_attributes(self):
+        with open(os.path.join('test', 'testfiles_for_unittests',
+                               'simple_gcc.elf.arm'), 'rb') as f:
+            elf = ELFFile(f)
+
+            sec = elf.get_section_by_name('.ARM.attributes')
+            self.assertEqual(sec['sh_type'], 'SHT_ARM_ATTRIBUTES')
+            self.assertEqual(sec.num_subsections, 1)
+
+            subsec = sec.subsections[0]
+            self.assertEqual(subsec.header['vendor_name'], 'aeabi')
+            self.assertEqual(subsec.num_subsubsections, 1)
+
+            subsubsec = subsec.subsubsections[0]
+            self.assertEqual(subsubsec.header.tag, 'TAG_FILE')
+
+            for i in subsubsec.iter_attributes('TAG_CPU_NAME'):
+                self.assertEqual(i.value, 'ARM7TDMI-S')
+
+            for i in subsubsec.iter_attributes('TAG_CPU_ARCH'):
+                self.assertEqual(i.value, 2)
+
     def test_DWARF_indirect_forms(self):
         # This file uses a lot of DW_FORM_indirect, and is also an ARM ELF
         # with non-trivial DWARF info.