Solaris リンカーには、デバッギングライブラリと mdb(1) モジュールが組み込まれています。デバッギングライブラリを使用すると、実行時のリンクプロセスをより詳細に監視できます。mdb(1) モジュールを使用すると、プロセスのデバッグを対話形式で行うことができます。
デバッギングライブラリは、アプリケーションと依存関係の実行を理解したり、デバッグする場合に役立ちます。このライブラリを使用して表示される情報のタイプは、定数のままであると予期されますが、この情報の正確な形式は、リリースごとにわずかに変更される場合があります。
実行時リンカーをよく理解していないと、デバッギング出力のなかには理解できないものがある可能性があります。しかし、一般的には、興味深い面が多いといえます。
デバッギングは、環境変数 LD_DEBUG
を使用して実行します。すべてのデバッギングの出力は、接頭辞としてプロセス識別子を持っていて、デフォルトごとに、標準的なエラーに対して送信されます。この環境変数は、1
つまたは複数のトークンを使用して、必要なデバッギングタイプを示す必要があります。
このデバッギングオプションとともに使用できるトークンは、LD_DEBUG=help
を使って表示できます。どの動的実行プログラムを使用しても、この情報を要求することができます。この場合、プロセス自体が終了した後でこの情報が表示されます。次に例を示します。
$ LD_DEBUG=help prog 11693: 11693: For debugging the runtime linking of an application: 11693: LD_DEBUG=token1,token2 prog 11693: enables diagnostics to the stderr. The additional 11693: option: 11693: LD_DEBUG_OUTPUT=file 11693: redirects the diagnostics to an output file created 11593: using the specified name and the process id as a 11693: suffix. All diagnostics are prepended with the 11693: process id. 11693: 11693: 11693: audit display runtime link-audit processing 11693: basic provide basic trace information/warnings 11693: bindings display symbol binding; detail flag shows 11693: absolute:relative addresses 11693: detail provide more information in conjunction with other 11693: options 11693: files display input file processing (files and libraries) 11693: help display this help message 11693: libs display library search paths 11693: move display move section processing 11693: reloc display relocation processing 11693: symbols display symbol table processing 11693: tls display TLS processing info 11693: unused display unused/unreferenced files 11693: versions display version processing |
この例では、実行時リンカーに有効なオプションを示しています。正確なオプションについては、リリースごとに異なる場合があります。
環境変数 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 foo(int data) { return (data); } $ cc -o foo.so.1 -K pic -G foo.c $ cat main.c extern int foo(); extern int bar; 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
を設定すると、実際の結合位置の実アドレスと相対アドレスに関する情報が出力されます。
実行時リンカーが、関数の再配置を実行すると、関数 .plt に関連したデータも書き換えられるため、この後に発生する呼び出しは、関数に直接送信されます。環境変数 LD_BIND_NOT
は、あらゆる値に設定されて、このデータの更新を防ぐことができます。この変数を、詳細結合に対するデバッギング要求とともに使用すると、関数結合すべての完全な実行時アカウントを入手できます。ただし、実行結果が大量に出力されることがあり、その場合、アプリケーションのパフォーマンスが低下します。
LD_DEBUG
を使用すれば、検索パスの使用状況を表示できます。たとえば、依存関係の配置に使用される検索パスのメカニズムは、次のように LD_DEBUG=libs
を設定して表示できます。
$ LD_DEBUG=libs prog 11775: 11775: find object=foo.so.1; searching 11775: search path=/tmp:. (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:. (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
を設定して表示できます。これを bindings
要求と結合すると、次のように、シンボル再配置プロセスが完全に表示されます。
$ LD_DEBUG=bindings,symbols 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) に読み込むことができる一群の dcmd および walker を提供します。デバッガモジュールを使用すると、実行時リンカーのさまざまな内部データ構造を検査できます。実行時リンカーの内部データ構造を理解するには、実行時リンカー内部に関する知識が必要であり、また、これはリリースごとに異なる可能性があります。しかし、これらの情報は、動的にリンクされたプロセスの基本的な構成要素を明らかにし、さまざまなデバッグを助けます。
次の例に、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. -ldl |
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 dcmd List - Display entries in a List dcmd ListRtmap - Display a List of Rt_Map's dcmd Lm_list - Display ld.so.1 Lm_list structure dcmd Rt_map - Display ld.so.1 Rt_map structure dcmd Rt_maps - Display list of Rt_map structures walk List - Walk a List walk Rt_maps - Walk a List of Rt_maps > ::bp main > :r |
プロセス内の動的オブジェクトは、リンクマップ Rt_map として表現され、このリンクマップは、リンクマップリスト上で管理されています。プロセスのすべてのリンクマップは、Rt_maps を使用して表示できます。
> ::Rt_maps Link-map lists (dynlm_list): 0xffbfe0d0 ---------------------------------------------- Lm_list: 0xff3f6f60 (LM_ID_BASE) ---------------------------------------------- Link-map* ADDR() NAME() ---------------------------------------------- 0xff3f9040 0x00010000 main 0xff3f9460 0xff3b0000 /lib/libdl.so.1 0xff3f977c 0xff280000 /lib/libc.so.1 ---------------------------------------------- Lm_list: 0xff3f6f88 (LM_ID_LDSO) ---------------------------------------------- 0xff3f8cc0 0xff3c0000 /lib/ld.so.1 |
個々のリンクマップは、Rt_map を使用して表示できます。
> 0xff3f9040::Rt_map Rt_map located at: 0xff3f9040 NAME: 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(3DL) が実行されるまでは、このシンボルはデバッガにとって未知であるにもかかわらず、遅延ブレークポイントを設定すると、動的オブジェクトが読み込まれたときに、実ブレークポイントが設定されます。
> ::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 Link-map* ADDR() NAME() ---------------------------------------------- 0xff3f9040 0x00010000 main 0xff3f9460 0xff3b0000 /lib/libdl.so.1 0xff3f977c 0xff280000 /lib/libc.so.1 0xff3f9ca4 0xff380000 ./foo.so.1 0xff37006c 0xff260000 ./bar.so.1 |
foo.so.1 のリンクマップは、dlopen(3DL) から返されたハンドルを示しています。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(3DL) 要求を満たすハンドルのオブジェクトを表現するリンクマップのリストです。この例では、依存関係は foo.so.1 と bar.so.1 です。
上の例は、デバッガモジュールの機能の基礎的な紹介になっていますが、正確なコマンド、使用方法、および出力は、リリースごとに異なる可能性があります。お使いのシステムで利用できる正確な機能については、それぞれのマニュアルまたはヘルプを参照してください。