public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Anthony G. Basile" <blueness@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/elfix:master commit in: misc/
Date: Wed, 26 Dec 2012 21:23:22 +0000 (UTC)	[thread overview]
Message-ID: <1356556989.beacfc74b3af09d5a87ea60edba019a8d7f51f6a.blueness@gentoo> (raw)

commit:     beacfc74b3af09d5a87ea60edba019a8d7f51f6a
Author:     Anthony G. Basile <blueness <AT> gentoo <DOT> org>
AuthorDate: Wed Dec 26 21:23:09 2012 +0000
Commit:     Anthony G. Basile <blueness <AT> gentoo <DOT> org>
CommitDate: Wed Dec 26 21:23:09 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/elfix.git;a=commit;h=beacfc74

misc/link_maps: encapsulate all logic in class LinkMap

---
 misc/link_maps |  302 +++++++++++++++++++++++++++++---------------------------
 1 files changed, 156 insertions(+), 146 deletions(-)

diff --git a/misc/link_maps b/misc/link_maps
index 3707298..508af24 100755
--- a/misc/link_maps
+++ b/misc/link_maps
@@ -1,14 +1,5 @@
 #!/usr/bin/env python
 
-#
-# Note: This alternative way of doing revdep-pax only
-# works on Gentoo systems where NEEDED.ELF.2 all the
-# information we need generated by scanelf during emerge.
-#
-# See /usr/lib/portage/bin/misc-functions.sh ~line 520
-# echo "${arch:3};${obj};${soname};${rpath};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
-#
-
 import os
 import sys
 import re
@@ -16,147 +7,181 @@ import pax
 import portage
 
 
-def get_object_needed():
-    """ Return object_needed dictionary which has structure
+class LinkMap:
 
-        {
-            abi1 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
-            abi2 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
-            ....
-        }
+    def __init__(self):
+        """ Put all the NEEDED.ELF.2 files for all installed packages
+        into a dictionary of the form
 
-    Here the sonames were obtained from the ELF object by scanelf -nm
-    (like readelf -d) during emerge.
-    """
+            { pkg : line_from_NEEDED.ELF.2, ... }
 
-    vardb = portage.db[portage.root]["vartree"].dbapi
+        where the line has the following form:
 
-    object_needed = {}
+           echo "${arch:3};${obj};${soname};${rpath};${needed}" >> \
+               "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
 
-    for pkg in vardb.cpv_all():
-        needs = vardb.aux_get(pkg, ['NEEDED.ELF.2'])[0].strip()
-        if not needs:            #skip empty lines
-            continue
-        lines = re.split('\n', needs)
-        for line in lines:
-            link = re.split(';', line)
-            abi = link[0]
-            elf = link[1]
-            sonames = re.split(',', link[4])
-            object_needed.setdefault(abi,{}).update({elf:sonames})
+        See /usr/lib/portage/bin/misc-functions.sh ~line 520
+        """
+        vardb = portage.db[portage.root]["vartree"].dbapi
 
-    return object_needed
+        self.pkgs = []
+        self.pkgs_needed = {}
 
+        for pkg in vardb.cpv_all():
+            needed = vardb.aux_get(pkg, ['NEEDED.ELF.2'])[0].strip()
+            if needed: # Some packages have no NEEDED.ELF.2
+                self.pkgs.append(pkg)
+                for line in re.split('\n', needed):
+                    self.pkgs_needed.setdefault(pkg,[]).append(re.split(';', line))
 
-def get_libraries():
-    """ Return library2soname dictionary which has structure
 
-        { full_path_to_library : (soname, abi), ... }
+    def get_object_needed(self):
+        """ Return object_needed dictionary which has structure
 
-    and its inverse which has structure
+            {
+                abi1 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
+                abi2 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
+                ....
+            }
 
-        { (soname, abi) : full_path_to_library, ... }
-    """
+        Here the sonames were obtained from the ELF object by scanelf -nm
+        (like readelf -d) during emerge.
+        """
+        object_needed = {}
 
-    vardb = portage.db[portage.root]["vartree"].dbapi
+        for pkg in self.pkgs:
+            for link in self.pkgs_needed[pkg]:
+                abi = link[0]
+                elf = link[1]
+                sonames = re.split(',', link[4])
+                object_needed.setdefault(abi,{}).update({elf:sonames})
 
-    library2soname = {}
-    soname2library = {}
+        return object_needed
 
-    for pkg in vardb.cpv_all():
-        needs = vardb.aux_get(pkg, ['NEEDED.ELF.2'])[0].strip()
-        if not needs:                                #skip empty lines
-            continue
-        lines = re.split('\n', needs)
-        for line in lines:
-            link = re.split(';', line)
-            abi = link[0]
-            elf = link[1]
-            soname = link[2]
-            if soname:                               #no soname => executable
-                library2soname[elf] = (soname,abi)
-                soname2library[(soname,abi)] = elf
 
-    return ( library2soname, soname2library )
+    def get_libraries(self):
+        """ Return library2soname dictionary which has structure
 
+            { full_path_to_library : (soname, abi), ... }
 
-def get_soname_needed( object_needed, library2soname ):
-    """ Return soname_needed dictionary which has structure:
+        and its inverse which has structure
 
-        {
-            abi1: { soname: [ soname1, soname2, ... ], .... },
-            abi2: { soname: [ soname1, soname2, ... ], .... },
-        }
+            { (soname, abi) : full_path_to_library, ... }
+        """
+        library2soname = {}
+        soname2library = {}
 
-    Here the soname1, soname2,... were obtained from soname's corresponding
-    ELF object by scanelf -n during emerge.
-    """
+        for pkg in self.pkgs:
+            for link in self.pkgs_needed[pkg]:
+                abi = link[0]
+                elf = link[1]
+                soname = link[2]
+                if soname:                               #no soname => executable
+                    library2soname[elf] = (soname,abi)
+                    soname2library[(soname,abi)] = elf
 
-    soname_needed = {}
+        return ( library2soname, soname2library )
 
-    for abi in object_needed:
-        for elf in object_needed[abi]:
-            try:
-                (soname, abi_check) = library2soname[elf]
-                if abi != abi_check:
-                    print('This should never happen!')
-                    sys.exit(1)
-                soname_needed.setdefault(abi,{}).update({soname:object_needed[abi][elf]})
-            except KeyError:
-                continue  # no soname, its probably an executable
-
-    return soname_needed
-
-
-def expand_linkings( object_needed, soname2library ):
-    """ Expands the object_needed dictionary which has structure
-
-        {
-            abi1 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
-            abi2 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
-            ....
-        }
-
-    such that the soname's are traced all the way to the end of
-    the link chain.  Here the sonames should be the same as those
-    obtained from the ELF object by ldd.
-    """
-
-    for abi in object_needed:
-        for elf in object_needed[abi]:
-            while True:
-                found_new_soname = False
-                for so in object_needed[abi][elf]:                              # For all the first links ...
-                    try:
-                        for sn in object_needed[abi][soname2library[(so,abi)]]: # go to the next links ...
-                            if sn in object_needed[abi][elf]:                   # skip if already included ...
-                                continue
-                            if not (sn,abi) in soname2library:                  # skip if vdso ...
-                                continue
-                            # This appends to the object_needed
-                            # and soname_needed lists.  No copy
-                            # was done so its the same lists in
-                            # memory for both, and its modified
-                            # for both.
-                            object_needed[abi][elf].append(sn)                  # otherwise collapse it back into
-                            found_new_soname = True                             # first links of the chain.
-
-                    except KeyError:                 # Not all nodes in the chain have a next node
-                        continue
-
-                if not found_new_soname:             # We're done, that last iteration found
-                    break                            # no new nodes
-
-
-def get_object_reverse_linkings( object_linkings ):
-    object_reverse_linkings = {}
 
-    for abi in object_linkings:
-        for elf in object_linkings[abi]:
-            for soname in object_linkings[abi][elf]:
-                object_reverse_linkings.setdefault(abi,{}).setdefault(soname,[]).append(elf)
+    def get_soname_needed(self, object_needed, library2soname ):
+        """ Return soname_needed dictionary which has structure:
+
+            {
+                abi1: { soname: [ soname1, soname2, ... ], .... },
+                abi2: { soname: [ soname1, soname2, ... ], .... },
+            }
+
+        Here the soname1, soname2,... were obtained from soname's corresponding
+        ELF object by scanelf -n during emerge.
+        """
+        soname_needed = {}
+
+        for abi in object_needed:
+            for elf in object_needed[abi]:
+                try:
+                    (soname, abi_check) = library2soname[elf]
+                    assert abi == abi_check # We should get the same abi associated with the soname
+                    soname_needed.setdefault(abi,{}).update({soname:object_needed[abi][elf]})
+                except KeyError:
+                    continue  # no soname, its probably an executable
+
+        return soname_needed
+
+
+    def expand_linkings(self, object_needed, soname2library):
+        """ Expands the object_needed dictionary which has structure
+
+            {
+                abi1 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
+                abi2 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
+                ....
+            }
+
+        such that the soname's are traced all the way to the end of
+        the link chain.  Here the sonames should be the same as those
+        obtained from the ELF object by ldd.
+        """
+        for abi in object_needed:
+            for elf in object_needed[abi]:
+                while True:
+                    found_new_soname = False
+                    for so in object_needed[abi][elf]:                              # For all the first links ...
+                        try:
+                            for sn in object_needed[abi][soname2library[(so,abi)]]: # go to the next links ...
+                                if sn in object_needed[abi][elf]:                   # skip if already included ...
+                                    continue
+                                if not (sn,abi) in soname2library:                  # skip if vdso ...
+                                    continue
+
+                                # This appends to the object_needed and soname_needed lists.  No copy was
+                                # done so its the same lists in memory for both, and its modified for both.
+
+                                object_needed[abi][elf].append(sn)                  # otherwise collapse it back into
+                                found_new_soname = True                             # first links of the chain.
 
-    return object_reverse_linkings
+                        except KeyError:                 # Not all nodes in the chain have a next node
+                            continue
+
+                    if not found_new_soname:             # We're done, that last iteration found
+                        break                            # no new nodes
+
+
+    def get_object_reverse_linkings(self, object_linkings):
+        """ Return object_reverse_linkings dictionary which has structure
+
+            {
+                abi1 : { soname : [ path_to_elf1, path_to_elf2, ... ], ... },
+                abi2 : { soname : [ path_to_elf3, path_to_elf4, ... ], ... },
+                ....
+            }
+        """
+        object_reverse_linkings = {}
+
+        for abi in object_linkings:
+            for elf in object_linkings[abi]:
+                for soname in object_linkings[abi][elf]:
+                    object_reverse_linkings.setdefault(abi,{}).setdefault(soname,[]).append(elf)
+
+        return object_reverse_linkings
+
+
+    def get_maps(self):
+        """ Generate the full forward and reverse links using the above functions """
+
+        # After get_object_needed() and get_soname_needed(), both object_linkings and
+        # soname_linkings are only one step into the entire link chain.
+
+        object_linkings = self.get_object_needed()
+        ( library2soname, soname2library ) = self.get_libraries()
+        soname_linkings = self.get_soname_needed( object_linkings, library2soname )
+
+        # After the appending in expand_linkings(), forward_linkings and soname_linkings
+        # have been extended through the entire chain of linking.  expand_linkings() is
+        # a "side-effect" function, so we note it here.
+        self.expand_linkings( soname_linkings, soname2library )
+        object_reverse_linkings = self.get_object_reverse_linkings( object_linkings )
+
+        return ( object_linkings, object_reverse_linkings, library2soname, soname2library )
 
 
 def main():
@@ -167,27 +192,12 @@ def main():
         print('RUN AS ROOT: cannot read all flags')
         sys.exit(0)
 
-    object_needed = get_object_needed()
-    ( library2soname, soname2library ) = get_libraries()
-    soname_needed = get_soname_needed( object_needed, library2soname )
-
-    # After the appending to needed in expand_linkings(), forward_needed
-    # and soname_needed have been extended through the entire chain of linking.
-    # If we want to keep only the object_needed and soname_needed, then do
-    # a copy before calling expand_linkings().
-    expand_linkings( soname_needed, soname2library )
-
-    object_linkings = object_needed
-    object_needed = None
-
-    soname_linkings = soname_needed
-    soname_needed = None
-
-    object_reverse_linkings = get_object_reverse_linkings( object_linkings )
+    link_maps = LinkMap()
+    ( object_linkings, object_reverse_linkings, library2soname, soname2library ) = link_maps.get_maps()
 
     layout = "{0:<30} => {1:<30}"
 
-    """ Print out all ELF objects and the NEEDED sonames and full library paths """
+    #Print out all ELF objects and the NEEDED sonames and full library paths
     for abi in object_linkings:
         for elf in object_linkings[abi]:
             sonames = object_linkings[abi][elf]
@@ -199,7 +209,7 @@ def main():
                     print('\t%s' % layout.format(soname, '***' ))
             print('')
 
-    """ Print out all ELF objects and the NEEDED sonames and full library paths """
+    # Print out all ELF objects and the NEEDED sonames and full library paths
     for abi in object_linkings:
         for soname in object_reverse_linkings[abi]:
             try:


             reply	other threads:[~2012-12-26 21:23 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-26 21:23 Anthony G. Basile [this message]
  -- strict thread matches above, loose matches on Subject: below --
2016-02-13 21:38 [gentoo-commits] proj/elfix:master commit in: misc/ Anthony G. Basile
2014-02-13 19:07 Anthony G. Basile
2013-05-21 15:21 Anthony G. Basile
2013-02-09 21:50 Anthony G. Basile
2012-12-27  3:11 Anthony G. Basile
2012-12-26 21:43 Anthony G. Basile
2012-12-26  3:42 Anthony G. Basile
2012-12-25 14:22 Anthony G. Basile
2012-12-24 23:26 Anthony G. Basile
2012-12-24 21:44 Anthony G. Basile
2012-12-24 21:08 Anthony G. Basile
2012-12-24  2:18 Anthony G. Basile
2012-12-24  1:54 Anthony G. Basile
2012-12-23 11:51 Anthony G. Basile
2012-12-23  4:53 Anthony G. Basile
2012-12-23  3:49 Anthony G. Basile
2012-12-23  3:49 Anthony G. Basile
2012-12-23  3:49 Anthony G. Basile
2012-12-23  3:47 Anthony G. Basile
2012-12-23  2:36 Anthony G. Basile
2012-12-23  2:36 Anthony G. Basile
2012-12-23  2:34 Anthony G. Basile
2012-12-23  1:02 Anthony G. Basile
2012-12-22 14:44 Anthony G. Basile
2012-12-22  4:21 Anthony G. Basile
2012-12-22  3:58 Anthony G. Basile
2012-12-22  1:06 Anthony G. Basile
2012-12-19  3:52 Anthony G. Basile
2011-07-08  1:32 Anthony G. Basile

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1356556989.beacfc74b3af09d5a87ea60edba019a8d7f51f6a.blueness@gentoo \
    --to=blueness@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox