aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2012-12-26 16:23:09 -0500
committerAnthony G. Basile <blueness@gentoo.org>2012-12-28 20:08:32 -0500
commitf906a7db7093a4c50d4f3620ce88bca816180efe (patch)
tree442212b7c9c39a1d317be6058f94a64a9c1293b4
parentmisc/link_maps: refactorize indentation (diff)
downloadelfix-f906a7db7093a4c50d4f3620ce88bca816180efe.tar.gz
elfix-f906a7db7093a4c50d4f3620ce88bca816180efe.tar.bz2
elfix-f906a7db7093a4c50d4f3620ce88bca816180efe.zip
misc/link_maps: encapsulate all logic in class LinkMap
-rwxr-xr-xmisc/link_maps302
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: