Solaris OS リンカーには、デバッギングライブラリとデバッギング mdb(1) モジュールが組み込まれています。デバッギングライブラリを使用すると、実行時のリンクプロセスをより詳細に監視できます。mdb(1) モジュールを使用すると、プロセスのデバッグを対話形式で行うことができます。
デバッギングライブラリは、アプリケーションの実行と依存関係を理解したり、デバッグする場合に役立ちます。このライブラリを使用して表示される情報のタイプは、定数のままであると予期されます。ただし、この情報の正確な形式は、リリースごとに若干変更される場合があります。
実行時リンカーをよく理解していないと、デバッギング出力のなかには理解できないものがある可能性があります。しかし、多くのものが一般的な関心を惹くものでしょう。
デバッグを有効にするには、環境変数 LD_DEBUG を使用します。すべてのデバッギングの出力は、接頭辞としてプロセス識別子を持っていて、デフォルトでは、標準エラーに対して送信されます。この環境変数は、1 つまたは複数のトークンを使用して、必要なデバッギングタイプを示す必要があります。
LD_DEBUG で使用可能なトークンを表示するには、LD_DEBUG=help を使用します。どのような動的実行可能プログラムを使用しても、この情報を要求することができます。これは、情報が表示されたあとでプロセスが終了するためです。
$ LD_DEBUG=help prog ...... 11693: files display input file processing (files and libraries) ...... |
環境変数 LD_DEBUG_OUTPUT を使用すれば、標準エラーの代わりに使用する出力ファイルを指定できます。出力ファイルの名前には、接尾辞としてプロセス ID が付きます。
セキュリティー保護されたアプリケーションのデバッギングは実行できません。
実行時に発生するシンボル結合の表示機能は、もっとも有効なデバッギングオプションの 1 つです。次の例では、2 つのローカル共有オブジェクト上に依存関係を持つ、非常に単純な動的実行可能プログラムを取り上げてみます。
$ cat bar.c int bar = 10; $ cc -o bar.so.1 -K pic -G bar.c $ cat foo.c int foo(int data) { return (data); } $ cc -o foo.so.1 -K pic -G foo.c $ cat main.c extern int foo(); extern int bar; int main() { return (foo(bar)); } $ cc -o prog main.c -R/tmp:. foo.so.1 bar.so.1 |
実行時シンボル結合は、LD_DEBUG=bindings を設定することによって表示されます。
$ LD_DEBUG=bindings prog 11753: ....... 11753: binding file=prog to file=./bar.so.1: symbol bar 11753: ....... 11753: transferring control: prog 11753: ....... 11753: binding file=prog to file=./foo.so.1: symbol foo 11753: ....... |
即時再配置で必要とされるシンボル bar は、アプリケーションが制御を取得する「前」に結合されます。これに対して、遅延再配置で要求されたシンボル foo は、アプリケーションが制御を受け取った後、関数が最初に呼び出されたときに結合されます。この再配置は、遅延結合のデフォルトモードを示しています。環境変数 LD_BIND_NOW が設定されている場合、シンボル結合はすべて、アプリケーションが制御を受け取る前に実行されます。
LD_DEBUG=bindings,detail と設定すると、実際の結合位置の実アドレスと相対アドレスに関する追加情報が表示されます。
LD_DEBUG を使用すれば、検索パスの使用状況を表示できます。たとえば、依存関係の配置に使用される検索パスのメカニズムは、次のように LD_DEBUG=libs を設定して表示できます。
$ LD_DEBUG=libs prog 11775: 11775: find object=foo.so.1; searching 11775: search path=/tmp:. (RUNPATH/RPATH from file prog) 11775: trying path=/tmp/foo.so.1 11775: trying path=./foo.so.1 11775: 11775: find object=bar.so.1; searching 11775: search path=/tmp:. (RUNPATH/RPATH from file prog) 11775: trying path=/tmp/bar.so.1 11775: trying path=./bar.so.1 11775: ....... |
アプリケーション prog 内に記録された「実行パス」は、2 つの依存関係 foo.so.1 と bar.so.1 の検索に影響を与えます。
これと同様の方法で、各シンボルを検索する検索パスは、LD_DEBUG=symbols を設定して表示できます。symbols と bindings を組み合わせれば、シンボル再配置処理の全容を把握できます。
$ LD_DEBUG=bindings,symbols prog 11782: ....... 11782: symbol=bar; lookup in file=./foo.so.1 [ ELF ] 11782: symbol=bar; lookup in file=./bar.so.1 [ ELF ] 11782: binding file=prog to file=./bar.so.1: symbol bar 11782: ....... 11782: transferring control: prog 11782: ....... 11782: symbol=foo; lookup in file=prog [ ELF ] 11782: symbol=foo; lookup in file=./foo.so.1 [ ELF ] 11782: binding file=prog to file=./foo.so.1: symbol foo 11782: ....... |
上記の例では、シンボル bar は、アプリケーション prog 内では検索されません。このようにデータ参照検索が省略される原因は、コピーの再配置時に使用される最適化にあります。この再配置タイプの詳細については、「コピー再配置」を参照してください。
デバッガモジュールは、mdb(1) に読み込むことができる一群の dcmds および walkers を提供します。デバッガモジュールを使用すると、実行時リンカーのさまざまな内部データ構造を検査できます。このデバッグ情報の多くを理解するには、実行時リンカー内部に関する知識が必要です。こうした内部の情報は、リリースごとに異なる可能性があります。しかし、これらの情報は、動的にリンクされたプロセスの基本的な構成要素を明らかにし、さまざまなデバッグを助けます。
次の例に、mdb(1) とデバッガモジュールを使用したいくつかのシナリオを示します。
$ cat main.c #include <dlfnc.h> int main() { void * handle; void (* fptr)(); if ((handle = dlopen("foo.so.1", RTLD_LAZY)) == NULL) return (1); if ((fptr = (void (*)())dlsym(handle, "foo")) == NULL) return (1); (*fptr)(); return (0); } $ cc -o main main.c -R. |
mdb(1) がデバッガモジュール ld.so を自動的に読み込まなかった場合は、明示的に読み込んでください。それにより、デバッガモジュールの機能を確認できます。
$ mdb main > ::load ld.so > ::dmods -l ld.so ld.so ----------------------------------------------------------------- dcmd Bind - Display a Binding descriptor dcmd Callers - Display Rt_map CALLERS binding descriptors dcmd Depends - Display Rt_map DEPENDS binding descriptors dcmd ElfDyn - Display Elf_Dyn entry dcmd ElfEhdr - Display Elf_Ehdr entry dcmd ElfPhdr - Display Elf_Phdr entry dcmd Groups - Display Rt_map GROUPS group handles dcmd GrpDesc - Display a Group Descriptor dcmd GrpHdl - Display a Group Handle dcmd Handles - Display Rt_map HANDLES group descriptors .... > ::bp main > :r |
プロセス内の動的オブジェクトは、リンクマップ Rt_map として表現され、このリンクマップは、リンクマップリスト上で管理されています。プロセスのすべてのリンクマップは、Rt_maps を使用して表示できます。
> ::Rt_maps Link-map lists (dynlm_list): 0xffbfe0d0 ---------------------------------------------- Lm_list: 0xff3f6f60 (LM_ID_BASE) ---------------------------------------------- lmco rtmap ADDR() NAME() ---------------------------------------------- [0xc] 0xff3f0fdc 0x00010000 main [0xc] 0xff3f1394 0xff280000 /lib/libc.so.1 ---------------------------------------------- Lm_list: 0xff3f6f88 (LM_ID_LDSO) ---------------------------------------------- [0xc] 0xff3f0c78 0xff3b0000 /lib/ld.so.1 |
個々のリンクマップは、Rt_map を使用して表示できます。
> 0xff3f9040::Rt_map Rt_map located at: 0xff3f9040 NAME: main PATHNAME: /export/home/user/main ADDR: 0x00010000 DYN: 0x000207bc NEXT: 0xff3f9460 PREV: 0x00000000 FCT: 0xff3f6f18 TLSMODID: 0 INIT: 0x00010710 FINI: 0x0001071c GROUPS: 0x00000000 HANDLES: 0x00000000 DEPENDS: 0xff3f96e8 CALLERS: 0x00000000 ..... |
オブジェクトの .dynamic セクションは、ElfDyn dcmd を使用して表示できます。次の例は、最初の 4 つのエントリを表示しています。
> 0x000207bc,4::ElfDyn Elf_Dyn located at: 0x207bc 0x207bc NEEDED 0x0000010f Elf_Dyn located at: 0x207c4 0x207c4 NEEDED 0x00000124 Elf_Dyn located at: 0x207cc 0x207cc INIT 0x00010710 Elf_Dyn located at: 0x207d4 0x207d4 FINI 0x0001071c |
mdb(1) は、遅延ブレークポイントを設定するときにとても有用です。この例では、関数 foo() に対するブレークポイントが有用です。foo.so.1 に対して dlopen(3C) が実行されるまでは、このシンボルはデバッガにとって未知であるにもかかわらず、遅延ブレークポイントを設定すると、動的オブジェクトが読み込まれたときに、実ブレークポイントが設定されます。
> ::bp foo.so.1`foo > :c > mdb: You've got symbols! > mdb: stop at foo.so.1`foo mdb: target stopped at: foo.so.1`foo: save %sp, -0x68, %sp |
この時点で、新しいオブジェクトが読み込まれました。
> *ld.so`lml_main::Rt_maps lmco rtmap ADDR() NAME() ---------------------------------------------- [0xc] 0xff3f0fdc 0x00010000 main [0xc] 0xff3f1394 0xff280000 /lib/libc.so.1 [0xc] 0xff3f9ca4 0xff380000 ./foo.so.1 [0xc] 0xff37006c 0xff260000 ./bar.so.1 |
foo.so.1 のリンクマップは、dlopen(3C) から返されたハンドルを示しています。Handles を使用すると、ハンドルの構造体を展開できます。
> 0xff3f9ca4::Handles -v HANDLES for ./foo.so.1 ---------------------------------------------- HANDLE: 0xff3f9f60 Alist[used 1: total 1] ---------------------------------------------- Group Handle located at: 0xff3f9f28 ---------------------------------------------- owner: ./foo.so.1 flags: 0x00000000 [ 0 ] refcnt: 1 depends: 0xff3f9fa0 Alist[used 2: total 4] ---------------------------------------------- Group Descriptor located at: 0xff3f9fac depend: 0xff3f9ca4 ./foo.so.1 flags: 0x00000003 [ AVAIL-TO-DLSYM,ADD-DEPENDENCIES ] ---------------------------------------------- Group Descriptor located at: 0xff3f9fd8 depend: 0xff37006c ./bar.so.1 flags: 0x00000003 [ AVAIL-TO-DLSYM,ADD-DEPENDENCIES ] |
ハンドルの依存関係は、dlsym(3C) 要求を満たすハンドルのオブジェクトを表現するリンクマップのリストです。この例では、依存関係は foo.so.1 と bar.so.1 です。
上の例は、デバッガモジュールの機能の基礎的な紹介になっていますが、正確なコマンド、使用方法、および出力は、リリースごとに異なる可能性があります。お使いのシステムで利用できる正確な機能については、mdb(1) の使用方法およびヘルプを参照してください。