[csw-maintainers] Checkpkg test for direct binding

Yann Rouillard yann at pleiades.fr.eu.org
Sat Aug 25 17:37:38 CEST 2012


Hi everybody,

As discussed previously in the direct binding discussion, here is the new
checkpkg test I am proposing to add to ensure direct binding is enabled in
packages.
Of course the idea is to enable this check when we agree on enabling direct
binding and after having tested it on a first set of package.

The full patch is attached, and I put an inline version without the unit
test part for easy commenting.

Feedbacks are welcome.

Yann

diff -ur v2.orig//lib/python/dependency_checks.py
v2/lib/python/dependency_checks.py
--- v2.orig//lib/python/dependency_checks.py Thu Aug 16 12:05:42 2012
+++ v2/lib/python/dependency_checks.py Sat Aug 25 16:14:45 2012
@@ -47,8 +47,8 @@

 def ProcessSoname(
     ldd_emulator,
-    soname, path_and_pkg_by_basename, binary_info, isalist, binary_path,
logger,
-    error_mgr,
+    soname, path_and_pkg_by_basename, binary_info, isalist, binary_path,
needed_symbols,
+    logger, error_mgr,
     pkgname, messenger):
   """This is not an ideal name for this function.

@@ -57,6 +57,28 @@
   """
   logging.debug("ProcessSoname(), %s %s"
                 % (binary_info["path"], soname))
+
+  # Even when direct binding is enabled, some symbols might not be
+  # directly bound because the library explicitely requested the symbol
+  # not to be drectly bound to.
+  # For example, libc.so.1 does it for symbol sigaction, free, malloc and
realloc
+  # So we consider that direct binding is enabled if at least one symbol
is directly
+  # bound to because that definitely means that -B direct or -z direct was
used.
+  direct_bind = False
+  for syminfo in needed_symbols:
+    if ('D' in syminfo['flags'] and 'B' in syminfo['flags']):
+      direct_bind = True
+      break
+
+  if not direct_bind:
+    messenger.Message(
+      "No symbol of binary %s is directly binded against library %s. "
+      "Please make sure the binaries are compiled using the \"-Bdirect\"
linker option."
+        % ("/" + binary_info["path"], soname))
+    error_mgr.ReportError(
+      pkgname, "no-direct-binding",
+      "%s is not directly binded to soname %s" % ("/" +
binary_info["path"], soname))
+
   orphan_sonames = []
   resolved = False
   path_list = path_and_pkg_by_basename[soname].keys()
@@ -146,11 +168,22 @@
   orphan_sonames = []
   for binary_info in pkg_data["binaries_dump_info"]:
     binary_path, binary_basename = os.path.split(binary_info["path"])
+
+    binary_needed_symbols = pkg_data["needed_symbols"][binary_info["path"]]
     for soname in binary_info["needed sonames"]:
+      if soname in binary_needed_symbols:
+        needed_symbols = binary_needed_symbols[soname]
+      else:
+ # If we are here, that means we got no information on symbols.
+ # No syminfo section was present in the elf file, that definitely
+ # imply that -Bdirect or -z direct was not used and the subsequent
+ # check on direct binding will catch it because it will find not symbols
+ needed_symbols = []
+
       orphan_sonames_tmp = ProcessSoname(
           ldd_emulator,
-          soname, path_and_pkg_by_basename, binary_info, isalist,
binary_path, logger,
-          error_mgr,
+          soname, path_and_pkg_by_basename, binary_info, isalist,
binary_path, needed_symbols,
+  logger, error_mgr,
           pkgname, messenger)
       orphan_sonames.extend(orphan_sonames_tmp)

diff -ur v2.orig//lib/python/dependency_checks_test.py
v2/lib/python/dependency_checks_test.py
--- v2.orig//lib/python/dependency_checks_test.py Tue Jun  5 23:52:51 2012
+++ v2/lib/python/dependency_checks_test.py Sat Aug 25 13:37:57 2012
@@ -258,6 +258,8 @@
        '/opt/csw/share/man': [u'CSWcommon', u'CSWgnuplot'],
        '/opt/csw/share/man/man1': ['CSWtree'],
        '/opt/csw/share/man/man1/tree.1': ['CSWtree']}
+    self.error_mgr_mock.ReportError('CSWtree', 'no-direct-binding',
+ '/opt/csw/bin/tree is not directly binded to soname libc.so.1')
     self.error_mgr_mock.NeedFile('CSWtree', u'/usr/lib/libc.so.1',
         'opt/csw/bin/tree needs the libc.so.1 soname')
     self.mox.ReplayAll()
diff -ur v2.orig//lib/python/inspective_package.py
v2/lib/python/inspective_package.py
--- v2.orig//lib/python/inspective_package.py Thu Aug 23 23:56:57 2012
+++ v2/lib/python/inspective_package.py Sat Aug 25 16:17:17 2012
@@ -229,6 +229,45 @@

     return defined_symbols

+
+  def GetNeededSymbols(self):
+    """Returns symbols needed for packaged ELF objects to work
+
+    To do this we parse output lines from elfdump -y, that command
+    will give us the content of the .SUNW_syminfo section which
+    contains additionnal informations on symbols linking.
+    """
+    binaries = self.ListBinaries()
+    needed_symbols = {}
+
+    for binary in binaries:
+      binary_abspath = os.path.join(self.directory, "root", binary)
+      # elfdump is the only tool that give us the syminfo flags
+      args = ["/usr/ccs/bin/elfdump", "-y", binary_abspath]
+      elfdump_proc = subprocess.Popen(
+          args,
+          stdout=subprocess.PIPE,
+          stderr=subprocess.PIPE)
+      stdout, stderr = elfdump_proc.communicate()
+      retcode = elfdump_proc.wait()
+      if retcode:
+        logging.error("%s returned an error: %s", args, stderr)
+        continue
+      elfdump_out = stdout.splitlines()
+
+      needed_symbols[binary] = {}
+      for line in elfdump_out:
+        syminfo = self._ParseElfdumpSyminfoLine(line)
+        if not syminfo:
+          continue
+ if syminfo['library']:
+          library = syminfo['library']
+          del syminfo['library']
+  symbols = needed_symbols[binary].setdefault(library, [])
+  symbols.append(syminfo)
+
+    return needed_symbols
+
   def GetLddMinusRlines(self):
     """Returns ldd -r output."""
     binaries = self.ListBinaries()
@@ -274,6 +313,22 @@
     sym = { 'address': fields[0], 'type': fields[1], 'name': fields[2] }
     return sym

+  def _ParseElfdumpSyminfoLine(self, line):
+    blank_line = (r'^\s*$')
+    header_line = (r'^(?:Syminfo
Section:\s+.SUNW_syminfo|\s*index\s+flags\s+bound\s+to\s+symbol)\s*$')
+    needed_symbol =
(r'\s*\[\d+\]\s+(?P<flags>[ABCDFILNPS]+)\s*(\[\d+\]\s+(?P<library>.*\S)|<self>)?\s+(?P<symbol>.*\S)\s*')
+    common_re = (r"(?:%s|%s|%s)" % (blank_line, header_line,
needed_symbol))
+
+    m = re.match(common_re, line)
+    if not m:
+      raise package.StdoutSyntaxError("Could not parse %s with %s"
+                                      % (repr(line), common_re))
+    syminfo = m.groupdict()
+    if 'library' in syminfo and syminfo['library']:
+      return syminfo
+    else:
+      return None
+
   def _ParseLddDashRline(self, line, binary=None):
     found_re = r"^\t(?P<soname>\S+)\s+=>\s+(?P<path_found>\S+)"
     symbol_not_found_re = (r"^\tsymbol not found:\s(?P<symbol>\S+)\s+"
diff -ur v2.orig//lib/python/package_stats.py v2/lib/python/package_stats.py
--- v2.orig//lib/python/package_stats.py Fri Aug 10 02:12:10 2012
+++ v2/lib/python/package_stats.py Sat Aug 25 15:58:49 2012
@@ -209,6 +209,7 @@
         "files_metadata": dir_pkg.GetFilesMetadata(),
         "mtime": self.GetMtime(),
  "ldd_info": dir_pkg.GetLddMinusRlines(),
+ "needed_symbols": dir_pkg.GetNeededSymbols(),
     }
     self.SaveStats(pkg_stats)
     logging.debug("Statistics of %s have been collected.",
repr(dir_pkg.pkgname))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.opencsw.org/pipermail/maintainers/attachments/20120825/3102031c/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: direct_binding_test.patch
Type: application/octet-stream
Size: 33473 bytes
Desc: not available
URL: <http://lists.opencsw.org/pipermail/maintainers/attachments/20120825/3102031c/attachment-0001.obj>


More information about the maintainers mailing list