Choose members of the dynamic tag enum based on the current machine (#183)
authorAudrey Dutcher <audrey@rhelmot.io>
Fri, 23 Feb 2018 13:30:52 +0000 (05:30 -0800)
committerEli Bendersky <eliben@users.noreply.github.com>
Fri, 23 Feb 2018 13:30:52 +0000 (05:30 -0800)
* Only use processor/os specific dynamic tags if that processor or os is in use

* Add testcase for machine-specific dynamic tags

* Clarify layout of ENUM_D_TAG

elftools/elf/elffile.py
elftools/elf/enums.py
elftools/elf/structs.py
test/test_dynamic.py
test/testfiles_for_unittests/android_dyntags.elf [new file with mode: 0644]

index a1509eeff5a944aa9787cdb31d2b6bfdf9f6dcce..289a5f9739336a0260ccc7dd77cf35f5352deace 100644 (file)
@@ -71,7 +71,10 @@ class ELFFile(object):
 
         self.structs.create_basic_structs()
         self.header = self._parse_elf_header()
-        self.structs.create_advanced_structs(self['e_type'], self['e_machine'])
+        self.structs.create_advanced_structs(
+                self['e_type'],
+                self['e_machine'],
+                self['e_ident']['EI_OSABI'])
         self.stream.seek(0)
         self.e_ident_raw = self.stream.read(16)
 
index 48ef99aee0f905baf1e0d1f6d87061c5864aa7f5..e37effa9a2c4caf24625edc699dac90d1e50babc 100644 (file)
@@ -468,7 +468,7 @@ ENUM_ST_SHNDX = dict(
 )
 
 # d_tag
-ENUM_D_TAG = dict(
+ENUM_D_TAG_COMMON = dict(
     DT_NULL=0,
     DT_NEEDED=1,
     DT_PLTRELSZ=2,
@@ -505,24 +505,6 @@ ENUM_D_TAG = dict(
     DT_PREINIT_ARRAYSZ=33,
     DT_NUM=34,
     DT_LOOS=0x6000000d,
-    DT_SUNW_AUXILIARY=0x6000000d,
-    DT_SUNW_RTLDINF=0x6000000e,
-    DT_SUNW_FILTER=0x6000000f,
-    DT_SUNW_CAP=0x60000010,
-    DT_SUNW_SYMTAB=0x60000011,
-    DT_SUNW_SYMSZ=0x60000012,
-    DT_SUNW_ENCODING=0x60000013,
-    DT_SUNW_SORTENT=0x60000013,
-    DT_SUNW_SYMSORT=0x60000014,
-    DT_SUNW_SYMSORTSZ=0x60000015,
-    DT_SUNW_TLSSORT=0x60000016,
-    DT_SUNW_TLSSORTSZ=0x60000017,
-    DT_SUNW_CAPINFO=0x60000018,
-    DT_SUNW_STRPAD=0x60000019,
-    DT_SUNW_CAPCHAIN=0x6000001a,
-    DT_SUNW_LDMACH=0x6000001b,
-    DT_SUNW_CAPCHAINENT=0x6000001d,
-    DT_SUNW_CAPCHAINSZ=0x6000001f,
     DT_HIOS=0x6ffff000,
     DT_LOPROC=0x70000000,
     DT_HIPROC=0x7fffffff,
@@ -556,6 +538,36 @@ ENUM_D_TAG = dict(
     DT_VERDEFNUM=0x6ffffffd,
     DT_VERNEED=0x6ffffffe,
     DT_VERNEEDNUM=0x6fffffff,
+    DT_AUXILIARY=0x7ffffffd,
+    DT_FILTER=0x7fffffff,
+    _default_=Pass,
+)
+
+# Above are the dynamic tags which are valid always.
+# Below are the dynamic tags which are only valid in certain contexts.
+
+ENUM_D_TAG_SOLARIS = dict(
+    DT_SUNW_AUXILIARY=0x6000000d,
+    DT_SUNW_RTLDINF=0x6000000e,
+    DT_SUNW_FILTER=0x6000000f,
+    DT_SUNW_CAP=0x60000010,
+    DT_SUNW_SYMTAB=0x60000011,
+    DT_SUNW_SYMSZ=0x60000012,
+    DT_SUNW_ENCODING=0x60000013,
+    DT_SUNW_SORTENT=0x60000013,
+    DT_SUNW_SYMSORT=0x60000014,
+    DT_SUNW_SYMSORTSZ=0x60000015,
+    DT_SUNW_TLSSORT=0x60000016,
+    DT_SUNW_TLSSORTSZ=0x60000017,
+    DT_SUNW_CAPINFO=0x60000018,
+    DT_SUNW_STRPAD=0x60000019,
+    DT_SUNW_CAPCHAIN=0x6000001a,
+    DT_SUNW_LDMACH=0x6000001b,
+    DT_SUNW_CAPCHAINENT=0x6000001d,
+    DT_SUNW_CAPCHAINSZ=0x6000001f,
+)
+
+ENUM_D_TAG_MIPS = dict(
     DT_MIPS_RLD_VERSION=0x70000001,
     DT_MIPS_TIME_STAMP=0x70000002,
     DT_MIPS_ICHECKSUM=0x70000003,
@@ -573,11 +585,26 @@ ENUM_D_TAG = dict(
     DT_MIPS_HIPAGENO=0x70000014,
     DT_MIPS_RLD_MAP=0x70000016,
     DT_MIPS_RLD_MAP_REL=0x70000035,
-    DT_AUXILIARY=0x7ffffffd,
-    DT_FILTER=0x7fffffff,
-    _default_=Pass,
 )
 
+# Here is the mapping from e_machine enum to the extra dynamic tags which it
+# validates. Solaris is missing from this list because its inclusion is not
+# controlled by e_machine but rather e_ident[EI_OSABI].
+# TODO: add the rest of the machine-specific dynamic tags, not just mips and
+# solaris
+
+ENUMMAP_EXTRA_D_TAG_MACHINE = dict(
+    EM_MIPS=ENUM_D_TAG_MIPS,
+    EM_MIPS_RS3_LE=ENUM_D_TAG_MIPS,
+)
+
+# Here is the full combined mapping from tag name to value
+
+ENUM_D_TAG = dict(ENUM_D_TAG_COMMON)
+ENUM_D_TAG.update(ENUM_D_TAG_SOLARIS)
+for k in ENUMMAP_EXTRA_D_TAG_MACHINE:
+    ENUM_D_TAG.update(ENUMMAP_EXTRA_D_TAG_MACHINE[k])
+
 ENUM_RELOC_TYPE_MIPS = dict(
     R_MIPS_NONE=0,
     R_MIPS_16=1,
index a89bfed1f554cb2a974574d1d60982a5a3b9b13c..660f6872f1a32b0550d8894357b09a34e43360c7 100644 (file)
@@ -72,7 +72,7 @@ class ELFStructs(object):
         self._create_leb128()
         self._create_ntbs()
 
-    def create_advanced_structs(self, e_type=None, e_machine=None):
+    def create_advanced_structs(self, e_type=None, e_machine=None, e_ident_osabi=None):
         """ Create all ELF structs except the ehdr. They may possibly depend
             on provided e_type and/or e_machine parsed from ehdr.
         """
@@ -81,7 +81,7 @@ class ELFStructs(object):
         self._create_chdr()
         self._create_sym()
         self._create_rel()
-        self._create_dyn()
+        self._create_dyn(e_machine, e_ident_osabi)
         self._create_sunw_syminfo()
         self._create_gnu_verneed()
         self._create_gnu_verdef()
@@ -225,9 +225,15 @@ class ELFStructs(object):
             self.Elf_sxword('r_addend'),
         )
 
-    def _create_dyn(self):
+    def _create_dyn(self, e_machine=None, e_ident_osabi=None):
+        d_tag_dict = dict(ENUM_D_TAG_COMMON)
+        if e_machine in ENUMMAP_EXTRA_D_TAG_MACHINE:
+            d_tag_dict.update(ENUMMAP_EXTRA_D_TAG_MACHINE[e_machine])
+        elif e_ident_osabi == 'ELFOSABI_SOLARIS':
+            d_tag_dict.update(ENUM_D_TAG_SOLARIS)
+
         self.Elf_Dyn = Struct('Elf_Dyn',
-            Enum(self.Elf_sxword('d_tag'), **ENUM_D_TAG),
+            Enum(self.Elf_sxword('d_tag'), **d_tag_dict),
             self.Elf_xword('d_val'),
             Value('d_ptr', lambda ctx: ctx['d_val']),
         )
index 9b242f04a94daa46a8ba256820f52f0813913585..1ef00809c45d695e59a36dfe59bfb5b0e14137b1 100644 (file)
@@ -68,6 +68,26 @@ class TestDynamic(unittest.TestCase):
         exp = [b'', b'__libc_start_main', b'__gmon_start__', b'abort']
         self.assertEqual(symbol_names, exp)
 
+    def test_sunw_tags(self):
+        def extract_sunw(filename):
+            with open(filename, 'rb') as f:
+                elf = ELFFile(f)
+                dyn = elf.get_section_by_name('.dynamic')
+
+                seen = set()
+                for tag in dyn.iter_tags():
+                    if type(tag.entry.d_tag) is str and \
+                            tag.entry.d_tag.startswith("DT_SUNW"):
+                        seen.add(tag.entry.d_tag)
+
+            return seen
+
+        f1 = extract_sunw(os.path.join('test', 'testfiles_for_unittests',
+            'exe_solaris32_cc.sparc.elf'))
+        f2 = extract_sunw(os.path.join('test', 'testfiles_for_unittests',
+            'android_dyntags.elf'))
+        self.assertEqual(f1, {'DT_SUNW_STRPAD', 'DT_SUNW_LDMACH'})
+        self.assertEqual(f2, set())
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/test/testfiles_for_unittests/android_dyntags.elf b/test/testfiles_for_unittests/android_dyntags.elf
new file mode 100644 (file)
index 0000000..f93d7f4
Binary files /dev/null and b/test/testfiles_for_unittests/android_dyntags.elf differ