Update readelf to v2.37, adapt readelf.py output and tests (#387)
[pyelftools.git] / test / run_readelf_tests.py
index 96447b4ab29d1e42ffc8b792d458da1e312c8175..59a039c5e214d25fb5b98cd5e1819b26d4cfd426 100755 (executable)
@@ -130,15 +130,16 @@ def compare_output(s1, s2):
     lines1 = prepare_lines(s1)
     lines2 = prepare_lines(s2)
 
-    flag_after_symtable = False
+    flag_in_debug_line_section = False
 
     if len(lines1) != len(lines2):
         return False, 'Number of lines different: %s vs %s' % (
                 len(lines1), len(lines2))
 
     for i in range(len(lines1)):
-        if 'symbol table' in lines1[i]:
-            flag_after_symtable = True
+        if lines1[i].endswith('debug_line section:'):
+            # .debug_line or .zdebug_line
+            flag_in_debug_line_section = True
 
         # readelf spelling error for GNU property notes
         lines1[i] = lines1[i].replace('procesor-specific type', 'processor-specific type')
@@ -162,12 +163,32 @@ def compare_output(s1, s2):
             sm = SequenceMatcher()
             sm.set_seqs(lines1[i], lines2[i])
             changes = sm.get_opcodes()
-            if flag_after_symtable:
-                # Detect readelf's adding @ with lib and version after
-                # symbol name.
-                if (    len(changes) == 2 and changes[1][0] == 'delete' and
-                        lines1[i][changes[1][1]] == '@'):
+            if flag_in_debug_line_section:
+                # readelf outputs an additional "View" column: ignore it
+                if len(lines1_parts) >= 2 and lines1_parts[-2] == 'view':
                     ok = True
+                else:
+                    # Fast check special-cased for the only ELF we have which
+                    # has this information (dwarf_gnuops4.so.elf)
+                    ok = (    lines1_parts[-2:] == ['1', 'x']
+                          and lines2_parts[-1] == 'x')
+            elif '[...]' in lines1[i]:
+                # Special case truncations with ellipsis like these:
+                #     .note.gnu.bu[...]        redelf
+                #     .note.gnu.build-i        pyelftools
+                # Or more complex for symbols with versions, like these:
+                #     _unw[...]@gcc_3.0        readelf
+                #     _unwind_resume@gcc_3.0   pyelftools
+                for p1, p2 in zip(lines1_parts, lines2_parts):
+                    dots_start = p1.find('[...]')
+                    if dots_start != -1:
+                        break
+                ok = p1.endswith('[...]') and p1[:dots_start] == p2[:dots_start]
+                if not ok:
+                    dots_end = dots_start + 5
+                    if len(p1) > dots_end and p1[dots_end] == '@':
+                        ok = (    p1[:dots_start] == p2[:dots_start]
+                              and p1[p1.rfind('@'):] == p2[p2.rfind('@'):])
             elif 'at_const_value' in lines1[i]:
                 # On 32-bit machines, readelf doesn't correctly represent
                 # some boundary LEB128 numbers
@@ -178,17 +199,11 @@ def compare_output(s1, s2):
             elif 'os/abi' in lines1[i]:
                 if 'unix - gnu' in lines1[i] and 'unix - linux' in lines2[i]:
                     ok = True
-            elif (  'unknown at value' in lines1[i] and
-                    'dw_at_apple' in lines2[i]):
-                ok = True
-            elif 'loos+0x474e553' in lines1[i]:
-                # readelf v2.29 does not know about PT_GNU_PROPERTY apparently
-                ok = lines2_parts[0] == 'gnu_property'
             elif len(lines1_parts) == 3 and lines1_parts[2] == 'nt_gnu_property_type_0':
                 # readelf does not seem to print a readable description for this
                 ok = lines1_parts == lines2_parts[:3]
             else:
-                for s in ('t (tls)', 'l (large)'):
+                for s in ('t (tls)', 'l (large)', 'd (mbind)'):
                     if s in lines1[i] or s in lines2[i]:
                         ok = True
                         break