tldr;
elfutilsのaddr2lineがLDCで生成したバイナリで期待通りに動かなかった場合は -generate-arange-section
をつけると幸せになれるかもしれない(タイトルママ)
環境
$ ldc2 -version| head -1
LDC - the LLVM D compiler (1.18.0):
$ eu-addr2line --version| head -2
eu-addr2line (elfutils) 0.170
Copyright (C) 2017 The elfutils developers <http://elfutils.org/>.
あらすじ
なんの変哲もないHello, World!プログラムを用意します。
import std.stdio;
void main()
{
writeln("Hello, World!");
}
このプログラムをデバッグ情報つきでビルドしたとき、binutilsのaddr2lineではアドレスをちゃんと <ファイル名>:<行番号>
の形に変換できていますが、elfutilsだと正しく変換できていません。
$ ldc2 -g helloworld.d
$ nm helloworld| grep _Dmain
000000000001f540 T _Dmain
$ eu-addr2line -e helloworld -f 1f540
_Dmain
??:0
binutilsのaddr2lineだとうまいこといきます。
$ addr2line --demangle=dlang -e helloworld -f 1f540
D main
/home/kubo39/dev/dlang/helloworld.d:3
どうして…どうして…
これはどうもelfutilsのaddr2lineの実装としてそうなっているようです。
直接的な原因としてはeu-addr2lineは .debug_aranges
セクションがない場合はbinutilsと違いCompilation Unitsをフルスキャンしてテーブルを作成するようなフォールバックを行わないからですが、 関連すると思われるIssueチケットのコメントで
Without .debug_aranges we would have to scan all CUs to create our own aranges table by inspecting the DW_AT_low_pc/DW_AT_high_pc or DW_AT_ranges attributes.
In theory we could do that, but it is not immediately obvious when we should.
If there is no .debug_aranges at all then it might be sensible to assume this does not mean there are really no CUs that cover program scope addresses. But if there are .debug_aranges then it seems bad to assume they are wrong or incomplete.
というようにこの振る舞いは意図的なもののようです。
けっきょくどうすればいいんや
調査時点でのLDCにおいてはデバッグ情報に .debug_aranges
を含んでいないのが問題だとわかりました。
LDCはコンパイラの引数に渡ってきたオプションでフロントエンドで解釈できないものをそのままバックエンドに流すようで、 -generate-arange-section
を渡すことで解決できるようです。もちろんバックエンドのLLVMがそのオプションを受け取って適切に .debug_aranges
を生成してくれる必要がありますが。
$ ldc2 -g -generate-arange-section helloworld.d
$ eu-addr2line -e helloworld -f 1f540
_Dmain
/home/kubo39/dev/dlang/helloworld.d:3
いやこの解決方法はどうなんだ。本来はコンパイラがいい感じに生成するべきなような。