gcc -g 标志:移动源代码
gcc -g flag: Moving the Source Code
我的理解是,当您使用 gcc -g
编译 C 代码时,gcc 将插入调试信息,其中包括对原始源代码的引用(例如行号)。然后 gdb 和 objdump 等其他程序稍后可以恢复这些引用。作为示例,我们将使用 objdump -S
打印与相应源代码交错的程序集。
我的目标是将已编译的二进制文件复制到另一台计算机,并且仍然能够检索此调试信息。但是,目前,当我这样做时,所有调试信息都丢失了。我也不介意复制源文件,但是第二台计算机是 运行 不同的 OS,所以文件结构不同,我不能将源文件放在完全相同的位置绝对位置,防止 objdump 找到源代码。我查看了二进制文件,看到一个看起来像这样的部分散布着一堆二进制文件:
/home/path/to/source/code
我尝试编辑它以匹配源的新路径,但它只是使二进制文件无效。
我还研究了 gcc flags 希望其中之一允许指定源代码的相对路径而不是绝对路径,但我找不到类似的东西。
作为参考,这是我希望从 objdump - S
获得的输出类型:
0804840b <main>:
#include <stdio.h>
int main(){
804840b: 8d 4c 24 04 lea 0x4(%esp),%ecx
804840f: 83 e4 f0 and [=10=]xfffffff0,%esp
8048412: ff 71 fc pushl -0x4(%ecx)
8048415: 55 push %ebp
8048416: 89 e5 mov %esp,%ebp
8048418: 51 push %ecx
8048419: 83 ec 14 sub [=10=]x14,%esp
for(int varName = 0; varName < 100; varName++){
804841c: c7 45 f0 00 00 00 00 movl [=10=]x0,-0x10(%ebp)
8048423: eb 32 jmp 8048457 <main+0x4c>
for(int innerLoop = 0; innerLoop < 30; innerLoop++){
8048425: c7 45 f4 00 00 00 00 movl [=10=]x0,-0xc(%ebp)
804842c: eb 1f jmp 804844d <main+0x42>
if(innerLoop == varName){
804842e: 8b 45 f4 mov -0xc(%ebp),%eax
8048431: 3b 45 f0 cmp -0x10(%ebp),%eax
8048434: 75 13 jne 8048449 <main+0x3e>
printf("%d\n", innerLoop);
8048436: 83 ec 08 sub [=10=]x8,%esp
8048439: ff 75 f4 pushl -0xc(%ebp)
804843c: 68 f0 84 04 08 push [=10=]x80484f0
8048441: e8 9a fe ff ff call 80482e0 <printf@plt>
8048446: 83 c4 10 add [=10=]x10,%esp
#include <stdio.h>
int main(){
for(int varName = 0; varName < 100; varName++){
for(int innerLoop = 0; innerLoop < 30; innerLoop++){
8048449: 83 45 f4 01 addl [=10=]x1,-0xc(%ebp)
804844d: 83 7d f4 1d cmpl [=10=]x1d,-0xc(%ebp)
8048451: 7e db jle 804842e <main+0x23>
#include <stdio.h>
int main(){
for(int varName = 0; varName < 100; varName++){
8048453: 83 45 f0 01 addl [=10=]x1,-0x10(%ebp)
8048457: 83 7d f0 63 cmpl [=10=]x63,-0x10(%ebp)
804845b: 7e c8 jle 8048425 <main+0x1a>
804845d: b8 00 00 00 00 mov [=10=]x0,%eax
if(innerLoop == varName){
printf("%d\n", innerLoop);
}
}
}
}
注意:虽然我使用 objdump 作为使用有关源文件信息的程序的示例,但它实际上并不是我感兴趣的 objdump 的输出。我 运行 不同需要访问相同信息的程序。问题是关于如何修复二进制文件,而不是如何使用 objdump。
gcc 和 clang 在生成调试信息时,会将 DWARF 属性DW_AT_comp_dir
设置为目标文件中每个编译单元的工作目录。
cc a.c b.c -g -o foo
objdump -Wi foo
会显示类似
的内容
Contents of the .debug_info section:
Compilation Unit @ offset 0x0:
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<11> DW_AT_name : a.c
<15> DW_AT_comp_dir : (indirect string, offset: 0x0): /home/user/src
Compilation Unit @ offset 0x4d:
<0><58>: Abbrev Number: 1 (DW_TAG_compile_unit)
<5e> DW_AT_name : b.c
<62> DW_AT_comp_dir : (indirect string, offset: 0x0): /home/user/src
通常用于转换目标文件的程序,objcopy,目前不支持更改这些 DWARF 属性。
但是 gcc 和 clang 有一个 -fdebug-prefix-map 选项,它应该在编译时做你想做的事情。
由于 gcc 使用 libiberty 的 getpwd
函数获取当前目录,该函数使用 PWD
环境变量(在检查其正确性之后)优先于 libc 的 getcwd
,我们可以得到运行 与 shell 的 pwd -L
内置值相同。
cc a.c b.c -g -fdebug-prefix-map=$(pwd -L)=. -o foo
会在DW_AT_comp_dir
属性中输出.
,而不是当前目录的路径名。
我的理解是,当您使用 gcc -g
编译 C 代码时,gcc 将插入调试信息,其中包括对原始源代码的引用(例如行号)。然后 gdb 和 objdump 等其他程序稍后可以恢复这些引用。作为示例,我们将使用 objdump -S
打印与相应源代码交错的程序集。
我的目标是将已编译的二进制文件复制到另一台计算机,并且仍然能够检索此调试信息。但是,目前,当我这样做时,所有调试信息都丢失了。我也不介意复制源文件,但是第二台计算机是 运行 不同的 OS,所以文件结构不同,我不能将源文件放在完全相同的位置绝对位置,防止 objdump 找到源代码。我查看了二进制文件,看到一个看起来像这样的部分散布着一堆二进制文件:
/home/path/to/source/code
我尝试编辑它以匹配源的新路径,但它只是使二进制文件无效。
我还研究了 gcc flags 希望其中之一允许指定源代码的相对路径而不是绝对路径,但我找不到类似的东西。
作为参考,这是我希望从 objdump - S
获得的输出类型:
0804840b <main>:
#include <stdio.h>
int main(){
804840b: 8d 4c 24 04 lea 0x4(%esp),%ecx
804840f: 83 e4 f0 and [=10=]xfffffff0,%esp
8048412: ff 71 fc pushl -0x4(%ecx)
8048415: 55 push %ebp
8048416: 89 e5 mov %esp,%ebp
8048418: 51 push %ecx
8048419: 83 ec 14 sub [=10=]x14,%esp
for(int varName = 0; varName < 100; varName++){
804841c: c7 45 f0 00 00 00 00 movl [=10=]x0,-0x10(%ebp)
8048423: eb 32 jmp 8048457 <main+0x4c>
for(int innerLoop = 0; innerLoop < 30; innerLoop++){
8048425: c7 45 f4 00 00 00 00 movl [=10=]x0,-0xc(%ebp)
804842c: eb 1f jmp 804844d <main+0x42>
if(innerLoop == varName){
804842e: 8b 45 f4 mov -0xc(%ebp),%eax
8048431: 3b 45 f0 cmp -0x10(%ebp),%eax
8048434: 75 13 jne 8048449 <main+0x3e>
printf("%d\n", innerLoop);
8048436: 83 ec 08 sub [=10=]x8,%esp
8048439: ff 75 f4 pushl -0xc(%ebp)
804843c: 68 f0 84 04 08 push [=10=]x80484f0
8048441: e8 9a fe ff ff call 80482e0 <printf@plt>
8048446: 83 c4 10 add [=10=]x10,%esp
#include <stdio.h>
int main(){
for(int varName = 0; varName < 100; varName++){
for(int innerLoop = 0; innerLoop < 30; innerLoop++){
8048449: 83 45 f4 01 addl [=10=]x1,-0xc(%ebp)
804844d: 83 7d f4 1d cmpl [=10=]x1d,-0xc(%ebp)
8048451: 7e db jle 804842e <main+0x23>
#include <stdio.h>
int main(){
for(int varName = 0; varName < 100; varName++){
8048453: 83 45 f0 01 addl [=10=]x1,-0x10(%ebp)
8048457: 83 7d f0 63 cmpl [=10=]x63,-0x10(%ebp)
804845b: 7e c8 jle 8048425 <main+0x1a>
804845d: b8 00 00 00 00 mov [=10=]x0,%eax
if(innerLoop == varName){
printf("%d\n", innerLoop);
}
}
}
}
注意:虽然我使用 objdump 作为使用有关源文件信息的程序的示例,但它实际上并不是我感兴趣的 objdump 的输出。我 运行 不同需要访问相同信息的程序。问题是关于如何修复二进制文件,而不是如何使用 objdump。
gcc 和 clang 在生成调试信息时,会将 DWARF 属性DW_AT_comp_dir
设置为目标文件中每个编译单元的工作目录。
cc a.c b.c -g -o foo
objdump -Wi foo
会显示类似
的内容Contents of the .debug_info section:
Compilation Unit @ offset 0x0:
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<11> DW_AT_name : a.c
<15> DW_AT_comp_dir : (indirect string, offset: 0x0): /home/user/src
Compilation Unit @ offset 0x4d:
<0><58>: Abbrev Number: 1 (DW_TAG_compile_unit)
<5e> DW_AT_name : b.c
<62> DW_AT_comp_dir : (indirect string, offset: 0x0): /home/user/src
通常用于转换目标文件的程序,objcopy,目前不支持更改这些 DWARF 属性。
但是 gcc 和 clang 有一个 -fdebug-prefix-map 选项,它应该在编译时做你想做的事情。
由于 gcc 使用 libiberty 的 getpwd
函数获取当前目录,该函数使用 PWD
环境变量(在检查其正确性之后)优先于 libc 的 getcwd
,我们可以得到运行 与 shell 的 pwd -L
内置值相同。
cc a.c b.c -g -fdebug-prefix-map=$(pwd -L)=. -o foo
会在DW_AT_comp_dir
属性中输出.
,而不是当前目录的路径名。