Эх сурвалжийг харах

Add readelf support to abi_check. Prefer readelf over nm

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@233360 91177308-0d34-0410-b5e6-96231b3b80d8
Eric Fiselier 10 жил өмнө
parent
commit
faa65e99a8

+ 88 - 12
utils/sym_check/sym_check/extract.py

@@ -8,29 +8,28 @@ import sys
 from sym_check import util
 from sym_check import util
 
 
 
 
-class Extractor(object):
+class NMExtractor(object):
     """
     """
-    Extractor - Extract symbol lists from libraries using nm.
+    NMExtractor - Extract symbol lists from libraries using nm.
     """
     """
 
 
     @staticmethod
     @staticmethod
-    def find_nm():
+    def find_tool():
         """
         """
         Search for the nm executable and return the path and type.
         Search for the nm executable and return the path and type.
         """
         """
-        nm_exe = distutils.spawn.find_executable('nm')
-        if nm_exe is not None:
-            return nm_exe
-        # ERROR no NM found
-        print("ERROR: Could not find nm")
-        sys.exit(1)
+        return distutils.spawn.find_executable('nm')
 
 
     def __init__(self):
     def __init__(self):
         """
         """
         Initialize the nm executable and flags that will be used to extract
         Initialize the nm executable and flags that will be used to extract
         symbols from shared libraries.
         symbols from shared libraries.
         """
         """
-        self.nm_exe = Extractor.find_nm()
+        self.nm_exe = self.find_tool()
+        if self.nm_exe is None:
+            # ERROR no NM found
+            print("ERROR: Could not find nm")
+            sys.exit(1)
         self.flags = ['-P', '-g']
         self.flags = ['-P', '-g']
 
 
     def extract(self, lib):
     def extract(self, lib):
@@ -60,6 +59,7 @@ class Extractor(object):
             'name': bits[0],
             'name': bits[0],
             'type': bits[1]
             'type': bits[1]
         }
         }
+        new_sym['name'] = new_sym['name'].replace('@@', '@')
         new_sym = self._transform_sym_type(new_sym)
         new_sym = self._transform_sym_type(new_sym)
         # NM types which we want to save the size for.
         # NM types which we want to save the size for.
         if new_sym['type'] == 'OBJECT' and len(bits) > 3:
         if new_sym['type'] == 'OBJECT' and len(bits) > 3:
@@ -74,7 +74,8 @@ class Extractor(object):
         if sym is None or len(sym) < 2:
         if sym is None or len(sym) < 2:
             return False
             return False
         bad_types = ['t', 'b', 'r', 'd', 'w']
         bad_types = ['t', 'b', 'r', 'd', 'w']
-        return sym['type'] not in bad_types
+        return (sym['type'] not in bad_types
+                and sym['name'] not in ['__bss_start', '_end', '_edata'])
 
 
     @staticmethod
     @staticmethod
     def _transform_sym_type(sym):
     def _transform_sym_type(sym):
@@ -90,6 +91,78 @@ class Extractor(object):
             sym['type'] = 'OBJECT'
             sym['type'] = 'OBJECT'
         return sym
         return sym
 
 
+class ReadElfExtractor(object):
+    """
+    NMExtractor - Extract symbol lists from libraries using nm.
+    """
+
+    @staticmethod
+    def find_tool():
+        """
+        Search for the nm executable and return the path and type.
+        """
+        return distutils.spawn.find_executable('readelf')
+
+    def __init__(self):
+        """
+        Initialize the nm executable and flags that will be used to extract
+        symbols from shared libraries.
+        """
+        self.tool = self.find_tool()
+        if self.tool is None:
+            # ERROR no NM found
+            print("ERROR: Could not find readelf")
+            sys.exit(1)
+        self.flags = ['--wide', '--symbols']
+
+    def extract(self, lib):
+        """
+        Extract symbols from a library and return the results as a dict of
+        parsed symbols.
+        """
+        cmd = [self.tool] + self.flags + [lib]
+        out, _, exit_code = util.execute_command_verbose(cmd)
+        if exit_code != 0:
+            raise RuntimeError('Failed to run %s on %s' % (self.nm_exe, lib))
+        dyn_syms = self.get_dynsym_table(out)
+        return self.process_syms(dyn_syms)
+
+    def process_syms(self, sym_list):
+        new_syms = []
+        for s in sym_list:
+            parts = s.split()
+            if not parts:
+                continue
+            assert len(parts) == 7 or len(parts) == 8 or len(parts) == 9
+            if len(parts) == 7:
+                continue
+            new_sym = {
+                'name': parts[7],
+                'size': int(parts[2]),
+                'type': parts[3],
+            }
+            assert new_sym['type'] in ['OBJECT', 'FUNC', 'NOTYPE']
+            if new_sym['type'] == 'NOTYPE':
+                continue
+            if new_sym['type'] == 'FUNC':
+                del new_sym['size']
+            new_syms += [new_sym]
+        return new_syms
+
+    def get_dynsym_table(self, out):
+        lines = out.splitlines()
+        start = -1
+        end = -1
+        for i in range(len(lines)):
+            if lines[i].startswith("Symbol table '.dynsym'"):
+                start = i + 2
+            if start != -1 and end == -1 and not lines[i].strip():
+                end = i + 1
+        assert start != -1
+        if end == -1:
+            end = len(lines)
+        return lines[start:end]
+
 
 
 def extract_symbols(lib_file):
 def extract_symbols(lib_file):
     """
     """
@@ -97,5 +170,8 @@ def extract_symbols(lib_file):
     The symbols are extracted using NM. They are then filtered and formated.
     The symbols are extracted using NM. They are then filtered and formated.
     Finally they symbols are made unique.
     Finally they symbols are made unique.
     """
     """
-    extractor = Extractor()
+    if ReadElfExtractor.find_tool():
+        extractor = ReadElfExtractor()
+    else:
+        extractor = NMExtractor()
     return extractor.extract(lib_file)
     return extractor.extract(lib_file)