代码编译后移动目录引发gdb找不到代码文件

咱们从一个最简单的C语言程序开始。源文件main.c 用户目录gdb文件夹下。ui

florian@florian-pc:~/gdb$ cat main.cspa

int main().net

{debug

    return 0;调试

};orm

而后将源文件编译为main(须要调试选项-g),并将main.c移动到src/main.c下,而后对main进行调试。blog

florian@florian-pc:~/gdb$ gcc main.c -o main -g字符串

florian@florian-pc:~/gdb$ mv main.c src/main.cget

florian@florian-pc:~/gdb$ gdb main源码

(gdb) b main

Breakpoint 1 at 0x8048397: file main.c, line 3.

(gdb) list

1   main.c: 没有那个文件或目录.

    in main.c

gdb中,使用list命令查看源代码时,没法找到源文件main.c

探究

因为对DWARF调试格式并不清晰,我本觉得使用调试选项编译的可执行程序内部包含了源文件的内容,这样不管源码是否存在,可执行程序均可以被正常调试。可是,从上边的例子中能够看出,事实并不是如此。

咱们能够做一个简单的推测:因为移动源文件的位置后,gdb没法找到源文件的位置,估计可执行文件的调试段内保存的不是源文件的内容,而是路径信息。

main.c移动回来,从新编译,生成目标文件main.o,并查看其段信息。

florian@florian-pc:~/gdb$ mv src/main.c main.c

florian@florian-pc:~/gdb$ gcc -c main.c -o main.o -g

florian@florian-pc:~/gdb$ objdump -s main.o

 

main.o:     file format elf32-i386

 

Contents of section .text:

 0000 5589e5b8 00000000 5dc3               U.......].     

……

Contents of section .debug_str:

 0000 6d61696e 2e63002f 686f6d65 2f666c6f      main.c./home/flo

 0010 7269616e 2f676462 00474e55 20432034      rian/gdb.GNU C 4

 0020 2e342e35 006d6169 6e00                      .4.5.main.     

……

咱们发如今.debug_str段内,有两个很明显的字符串信息。

1/home/florian/gdb:看起来很像源文件所在的绝对路径。

2main.c:显而易见,是源文件的名称。

验证

咱们再把main.c移动到src目录下,再次编译,看看字符串的信息有何变化。

florian@florian-pc:~/gdb$ mv main.c src/main.c

florian@florian-pc:~/gdb$ gcc -c src/main.c -o main.o -g

florian@florian-pc:~/gdb$ objdump -s main.o

 

main.o:     file format elf32-i386

 

Contents of section .text:

 0000 5589e5b8 00000000 5dc3               U.......].     

……

Contents of section .debug_str:

 0000 2f686f6d 652f666c 6f726961 6e2f6764      /home/florian/gd

 0010 6200474e 55204320 342e342e 35007372      b.GNU C 4.4.5.sr

 0020 632f6d61 696e2e63 006d6169 6e00           c/main.c.main. 

.debug_str段内的两个字符串信息发生了变化。

1/home/florian/gdb:可见该字符串为执行gcc命令时的当前目录的绝对路径。

2src/main.c:该字符串为源文件相对于当前目录的相对路径。

将两个目录合并,即可以获得源文件的绝对路径:

/home/florian/gdb /src/main.c

结论

因而可知,使用调试选项编译生成的可执行文件内并不是保存了源文件的内容,而是源文件的绝对路径信息。DWARF调试格式(详见这里)定义的其余debug段内保存了二进制代码与源文件行号的对应关系,这样gdblist命令工做时,实际是读取可执行文件内的行号信息,并将源文件的代码内容显示出来。这也是为何将源文件移动后,list命令信息没法找到源文件的缘由。

从这里,咱们也能够清楚一个事实:当源码目录的源文件路径发生变化后,若是须要对可执行文件进行调试,则必须从新编译。

相似的问题不单单在gdblist命令中存在,objdump –S命令用于交叉显示反汇编代码与源代码,一样会受移动源文件的影响。

相关文章
相关标签/搜索