このあたりで質問した内容。修正がコミットされて解決した。
Userland DTrace のコンパイル時の処理
Userland DTrace では、USDT provider(ユーザレベル静的定義トレースプロバイダ)を定義する際に、プローブをC言語のヘッダファイルとして生成する機能がある。プローブ定義はD言語で次のような書式を使って記述する。
provider sample {
probe first__read(int, char *);
probe debuglog(char *);
};
これをfoo.dというファイルに置いてdtrace -h -s foo.dとすると、次のようなマクロ定義が含まれるfoo.hというファイルができる。
#define SAMPLE_FIRST_READ(arg0, arg1) \
__dtrace_sample___first__read(arg0, arg1)
#define SAMPLE_DEBUGLOG(arg0) \
__dtrace_sample___debuglog(arg0)
プログラムではこのfoo.hをインクルードして、プローブを置きたいところにマクロを記述する。関数呼出だが、DTraceを有効にしなければnop命令に書き換えられるので、性能への影響は小さい。
これらの関数は当然ながら対象プログラムに含まれていない。そのため、対象プログラムのオブジェクトファイル(ここではsample.oとする)ができた後に、次のように-Gオプションをつけてdtraceコマンドを実行することで生成する。
% dtrace -G -o foo.o -s foo.d sample.o
foo.oには、foo.dで定義されたシンボルの実体が入っている。したがって、最後にすべてをリンクすればUserland DTraceに対応したバイナリができあがる。
シンボル置換
foo.dで定義したfirst_readというプローブは名前に二重下線が含まれているが、実際のプローブ名はfirst-readのようにハイフンに置き換えられる。この処理は、dtrace -Gコマンドがオブジェクトファイルの中のシンボルテーブルを直接書き換えて実現している。
% nm sample.o
U __dtrace_sample___first__read
U __stack_chk_fail
U __stack_chk_guard
0000000000000000 T main
U read
% dtrace -C -x nolibs -G -o foo.o -s foo.d sample.o
% nm sample.o
U __dtrace_sample___first-read
U __stack_chk_fail
U __stack_chk_guard
0000000000000000 T main
U ead
プログラムのオブジェクトファイルにある最初の__dtrace_sample__first__readというシンボルが、dtrace -Gコマンドの後に置き換わっているのが分かる。
DTraceのプローブを定義しながら開発を進めていたところ、時々プログラムのリンク時にエラーが出るようになった。先ほどの実行例を良くみると、置き換え後の read のシンボルの頭が 1 文字欠けているのが分かると思う。プローブの名前にも read があるので、これは置き換えの処理がおかしいのでは、というところまであたりをつけたところで、冒頭の質問メールを出してみた。
するとIllumos-gate のバグ報告6653で報告されているものと同一の症状のようだ。原因は次のとおりである。
- シンボルテーブルはテーブルのオフセットが記録されているが、個々のシンボルがテーブル内でユニークな領域を占める保証はない。つまり
"first-read"というシンボルと"read"というシンボルは、同じ部分文字列を含む可能性がある。
ELFのシンボルテーブルを生成するツールによっては文字列の重複部分を最適化するようだ。__ を長さの違う - に置換するため、オフセットがずれてreadの頭一文字が欠けてしまう。レポートには binutils の gas 2.26 以降で発生するとある。dtrace -Gの前にobjcopyを実行してsample.oをコピーすると、症状が出なかった。
そもそもシンボルテーブルを書き換えるのではなくて、シンボルのルックアップ時に__を-に置き換えるべきなのでは、というもっともな指摘もあり、FreeBSDにはこういう修正がcommitされた。FreeBSD 10 系はそもそも問題が発生するシンボルテーブルを生成しないので影響はない。
Userland DTraceは使っているひとが少ないのか、不具合がまだまだあるようだ。