Libtree: ライブラリが発見されるかどうかをツリー形式で説明する `ldd`
(github.com/haampie)- libtree は、
lddの出力をツリーに変換し、共有ライブラリがどのように発見されたのか、またはなぜ見つからないのかを説明するツール - デフォルトの出力では一部の 標準依存関係 を隠し、
-v、-vv、-vvvで隠されたライブラリや既に出会ったライブラリの依存関係まで段階的に確認できる --pathまたは-pは soname の代わりに パス を表示し、--max-depthで再帰探索の深さを制限できる- インストールは v3.1.1 の事前ビルド済みバイナリ、Fedora/RHEL/CentOS、Ubuntu 22.04+、GNU Guix から可能
- ソースからのビルドには C99 を理解する C コンパイラが必要で、
make使用時はLDFLAGS=-staticが推奨される
libtree がすること
- libtree は
lddをツリー形式に変換するツール - 共有ライブラリが どのように発見されるか、またはなぜ場所を見つけられないのかを説明する
- README には
doc/screenshot.pngのスクリーンショットが含まれている
出力オプション
- デフォルトの出力では一部の 標準依存関係 は表示されない
- より詳細な出力は verbosity オプションで制御する
libtree -v: デフォルトでスキップされるライブラリを表示するlibtree -vv: デフォルトでスキップされるライブラリの依存関係も表示するlibtree -vvv: 既に出会ったライブラリの依存関係も表示する
--pathまたは-pフラグは soname の代わりに パス を表示する- 例:
libtree -p $(which tar)
- 例:
--max-depthは再帰の深さを制限する
インストール方法
- Prebuilt binaries for v3.1.1: Linux 向けの事前ビルド済みバイナリを提供
- Fedora / RHEL / CentOS では
dnfでインストールする- RHEL および派生ディストリビューションでは、先に
epel-releaseを有効化する dnf install libtree-ldd
- RHEL および派生ディストリビューションでは、先に
- Ubuntu 22.04+ では
apt-get install libtreeでインストールする - GNU Guix では
guix install libtreeでインストールする - Older release v2.0.0 も提供されている
ソースからビルド
libtreeには C99 を理解する C コンパイラが必要- 基本的なビルド手順は、リポジトリをクローンしてから
makeを実行する方法git clone https://github.com/haampie/libtree.gitcd libtreemake
make使用時はLDFLAGS=-staticが推奨される- README には、
curlでlibtree.cを取得してコンパイルする unsafe quick install コマンドも別の折りたたみセクションとして用意されている
2件のコメント
Hacker News の意見
このツールも、
lddが検査対象ライブラリの一部を実際に実行してしまうという予想外の動作をそのまま踏襲しているのだろうか?https://catonmat.net/ldd-arbitrary-code-execution
lddは対象バイナリを実行しない参考: https://manpages.debian.org/unstable/manpages/ldd.1.en.html#...
実際には ELF ファイルを直接パースし、依存関係も再帰的にパースしているようで、なかなか良い
objdumpを使うと、ELF ファイルにエンコードされているそのままのデータを出力してくれるvdso が検索するライブラリ一覧まで含まれる
似たツールとして lddtree がある
https://github.com/gentoo/pax-utils/tree/master
lddで欠けている依存関係を再帰的に追い続けるのはかなり退屈なのでこれは良い改善に見えるし、次に曖昧な
not foundに出会ったら使ってみるつもり基本的には Linux CLI 版の depends.exe みたいなもの
代わりに https://github.com/lucasg/Dependencies を使うほうがよい。これも完全に最新というわけではないが……
Visual Studio をインストールしていて、インストーラーで
x64/x86 build tools (latest)を選んでいるなら、VS Developer Command Prompt でdumpbin /dependentsを実行するのが今でも最も信頼できる選択肢[1] https://www.dependencywalker.com/
色が何を意味するのか気になる人のために書いておくと、manpage/README では見つけられなかった
マゼンタ: 除外リストに入っており、
-v[v[v]]の場合だけ表示される青: 以前に見た項目なので、複数回出てくる依存関係を見つけられる
「ライブラリが見つかる、または見つからない理由」とはどういう意味?
LD_LIBRARY_PATHにあるかないかのどちらかでは?スクリーンショットだけでは、これが何を指しているのかよく分からない
システムの検索パス、runpath、rpath、
LD_LIBRARY_PATHなど、異なるディレクトリ検索方法がいくつもあるライブラリは普通
foo.soのような短い名前でリンクされるが、ライブラリのフルパスで動的リンクされることもある付け加えると、一般に
LD_LIBRARY_PATHの設定は避けられるなら避けたほうがずっとよい。常に可能とは限らないが、設定するとすべての実行で検索優先順位の最上位に来る。何かがライブラリのフルパスで動的リンクされていてもLD_LIBRARY_PATHが優先され、検索方法を完全に平坦化してしまうLD_LIBRARY_PATH内にある必要はないタイトルの要点は、libtree が実行ファイルからすべての直接・間接依存関係へ続くパスを簡単に見つけられるようにする、ということ。その用途の一つが、欠けている依存関係の問題を把握する助けになること
実際にパッケージシステムを使っているなら依存関係が欠けることはあまりないはずなので、libtree は別の理由で使う可能性が高い
LD_LIBRARY_PATHにあるかないかだけではなく、各ライブラリごとにロード時に評価される RPATH もあるより大きなポイントは、依存関係がグラフを成し、それを木のように表示できるということ。どのライブラリを必要としたライブラリのせいで特定のライブラリが見つからなかったのかを知るのは有用
LD_LIBRARY_PATHだけでライブラリを探すわけではない。ローダーはライブラリを見つけるために、ほかにも複数の情報源を考慮する通常の設定なら、ロードされる各バイナリの一般的な ELF フィールドと、ローダーが知っている他のパスの組み合わせになる
同じライブラリの複数バージョンや同名の複数ライブラリがあるシステムで
LD_LIBRARY_PATHに依存するのは、かなり近視眼的になりうる。ローダーは各バイナリについてLD_LIBRARY_PATHのパスを順番に検索し、最初に一致したライブラリを選ぶ。別の方法でより高い優先順位のパスを設定していなければ、そのライブラリが実際に望んでいるものではない可能性があり、実行時に予期しないエラーにつながりうるより良い方法は、そのバイナリが必要とするライブラリの場所を指すように RPATH を設定すること
環境と RPATH 設定が一貫していないと、同じライブラリの複数バージョンを同時にロードすることもある。このツールは問題があるか、そしてなぜそうなのかを把握する助けになる
LD_LIBRARY_PATHがあるこのツールは
lddベースなので、おそらくDYLD_LIBRARY_PATH、DYLD_FALLBACK_FRAMEWORK_PATH、DYLD_FALLBACK_LIBRARY_PATH、@executable_path、@loader_path、@rpathも解釈するはず本当に便利。普段は実際の要件が何なのかを把握しようとして、
readelfでセクションを読んでいるLD_DEBUG=libsでは足りない?バグかどうかは分からないが、vim の例では
lddと libtree が互いに異なるライブラリを示しているたとえば
linux-vdso.so.1はlddではリストの一番上に出てくるが、libtree にはまったく出てこないlinux-vdso.so.1はファイルシステムのどこかで見つけられる実体のあるライブラリではなく、ELF ファイル内でも参照されていないため、libtree には分からない代わりに、新しく開始したプロセスのアドレス空間へカーネルが自動的にマッピングする。
gettimeofdayのような関数でシステムコールのオーバーヘッドを避けるための最適化機能。参考: https://man7.org/linux/man-pages/man7/vdso.7.htmlNixOS でクローズドソースのバイナリを実行するために何を含めるべきか調べようとして、
lddを再帰的に回す雑な小さなスクリプトを作ったことがあるまたそういうことをすることになったら、このツールを試してみるつもり
良さそうですね!!