[csw-maintainers] Checkpkg test for direct binding

Maciej (Matchek) Bliziński maciej at opencsw.org
Sat Aug 25 18:24:55 CEST 2012


2012/8/25 Yann Rouillard <yann at pleiades.fr.eu.org>

> 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']):
>

The parentheses are not necessary.


> +      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"]]
>

We need to think whether we will reindex all packages, or we'll accept
older data structures without throwing IndexError in the line above.


>      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
>

In what circumstances does syminfo come back empty? Is it when we can't
parse the text output?


> + if syminfo['library']:
> +          library = syminfo['library']
> +          del syminfo['library']
>

Will the del above actually free anything? If the whole syminfo stays
around, all its elements will too.


> +  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/d3215845/attachment-0001.html>


More information about the maintainers mailing list