🐩

llvm-dwarfdump コマンドの使い方メモ

2021/05/15に公開

はじめに

最近デバッガについて少し理解したいと思っています。
今回はllvm-dwarfdumpコマンドの使い方について記載をします。

DWARF

DWARFとはデバッグ用データフォーマットの規格のこと。
公式サイトは以下。
http://dwarfstd.org/

llvm-dwarfdump

llvm-dwarfdump
DWARFの情報をダンプするツールです。
当然ですが、ダンプするバイナリにDWARFの情報がないといけません。

サンプルとして以下のようなコードを用意します。

sample001.c
#include <stdio.h>

int main(void){
    printf("hello\n");
    return 0;
}

clangで以下のようにコンパイルします。
ポイントは-gオプションを付けて、デバッグ情報を付加することです。
-gdwarf-5についてはDWARFのバージョンを指定することができます。
(-gdwarf-5でVer5。Ver5が最新のようです)
-gembed-sourceについてはよくわかりません。
DWARF内にコードの内容を埋め込むことができるのでしょうか。
公式のドキュメントはこちら

$ clang -g -gdwarf-5 -gembed-source -o sample001 sample001.c 

llvm-dwarfdumpで情報を表示します。
-aオプションですべての情報を出力します。

$ llvm-dwarfdump -a sample001

今回は出力結果の以下の部分について説明をします。
llvm-dwarfdumpの出力結果の内容に以下のようなものが出力されます。

$ llvm-dwarfdump -a sample001
<省略>
file_names[  0]:
           name: "sample001.c"
      dir_index: 0
   md5_checksum: f2c9e6c49dc46644f6dbcdb88625f856
         source: "#include <stdio.h>\n\nint main(void){\n    printf(\"hello\\n\");\n    return 0;\n}\n"

Address            Line   Column File   ISA Discriminator Flags
------------------ ------ ------ ------ --- ------------- -------------
0x0000000000401130      3      0      0   0             0  is_stmt
0x000000000040113f      4      5      0   0             0  is_stmt prologue_end
0x0000000000401150      5      5      0   0             0  is_stmt
0x0000000000401158      5      5      0   0             0  is_stmt end_sequence
<省略>

ここに記載されているAddress(0x0000000000401130, 0x000000000040113f,
0x0000000000401150, 0x0000000000401158)がなにかというと
コンパイル後の命令が置かれるアドレスになります。
llvm-objdumpコマンドで確認をしてみます。
以下の★箇所を見ると上記llvm-dwarfdumpで出力されたアドレスと一致しています。

$ llvm-objdump -d -S sample001 | grep -A 20 main
0000000000401130 <main>:
; int main(void){
  401130★: 55                            pushq   %rbp
  401131: 48 89 e5                      movq    %rsp, %rbp
  401134: 48 83 ec 10                   subq    $16, %rsp
  401138: c7 45 fc 00 00 00 00          movl    $0, -4(%rbp)
;     printf("hello\n");
  40113f★: 48 bf 04 20 40 00 00 00 00 00 movabsq $4202500, %rdi
  401149: b0 00                         movb    $0, %al
  40114b: e8 e0 fe ff ff                callq   0x401030 <printf@plt>
;     return 0;
  401150★: 31 c0                         xorl    %eax, %eax
  401152: 48 83 c4 10                   addq    $16, %rsp
  401156: 5d                            popq    %rbp
  401157: c3                            retq
  401158★: 0f 1f 84 00 00 00 00 00       nopl    (%rax,%rax)

ここで、もう一度llvm-dwarfdumpの結果を確認します。

$ llvm-dwarfdump -a sample001
<省略>
Address            Line   Column File   ISA Discriminator Flags
------------------ ------ ------ ------ --- ------------- -------------
0x0000000000401130      3      0      0   0             0  is_stmt
0x000000000040113f      4      5      0   0             0  is_stmt prologue_end
0x0000000000401150      5      5      0   0             0  is_stmt
0x0000000000401158      5      5      0   0             0  is_stmt end_sequence
<省略>

二列目のLineについてはコードの行数になります。
最初に例として書いたコードをもう一度記載します(コメントに行数を書いています。)

sample001.c
#include <stdio.h>     // 1
                       // 2
int main(void){        // 3
    printf("hello\n"); // 4
    return 0;          // 5
}                      // 6

もう一度 llvm-dwarfdumpの出力を確認します。
今度はコード部の箇所に★とコード上の行数を記載しました。

$ llvm-objdump -d -S sample001 | grep -A 20 main
0000000000401130 <main>:
; int main(void){★ // 3
  401130: 55                            pushq   %rbp
  401131: 48 89 e5                      movq    %rsp, %rbp
  401134: 48 83 ec 10                   subq    $16, %rsp
  401138: c7 45 fc 00 00 00 00          movl    $0, -4(%rbp)
;     printf("hello\n");★ // 4
  40113f: 48 bf 04 20 40 00 00 00 00 00 movabsq $4202500, %rdi
  401149: b0 00                         movb    $0, %al
  40114b: e8 e0 fe ff ff                callq   0x401030 <printf@plt>
;     return 0;★ // 5
  401150: 31 c0                         xorl    %eax, %eax
  401152: 48 83 c4 10                   addq    $16, %rsp
  401156: 5d                            popq    %rbp
  401157: c3                            retq
  401158: 0f 1f 84 00 00 00 00 00       nopl    (%rax,%rax)

llvm-objdumpの出力とllvm-dwarfdumpの情報が一致していることがわかりました。

まとめ

デバッガで、指定した行でブレークポイントを設定する、ということを
やりますが、そのときは今回書いたDWARFの情報(llvm-dwarfdumpで出力された情報)を
使用しているのでしょう(きっと)。

関連

https://zenn.dev/saitoyutaka/articles/817e0f44c858bc

Discussion