From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id 3EE5A1381FB for ; Wed, 26 Dec 2012 21:23:34 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 44DFD21C007; Wed, 26 Dec 2012 21:23:25 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id A923121C007 for ; Wed, 26 Dec 2012 21:23:24 +0000 (UTC) Received: from hornbill.gentoo.org (hornbill.gentoo.org [94.100.119.163]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 93F9333D790 for ; Wed, 26 Dec 2012 21:23:23 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by hornbill.gentoo.org (Postfix) with ESMTP id 33650E543D for ; Wed, 26 Dec 2012 21:23:22 +0000 (UTC) From: "Anthony G. Basile" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Anthony G. Basile" Message-ID: <1356556989.beacfc74b3af09d5a87ea60edba019a8d7f51f6a.blueness@gentoo> Subject: [gentoo-commits] proj/elfix:master commit in: misc/ X-VCS-Repository: proj/elfix X-VCS-Files: misc/link_maps X-VCS-Directories: misc/ X-VCS-Committer: blueness X-VCS-Committer-Name: Anthony G. Basile X-VCS-Revision: beacfc74b3af09d5a87ea60edba019a8d7f51f6a X-VCS-Branch: master Date: Wed, 26 Dec 2012 21:23:22 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 7ab171c3-9f4f-4c1a-9e25-dce4117871a4 X-Archives-Hash: 3f07311a9f875a831e9164c1896f6b3c commit: beacfc74b3af09d5a87ea60edba019a8d7f51f6a Author: Anthony G. Basile gentoo org> AuthorDate: Wed Dec 26 21:23:09 2012 +0000 Commit: Anthony G. Basile gentoo 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: