diff options
Diffstat (limited to 'misc/link_maps')
-rwxr-xr-x | misc/link_maps | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/misc/link_maps b/misc/link_maps new file mode 100755 index 0000000..a6adacd --- /dev/null +++ b/misc/link_maps @@ -0,0 +1,224 @@ +#!/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 +import pax + + +""" +Return object_needed dictionary which has structure + + { full_path_to_ELF_object : [ soname1, soname2, ... ], ... } + +Here the sonames were obtained from the ELF object by scanelf -nm +(like readelf -d) during emerge. +""" +def get_object_needed(): + + var_db_pkg = '/var/db/pkg' + + object_needed = {} + for cat in os.listdir(var_db_pkg): + catdir = '%s/%s' % (var_db_pkg, cat) + for pkg in os.listdir(catdir): + pkgdir = '%s/%s' % (catdir, pkg) + need = '%s/%s' % (pkgdir, 'NEEDED.ELF.2') + try: + g = open(need, 'r') + needs = g.readlines() + for line in needs: + line = line.strip() + link = re.split(';', line) + elf = link[1] + sonames = re.split(',', link[4]) + object_needed[elf] = sonames + except IOError: + continue #File probably doesn't exist, which is okay + + return object_needed + + +""" +Return library2soname dictionary which has structure + + { full_path_to_library : soname, ... } + +and its inverse which has structure + + { soname : full_path_to_library, ... } +""" +def get_libraries(): + + var_db_pkg = '/var/db/pkg' + + library2soname = {} + soname2library = {} + + for cat in os.listdir(var_db_pkg): + catdir = '%s/%s' % (var_db_pkg, cat) + for pkg in os.listdir(catdir): + pkgdir = '%s/%s' % (catdir, pkg) + need = '%s/%s' % (pkgdir, 'NEEDED.ELF.2') + try: + g = open(need, 'r') + needs = g.readlines() + for line in needs: + line = line.strip() + link = re.split(';', line) + elf = link[1] + soname = link[2] + if soname: #no soname => executable + library2soname[elf] = soname + soname2library[soname] = elf + except IOError: + continue #File probably doesn't exist, which is okay + + return ( library2soname, soname2library ) + + +""" +Return get_soname_needed dictionary which has structure: + + { soname : [ soname1, soname2, ... ], .... } + +Here the soname1, soname2,... were obtained from soname's corresponding +ELF object by scanelf -n during emerge. +""" +def get_soname_needed( object_needed, library2soname ): + + soname_needed = {} + + for elf in object_needed: + try: + soname = library2soname[elf] + soname_needed[soname] = object_needed[elf] + #soname_needed[soname] = copy(object_needed[elf]) #copy the list + except KeyError: + continue # no soname, its probably an executable + + return soname_needed + + +def get_soname_linkings( soname_needed, soname2library ): + for soname in soname_needed: + while True: + count = 0 + for s in soname_needed[soname]: + try: + for sf in soname_needed[s]: + if sf in soname_needed[soname]: # Skip it if we already included it + continue + if not sf in soname2library: #Skip if its a vdso + continue + # This appends to the object_needed and soname_needed list. + # No copy was done so its the same list in memory for both. + soname_needed[soname].append(sf) + count = 1 + except KeyError: + continue + + if count == 0: + break + return + + +def get_object_reverse_linkings( object_linkings ): + object_reverse_linkings = {} + + for elf in object_linkings: + for soname in object_linkings[elf]: + object_reverse_linkings.setdefault(soname,[]).append(elf) + + return object_reverse_linkings + + +def main(): + + # Run as root to be able to real all files + uid = os.getuid() + if uid != 0: + 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 get_soname_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 get_soname_linkings(). + get_soname_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 ) + + """ Print out all ELF objects and their PaX flags + for elf in object_needed: + try: + flags = pax.getflags(elf)[0] + if flags: + print("%s %s" % (flags, elf)) + else: + print("NONE: %s" % elf) + except pax.error: + print("CANT: %s" % elf) + + """ + + """ Print out all sonames and their library paths + for soname in sorted(soname2library): + elf = soname2library[soname] + print("%s : %s" % ( soname, elf )) + """ + + + """ Print out all ELF objects and the NEEDED sonames and full library paths + for elf in object_needed: + sonames = object_needed[elf] + print("%s" % elf) + for soname in sorted(object_needed[elf]): + try: + print("\t%s\t=> %s" % (soname, soname2library[soname])) + except KeyError: + print("\t%s\t=> ****" % soname) + print("\n\n") + """ + + """ Print out all the soname to soname NEEDED + for soname in soname_needed: + print("%s" % soname) + for s in soname_needed[soname]: + print("\t%s" % s ) + print('') + """ + + + """ Print out all the soname to soname linkings + for soname in soname_linkings: + print("%s => %s" % (soname, soname2library[soname])) + for s in soname_linkings[soname]: + if s in soname2library: + print("\t%s => %s" % (s, soname2library[s])) + else: + print("\t%s => ****" %s ) + print('') + """ + +if __name__ == '__main__': + main() |