aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2007-12-31 23:33:27 +0000
committerMike Frysinger <vapier@gentoo.org>2007-12-31 23:33:27 +0000
commitd1f28575d300b1f66004905ae7dbbc5720c60ba2 (patch)
treebc8b0495746e0621e4e0197372ed52fd7a720f42 /lddtree.sh
parentfix another typo pointed out by fabian (diff)
downloadpax-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-xlddtree.sh120
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}