Go to main content
Oracle® Solaris 11.3 リンカーとライブラリガイド

印刷ビューの終了

更新: 2015 年 10 月
 
 

デバッグ支援

Oracle Solaris 実行時リンカーには、デバッグライブラリとデバッグを行う mdb(1) モジュールが備わっています。デバッギングライブラリを使用すると、実行時のリンクプロセスをより詳細に監視できます。mdb(1) モジュールを使用すると、プロセスのデバッグを対話形式で行うことができます。

実行時リンカーのデバッグ機能

実行時リンカーには、アプリケーションの実行時リンクとその依存関係を詳細に追跡できるデバッグ機能が備わっています。この機能によって表示される情報の種類は変更されない予定です。ただし、この情報の正確な形式は、リリースごとに若干変更される場合があります。

実行時リンカーをよく理解していないと、デバッギング出力のなかには理解できないものがある可能性があります。しかし、多くのものが一般的な関心を惹くものでしょう。

デバッグを有効にするには、環境変数 LD_DEBUG を使用します。デバッグのすべての出力の前に、処理識別子が追加されます。この環境変数は、1 つまたは複数のトークンを使用して、必要なデバッギングタイプを示す必要があります。

LD_DEBUG で使用可能なトークンを表示するには、LD_DEBUG=help を使用します。

$ LD_DEBUG=help  prog

prog は任意の動的実行可能ファイルです。制御が prog に移る前に、このプロセスはヘルプ情報を表示して終了します。実行可能ファイルの選択は重要ではありません。

デフォルトでは、すべてのデバッグ出力が標準エラー出力ファイルである stderr に送られます。output トークンを使用すると、ファイルにデバッグを出力できます。たとえば、名前が rtld-debug.txt のファイルにヘルプテキストを取り込むことができます。

$ LD_DEBUG=help,output=rtld-debug.txt  prog

また、デバッグ出力は環境変数 LD_DEBUG_OUTPUT を設定することによってリダイレクトできます。LD_DEBUG_OUTPUT が使用された場合、処理識別子が接尾辞として出力ファイル名に追加されます。

LD_DEBUG_OUTPUT と output のトークンが両方指定された場合、LD_DEBUG_OUTPUT が優先されます。LD_DEBUG_OUTPUT と output のトークンが両方指定された場合、LD_DEBUG_OUTPUT が優先されます。fork(2) を呼び出すプログラムで output トークンを使用すると、それぞれのプロセスで同じファイルにデバッグ出力を書き込むことになります。デバッグ出力は順序に規則性がなく、不完全なものになります。このような場合には、LD_DEBUG_OUTPUT を使用して、個別のファイルに各プロセスのデバッグ出力を指定してください。

セキュアなアプリケーションのデバッギングは実行できません。

実行時に発生するシンボル結合の表示機能は、もっとも有効なデバッギングオプションの 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.1bar.so.1 の検索に影響を与えます。

これと同様の方法で、各シンボルを検索する検索パスは、LD_DEBUG=symbols を設定して表示できます。symbolsbindings を組み合わせれば、シンボル再配置処理の全容を把握できます。

$ 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.1bar.so.1 です。


注 -  上の例は、デバッガモジュールの機能の基礎的な紹介になっていますが、正確なコマンド、使用方法、および出力は、リリースごとに異なる可能性があります。使用しているシステムで利用できる正確な機能については、mdb(1) の使用方法およびヘルプを参照してください。