(
    path: str,
    root: str = "/",
    prefix: str = "",
    ldpaths: Optional[Dict[str, List[str]]] = None,
    display: Optional[str] = None,
    _first: bool = True,
    _all_libs: Dict = {},
)
return ret
Parse the ELF dependency tree of the specified file

    Parameters
    ----------
    path
        The ELF to scan
    root
        The root tree to prepend to paths; this applies to interp and rpaths
        only as ``path`` and ``ldpaths`` are expected to be prefixed already
    prefix
        The path under ``root`` to search
    ldpaths
        dict containing library paths to search; should have the keys:
        conf, env, interp. If not supplied, the function ``load_ld_paths``
        will be called.
    display
        The path to show rather than ``path``
    _first
        Recursive use only; is this the first ELF?
    _all_libs
        Recursive use only; dict of all libs we've seen

    Returns
    -------
    a dict containing information about all the ELFs; e.g.
    {
      'interp': '/lib64/ld-linux.so.2',
      'needed': ['libc.so.6', 'libcurl.so.4',],
      'libs': {
        'libc.so.6': {
          'path': '/lib64/libc.so.6',
          'needed': [],
        },
        'libcurl.so.4': {
          'path': '/usr/lib64/libcurl.so.4',
          'needed': ['libc.so.6', 'librt.so.1',],
        },
      },
    }
Parse the ELF dependency tree of the specified file
Parse the ELF dependency tree of the specified file
def lddtree(
    path: str,
    root: str = "/",
    prefix: str = "",
    ldpaths: Optional[Dict[str, List[str]]] = None,
    display: Optional[str] = None,
    _first: bool = True,
    _all_libs: Dict = {},
) -> Dict:
    """Parse the ELF dependency tree of the specified file

    Parameters
    ----------
    path
        The ELF to scan
    root
        The root tree to prepend to paths; this applies to interp and rpaths
        only as ``path`` and ``ldpaths`` are expected to be prefixed already
    prefix
        The path under ``root`` to search
    ldpaths
        dict containing library paths to search; should have the keys:
        conf, env, interp. If not supplied, the function ``load_ld_paths``
        will be called.
    display
        The path to show rather than ``path``
    _first
        Recursive use only; is this the first ELF?
    _all_libs
        Recursive use only; dict of all libs we've seen

    Returns
    -------
    a dict containing information about all the ELFs; e.g.
    {
      'interp': '/lib64/ld-linux.so.2',
      'needed': ['libc.so.6', 'libcurl.so.4',],
      'libs': {
        'libc.so.6': {
          'path': '/lib64/libc.so.6',
          'needed': [],
        },
        'libcurl.so.4': {
          'path': '/usr/lib64/libcurl.so.4',
          'needed': ['libc.so.6', 'librt.so.1',],
        },
      },
    }
    """
    if not ldpaths:
        ldpaths = load_ld_paths().copy()

    if _first:
        _all_libs = {}

    ret = {
        "interp": None,
        "path": path if display is None else display,
        "realpath": path,
        "needed": [],
        "rpath": [],
        "runpath": [],
        "libs": _all_libs,
    }  # type: Dict[str, Any]

    log.debug("lddtree(%s)" % path)

    with open(path, "rb") as f:
        elf = ELFFile(f)

        # If this is the first ELF, extract the interpreter.
        if _first:
            for segment in elf.iter_segments():
                if segment.header.p_type != "PT_INTERP":
                    continue

                interp = segment.get_interp_name()
                log.debug("  interp           = %s", interp)
                ret["interp"] = normpath(root + interp)
                ret["libs"][os.path.basename(interp)] = {
                    "path": ret["interp"],
                    "realpath": readlink(ret["interp"], root, prefixed=True),
                    "needed": [],
                }
                # XXX: Should read it and scan for /lib paths.
                ldpaths["interp"] = [
                    normpath(root + os.path.dirname(interp)),
                    normpath(
                        root + prefix + "/usr" + os.path.dirname(interp).lstrip(prefix)
                    ),
                ]
                log.debug("  ldpaths[interp]  = %s", ldpaths["interp"])
                break

        # Parse the ELF's dynamic tags.
        libs = []  # type: List[str]
        rpaths = []  # type: List[str]
        runpaths = []  # type: List[str]
        for segment in elf.iter_segments():
            if segment.header.p_type != "PT_DYNAMIC":
                continue

            for t in segment.iter_tags():
                if t.entry.d_tag == "DT_RPATH":
                    rpaths = parse_ld_paths(t.rpath, path=path, root=root)
                elif t.entry.d_tag == "DT_RUNPATH":
                    runpaths = parse_ld_paths(t.runpath, path=path, root=root)
                elif t.entry.d_tag == "DT_NEEDED":
                    libs.append(t.needed)
            if runpaths:
                # If both RPATH and RUNPATH are set, only the latter is used.
                rpaths = []

            # XXX: We assume there is only one PT_DYNAMIC.  This is
            # probably fine since the runtime ldso does the same.
            break
        if _first:
            # Propagate the rpaths used by the main ELF since those will be
            # used at runtime to locate things.
            ldpaths["rpath"] = rpaths
            ldpaths["runpath"] = runpaths
            log.debug("  ldpaths[rpath]   = %s", rpaths)
            log.debug("  ldpaths[runpath] = %s", runpaths)
        ret["rpath"] = rpaths
        ret["runpath"] = runpaths
        ret["needed"] = libs

        # Search for the libs this ELF uses.
        all_ldpaths = None  # type: Optional[List[str]]
        for lib in libs:
            if lib in _all_libs:
                continue
            if all_ldpaths is None:
                all_ldpaths = (
                    ldpaths["rpath"]
                    + rpaths
                    + runpaths
                    + ldpaths["env"]
                    + ldpaths["runpath"]
                    + ldpaths["conf"]
                    + ldpaths["interp"]
                )
            realpath, fullpath = find_lib(elf, lib, all_ldpaths, root)
            _all_libs[lib] = {
                "realpath": realpath,
                "path": fullpath,
                "needed": [],
            }
            if realpath and fullpath:
                lret = lddtree(
                    realpath,
                    root,
                    prefix,
                    ldpaths,
                    display=fullpath,
                    _first=False,
                    _all_libs=_all_libs,
                )
                _all_libs[lib]["needed"] = lret["needed"]

        del elf

    return ret
def lddtree ( path : str , root : str = "/" , prefix : str = "" , ldpaths : Optional [ Dict [ str , List [ str ] ] ] = None , display : Optional [ str ] = None , _first : bool = True , _all_libs : Dict = { } , ) -> Dict : if not ldpaths : ldpaths = load_ld_paths ( ) . copy ( ) if _first : _all_libs = { } ret = { "interp" : None , "path" : path if display is None else display , "realpath" : path , "needed" : [ ] , "rpath" : [ ] , "runpath" : [ ] , "libs" : _all_libs , } # type: Dict[str, Any] log . debug ( "lddtree(%s)" % path ) with open ( path , "rb" ) as f : elf = ELFFile ( f ) # If this is the first ELF, extract the interpreter. if _first : for segment in elf . iter_segments ( ) : if segment . header . p_type != "PT_INTERP" : continue interp = segment . get_interp_name ( ) log . debug ( "  interp           = %s" , interp ) ret [ "interp" ] = normpath ( root + interp ) ret [ "libs" ] [ os . path . basename ( interp ) ] = { "path" : ret [ "interp" ] , "realpath" : readlink ( ret [ "interp" ] , root , prefixed = True ) , "needed" : [ ] , } # XXX: Should read it and scan for /lib paths. ldpaths [ "interp" ] = [ normpath ( root + os . path . dirname ( interp ) ) , normpath ( root + prefix + "/usr" + os . path . dirname ( interp ) . lstrip ( prefix ) ) , ] log . debug ( "  ldpaths[interp]  = %s" , ldpaths [ "interp" ] ) break # Parse the ELF's dynamic tags. libs = [ ] # type: List[str] rpaths = [ ] # type: List[str] runpaths = [ ] # type: List[str] for segment in elf . iter_segments ( ) : if segment . header . p_type != "PT_DYNAMIC" : continue for t in segment . iter_tags ( ) : if t . entry . d_tag == "DT_RPATH" : rpaths = parse_ld_paths ( t . rpath , path = path , root = root ) elif t . entry . d_tag == "DT_RUNPATH" : runpaths = parse_ld_paths ( t . runpath , path = path , root = root ) elif t . entry . d_tag == "DT_NEEDED" : libs . append ( t . needed ) if runpaths : # If both RPATH and RUNPATH are set, only the latter is used. rpaths = [ ] # XXX: We assume there is only one PT_DYNAMIC.  This is # probably fine since the runtime ldso does the same. break if _first : # Propagate the rpaths used by the main ELF since those will be # used at runtime to locate things. ldpaths [ "rpath" ] = rpaths ldpaths [ "runpath" ] = runpaths log . debug ( "  ldpaths[rpath]   = %s" , rpaths ) log . debug ( "  ldpaths[runpath] = %s" , runpaths ) ret [ "rpath" ] = rpaths ret [ "runpath" ] = runpaths ret [ "needed" ] = libs # Search for the libs this ELF uses. all_ldpaths = None # type: Optional[List[str]] for lib in libs : if lib in _all_libs : continue if all_ldpaths is None : all_ldpaths = ( ldpaths [ "rpath" ] + rpaths + runpaths + ldpaths [ "env" ] + ldpaths [ "runpath" ] + ldpaths [ "conf" ] + ldpaths [ "interp" ] ) realpath , fullpath = find_lib ( elf , lib , all_ldpaths , root ) _all_libs [ lib ] = { "realpath" : realpath , "path" : fullpath , "needed" : [ ] , } if realpath and fullpath : lret = lddtree ( realpath , root , prefix , ldpaths , display = fullpath , _first = False , _all_libs = _all_libs , ) _all_libs [ lib ] [ "needed" ] = lret [ "needed" ] del elf return ret