llvm-symbolizer - 將地址轉換為原始程式碼位置

語法

llvm-symbolizer [選項] [地址…]

描述

llvm-symbolizer 從命令列讀取輸入名稱和地址,並將相應的原始程式碼位置列印到標準輸出。 它也可以透過 符號標記 使用 --filter-markup 對包含日誌進行符號化。 地址可以指定為數字或符號名稱。

如果在命令列上沒有指定地址,它會從標準輸入讀取地址。 如果在命令列上沒有指定輸入名稱,但指定了地址,則第一個地址值將被視為輸入名稱。 如果無法識別輸入值,它會報告找不到原始程式碼資訊。

輸入名稱可以與地址一起在標準輸入上指定,也可以作為命令列上的位置參數指定。 根據預設,輸入名稱會被解釋為物件檔案路徑。 但是,在名稱前面加上 BUILDID: 表示它是十六進位組建 ID,而不是路徑。 這將查找相應的偵錯二進制檔案。 為了保持一致性,在名稱前面加上 FILE: 明確表示它是物件檔案路徑(預設)。

位置參數或標準輸入值前面可以加上「DATA」或「CODE」,表示地址應該分別符號化為資料或可執行程式碼。 如果兩者都沒有指定,則假設為「CODE」。 DATA 被符號化為地址和符號大小,而不是行號。

llvm-symbolizer 在解析命令列選項後,會解析環境變數 LLVM_SYMBOLIZER_OPTS 中的選項。 當 llvm-symbolizer 由其他程式或執行階段呼叫時,LLVM_SYMBOLIZER_OPTS 主要用於補充命令列選項。

範例

以下所有範例都使用以下兩個原始程式碼檔案作為輸入。 它們混合使用 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,並且編譯方式如下。第一種情況顯示預設的絕對路徑,第二種情況顯示 –basenames,第三種情況顯示 –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 - 沒有對應行號的位址(與第零行關聯的位址)的 --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 <位移>

在執行查找時,將指定的位移添加到目標檔案位址。這可以用於執行查找,就像目標被位移重新定位一樣。

--skip-line-zero

如果位址沒有關聯的行號,請使用行號表中當前序列的最後一個行號。此類行在輸出中被標記為「近似值」,因為它們可能會產生誤導。

--basenames, -s

僅列印檔案名稱而不包含任何目錄,而不是絕對路徑。

--build-id

使用給定的建置 ID 查找目標,指定為十六進制字串。與 --obj 互斥。

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

指定是否在 --filter-markup 模式中使用顏色。預設值為 auto,它會偵測標準輸出是否支援顏色。單獨指定 --color 等同於 --color=always

--debug-file-directory <路徑>

提供目錄的路徑,其中包含 .build-id 子目錄,用於搜尋已剝離二進制檔案的偵錯資訊。將按照給定的順序搜尋此參數的多個實例。

--debuginfod, --no-debuginfod

是否嘗試對偵錯二進制檔案進行 debuginfod 查找。除非另有指定,否則僅當已編譯 libcurl (LLVM_ENABLE_CURL) 並且環境變數 DEBUGINFOD_URLS 提供至少一個伺服器 URL 時,才會啟用 debuginfod。

--demangle, -C

如果名稱經過編碼,則印出解碼後的函數名稱(例如,編碼後的名稱 _Z3bazv 會變成 baz(),而未經編碼的名稱 foz 則會照原樣印出)。預設值為 true。

--dwp <path>

對於任何具有分割 DWARF 除錯資料的 CUs,請使用 <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 樣式的差異在於

  • 不印出原始程式碼位置的欄位。

  • 不會在地址報告後添加空行。

  • 當未顯示內嵌框架時,不會將內嵌函式的名稱替換為最上層呼叫者的名稱。

  • 當地址的除錯資料判別器非零時,會印出該判別器。產生判別器的一種方法是使用 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)