#!/usr/bin/env python3
import os
import re
from elftools.elf.elffile import ELFFile
from elftools.elf.dynamic import DynamicSection, DynamicSegment
from elftools.common.exceptions import ELFError
from elftools.common.py3compat import bytes2str

class BrokenFinder():

    def __init__(self):
        self.needed = set() # shared libraries which are needed by others or by programs
        self.found = set()  # 'shared libraries' (could also be symlinks) that we found so far

    def enumerate_shared_libs(self):
        somatching = re.compile(r""".*\.so\Z # normal shared object
        |.*\.so(\.\d+)+ # versioned shared object""", re.VERBOSE)
        for dpath, dnames, fnames in os.walk("/usr"):
            for fullname, fname in ((os.path.join(dpath, fname),fname) for fname in fnames if re.match(somatching ,fname)):
                self.found.add(fname)
                if not os.path.islink(fullname):
                    yield fullname

    def list_needed(self, sofile):
        with open(sofile, 'rb') as f:
            try:
                elffile = ELFFile(f)
                for section in elffile.iter_sections():
                    if not isinstance(section, DynamicSection):
                        continue

                    for tag in section.iter_tags():
                        if tag.entry.d_tag == 'DT_NEEDED':
                            yield bytes2str(tag.needed)
                raise StopIteration
            except ELFError:
                raise StopIteration  # not an ELF file


    def check(self):
        for solib in self.enumerate_shared_libs():
            self.needed.update(set(self.list_needed(solib)))
        print(self.needed  - self.found)

b = BrokenFinder()
b.check()

@@ -36,16 +36,53 @@
 port re%0A
+from collections import defaultdict%0A%0A
 from elf
@@ -326,97 +326,8 @@
 f):%0A
-        self.needed = set() # shared libraries which are needed by others or by programs%0A
     
@@ -416,16 +416,65 @@
 d so far
+%0A        self.lib2required_by = defaultdict(list)
 %0A%0A    de
@@ -947,19 +947,22 @@
     def 
-lis
+collec
 t_needed
@@ -1366,71 +1366,67 @@
     
-yield bytes2str(tag.needed)%0A                raise StopIteration
+self.lib2required_by%5Bbytes2str(tag.needed)%5D.append(sofile)%0A
 %0A   
@@ -1471,27 +1471,12 @@
     
-raise StopIteration
+pass
   # 
@@ -1586,91 +1586,329 @@
 elf.
-needed.update(set(self.list_needed(solib)))%0A        print(self.needed  - self.found
+collect_needed(solib)%0A        missing_libs = self.lib2required_by.keys()  - self.found%0A        if missing_libs:%0A            print(%22==The following libraries were not found%22)%0A        for missing_lib in (missing_libs):%0A            print(%22%7B%7D required by: %7B%7D%22.format(missing_lib, ', '.join(self.lib2required_by%5Bmissing_lib%5D))
 )%0A%0Ab

store which library requires a specific lib