Macos Apple GCC在可执行文件中的何处/如何存储DWARF

Macos Apple GCC在可执行文件中的何处/如何存储DWARF,macos,gcc,objdump,dwarf,dsymutil,Macos,Gcc,Objdump,Dwarf,Dsymutil,Apple GCC在可执行文件中的何处/如何存储DWARF 我通过gcc-gdwarf-2(Apples-gcc)编译了一个二进制文件。但是,无论是objdump-g还是objdump-h都没有向我显示任何调试信息 此外,libbfd找不到任何调试信息。(我在binutils邮件列表上询问了此事。) 但是,我可以通过dsymutil(到dSYM中)提取调试信息。libbfd也能够读取这些调试信息。看起来它实际上没有 我跟踪了dsymutil,它读取了所有*.o文件objdump-h还列出了其中的

Apple GCC在可执行文件中的何处/如何存储DWARF

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

此外,libbfd找不到任何调试信息。(我在binutils邮件列表上询问了此事。)


但是,我可以通过
dsymutil
(到dSYM中)提取调试信息。libbfd也能够读取这些调试信息。

看起来它实际上没有

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

因此,这些信息似乎没有被复制到二进制文件中



也可以找到一些相关的评论。

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

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

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

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

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

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

还有一个额外的改进使得所有这些工作都可以进行,即Mach-O二进制文件中包含的UUID。每次链接器创建二进制文件时,它都会在LC_UUID load命令(v.
otool-hlv
dwarfdump--UUID
)中发出一个128位的UUID。这将唯一标识该二进制文件。当
dsymutil
创建dSYM时,它包括该UUID。如果调试器有匹配的UUID,那么它们只会将dSYM和可执行文件关联起来——没有不可靠的文件mod时间戳或类似的东西

我们还可以使用UUID来定位二进制文件的DSYM。它们出现在碰撞报告中,我们提供了一个聚光灯导入器,您可以使用它来搜索它们,例如。
mdfind“com\u apple\u xcode\u dsym\u uuids==E21A4165-29D5-35DC-D08D-368476F85EE1”
如果dSYM位于聚光灯索引位置。您甚至可以为您的公司提供一个dSYM存储库,以及一个程序,该程序可以在给定UUID的情况下检索正确的dSYM—可能是一个小mysql数据库或类似的—因此您可以在随机可执行文件上运行调试器,并立即获得该可执行文件的所有调试信息。您可以使用UUID做一些非常简单的事情

但无论如何,要回答您最初的问题:非压缩二进制文件具有调试映射,.o文件具有DWARF,当运行
dsymutil
时,这些文件组合起来创建dSYM包


如果要查看调试映射条目,请执行
nm-pa executable
,它们都在那里。它们是以旧stab
nlist
记录的形式出现的-链接器已经知道如何处理stab,因此使用起来很简单-但是您将看到它是如何工作的,没有太多问题,如果您不确定,可以参考一些stab文档。

OSX似乎有两种放置调试信息的方法:

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

  • 在名为.dSYM的单独捆绑包(目录)中

  • 如果我使用
    g++-g main.cpp-o foo
    使用Apple的Clang进行编译,我会得到名为
    foo.dSYM
    的包。但是,如果使用CMake,则会在对象文件中获取调试信息。我猜是因为它执行了一个单独的
    gcc-cmain.cpp-omain.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 }
    ...
    

    不可以。您可以通过
    dsymutil
    创建dSYM。但我的问题是,调试信息在哪里。也就是说,
    dsymutil
    从哪里获取它。但我已经有了答案(见我自己的答案)。它们实际上不是二进制文件,二进制文件引用了
    *.o
    文件,这也是
    dsymutil
    获取数据的地方。你的问题很模糊。我将其解释为,当与调试器中的可执行文件一起使用时,调试信息存储在哪里。是的,这是我的问题。答案是,它存储在
    *.o
    文件中。当您创建一个dSYM时,当然在dSYM中还有另一个副本。但是在创建dSYM之前,没有dSYM。这就是我在问题中所说的。(“但是,我可以通过
    dsymutil
    提取调试信息”)您不会自动获取dSYM。您必须调用
    dsymutil
    。(我想,当您使用Xcode时,Xcode会自动执行该操作。)或者我错了吗?
    dsymutil
    如何知道.o文件在哪里?我在主页上看不到可以告诉它的选项。我还需要编译二进制文件
    -g3
    ,如果需要,我可以在编译完
    后将其剥离吗