diff options
author | Mike Frysinger <vapier@gentoo.org> | 2007-12-31 23:33:27 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2007-12-31 23:33:27 +0000 |
commit | d1f28575d300b1f66004905ae7dbbc5720c60ba2 (patch) | |
tree | bc8b0495746e0621e4e0197372ed52fd7a720f42 /lddtree.sh | |
parent | fix another typo pointed out by fabian (diff) | |
download | pax-utils-d1f28575d300b1f66004905ae7dbbc5720c60ba2.tar.gz pax-utils-d1f28575d300b1f66004905ae7dbbc5720c60ba2.tar.bz2 pax-utils-d1f28575d300b1f66004905ae7dbbc5720c60ba2.zip |
print the ELF dependency tree as a ......... tree
Diffstat (limited to 'lddtree.sh')
-rwxr-xr-x | lddtree.sh | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/lddtree.sh b/lddtree.sh new file mode 100755 index 0000000..2281c5d --- /dev/null +++ b/lddtree.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +argv0=${0##*/} + +usage() { + cat <<-EOF + Display ELF dependencies as a tree + + Usage: ${argv0} [options] <ELF file[s]> + + Options: + -a Show all duplicated dependencies + -x Run with debugging + -h Show this help output + EOF + exit ${1:-0} +} + +SHOW_ALL=false +SET_X=false + +opts="hax" +getopt -Q -- "${opts}" "$@" || exit 1 +eval set -- $(getopt -- "${opts}" "$@") +while [[ -n $1 ]] ; do + case $1 in + -a) SHOW_ALL=true;; + -x) SET_X=true;; + -h) usage;; + --) shift; break;; + -*) usage 1;; + esac + shift +done + +${SET_X} && set -x + +ret=0 +error() { + echo "${argv0}: $*" 1>&2 + ret=1 + return 1 +} + +find_elf() { + local elf=$1 needed_by=$2 + if [[ ${elf} == */* ]] && [[ -e ${elf} ]] ; then + echo "${elf}" + return 0 + else + check_paths() { + local elf=$1 ; shift + local path + for path in "$@" ; do + if [[ -e ${path}/${elf} ]] ; then + echo "${path}/${elf}" + return 0 + fi + done + return 1 + } + check_paths "${elf}" $(scanelf -qF '#F%r' "${needed_by}") && return 0 + check_paths "${elf}" $(sed -e 's:^[[:space:]]*#.*::' /etc/ld.so.conf) && return 0 + fi + return 1 +} + +show_elf() { + local elf=$1 indent=$2 parent_elfs=$3 + local rlib lib libs + local interp resolved=$(find_elf "${elf}") + elf=${elf##*/} + + printf "%${indent}s%s => " "" "${elf}" + if [[ ,${parent_elfs}, == *,${elf},* ]] ; then + printf "!!! circular loop !!!\n" "" + return + fi + parent_elfs="${parent_elfs},${elf}" + printf "${resolved:-not found}" + if [[ ${indent} -eq 0 ]] ; then + interp=$(scanelf -qF '#F%i' "${elf}") + printf " (interpreter => ${interp:-none})" + interp=${interp##*/} + fi + printf "\n" + + [[ -z ${resolved} ]] && return + + libs=$(scanelf -qF '#F%n' "${resolved}") + + local my_allhits + if ! ${SHOW_ALL} ; then + my_allhits="${allhits}" + allhits="${allhits},${interp},${libs}" + fi + + for lib in ${libs//,/ } ; do + lib=${lib##*/} + [[ ,${my_allhits}, == *,${lib},* ]] && continue + rlib=$(find_elf "${lib}" "${resolved}") + show_elf "${rlib:-${lib}}" $((indent + 4)) "${parent_elfs}" + done +} + +for elf in "$@" ; do + if [[ ! -e ${elf} ]] ; then + error "${elf}: file does not exist" + elif [[ ! -r ${elf} ]] ; then + error "${elf}: file is not readable" + elif [[ -d ${elf} ]] ; then + error "${elf}: is a directory" + else + allhits="" + [[ ${elf} != */* ]] && elf="./${elf}" + show_elf "${elf}" 0 "" + fi +done + +exit ${ret} |