このあたりで質問した内容。修正がコミットされて解決した。
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は使っているひとが少ないのか、不具合がまだまだあるようだ。