2012-04-06 63 views
9

Apples GCC在何處/如何將DWARF存儲在可執行文件中?蘋果GCC在哪裏/如何在可執行文件中存儲DWARF

我通過gcc -gdwarf-2(蘋果GCC)編譯了一個二進制文件。但是,objdump -gobjdump -h都沒有顯示任何調試信息。

另外libbfd沒有找到任何調試信息。 (我在binutils郵件列表上詢問了有關它的信息here。)

但是我能夠通過dsymutil(進入dSYM)提取調試信息。然後libbfd也能夠讀取那些調試信息。

回答

35

在Mac OS X上,當鏈接程序時,決定讓鏈接器(ld)不處理所有調試信息。調試信息通常是程序可執行文件大小的10倍,因此鏈接器會處理所有調試信息並將其包含在可執行二進制文件中對鏈接時間造成嚴重損害。對於迭代開發 - 編譯,鏈接,編譯,鏈接,調試,編譯鏈接 - 這是一個真正的打擊。

相反,編譯器在.s文件中生成DWARF調試信息,彙編器將其輸出到.o文件中,並且鏈接器在可執行二進制文件中包含一個「調試映射」,它告訴調試信息用戶所有鏈接期間符號被重新定位。

消費者(執行.o-file調試)從可執行文件加載調試映射,並根據需要處理.o文件中的所有DWARF,並根據調試映射的指示重新映射這些符號。

dsymutil可以被認爲是一個調試信息鏈接器。它執行相同的過程 - 讀取調試映射,從.o文件加載DWARF,重新定位所有地址 - 然後在其最終的鏈接地址上輸出一個包含所有DWARF的二進制文件。這是dSYM軟件包。

一旦你有一個dSYM包,你已經有了普通的舊標準DWARF,任何矮人閱讀工具(可以處理Mach-O二進制文件)都可以處理。

有一個額外的改進,使所有這些工作,包括在Mach-O二進制文件中的UUID。每次鏈接器創建一個二進制文件時,它都會在LC_UUID加載命令(v。otool -hlvdwarfdump --uuid)中發出一個128位的UUID。這唯一標識該二進制文件。當dsymutil創建dSYM時,它包含該UUID。調試器只會將dSYM和可執行文件相關聯(如果它們具有匹配的UUID) - 沒有可怕的文件模型時間戳或類似的東西。

我們也可以使用UUID來定位二進制文​​件的dSYM。它們顯示在崩潰報告中,我們包含一個Spotlight導入器,您可以使用它搜索它們,例如 mdfind "com_apple_xcode_dsym_uuids == E21A4165-29D5-35DC-D08D-368476F85EE1" 如果dSYM位於Spotlight索引位置。你甚至可以爲你的公司提供一個dSYM的存儲庫,並且一個程序可以在給定UUID的情況下檢索正確的dSYM - 也許是一個小的mysql數據庫或類似的東西 - 這樣你就可以在一個隨機可執行文件上運行調試器,該可執行文件的信息。你可以用UUID做一些非常整齊的事情。

但無論如何,要回答您的原點問題:未剝離的二進制文件具有調試映射,.o文件具有DWARF,並且當運行dsymutil時,這些文件合併在一起以創建dSYM包。

如果您想查看調試映射條目,請執行nm -pa executable,它們都在那裏。它們的形式是舊的nlist記錄 - 鏈接器已經知道如何處理刺,所以最簡單的方法是使用它們 - 但是你會看到它是如何工作的,沒有太多的麻煩,如果你喜歡,可以參考一些刺傷文檔不確定。

+0

'dsymutil'如何知道.o文件的位置?我在手冊中看不到任何選項來告訴它。我也需要編譯二進制'-g3',如果是的話,我可以在我使用'dsymutil'之後剝離它嗎?謝謝。 – mxcl 2013-06-25 21:03:55

+1

在使用.o文件的文件名剝離之前,可執行文件中有「調試映射」條目。 'nm -pa binary | grep OSO'會列出它們。它們採用舊的調試格式(因爲鏈接器已經知道如何處理該格式)。創建完dSYM後,可以將它們從可執行文件中刪除。你不需要在Mac平臺上使用'-g3','-g'就足夠了。我認爲'-g3'輸出預處理宏信息,但lldb在Mac OS X上沒有讀取(我不知道是否clang會輸出它)。 – 2013-06-25 21:21:00

+1

感謝您提供詳細而有用的答案。 – mxcl 2013-06-26 04:01:07

2

看來它實際上沒有。

我跟蹤到dsymutil,它讀取所有*.o文件。 objdump -h也列出了它們中的所有調試信息。

因此,似乎這些信息不會被複制到二進制文件。


對此的一些相關評論也可以在here找到。

0

Apple將調試信息存儲在名爲* .dSYM的單獨文件中。您可以在這些文件上運行dwarfdump並查看DWARF調試信息條目。

+0

號你可以通過'dsymutil' * *創建的的dSYM。但我的問題是,調試信息在哪裏。即'dsymutil'從哪裏得到它。但我已經有了答案(請參閱我自己的答案)。它們實際上不在二進制文件中,二進制文件引用'* .o'文件,這也是'dsymutil'從中獲取數據的地方。 – Albert 2012-04-14 22:45:29

+0

那麼你的問題是模糊的。我將它解釋爲在調試器中與可執行文件一起使用時存儲的調試信息的位置。 – Bogatyr 2012-04-15 12:14:07

+0

是的,那是我的問題。答案是,它存儲在'* .o'文件中。當你創建一個dSYM時,當然你在dSYM中有另一個副本。但是在創建dSYM之前,沒有dSYM。這就是我在我的問題中所說的。 (「但我可以通過'dsymutil'提取調試信息。」)您不會自動獲取dSYM。你必須調用'dsymutil'。 (我認爲,當你使用Xcode時,Xcode會自動執行。)或者我錯了嗎? – Albert 2012-04-15 18:06:33

0

似乎有兩種方法OSX放置調試信息:

  1. 在用於編譯的.o目標文件。二進制文件存儲對這些文件的引用(通過絕對路徑)。

  2. 在一個單獨的包(目錄)使用g++ -g main.cpp -o foo我會得到一個名爲foo.dSYM捆稱爲.dSYM

如果我與蘋果鏘編譯。但是如果我使用CMake,我會在對象文件中獲得調試信息。我猜是因爲它做了一個單獨的步驟gcc -c main.cpp -o main.o

無論如何,我發現這個命令的情況下,1非常有用:

$ dsymutil -dump-debug-map main 
--- 
triple:   'x86_64-apple-darwin' 
binary-path:  main 
objects:   
    - filename:  /Users/tim/foo/build/CMakeFiles/main.dir/main.cpp.o 
    timestamp:  1485951213 
    symbols:   
     - { sym: __ZNSt3__111char_traitsIcE11eq_int_typeEii, objAddr: 0x0000000000000D50, binAddr: 0x0000000100001C90, size: 0x00000020 } 
     - { sym: __ZNSt3__111char_traitsIcE6lengthEPKc, objAddr: 0x0000000000000660, binAddr: 0x00000001000015A0, size: 0x00000020 } 
     - { sym: GCC_except_table3, objAddr: 0x0000000000000DBC, binAddr: 0x0000000100001E2C, size: 0x00000000 } 
     - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000F40, size: 0x00000090 } 
     - { sym: __ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m, objAddr: 0x00000000000001F0, binAddr: 0x0000000100001130, size: 0x00000470 } 
     - { sym: ___clang_call_terminate, objAddr: 0x0000000000000D40, binAddr: 0x0000000100001C80, size: 0x00000010 } 
     - { sym: GCC_except_table5, objAddr: 0x0000000000000E6C, binAddr: 0x0000000100001EDC, size: 0x00000000 } 
     - { sym: __ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_, objAddr: 0x0000000000000680, binAddr: 0x00000001000015C0, size: 0x000006C0 } 
     - { sym: __ZNSt3__14endlIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_, objAddr: 0x00000000000000E0, binAddr: 0x0000000100001020, size: 0x00000110 } 
     - { sym: GCC_except_table2, objAddr: 0x0000000000000D7C, binAddr: 0x0000000100001DEC, size: 0x00000000 } 
     - { sym: __ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc, objAddr: 0x0000000000000090, binAddr: 0x0000000100000FD0, size: 0x00000050 } 
     - { sym: __ZNSt3__111char_traitsIcE3eofEv, objAddr: 0x0000000000000D70, binAddr: 0x0000000100001CB0, size: 0x0000000B } 
...