源文件移动后gdb不显示代码的原因

 

问题

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

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

int main()

{

return 0;

};

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

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

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

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:看起来很像源文件所在的绝对路径。

(2)main.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命令时的当前目录的绝对路径。

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

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

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

结论

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

从这里,我们也可以清楚一个事实:当源码目录的源文件路径发生变化后,如果需要对可执行文件进行调试,则必须重新编译。

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

源文件移动后gdb不显示代码的原因的更多相关文章

  1. js DIV延时几秒后消失或显示代码

    1.最常用的方法:  代码如下 复制代码 <script language='javascript' type='text/javascript'> $(function () {     ...

  2. vue页面加载前显示{{代码}}的原因及解决办法

    进入正题,简单说说自己对html中出现{{}}的原因及解决办法: 这样写的话,就会出现{{}}一闪的情况: 原因:html的加载顺序: 解析html结构 -> 加载外部脚本和样式表文件 -> ...

  3. 解决Button设置disabled后无法执行后台代码问题

    一.开始调式下面的程序,发现Button在js中设置disabled后无法执行后台代码(btnsave_Click)问题 <asp:Button ID="btnsave" r ...

  4. C# Winform中DataGridView绑定后DataGridViewCheckBoxColumn无法显示的问题

    在控件DataGridView绑定数据源后,发现DataGridViewCheckBoxColumn不能显示当前的check值.经过一番努力,现将完整代码奉献出来,仅供参考. 错误代码: /*禁止自动 ...

  5. 20145311利用gdb调试汇编代码

    利用GDB调试汇编代码 首先编写c语言原代码,我使用的是同学分析过的代码 #include<stdio.h>short addend1 = 1;static int addend2 = 2 ...

  6. 如何通过VIM把代码格式化后生成HTML网页代码

    本文转自http://wangxiaoyu.blog.51cto.com/922065/203471 需求及思路:演示需要,需要网站上嵌入一些代码,我的建议做法是根据代码文件,生成相应的HTML代码, ...

  7. tableview 选中一行后,不显示选中颜色

    tableview 选中一行后,不显示选中颜色 千万不要将tableview的allowsSelection设置成NO,那样的话可能导致tableview不能响应点击动作. 应该使用:cell.sel ...

  8. C#读写Access数据库、表格datagridview窗体显示代码实例

    C#读写Access数据库.表格datagridview窗体显示代码实例 最近项目中用到C#对于Access数据库表读写.mdb操作,学习了下相关的东西,这里先整理C#对于Access数据库的操作,对 ...

  9. 解决echart在IE中使用时,在div中加入postion后图表不显示问题

    <!-- 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main" style="height:400px;width:1 ...

随机推荐

  1. 虚拟机下CentOS 配置IP地址的三种方法

    1.自动获取IP地址(我不是用的这种方法,不做过多介绍) 虚拟机使用桥接模式,相当于连接到物理机的网络里,物理机网络有DHCP服务器自动分配IP地址. #dhclient 自动获取ip地址命令 #if ...

  2. prototype 和__proto__

    //Animal构造函数 function Animal(name){ this.name = name; } //Animal原型对象 Animal.prototype = { id:"A ...

  3. ASP.NET - 回滚事务

    SqlConnection con =new SqlConnection(ConnectionDb.conStr);//获取数据库连接 con.Open();//打开连接 SqlTransaction ...

  4. win 文字转化为语音

    mshta vbscript:createobject("sapi.spvoice").speak("hello")(window.close)

  5. BZOJ1565 [NOI2009]植物大战僵尸(拓扑排序 + 最大权闭合子图)

    题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=1565 Description Input Output 仅包含一个整数,表示可以 ...

  6. 每天一个linux命令--批处理

    简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理. 创建批处理脚本wanghy.sh: #!/bin/sh cd /opt/virgo-tomcat-se ...

  7. Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数

    特殊变量列表 变量 含义 $0 当前脚本的文件名 $n 传递给脚本或函数的参数.n 是一个数字,表示第几个参数.例如,第一个参数是$1,第二个参数是$2. $# 传递给脚本或函数的参数个数. $* 传 ...

  8. Logical query-processing phases

    Logical query-processing phases in brief (1) FROM This phase identifies the query’s source tables an ...

  9. Easyui Ajax验证Form表单。。。

        今天做项目用到easyui Ajax验证表单.本想自定义一个easyui的验证,查资料发现easyui 自带了一个通用的验证!见以下下截图. 后台返回值 true验证通过,返回false验证失 ...

  10. what do i get for?

    有时候经常反思,做事究竟为了什么? 有时候,又无法解释,过去做的一些事情,是为了什么? 就像上小学时候明明挺到讨厌学习的,但上了初中后就开始玩命学习了 上高中时候认为自己真的是喜欢上学习了,上大学尼玛 ...