苹果GCC在哪里/如何在可执行文件中存储矮人

时间:2022-02-14 13:23:21

Where/how does Apples GCC store DWARF inside an executable?

苹果GCC在哪里/如何在可执行文件中存储矮人?

I compiled a binary via gcc -gdwarf-2 (Apples GCC). However, neither objdump -g nor objdump -h does show me any debug information.

我通过gcc - g矮人-2(苹果)编译了一个二进制文件。但是,objdump -g和objdump -h都没有显示任何调试信息。

Also libbfd does not find any debug information. (I asked on the binutils-mailinglist about it here.)

libbfd也没有找到任何调试信息。(我在binutils-mailinglist上问过这个问题。)

I am able however to extract the debugging information via dsymutil (into a dSYM). libbfd is also able to read those debug info then.

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

4 个解决方案

#1


36  

On Mac OS X there was a decision to have the linker (ld) not process all of the debug information when you link your program. The debug information is often 10x the size of the program executable so having the linker process all of the debug info and include it in the executable binary was a serious detriment to link times. For iterative development - compile, link, compile, link, debug, compile link - this was a real hit.

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

Instead the compiler generates the DWARF debug information in the .s files, the assembler outputs it in the .o files, and the linker includes a "debug map" in the executable binary which tells debug info users where all of the symbols were relocated during the link.

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

A consumer (doing .o-file debugging) loads the debug map from the executable and processes all of the DWARF in the .o files as-needed, remapping the symbols as per the debug map's instructions.

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

dsymutil can be thought of as a debug info linker. It does this same process -- read the debug map, load the DWARF from the .o files, relocate all the addresses -- and then outputs a single binary of all the DWARF at their final, linked addresses. This is the dSYM bundle.

dsymutil可以被视为调试信息链接器。它执行相同的过程——读取调试映射、从.o文件装载DWARF,重新放置所有地址——然后在所有的DWARF的最终链接地址上输出一个二进制文件。这是dSYM包。

Once you have a dSYM bundle, you've got plain old standard DWARF that any dwarf reading tool (which can deal with Mach-O binary files) can process.

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

There is an additional refinement that makes all of this work, the UUIDs included in Mach-O binaries. Every time the linker creates a binary, it emits a 128-bit UUID in the LC_UUID load command (v. otool -hlv or dwarfdump --uuid). This uniquely identifies that binary file. When dsymutil creates the dSYM, it includes that UUID. The debuggers will only associate a dSYM and an executable if they have matching UUIDs -- no dodgy file mod timestamps or anything like that.

有一个额外的改进,使所有这些工作,包括在Mach-O二进制文件中的uid。每次链接器创建一个二进制文件时,它都会在LC_UUID load命令(v. otool -hlv或矮人fdump - UUID)中发出128位UUID。这惟一地标识二进制文件。当dsymutil创建dSYM时,它包含该UUID。调试器只有在有匹配的uuid时才会将dSYM和可执行文件关联起来——没有可疑的文件mod时间戳或类似的东西。

We can also use the UUIDs to locate the dSYMs for binaries. They show up in crash reports, we include a Spotlight importer that you can use to search for them, e.g. mdfind "com_apple_xcode_dsym_uuids == E21A4165-29D5-35DC-D08D-368476F85EE1" if the dSYM is located in a Spotlight indexed location. You can even have a repository of dSYMs for your company and a program that can retrieve the correct dSYM given a UUID - maybe a little mysql database or something like that - so you run the debugger on a random executable and you instantly have all the debug info for that executable. There are some pretty neat things you can do with the UUIDs.

我们还可以使用uuid来定位二进制文件的dSYMs。它们出现在崩溃报告中,我们包括一个您可以用来搜索它们的Spotlight importer,例如mdfind“com_apple_xcode_dsym_dsym_uid == e21a4165 - 29d5 - 35dc - d08476f85ee1”,如果dSYM位于Spotlight索引位置。你甚至可以为贵公司dSYMs库和一个程序,可以检索正确的dSYM给定一个UUID,也许一个mysql数据库之类的——所以你上运行调试器随机执行立即都可执行的调试信息。你可以用uuid做一些很简单的事情。

But anyway, to answer your origin question: The unstripped binary has the debug map, the .o files have the DWARF, and when dsymutil is run these are combined to create the dSYM bundle.

但是,无论如何,为了回答您的原始问题:未剥离的二进制文件具有调试映射,.o文件具有DWARF,并且当运行dsymutil时,将它们组合起来创建dSYM包。

If you want to see the debug map entries, do nm -pa executable and they're all there. They are in the form of the old stabs nlist records - the linker already knew how to process stabs so it was easiest to use them - but you'll see how it works without much trouble, maybe refer to some stabs documentation if you're uncertain.

如果您想查看调试映射条目,请执行nm -pa可执行文件,它们都在那里。它们以旧的stabs nlist记录的形式出现——链接器已经知道如何处理stabs,所以使用它们是最容易的——但是您将看到它是如何工作的,不会遇到很多麻烦,如果您不确定,可以参考一些stabs文档。

#2


2  

It seems it actually doesn't.

看起来它实际上并没有。

I traced dsymutil and it reads all the *.o files. objdump -h also lists all the debug info in them.

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

So it seems that those info isn't copied over to the binary.

看起来这些信息不是复制到二进制的。


Some related comments about this can also be found here.

关于这一点的一些相关评论也可以在这里找到。

#3


0  

Apple stores debugging information in separate files named *.dSYM. You can run dwarfdump on those files and see the DWARF Debug Info Entries.

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

#4


0  

It seems there are two ways for OSX to place debug information:

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

  1. In the .o object files used for compilation. The binary stores a reference to these files (by absolute path).

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

  2. In a separate bundle (directory) called .dSYM

    在一个名为.dSYM的单独包(目录)中

If I compile with Apple's Clang using g++ -g main.cpp -o foo I get the bundle called foo.dSYM. However if I use CMake I get the debug info in the object files. I guess because it does a separate gcc -c main.cpp -o main.o step?

如果我使用g++ -g main编译苹果的Clang。cpp -o foo我得到一个名为foo。dsym的包。但是,如果我使用CMake,我将在目标文件中获得调试信息。我猜是因为它是独立的gcc -c main。cpp - o主要。哪一步?

Anyway I found this command very useful for case 1:

总之,我发现这个命令对案例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 }
...

#1


36  

On Mac OS X there was a decision to have the linker (ld) not process all of the debug information when you link your program. The debug information is often 10x the size of the program executable so having the linker process all of the debug info and include it in the executable binary was a serious detriment to link times. For iterative development - compile, link, compile, link, debug, compile link - this was a real hit.

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

Instead the compiler generates the DWARF debug information in the .s files, the assembler outputs it in the .o files, and the linker includes a "debug map" in the executable binary which tells debug info users where all of the symbols were relocated during the link.

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

A consumer (doing .o-file debugging) loads the debug map from the executable and processes all of the DWARF in the .o files as-needed, remapping the symbols as per the debug map's instructions.

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

dsymutil can be thought of as a debug info linker. It does this same process -- read the debug map, load the DWARF from the .o files, relocate all the addresses -- and then outputs a single binary of all the DWARF at their final, linked addresses. This is the dSYM bundle.

dsymutil可以被视为调试信息链接器。它执行相同的过程——读取调试映射、从.o文件装载DWARF,重新放置所有地址——然后在所有的DWARF的最终链接地址上输出一个二进制文件。这是dSYM包。

Once you have a dSYM bundle, you've got plain old standard DWARF that any dwarf reading tool (which can deal with Mach-O binary files) can process.

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

There is an additional refinement that makes all of this work, the UUIDs included in Mach-O binaries. Every time the linker creates a binary, it emits a 128-bit UUID in the LC_UUID load command (v. otool -hlv or dwarfdump --uuid). This uniquely identifies that binary file. When dsymutil creates the dSYM, it includes that UUID. The debuggers will only associate a dSYM and an executable if they have matching UUIDs -- no dodgy file mod timestamps or anything like that.

有一个额外的改进,使所有这些工作,包括在Mach-O二进制文件中的uid。每次链接器创建一个二进制文件时,它都会在LC_UUID load命令(v. otool -hlv或矮人fdump - UUID)中发出128位UUID。这惟一地标识二进制文件。当dsymutil创建dSYM时,它包含该UUID。调试器只有在有匹配的uuid时才会将dSYM和可执行文件关联起来——没有可疑的文件mod时间戳或类似的东西。

We can also use the UUIDs to locate the dSYMs for binaries. They show up in crash reports, we include a Spotlight importer that you can use to search for them, e.g. mdfind "com_apple_xcode_dsym_uuids == E21A4165-29D5-35DC-D08D-368476F85EE1" if the dSYM is located in a Spotlight indexed location. You can even have a repository of dSYMs for your company and a program that can retrieve the correct dSYM given a UUID - maybe a little mysql database or something like that - so you run the debugger on a random executable and you instantly have all the debug info for that executable. There are some pretty neat things you can do with the UUIDs.

我们还可以使用uuid来定位二进制文件的dSYMs。它们出现在崩溃报告中,我们包括一个您可以用来搜索它们的Spotlight importer,例如mdfind“com_apple_xcode_dsym_dsym_uid == e21a4165 - 29d5 - 35dc - d08476f85ee1”,如果dSYM位于Spotlight索引位置。你甚至可以为贵公司dSYMs库和一个程序,可以检索正确的dSYM给定一个UUID,也许一个mysql数据库之类的——所以你上运行调试器随机执行立即都可执行的调试信息。你可以用uuid做一些很简单的事情。

But anyway, to answer your origin question: The unstripped binary has the debug map, the .o files have the DWARF, and when dsymutil is run these are combined to create the dSYM bundle.

但是,无论如何,为了回答您的原始问题:未剥离的二进制文件具有调试映射,.o文件具有DWARF,并且当运行dsymutil时,将它们组合起来创建dSYM包。

If you want to see the debug map entries, do nm -pa executable and they're all there. They are in the form of the old stabs nlist records - the linker already knew how to process stabs so it was easiest to use them - but you'll see how it works without much trouble, maybe refer to some stabs documentation if you're uncertain.

如果您想查看调试映射条目,请执行nm -pa可执行文件,它们都在那里。它们以旧的stabs nlist记录的形式出现——链接器已经知道如何处理stabs,所以使用它们是最容易的——但是您将看到它是如何工作的,不会遇到很多麻烦,如果您不确定,可以参考一些stabs文档。

#2


2  

It seems it actually doesn't.

看起来它实际上并没有。

I traced dsymutil and it reads all the *.o files. objdump -h also lists all the debug info in them.

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

So it seems that those info isn't copied over to the binary.

看起来这些信息不是复制到二进制的。


Some related comments about this can also be found here.

关于这一点的一些相关评论也可以在这里找到。

#3


0  

Apple stores debugging information in separate files named *.dSYM. You can run dwarfdump on those files and see the DWARF Debug Info Entries.

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

#4


0  

It seems there are two ways for OSX to place debug information:

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

  1. In the .o object files used for compilation. The binary stores a reference to these files (by absolute path).

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

  2. In a separate bundle (directory) called .dSYM

    在一个名为.dSYM的单独包(目录)中

If I compile with Apple's Clang using g++ -g main.cpp -o foo I get the bundle called foo.dSYM. However if I use CMake I get the debug info in the object files. I guess because it does a separate gcc -c main.cpp -o main.o step?

如果我使用g++ -g main编译苹果的Clang。cpp -o foo我得到一个名为foo。dsym的包。但是,如果我使用CMake,我将在目标文件中获得调试信息。我猜是因为它是独立的gcc -c main。cpp - o主要。哪一步?

Anyway I found this command very useful for case 1:

总之,我发现这个命令对案例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 }
...