Hi everybody,<div><br></div><div>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.</div><div>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.</div>
<div><br></div><div>The full patch is attached, and I put an inline version without the unit test part for easy commenting.</div><div><br></div><div>Feedbacks are welcome.</div><div><br></div><div>Yann</div><div><br></div>
<div><div>diff -ur v2.orig//lib/python/dependency_checks.py v2/lib/python/dependency_checks.py</div><div>--- v2.orig//lib/python/dependency_checks.py<span class="Apple-tab-span" style="white-space:pre">    </span>Thu Aug 16 12:05:42 2012</div>
<div>+++ v2/lib/python/dependency_checks.py<span class="Apple-tab-span" style="white-space:pre">        </span>Sat Aug 25 16:14:45 2012</div><div>@@ -47,8 +47,8 @@</div><div> </div><div> def ProcessSoname(</div><div>     ldd_emulator,</div>
<div>-    soname, path_and_pkg_by_basename, binary_info, isalist, binary_path, logger,</div><div>-    error_mgr,</div><div>+    soname, path_and_pkg_by_basename, binary_info, isalist, binary_path, needed_symbols,</div><div>
+    logger, error_mgr,</div><div>     pkgname, messenger):</div><div>   """This is not an ideal name for this function.</div><div> </div><div>@@ -57,6 +57,28 @@</div><div>   """</div><div>   logging.debug("ProcessSoname(), %s %s"</div>
<div>                 % (binary_info["path"], soname))</div><div>+</div><div>+  # Even when direct binding is enabled, some symbols might not be</div><div>+  # directly bound because the library explicitely requested the symbol</div>
<div>+  # not to be drectly bound to.</div><div>+  # For example, libc.so.1 does it for symbol sigaction, free, malloc and realloc</div><div>+  # So we consider that direct binding is enabled if at least one symbol is directly</div>
<div>+  # bound to because that definitely means that -B direct or -z direct was used.</div><div>+  direct_bind = False</div><div>+  for syminfo in needed_symbols:</div><div>+    if ('D' in syminfo['flags'] and 'B' in syminfo['flags']):</div>
<div>+      direct_bind = True</div><div>+      break</div><div>+</div><div>+  if not direct_bind:    </div><div>+    messenger.Message(</div><div>+      "No symbol of binary %s is directly binded against library %s. "</div>
<div>+      "Please make sure the binaries are compiled using the \"-Bdirect\" linker option."</div><div>+        % ("/" + binary_info["path"], soname))</div><div>+    error_mgr.ReportError(</div>
<div>+      pkgname, "no-direct-binding",</div><div>+      "%s is not directly binded to soname %s" % ("/" + binary_info["path"], soname))</div><div>+</div><div>   orphan_sonames = []</div>
<div>   resolved = False</div><div>   path_list = path_and_pkg_by_basename[soname].keys()</div><div>@@ -146,11 +168,22 @@</div><div>   orphan_sonames = []</div><div>   for binary_info in pkg_data["binaries_dump_info"]:</div>
<div>     binary_path, binary_basename = os.path.split(binary_info["path"])</div><div>+</div><div>+    binary_needed_symbols = pkg_data["needed_symbols"][binary_info["path"]]</div><div>     for soname in binary_info["needed sonames"]:</div>
<div>+      if soname in binary_needed_symbols:</div><div>+        needed_symbols = binary_needed_symbols[soname]</div><div>+      else:</div><div>+<span class="Apple-tab-span" style="white-space:pre">   </span># If we are here, that means we got no information on symbols.</div>
<div>+<span class="Apple-tab-span" style="white-space:pre">     </span># No syminfo section was present in the elf file, that definitely</div><div>+<span class="Apple-tab-span" style="white-space:pre">   </span># imply that -Bdirect or -z direct was not used and the subsequent</div>
<div>+<span class="Apple-tab-span" style="white-space:pre">     </span># check on direct binding will catch it because it will find not symbols</div><div>+<span class="Apple-tab-span" style="white-space:pre">    </span>needed_symbols = []</div>
<div>+</div><div>       orphan_sonames_tmp = ProcessSoname(</div><div>           ldd_emulator,</div><div>-          soname, path_and_pkg_by_basename, binary_info, isalist, binary_path, logger,</div><div>-          error_mgr,</div>
<div>+          soname, path_and_pkg_by_basename, binary_info, isalist, binary_path, needed_symbols,</div><div>+<span class="Apple-tab-span" style="white-space:pre">       </span>  logger, error_mgr,</div><div>           pkgname, messenger)</div>
<div>       orphan_sonames.extend(orphan_sonames_tmp)</div><div> </div><div>diff -ur v2.orig//lib/python/dependency_checks_test.py v2/lib/python/dependency_checks_test.py</div><div>--- v2.orig//lib/python/dependency_checks_test.py<span class="Apple-tab-span" style="white-space:pre"> </span>Tue Jun  5 23:52:51 2012</div>
<div>+++ v2/lib/python/dependency_checks_test.py<span class="Apple-tab-span" style="white-space:pre">   </span>Sat Aug 25 13:37:57 2012</div><div>@@ -258,6 +258,8 @@</div><div>        '/opt/csw/share/man': [u'CSWcommon', u'CSWgnuplot'],</div>
<div>        '/opt/csw/share/man/man1': ['CSWtree'],</div><div>        '/opt/csw/share/man/man1/tree.1': ['CSWtree']}</div><div>+    self.error_mgr_mock.ReportError('CSWtree', 'no-direct-binding', </div>
<div>+<span class="Apple-tab-span" style="white-space:pre">     </span> '/opt/csw/bin/tree is not directly binded to soname libc.so.1') </div><div>     self.error_mgr_mock.NeedFile('CSWtree', u'/usr/lib/libc.so.1',</div>
<div>         'opt/csw/bin/tree needs the libc.so.1 soname')</div><div>     self.mox.ReplayAll()</div><div>diff -ur v2.orig//lib/python/inspective_package.py v2/lib/python/inspective_package.py</div><div>--- v2.orig//lib/python/inspective_package.py<span class="Apple-tab-span" style="white-space:pre">      </span>Thu Aug 23 23:56:57 2012</div>
<div>+++ v2/lib/python/inspective_package.py<span class="Apple-tab-span" style="white-space:pre">       </span>Sat Aug 25 16:17:17 2012</div><div>@@ -229,6 +229,45 @@</div><div> </div><div>     return defined_symbols</div><div>
 </div><div>+</div><div>+  def GetNeededSymbols(self):</div><div>+    """Returns symbols needed for packaged ELF objects to work</div><div>+</div><div>+    To do this we parse output lines from elfdump -y, that command</div>
<div>+    will give us the content of the .SUNW_syminfo section which </div><div>+    contains additionnal informations on symbols linking.</div><div>+    """</div><div>+    binaries = self.ListBinaries()</div>
<div>+    needed_symbols = {}</div><div>+</div><div>+    for binary in binaries:</div><div>+      binary_abspath = os.path.join(self.directory, "root", binary)</div><div>+      # elfdump is the only tool that give us the syminfo flags</div>
<div>+      args = ["/usr/ccs/bin/elfdump", "-y", binary_abspath]</div><div>+      elfdump_proc = subprocess.Popen(</div><div>+          args,</div><div>+          stdout=subprocess.PIPE,</div><div>+          stderr=subprocess.PIPE)</div>
<div>+      stdout, stderr = elfdump_proc.communicate()</div><div>+      retcode = elfdump_proc.wait()</div><div>+      if retcode:</div><div>+        logging.error("%s returned an error: %s", args, stderr)</div>
<div>+        continue</div><div>+      elfdump_out = stdout.splitlines()</div><div>+</div><div>+      needed_symbols[binary] = {}</div><div>+      for line in elfdump_out:</div><div>+        syminfo = self._ParseElfdumpSyminfoLine(line)</div>
<div>+        if not syminfo:</div><div>+          continue</div><div>+<span class="Apple-tab-span" style="white-space:pre">    </span>if syminfo['library']:</div><div>+          library = syminfo['library']<span class="Apple-tab-span" style="white-space:pre">                </span> </div>
<div>+          del syminfo['library']</div><div>+<span class="Apple-tab-span" style="white-space:pre">     </span>  symbols = needed_symbols[binary].setdefault(library, [])</div><div>+<span class="Apple-tab-span" style="white-space:pre">  </span>  symbols.append(syminfo)</div>
<div>+</div><div>+    return needed_symbols</div><div>+</div><div>   def GetLddMinusRlines(self):</div><div>     """Returns ldd -r output."""</div><div>     binaries = self.ListBinaries()</div>
<div>@@ -274,6 +313,22 @@</div><div>     sym = { 'address': fields[0], 'type': fields[1], 'name': fields[2] }</div><div>     return sym</div><div> </div><div>+  def _ParseElfdumpSyminfoLine(self, line):</div>
<div>+    blank_line = (r'^\s*$')</div><div>+    header_line = (r'^(?:Syminfo Section:\s+.SUNW_syminfo|\s*index\s+flags\s+bound\s+to\s+symbol)\s*$')</div><div>+    needed_symbol = (r'\s*\[\d+\]\s+(?P<flags>[ABCDFILNPS]+)\s*(\[\d+\]\s+(?P<library>.*\S)|<self>)?\s+(?P<symbol>.*\S)\s*')</div>
<div>+    common_re = (r"(?:%s|%s|%s)" % (blank_line, header_line, needed_symbol))</div><div>+</div><div>+    m = re.match(common_re, line)</div><div>+    if not m:</div><div>+      raise package.StdoutSyntaxError("Could not parse %s with %s"</div>
<div>+                                      % (repr(line), common_re))</div><div>+    syminfo = m.groupdict()</div><div>+    if 'library' in syminfo and syminfo['library']:</div><div>+      return syminfo</div>
<div>+    else:</div><div>+      return None</div><div>+</div><div>   def _ParseLddDashRline(self, line, binary=None):</div><div>     found_re = r"^\t(?P<soname>\S+)\s+=>\s+(?P<path_found>\S+)"</div>
<div>     symbol_not_found_re = (r"^\tsymbol not found:\s(?P<symbol>\S+)\s+"</div><div>diff -ur v2.orig//lib/python/package_stats.py v2/lib/python/package_stats.py</div><div>--- v2.orig//lib/python/package_stats.py<span class="Apple-tab-span" style="white-space:pre">     </span>Fri Aug 10 02:12:10 2012</div>
<div>+++ v2/lib/python/package_stats.py<span class="Apple-tab-span" style="white-space:pre">    </span>Sat Aug 25 15:58:49 2012</div><div>@@ -209,6 +209,7 @@</div><div>         "files_metadata": dir_pkg.GetFilesMetadata(),</div>
<div>         "mtime": self.GetMtime(),</div><div> <span class="Apple-tab-span" style="white-space:pre">  </span>"ldd_info": dir_pkg.GetLddMinusRlines(),</div><div>+<span class="Apple-tab-span" style="white-space:pre">  </span>"needed_symbols": dir_pkg.GetNeededSymbols(),</div>
<div>     }</div><div>     self.SaveStats(pkg_stats)</div><div>     logging.debug("Statistics of %s have been collected.", repr(dir_pkg.pkgname))</div><div><br></div></div>