Apples GCC在哪里/如何将DWARF存储在可执行文件中

时间:2012-04-06 14:11:38

标签: macos gcc objdump dwarf dsymutil

Apples GCC在哪里/如何将DWARF存储在可执行文件中?

我通过gcc -gdwarf-2(Apples GCC)编译了一个二进制文件。但是,objdump -gobjdump -h都没有向我显示任何调试信息。

libbfd也找不到任何调试信息。 (我在binutils-mailinglist上询问了它here。)

然而,我能够通过dsymutil(进入dSYM)提取调试信息。 libbfd也可以读取那些调试信息。

4 个答案:

答案 0 :(得分:42)

在Mac OS X上,当您链接程序时,决定让链接器(ld)不处理所有调试信息。调试信息通常是程序可执行文件大小的10倍,因此让链接器处理所有调试信息并将其包含在可执行二进制文件中会严重损害链接时间。对于迭代开发 - 编译,链接,编译,链接,调试,编译链接 - 这是一个真正的打击。

相反,编译器在.s文件中生成DWARF调试信息,汇编器在.o文件中输出它,链接器在可执行二进制文件中包含一个“调试映射”,它告诉调试信息用户所有符号的位置在链接期间重新安置。

使用者(执行.o文件调试)从可执行文件加载调试映射并根据需要处理.o文件中的所有DWARF,根据调试映射的说明重新映射符号。

dsymutil可以被认为是调试信息链接器。它执行相同的过程 - 读取调试映射,从.o文件加载DWARF,重新定位所有地址 - 然后在最终的链接地址输出所有DWARF的单个二进制文件。这是dSYM捆绑包。

一旦你有了一个dSYM软件包,你就可以使用普通的旧标准DWARF,任何矮人阅读工具(可以处理Mach-O二进制文件)都可以处理。

还有一个额外的改进使所有这些工作,UUID包含在Mach-O二进制文件中。每次链接器创建二进制文件时,它都会在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,它们就在那里。它们是旧的stabs nlist记录的形式 - 链接器已经知道如何处理stabs,因此最容易使用它们 - 但你会看到它如何工作没有太多麻烦,如果你是的话可能会参考一些stabs文档不确定的。

答案 1 :(得分:2)

似乎它实际上没有。

我跟踪了dsymutil,它会读取所有*.o个文件。 objdump -h还列出了其中的所有调试信息。

所以似乎这些信息不会被复制到二进制文件中。


有关此问题的一些相关评论也可以找到here

答案 2 :(得分:0)

OSX似乎有两种方式来放置调试信息:

  1. 在用于编译的.o目标文件中。二进制文件存储对这些文件的引用(通过绝对路径)。

  2. 在名为.dSYM

  3. 的单独包(目录)中

    如果我使用g++ -g main.cpp -o foo使用Apple的Clang编译,我会得到名为foo.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 }
    ...
    

答案 3 :(得分:-1)

Apple将调试信息存储在名为* .dSYM的单独文件中。您可以对这些文件运行dwarfdump并查看DWARF调试信息条目。