llvm-symbolizer - アドレスをソースコードの場所へ変換する

概要

llvm-symbolizer [オプション] [アドレス…]

説明

llvm-symbolizer はコマンドラインから入力名とアドレスを読み取り、対応するソースコードの場所を標準出力に出力します。また、シンボライザーマークアップを含むログを --filter-markup を介してシンボル化することもできます。アドレスは数値またはシンボル名として指定できます。

コマンドラインでアドレスが指定されていない場合、標準入力からアドレスを読み取ります。コマンドラインで入力名が指定されていないがアドレスが指定されている場合は、最初のアドレス値が入力名として扱われます。入力値が認識されない場合は、ソース情報が見つからないことが報告されます。

入力名は、標準入力またはコマンドライン上の位置引数としてアドレスとともに指定できます。デフォルトでは、入力名はオブジェクトファイルのパスとして解釈されます。ただし、名前の先頭に BUILDID: を付けると、パスではなく 16 進数のビルド ID であることを示します。これにより、対応するデバッグバイナリが検索されます。整合性を保つために、名前の先頭に FILE: を付けると、オブジェクトファイルのパスであることが明示的に示されます(デフォルト)。

位置引数または標準入力の値の前に "DATA" または "CODE" を付けると、アドレスをそれぞれデータまたは実行可能コードとしてシンボル化する必要があることを示します。どちらも指定しない場合は、"CODE" が想定されます。DATA は行番号ではなくアドレスとシンボルサイズとしてシンボル化されます。

llvm-symbolizer は、コマンドラインからオプションを解析した後、環境変数 LLVM_SYMBOLIZER_OPTS からオプションを解析します。LLVM_SYMBOLIZER_OPTS は、主に llvm-symbolizer が別のプログラムまたはランタイムによって呼び出される場合に、コマンドラインオプションを補完するのに役立ちます。

次のすべての例では、次の 2 つのソースファイルを入力として使用します。これらの名前がどのように異なる方法で出力されるかを示すために、C スタイルと C++ スタイルのリンケージを組み合わせて使用します(--demangle を参照)。

// test.h
extern "C" inline int foz() {
  return 1234;
}
// test.cpp
#include "test.h"
int bar=42;

int foo() {
  return bar;
}

int baz() {
  volatile int k = 42;
  return foz() + k;
}

int main() {
  return foo() + baz();
}

これらのファイルは次のようにビルドされます

$ clang -g test.cpp -o test.elf
$ clang -g -O2 test.cpp -o inlined.elf

例 1 - コマンドライン上のアドレスとオブジェクト

$ llvm-symbolizer --obj=test.elf 0x4004d0 0x400490
foz
/tmp/test.h:1:0

baz()
/tmp/test.cpp:11:0

例 2 - 標準入力のアドレス

$ cat addr.txt
0x4004a0
0x400490
0x4004d0
$ llvm-symbolizer --obj=test.elf < addr.txt
main
/tmp/test.cpp:15:0

baz()
/tmp/test.cpp:11:0

foz
/tmp/./test.h:1:0

例 3 - アドレス付きで指定されたオブジェクト

$ llvm-symbolizer "test.elf 0x400490" "FILE:inlined.elf 0x400480"
baz()
/tmp/test.cpp:11:0

foo()
/tmp/test.cpp:8:10

$ cat addr2.txt
FILE:test.elf 0x4004a0
inlined.elf 0x400480

$ llvm-symbolizer < addr2.txt
main
/tmp/test.cpp:15:0

foo()
/tmp/test.cpp:8:10

例 4 - BUILDID および FILE プレフィックス

$ llvm-symbolizer "FILE:test.elf 0x400490" "DATA BUILDID:123456789abcdef 0x601028"
baz()
/tmp/test.cpp:11:0

bar
6295592 4

$ cat addr3.txt
FILE:test.elf 0x400490
DATA BUILDID:123456789abcdef 0x601028

$ llvm-symbolizer < addr3.txt
baz()
/tmp/test.cpp:11:0

bar
6295592 4

例 5 - CODE および DATA プレフィックス

$ llvm-symbolizer --obj=test.elf "CODE 0x400490" "DATA 0x601028"
baz()
/tmp/test.cpp:11:0

bar
6295592 4

$ cat addr4.txt
CODE test.elf 0x4004a0
DATA inlined.elf 0x601028

$ llvm-symbolizer < addr4.txt
main
/tmp/test.cpp:15:0

bar
6295592 4

例 6 - パス形式のオプション

この例では、上記と同じソースファイルを使用しますが、ソースファイルのフルパスは /tmp/foo/test.cpp であり、次のようにコンパイルされます。最初のケースはデフォルトの絶対パス、2 番目のケースは –basenames、3 番目のケースは –relativenames を示しています。

$ pwd
/tmp
$ clang -g foo/test.cpp -o test.elf
$ llvm-symbolizer --obj=test.elf 0x4004a0
main
/tmp/foo/test.cpp:15:0
$ llvm-symbolizer --obj=test.elf 0x4004a0 --basenames
main
test.cpp:15:0
$ llvm-symbolizer --obj=test.elf 0x4004a0 --relativenames
main
foo/test.cpp:15:0

例 7 - シンボル名としてのアドレス

$ llvm-symbolizer --obj=test.elf main
main
/tmp/test.cpp:14:0
$ llvm-symbolizer --obj=test.elf "CODE foz"
foz
/tmp/test.h:1:0

例 8 - 行対応がないアドレス(行 0 に関連付けられたアドレス)に対する --skip-line-zero 出力

// test.c
int foo = 0;
int x = 1234;
int main() {
  if (x)
    return foo;
  else
    return x;
}

これらのファイルは次のようにビルドされます

$ clang -g -O2 -S test.c -o test.s
$ llvm-mc -filetype=obj -triple=x86_64-unknown-linux  test.s -o test.o
$ llvm-symbolizer --obj=test.o --skip-line-zero 0xa
main
/tmp/test.c:5:7 (approximate)

オプション

--adjust-vma <offset>

ルックアップを実行するときに、指定されたオフセットをオブジェクトファイルのアドレスに追加します。これは、オブジェクトがオフセットによって再配置されたかのようにルックアップを実行するために使用できます。

--skip-line-zero

アドレスに関連付けられた行番号がない場合は、ラインテーブルの現在のシーケンスから最後の行番号を使用します。このような行は、誤解を招く可能性があるため、出力では「概算」とラベル付けされます。

--basenames, -s

絶対パスではなく、ディレクトリを含まないファイル名のみを出力します。

--build-id

16 進数文字列として指定された、指定されたビルド ID を使用してオブジェクトを検索します。--obj とは相互に排他的です。

--color [=<always|auto|never>]

--filter-markup モードで色を使用するかどうかを指定します。デフォルトは auto で、標準出力が色をサポートしているかどうかを検出します。--color 単独で指定することは --color=always と同等です。

--debug-file-directory <path>

ストリップされたバイナリのデバッグ情報を検索するために、.build-id サブディレクトリを含むディレクトリへのパスを指定します。この引数の複数のインスタンスは、指定された順序で検索されます。

--debuginfod, --no-debuginfod

デバッグバイナリの debuginfod ルックアップを試行するかどうか。特に指定がない限り、debuginfod は libcurl がコンパイルされている場合(LLVM_ENABLE_CURL)および環境変数 DEBUGINFOD_URLS によって少なくとも 1 つのサーバー URL が提供されている場合にのみ有効になります。

--demangle, -C

名前がマングルされている場合は、デマングルされた関数名を出力します(例:マングルされた名前 _Z3bazvbaz() になり、マングルされていない名前 foz はそのまま出力されます)。デフォルトは true です。

--dwp <path>

分割された DWARF デバッグデータを持つ CU については、<path> にある指定された DWP ファイルを使用します。

--fallback-debug-path <path>

別のファイルにデバッグデータが含まれており、GNU デバッグリンクセクションによって参照されている場合、オブジェクトに対する相対的な位置が見つからない場合は、指定されたパスをデバッグデータの検索の基礎として使用します。

--filter-markup

標準入力から読み取り、含まれている シンボライザーマークアップ を人間が読める形式に変換し、結果を標準出力に出力します。次のマークアップ要素はまだサポートされていません

  • {{{hexdict}}}

  • {{{dumpfile}}}

{{{bt}}} バックトレース要素は、次の構文を使用してフレームをレポートします

#<number>[.<inline>] <address> <function> <file>:<line>:<col> (<module>+<relative address>)

<inline> は、<number> に対応する呼び出し元にインライン化された呼び出しのフレーム番号を提供します。インライン化された呼び出し番号は 1 から始まり、呼び出し先から呼び出し元に向かって増加します。

<address> は、関数呼び出し命令内のアドレスです。このアドレスは命令の先頭であるとは限りません。<relative address> は、そのアドレスにロードされた <module> 内の対応する仮想オフセットです。

--functions [=<none|short|linkage>], -f

関数名の表示方法を指定します(関数名を省略、短い関数名を表示、または完全なリンケージ名を表示)。デフォルトは linkage です。

--help, -h

このコマンドのヘルプと使用法を表示します。

--inlining, --inlines, -i

ソースコードの場所がインライン関数内にある場合、すべてのインラインフレームを表示します。これはデフォルトです。

--no-inlines

インラインフレームを表示しません。

--no-demangle

デマングルされた関数名を表示しません。

--obj <path>, --exe, -e

シンボル化するオブジェクトファイルへのパス。 - が指定された場合、オブジェクトを標準入力ストリームから直接読み込みます。 --build-id とは相互に排他的です。

--output-style <LLVM|GNU|JSON>

優先する出力スタイルを指定します。デフォルトは LLVM です。出力スタイルが GNU に設定されている場合、ツールは GNU の addr2line のスタイルに従います。 LLVM スタイルとの違いは次のとおりです。

  • ソースコードの場所の列を表示しません。

  • アドレスのレポートの後に空行を追加しません。

  • インラインフレームが表示されない場合、インライン関数の名前を最上位の呼び出し元の名前に置き換えません。

  • アドレスのデバッグデータ識別子がゼロでない場合に表示します。識別子を生成する 1 つの方法は、clang の -fdebug-info-for-profiling でコンパイルすることです。

JSON スタイルは、JSON で機械可読な出力を提供します。アドレスが

標準入力経由で提供される場合、出力 JSON は個々のオブジェクトのシーケンスになります。それ以外の場合、すべての結果は単一の配列に含まれます。

$ llvm-symbolizer --obj=inlined.elf 0x4004be 0x400486 -p
baz() at /tmp/test.cpp:11:18
 (inlined by) main at /tmp/test.cpp:15:0

foo() at /tmp/test.cpp:6:3

$ llvm-symbolizer --output-style=LLVM --obj=inlined.elf 0x4004be 0x400486 -p --no-inlines
main at /tmp/test.cpp:11:18

foo() at /tmp/test.cpp:6:3

$ llvm-symbolizer --output-style=GNU --obj=inlined.elf 0x4004be 0x400486 -p --no-inlines
baz() at /tmp/test.cpp:11
foo() at /tmp/test.cpp:6

$ clang -g -fdebug-info-for-profiling test.cpp -o profiling.elf
$ llvm-symbolizer --output-style=GNU --obj=profiling.elf 0x401167 -p --no-inlines
main at /tmp/test.cpp:15 (discriminator 2)

$ llvm-symbolizer --output-style=JSON --obj=inlined.elf 0x4004be 0x400486 -p
[
  {
    "Address": "0x4004be",
    "ModuleName": "inlined.elf",
    "Symbol": [
      {
        "Column": 18,
        "Discriminator": 0,
        "FileName": "/tmp/test.cpp",
        "FunctionName": "baz()",
        "Line": 11,
        "StartAddress": "0x4004be",
        "StartFileName": "/tmp/test.cpp",
        "StartLine": 9
      },
      {
        "Column": 0,
        "Discriminator": 0,
        "FileName": "/tmp/test.cpp",
        "FunctionName": "main",
        "Line": 15,
        "StartAddress": "0x4004be",
        "StartFileName": "/tmp/test.cpp",
        "StartLine": 14
      }
    ]
  },
  {
    "Address": "0x400486",
    "ModuleName": "inlined.elf",
    "Symbol": [
      {
        "Column": 3,
        "Discriminator": 0,
        "FileName": "/tmp/test.cpp",
        "FunctionName": "foo()",
        "Line": 6,
        "StartAddress": "0x400486",
        "StartFileName": "/tmp/test.cpp",
        "StartLine": 5
      }
    ]
  }
]
--pretty-print, -p

人間が読める形式で出力します。 --inlining が指定されている場合、囲んでいるスコープの先頭に(インライン化元)が付きます。JSON 出力の場合、このオプションを指定すると JSON がインデントされ、複数行に分割されます。それ以外の場合、JSON 出力はコンパクトな形式で表示されます。

$ llvm-symbolizer --obj=inlined.elf 0x4004be --inlining --pretty-print
baz() at /tmp/test.cpp:11:18
 (inlined by) main at /tmp/test.cpp:15:0
--print-address, --addresses, -a

ソースコードの場所の前にアドレスを表示します。デフォルトは false です。

$ llvm-symbolizer --obj=inlined.elf --print-address 0x4004be
0x4004be
baz()
/tmp/test.cpp:11:18
main
/tmp/test.cpp:15:0

$ llvm-symbolizer --obj=inlined.elf 0x4004be --pretty-print --print-address
0x4004be: baz() at /tmp/test.cpp:11:18
 (inlined by) main at /tmp/test.cpp:15:0
--print-source-context-lines <N>

シンボル化された各アドレスに対して、ソースコンテキストの N 行を表示します。

$ llvm-symbolizer --obj=test.elf 0x400490 --print-source-context-lines=3
baz()
/tmp/test.cpp:11:0
10  :   volatile int k = 42;
11 >:   return foz() + k;
12  : }
--relativenames

絶対パスではなく、コンパイルディレクトリに対する相対パスでファイルパスを表示します。コンパイラへのコマンドラインにフルパスが含まれている場合、これはデフォルトと同じになります。

--verbose

アドレス、行、列の詳細な情報を表示します。

$ llvm-symbolizer --obj=inlined.elf --verbose 0x4004be
baz()
  Filename: /tmp/test.cpp
  Function start filename: /tmp/test.cpp
  Function start line: 9
  Function start address: 0x4004b6
  Line: 11
  Column: 18
main
  Filename: /tmp/test.cpp
  Function start filename: /tmp/test.cpp
  Function start line: 14
  Function start address: 0x4004b0
  Line: 15
  Column: 18
--version, -v

ツールのバージョン情報を表示します。

@<FILE>

応答ファイル <FILE> からコマンドラインオプションを読み込みます。

WINDOWS/PDB 固有のオプション

--dia

シンボル化に Windows DIA SDK を使用します。DIA SDK が見つからない場合、llvm-symbolizer はネイティブ実装にフォールバックします。

MACH-O 固有のオプション

--default-arch <arch>

バイナリに複数のアーキテクチャのオブジェクトファイルが含まれている場合(例:Mach-O ユニバーサルバイナリ)、指定されたアーキテクチャのオブジェクトファイルをシンボル化します。入力で binary_name:arch_name と記述してアーキテクチャを指定することもできます(以下の例を参照)。どちらの方法でもアーキテクチャが指定されていない場合、アドレスはシンボル化されません。デフォルトは空文字列です。

$ cat addr.txt
/tmp/mach_universal_binary:i386 0x1f84
/tmp/mach_universal_binary:x86_64 0x100000f24

$ llvm-symbolizer < addr.txt
_main
/tmp/source_i386.cc:8

_main
/tmp/source_x86_64.cc:8
--dsym-hint <path/to/file.dSYM>

バイナリのデバッグ情報がデフォルトの場所に存在しない場合は、このオプションで指定された .dSYM パスでデバッグ情報を探します。このフラグは複数回使用できます。

終了ステータス

llvm-symbolizer は 0 を返します。その他の終了コードは、内部プログラムエラーを意味します。

関連項目

llvm-addr2line(1)