Fix for mixed version loclists, tests (#521) master
authorSeva Alekseyev <sevaa@yarxi.ru>
Thu, 16 Nov 2023 02:12:15 +0000 (21:12 -0500)
committerGitHub <noreply@github.com>
Thu, 16 Nov 2023 02:12:15 +0000 (18:12 -0800)
elftools/dwarf/dwarfinfo.py
scripts/dwarfdump.py
test/test_dwarf_llpair.py [new file with mode: 0644]
test/testfiles_for_dwarfdump/dwarf_llpair.elf [new file with mode: 0644]
test/testfiles_for_dwarfdump/llpair.c [new file with mode: 0644]
test/testfiles_for_dwarfdump/llpaira.c [new file with mode: 0644]
test/testfiles_for_unittests/dwarf_llpair.elf [new file with mode: 0644]

index 96f33d9e8ca441fcea4725ad0b5993fdac9e5463..406146286902fdc221fb5444d344d2eb78a7a3b9 100644 (file)
@@ -367,7 +367,7 @@ class DWARFInfo(object):
         elif self.debug_loc_sec and self.debug_loclists_sec is None:
             return LocationLists(self.debug_loc_sec.stream, self.structs, 4, self)
         elif self.debug_loc_sec and self.debug_loclists_sec:
-            return LocationListsPair(self.debug_loclists_sec.stream, self.debug_loclists_sec.stream, self.structs, self)
+            return LocationListsPair(self.debug_loc_sec.stream, self.debug_loclists_sec.stream, self.structs, self)
         else:
             return None
 
index bf05bdb9e5fe030dc895a98e5657f68b8c0d2bcf..6d46ba59805cef0d0dc7d2d1f3916ebc351b703e 100644 (file)
@@ -325,7 +325,9 @@ ATTR_DESCRIPTIONS = dict(
     DW_AT_call_line=_desc_value,
     DW_AT_call_file=_desc_decl_file,
     DW_AT_abstract_origin=_desc_origin,
-    DW_AT_specification=_desc_spec
+    DW_AT_specification=_desc_spec,
+    DW_AT_call_site_value=lambda attr, die: _desc_expression(attr.value, die) if attr.form.startswith('DW_FORM_block') else _desc_locations(attr, die),
+    DW_AT_GNU_call_site_value=lambda attr, die: _desc_expression(attr.value, die) if attr.form.startswith('DW_FORM_block') else _desc_locations(attr, die),
 )
 
 class ReadElf(object):
diff --git a/test/test_dwarf_llpair.py b/test/test_dwarf_llpair.py
new file mode 100644 (file)
index 0000000..e4f0c7e
--- /dev/null
@@ -0,0 +1,48 @@
+#-------------------------------------------------------------------------------
+# elftools tests
+#
+# Seva Alekseyev (sevaa@sprynet.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+import unittest
+import os
+from elftools.dwarf.locationlists import LocationListsPair, LocationParser
+from elftools.elf.elffile import ELFFile
+
+class TestLocListsPair(unittest.TestCase):
+    def test_llpair(self):
+        path = os.path.join('test', 'testfiles_for_unittests',
+                            'dwarf_llpair.elf')
+        with open(path, 'rb') as f:
+            elffile = ELFFile(f)
+            dwarfinfo = elffile.get_dwarf_info(follow_links=False)
+            # This binary has both V4- loclists and V5+ loclists
+            self.assertTrue(dwarfinfo.debug_loc_sec and dwarfinfo.debug_loclists_sec)
+            # On this binary, it's a pair object
+            llp = dwarfinfo.location_lists()
+            self.assertTrue(isinstance(llp, LocationListsPair))
+            locparser = LocationParser(llp)
+
+            CUs = list(dwarfinfo.iter_CUs())     
+
+            # The first CU is the v5 one
+            # Just in case, make sure we can hit a loclist in a V5 section
+            CU = CUs[0]
+            self.assertTrue(CU.header.version == 5)
+            # DW_TAG_variable for i inside b()
+            die = next(die for die in CU.iter_DIEs() if die.offset == 0x333)
+            ll = locparser.parse_from_attribute(die.attributes['DW_AT_location'], CU.header.version, die=die)
+            self.assertTrue(len(ll) == 8)
+
+            # The second CU is the V2 one
+            # Now hit a loclist in a V4- sectoin
+            # This would fail before 11/15/2023
+            CU = CUs[1]
+            self.assertTrue(CU.header.version == 2)
+            # DW_TAG_variable for i inside a()
+            die = next(die for die in CU.iter_DIEs() if die.offset == 0x796)
+            ll = locparser.parse_from_attribute(die.attributes['DW_AT_location'], CU.header.version, die=die)
+            self.assertTrue(len(ll) == 7)
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/test/testfiles_for_dwarfdump/dwarf_llpair.elf b/test/testfiles_for_dwarfdump/dwarf_llpair.elf
new file mode 100644 (file)
index 0000000..5909d60
Binary files /dev/null and b/test/testfiles_for_dwarfdump/dwarf_llpair.elf differ
diff --git a/test/testfiles_for_dwarfdump/llpair.c b/test/testfiles_for_dwarfdump/llpair.c
new file mode 100644 (file)
index 0000000..712b3ad
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+To compile:
+Linux x86-64
+gcc version 8.3.0
+
+gcc -gdwarf-2 -O2 -c llpaira.c
+gcc -gdwarf-5 -O2 -o dwarf_llpair.elf llpair.c llpaira.o
+*/
+#include <stdlib.h>
+#include <stdio.h>
+
+extern void a(int n);
+
+void b(int n)
+{
+    int i;
+    for(i=0;i<n;i++)
+        printf("%d\n", i*i);
+    printf("%d\n", rand()*rand()*rand() + rand()*rand() + rand());
+    for(i=0;i<10;i++)
+        printf("%d\n", i*i+76543*i);
+    printf("%d\n", n);
+}
+
+int main()
+{
+    b(rand());
+    return 0;
+}
\ No newline at end of file
diff --git a/test/testfiles_for_dwarfdump/llpaira.c b/test/testfiles_for_dwarfdump/llpaira.c
new file mode 100644 (file)
index 0000000..58baf6e
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+void a(int n)
+{
+    int i;
+    for(i=0;i<n;i++)
+        printf("%d\n", i*i);
+    for(i=0;i<10;i++)
+        printf("%d\n", i*i+76543*i);
+    printf("%d\n", n);
+}
\ No newline at end of file
diff --git a/test/testfiles_for_unittests/dwarf_llpair.elf b/test/testfiles_for_unittests/dwarf_llpair.elf
new file mode 100644 (file)
index 0000000..5909d60
Binary files /dev/null and b/test/testfiles_for_unittests/dwarf_llpair.elf differ