您的位置:首页 > 其它

GDB调试技巧

2009-11-26 20:00 309 查看
在公司工作了一段时间,发现B/S结构的代码调试很麻烦,经常用的手段是通过printf打一串消息来进行跟踪,然后估计问题出在哪里。通过逐步添加printf语句,获得越来越多的信息最终确定问题的根源。我感觉这样比较麻烦,如果能把gdb的单步调试功能用上就好了。工作之余,做了一定的尝试,希望对跟我一样感到麻烦的人有一丁点帮助。
调试信息的生成
进行gdb调试时最重要的是要保存调试信息,.c与.cpp文件编译之后可生成.o、.a、.so以及可执行文件等等。如果依赖文件中存在.c或.cpp文件,编译时加上-g选项,那么就可以用gdb调试目标文件了。值得注意的是:如果将.c或.cpp编译(加上了-g)成.o文件,再将这些.o文件编译(没有用到-g)成.so,虽然编译成.so时没有用到-g,但.so文件中仍然保存了调试信息,仍可用gdb调试。
保存调试信息的根源在于用-g编译.c与.cpp文件,其他中间过程可不用-g。
利用部分源文件调试
gdb调试时,如果有源代码,那就能单步执行,一步一步的查看结果,能方便的定位问题。但是,如果源代码很庞大,而公司又不允许把全部代码拿出去调试,那就可以只拿一部分代码出去调试。在此我做了一个小实验来说明这个问题。
假设代码放在3个目录下:
1. show目录,包含2个文件:
【1】show.h
void show();
【2】show.c
#include "show.h"
#include <stdio.h>

void show()
{
printf("show/n");
}
2. display目录,包含2个文件:
【1】display.h
void display()
【2】display.c
#include "display.h"
#include <stdio.h>

void display()
{
printf("display/n");
}
3.main目录,包含一个文件:
#include "../show/show.h"
#include "../display/display.h"

int main()
{
show();
display();
}

将show.c编译成共享库:gcc -shared -g -o libshow.so show.c,将libshow.so拷贝到/lib下。
将display.c编译为.o文件:gcc -g -c display.c。
生成可执行文件:gcc -g -o main main.c ../display/display.o –lshow。
此时可用gdb main进行单步调试,执行到show();时按s进入函数。如果将.so与main拷贝到另一台机器上,不拷贝源码,运行gdb main时由于没有源码,无法单步调试,此时将main.c拷贝过来即可单步调试。
如果想进入show函数调试,可将show.c拷贝过来,放到跟main同样的路径下。
同理,如果想进入display函数调试,可将display.c拷贝过来,放到跟main同样的路径下。
无论编译时源文件的路径怎样,部署之后,只需将源文件与可执行文件放在同一目录即可进行调试。
另外一个问题是,如果没有拷贝main.c,又想调试display函数怎么办?这就需要用到断点:
【1】gdb main
【2】l display.c:1
【3】b display.c:6
【4】r
可以看到已经执行到display函数里边了,这下又可以通过按n来进行单步调试了。同样的方法适用于调试show函数,不过用“l show.c:1”时会提示找不到源文件(这一步可不必执行),此时不用理会直接用“b show.c:6”设置断点即可。
段错误的处理
程序运行时经常遇到烦人的段错误,可用core文件进行调试。
敲入指令“ulimit -c”,如果输出0就表示不会产生core文件,应该进行修改以允许core文件的产生,“ulimit -c unlimited”或者“ulimit -c 1024”等等。
假设运行main时产生了段错误并产生了core文件“core.2182”,此时就可以用“gdb main core.2182”进行调试,就可以看到出错信息,如果有源文件并且编译时用到了-g,那就还可以看到出错的是哪条语句。

总的来说,编译.c或.cpp时加上-g选项保存调试信息,可将我们关注的部分源代码与可执行文件放在同一目录下进行单步调试跟踪,当程序出现段错误时可利用core文件查看出错信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: