リンカーとライブラリ

デバッギングエイド

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: 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:           detail flag shows resolution and linker table addition
11693: versions  display version processing
11693: audit     display runtime link-audit processing

この例では、実行時リンカーに有効なオプションを示しています。正確なオプションについては、リリースごとに異なる場合があります。

環境変数 LD_DEBUG_OUTPUT を使用すると、出力ファイルを標準エラーの代わりに使用するように指定できます。出力ファイルの名前には、接尾辞としてプロセス ID が付きます。

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

実行時に発生するシンボル結合の表示機能は、最も有効なデバッギングオプションの 1 つです。次の例では、2 つのローカル共有オブジェクト上に依存関係を持つ、非常に単純な動的実行プログラムを取り上げてみます。


$ cat bar.c
int bar = 10;
$ cc -o bar.so.1 -Kpic -G bar.c
 
$ cat foo.c
foo(int data)
{
        return (data);
}
$ cc -o foo.so.1 -Kpic -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.1bar.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 内では検索されません。これは、コピーの再配置を処理するときに行なわれる最適化が原因です。この再配置タイプの詳細については、コピー再配置を参照してください。

デバッガモジュール

デバッガモジュールは、一群の dcmd および walker を提供し、これらのモジュールを mdb(1) に読み込んで、実行時リンカーのさまざまな内部データ構造を検査するために使用できます。実行時リンカーの内部データ構造を理解するには、実行時リンカー内部に関する知識が必要であり、また、これはリリースごとに異なる可能性があります。しかし、これらの情報は、動的にリンクされたプロセスの基本的な構成要素を明らかにし、さまざまなデバッグを助けます。

次の例では、mdb(1) とこのデバッガモジュールの使用方法に関するシナリオをいくつか紹介します。


$ cat main.c
#include  <dlfcn.h>

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 Dl_handle            - display Dl_handle structure
  dcmd Dyn                  - display Dynamic entry
  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 Permit               - display Permit structure
  dcmd Rt_map               - display ld.so.1 Rt_map structure
  dcmd Rt_maps              - display list of Rt_map structures
  walk List                 - walk List structure
  walk Rt_maps              - walk list of Rt_map structures
> ::bp main
> :r

プロセス内の動的オブジェクトは、リンクマップ Rt_map として表現され、このリンクマップは、リンクマップリスト上で管理されています。プロセスのすべてのリンクマップは、Rt_maps を使用して表示できます。


> ::Rt_maps
Objects on linkmap: <base>
    rtmap*     ADDR       NAME
    ---------------------------------------------
    0xff3b0030 0x00010000 main
    0xff3b0434 0xff3a0000 /usr/lib/libdl.so.1
    0xff3b0734 0xff280000 /usr/lib/libc.so.1
Objects on linkmap: <ld.so.1>
    rtmap*     ADDR       NAME
    ---------------------------------------------
    0xff3f7c68 0xff3c0000 /usr/lib/ld.so.1

個々のリンクマップは、Rt_map を使用して表示できます。


> 0xff3b0030::Rt_map
Rt_map located at: 0xff3b0030
    NAME: main
    ADDR: 0x00010000   DYN: 0x000209d8
    NEXT: 0xff3b0434  PREV: 0x00000000
    .....
    LIST: 0xff3f60cc [ld.so.1`lml_main]

オブジェクトの .dynamic セクションは、Dyn dcmd を使用して表示できます。次の例は、最初の 4 つのエントリを表示しています。


> 0x000209d8,4::Dyn
Dyn located at: 209d8
0x209d8  NEEDED  0x000001d7
Dyn located at: 209e0
0x209e0  NEEDED  0x000001e2
Dyn located at: 209e8
0x209e8  INIT  0x00010870
Dyn located at: 209f0
0x209f0  FINI  0x000108c0

mdb(1) は、遅延ブレークポイントを設定するときにとても有用です。次の例では、関数 foo() にブレークポイントを設定しています。 foo.so.1 に対して dlopen(3DL) が実行されるまでは、このシンボルはデバッガにとって未知であるにもかかわらず、遅延ブレークポイントを設定すると、動的オブジェクトが読み込まれたときに、実ブレークポイントが設定されます。


> ::bp foo.so.1`foo
> :r
> 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
rtmap*     ADDR       NAME
---------------------------------------------
0xff3b0030 0x00010000 main
0xff3b0434 0xff3a0000 /usr/lib/libdl.so.1
0xff3b0734 0xff280000 /usr/lib/libc.so.1
0xff3b0c1c 0xff370000 ./foo.so.1
0xff3b1030 0xff350000 ./bar.so.1

foo.so.1 のリンクマップは、dlopen(3DL) から返されたハンドルを示しています。Dl_handle を使用して、ハンドルの構造体を展開できます。


> 0xff3b0c1c::Rt_map
Rt_map located at: 0xff3b0c1c
    NAME: ./foo.so.1
    ADDR: 0xff370000   DYN: 0xff3805c8
    NEXT: 0xff3b1030  PREV: 0xff3b0734
     FCT: 0xff3f6080
  .......
  PERMIT: 0xff3b0f94 HANDLE: 0xff3b0f38

> 0xff3b0f38::Dl_handle
Dl_handle located at: ff3b0f38
   permit: 0xff3b0f7c
  usercnt:        1 permcnt:        2
  depends: 0xff3b0f44 [0xff3b0fc4, 0xff3b1358]
  parents: 0xff3b0f4c [0x00000000, 0x00000000]

ハンドルの依存関係は、dlsym(3DL) 要求を満たすハンドルのオブジェクトを表現するリンクマップのリストです。


> 0xff3b0f44::ListRtmap
Listnode   data       next       Rt_map name
---------------------------------------------
0xff3b0fc4 0xff3b0c1c 0xff3b1358 ./foo.so.1
0xff3b1358 0xff3b1030 0x00000000 ./bar.so.1

注 –

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