Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lddtree.sh: Add an "ldd-mode" for when the command is executed as *ldd #17

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions lddtree.py
Original file line number Diff line number Diff line change
Expand Up @@ -851,13 +851,18 @@ def GetParser() -> argparse.ArgumentParser:
action=_NormalizePathAction,
help="Search for all files/dependencies in ROOT",
)
group.add_argument(
"--auto-root",
action="store_true",
help="Automatically prefix input ELFs with ROOT",
)
group.add_argument(
"--no-auto-root",
dest="auto_root",
action="store_false",
default=True,
help="Do not automatically prefix input ELFs with ROOT",
help=argparse.SUPPRESS,
)
group.set_defaults(auto_root=False)
group.add_argument(
"-C",
"--cwd",
Expand Down
84 changes: 56 additions & 28 deletions lddtree.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ usage() {
-a Show all duplicated dependencies
-x Run with debugging
-R <root> Use this ROOT filesystem tree
--no-auto-root Do not automatically prefix input ELFs with ROOT
--auto-root Automatically prefix input ELFs with ROOT
-l Display output in a flat format
-h Show this help output
-V Show version information

When called as *ldd (e.g. via a symlink), the output resembles the regular
ldd command by default.
EOF
exit ${1:-0}
}
Expand Down Expand Up @@ -124,45 +127,66 @@ find_elf() {
}

show_elf() {
local elf=$1 indent=$2 parent_elfs=$3
local elf=$1 indent=$2 parent_elfs=$3 inputs=$4
local rlib lib libs
local resolved
find_elf "${elf}"
resolved=${_find_elf}
elf=${elf##*/}

${LIST} || printf "%${indent}s%s => " "" "${elf}"
if [[ ,${parent_elfs}, == *,${elf},* ]] ; then
${LIST} || printf "!!! circular loop !!!\n" ""
return
local loop=false
[[ ,${parent_elfs}, == *,${elf},* ]] && loop=true

if ${LDD_MODE} ; then
if [[ ${indent} -gt 0 ]] ; then
printf "\t%s => " "${elf}"
elif [[ ${inputs} -gt 1 ]] ; then
printf "%s:\n" "${resolved}"
fi
elif ${LIST} ; then
:
else
printf "%${indent}s%s => " "" "${elf}"
${loop} && printf "!!! circular loop !!!\n"
fi

${loop} && return
parent_elfs="${parent_elfs},${elf}"
if ${LIST} ; then
echo "${resolved:-$1}"

if ${LDD_MODE} ; then
if [[ ${indent} -gt 0 ]] ; then
printf "%s" "${resolved:-not found} (0xdeadbeef)"
fi
elif ${LIST} ; then
printf "%s" "${resolved:-$1}"
else
printf "${resolved:-not found}"
printf "%s" "${resolved:-not found}"
fi

if [[ ${indent} -eq 0 ]] ; then
local elf_specs interp full_interp
local elf_specs full_interp root_interp base_interp

elf_specs=$(elf_specs "${resolved}")
interp=$(scanelf -qF '#F%i' "${resolved}")
[[ -n ${interp} ]] && interp="${ROOT}${interp#/}"
full_interp=$(scanelf -qF '#F%i' "${resolved}")
base_interp=${full_interp##*/}
[[ -n ${full_interp} ]] && root_interp="${ROOT}${full_interp#/}"

if ${LIST} ; then
[[ -n ${interp} ]] && echo "${interp}"
# If we are in the default mode, then we want to show the "duplicate"
# interp lines -- first the header (interp=>xxx), and then the DT_NEEDED
# line to show that the ELF is directly linked against the interp.
# Otherwise, we only want to show the interp once.
if ${LDD_MODE} ; then
[[ -n ${root_interp} ]] && printf "\t%s" "${root_interp} (0xdeadbeef)"
allhits+=",${base_interp}"
elif ${LIST} ; then
[[ -n ${root_interp} ]] && printf "\n%s" "${root_interp}"
allhits+=",${base_interp}"
else
printf " (interpreter => ${interp:-none})"
printf " (interpreter => %s)" "${root_interp:-none}"
fi
full_interp=${interp}
interp=${interp##*/}
# If we are in non-list mode, then we want to show the "duplicate" interp
# lines -- first the header (interp=>xxx), and then the DT_NEEDED line to
# show that the ELF is directly linked against the interp.
# If we're in list mode though, we only want to show the interp once.
${LIST} && allhits+=",${interp}"
fi
${LIST} || printf "\n"

printf "\n"

[[ -z ${resolved} ]] && return

Expand All @@ -186,13 +210,13 @@ show_elf() {
# the ldso won't load another copy of ldso into memory from the search
# path, it'll reuse the existing copy that was loaded from the full
# hardcoded path.
if [[ ${lib} == "${interp}" ]] ; then
if [[ ${lib} == "${base_interp}" ]] ; then
rlib=${full_interp}
else
find_elf "${lib}" "${resolved}"
rlib=${_find_elf}
fi
show_elf "${rlib:-${lib}}" $((indent + 4)) "${parent_elfs}"
show_elf "${rlib:-${lib}}" $((indent + 4)) "${parent_elfs}" "${inputs}"
done
}

Expand All @@ -202,7 +226,10 @@ if [[ $1 != "/../..source.lddtree" ]] ; then
SHOW_ALL=false
SET_X=false
LIST=false
AUTO_ROOT=true
AUTO_ROOT=false
LDD_MODE=false

[[ ${argv0} = *ldd ]] && LDD_MODE=true

while getopts haxVR:l-: OPT ; do
case ${OPT} in
Expand All @@ -211,9 +238,10 @@ while getopts haxVR:l-: OPT ; do
h) usage;;
V) version;;
R) ROOT="${OPTARG%/}/";;
l) LIST=true;;
l) LIST=true LDD_MODE=false;;
-) # Long opts ftw.
case ${OPTARG} in
auto-root) AUTO_ROOT=true;;
no-auto-root) AUTO_ROOT=false;;
*) usage 1;;
esac
Expand Down Expand Up @@ -241,7 +269,7 @@ for elf ; do
else
allhits=""
[[ ${elf} != */* ]] && elf="./${elf}"
show_elf "${elf}" 0 ""
show_elf "${elf}" 0 "" $#
fi
done
exit ${ret}
Expand Down
11 changes: 9 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -116,18 +116,25 @@ executable('scanmacho',
install : true
)

install_data('lddtree.sh',
install_dir : get_option('bindir')
)
lddtree_impl = get_option('lddtree_implementation')
if lddtree_impl != 'none'
if lddtree_impl == 'python'
install_data('lddtree.py',
install_dir : get_option('bindir')
)
suffix = '.py'
else
suffix = '.sh'
endif
install_data('lddtree' + suffix,
rename : 'lddtree',
install_symlink('lddtree',
pointing_to : 'lddtree' + suffix,
install_dir : get_option('bindir')
)
endif

install_data('symtree.sh',
rename : 'symtree',
install_dir : get_option('bindir')
Expand Down