DW_AT_const_value is not a location, take 2 (#277)
authorSeva Alekseyev <sevaa@yarxi.ru>
Sat, 7 Mar 2020 14:05:01 +0000 (09:05 -0500)
committerGitHub <noreply@github.com>
Sat, 7 Mar 2020 14:05:01 +0000 (06:05 -0800)
Fixes #274

elftools/dwarf/locationlists.py
test/test_dwarf_constisntloc.py [new file with mode: 0644]
test/test_dwarf_locexpr_on_gnucall.py [new file with mode: 0644]
test/testfiles_for_unittests/dwarf_gnuops1.o [new file with mode: 0644]
test/testfiles_for_unittests/pascalenum.o [new file with mode: 0644]

index 5fba0c356fadc8e782195fcfc307a11f425f44ba..2f8c51e41ebc9658fe7a8389fed9c4c4d40c2abe 100644 (file)
@@ -104,13 +104,15 @@ class LocationParser(object):
 
     @staticmethod
     def _attribute_has_loc_expr(attr, dwarf_version):
-        return (dwarf_version < 4 and attr.form == 'DW_FORM_block1' or
-                attr.form == 'DW_FORM_exprloc')
+        return ((dwarf_version < 4 and attr.form == 'DW_FORM_block1' and
+            not attr.name == 'DW_AT_const_value') or
+            attr.form == 'DW_FORM_exprloc')
 
     @staticmethod
     def _attribute_has_loc_list(attr, dwarf_version):
         return ((dwarf_version < 4 and
-                 attr.form in ('DW_FORM_data4', 'DW_FORM_data8')) or
+                 attr.form in ('DW_FORM_data4', 'DW_FORM_data8') and
+                 not attr.name == 'DW_AT_const_value') or
                 attr.form == 'DW_FORM_sec_offset')
 
     @staticmethod
@@ -120,4 +122,7 @@ class LocationParser(object):
                                'DW_AT_data_member_location',
                                'DW_AT_frame_base', 'DW_AT_segment',
                                'DW_AT_static_link', 'DW_AT_use_location',
-                               'DW_AT_vtable_elem_location'))
+                               'DW_AT_vtable_elem_location',
+                               'DW_AT_GNU_call_site_value',
+                               'DW_AT_GNU_call_site_target',
+                               'DW_AT_GNU_call_site_data_value'))
diff --git a/test/test_dwarf_constisntloc.py b/test/test_dwarf_constisntloc.py
new file mode 100644 (file)
index 0000000..b97ef39
--- /dev/null
@@ -0,0 +1,39 @@
+#------------------------------------------------------------------------------
+# elftools tests
+#
+# Seva Alekseyev (sevaa@sprynet.com)
+# This code is in the public domain
+#------------------------------------------------------------------------------
+
+import unittest
+import os, sys, io
+
+sys.path.insert(1, os.getcwd())
+
+from elftools.elf.elffile import ELFFile
+from elftools.dwarf.dwarfinfo import DWARFInfo, DebugSectionDescriptor, DwarfConfig
+from elftools.dwarf.locationlists import LocationParser
+
+class TestConstWithData4IsntLocation(unittest.TestCase):
+    def _test_file(self, filename):
+        filepath = os.path.join('test', 'testfiles_for_unittests', filename)
+        print('Reading %s...' % (filename))
+        with open(filepath, 'rb') as f:
+            elffile = ELFFile(f)
+            dwarfinfo = elffile.get_dwarf_info()
+            locparser = LocationParser(dwarfinfo.location_lists())
+            for CU in dwarfinfo.iter_CUs():
+                print("Compile unit %s..." % CU.get_top_DIE().attributes['DW_AT_name'].value.decode('utf-8'))
+                ver = CU['version']
+                for DIE in CU.iter_DIEs():
+                    for key in DIE.attributes:
+                        attr = DIE.attributes[key]
+                        if LocationParser.attribute_has_location(attr, ver):
+                            # This will crash on unpatched library on DIE at 0x9f
+                            locparser.parse_from_attribute(attr, ver)
+
+    def test_main(self):
+        self._test_file('pascalenum.o')
+
+if __name__ == '__main__':
+    unittest.main()    
diff --git a/test/test_dwarf_locexpr_on_gnucall.py b/test/test_dwarf_locexpr_on_gnucall.py
new file mode 100644 (file)
index 0000000..ba24da5
--- /dev/null
@@ -0,0 +1,39 @@
+#------------------------------------------------------------------------------
+# elftools tests
+#
+# Seva Alekseyev (sevaa@sprynet.com)
+# This code is in the public domain
+#------------------------------------------------------------------------------
+
+import unittest
+import os, sys, io
+
+# sys.path.insert(1, os.getcwd())
+
+from elftools.elf.elffile import ELFFile
+from elftools.dwarf.dwarfinfo import DWARFInfo, DebugSectionDescriptor, DwarfConfig
+from elftools.dwarf.locationlists import LocationParser
+
+class TestGNUCallAttributesHaveLocation(unittest.TestCase):
+    def _test_file(self, filename):
+        filepath = os.path.join('test', 'testfiles_for_unittests', filename)
+        print('Reading %s...' % (filename))
+        with open(filepath, 'rb') as f:
+            elffile = ELFFile(f)
+            dwarfinfo = elffile.get_dwarf_info()
+            for CU in dwarfinfo.iter_CUs():
+                ver = CU['version']
+                print("Compile unit %s..." % CU.get_top_DIE().attributes['DW_AT_name'].value.decode('utf-8'))
+
+                for DIE in CU.iter_DIEs():
+                    for key in DIE.attributes:
+                        attr = DIE.attributes[key]
+                        if attr.form == 'DW_FORM_exprloc':
+                            self.assertTrue(LocationParser.attribute_has_location(attr, CU['version']), "Attribute %s not recognized as a location" % key)
+
+
+    def test_main(self):
+        self._test_file('dwarf_gnuops1.o')
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/test/testfiles_for_unittests/dwarf_gnuops1.o b/test/testfiles_for_unittests/dwarf_gnuops1.o
new file mode 100644 (file)
index 0000000..d489f64
Binary files /dev/null and b/test/testfiles_for_unittests/dwarf_gnuops1.o differ
diff --git a/test/testfiles_for_unittests/pascalenum.o b/test/testfiles_for_unittests/pascalenum.o
new file mode 100644 (file)
index 0000000..a8520e8
Binary files /dev/null and b/test/testfiles_for_unittests/pascalenum.o differ