在GDB调试程序的时候,如果程序带有很长的参数列表,或者调试命令本身很长,需要频繁启动调试会话时,频繁输入参数或者命令严重拖慢调试节奏,这里记录一个GDB非常有用的参数-x,可以将调试参数和调试命令以调试脚本的形式提供给GDB调试会话,这样就不用频繁输入调试命令和参数了。
Linux上,万事不决问"男人","man"就是这个男人(还好是单数,如果是men就有点儿邪恶了), 我们先man一把gdb,看官方文档对 "-x"选项的解释。
所以,我们可以在gdb -x参数后面,跟随一个gdb命令脚本来进行程序调试,脚本的格式和.gdbinit相同,以文本的形式提供。不同之处在于.gdbinit是默认的GDB脚本,无需选项指定,如果当前目录或者环境目录存在,GDB会自动调用执行,但是对于任意名字的GDB 脚本文件,则需要 -x选项指定了。
比如,在调试某款平台的时候,我写了两个脚本,第一个脚本是ddrinit,用于初始化内存,使内存可用,内容如下:
第二个是osinit,用于内存初始化完毕后,加载程序固件.
使用方法很简单,执行gdb -x ddrinit后,q退出,接着执行gdb -x osinit,运行固件就可以调试了。
同样的方式可以在Linux Native平台上调试native 应用:
比如,调试darknet的时候,由于darknet的推理命令特别的长,我们就可以用这种方式,将参数列表写在gdb脚本文件中,不用每次都在GDB会话中set args输入。
./darknet detector test ./cfg/coco.data ./cfg/yolov3.cfg ./yolov3.weights data/dog.jpg -i 0 -thresh 0.25
编辑gdb脚本文件,命名为args.
接着执行命令
gdb ./darknet -x args
就可以愉快的调试了:
其它调试技巧
带参数调试的另一种方式:
gdb --args ./qemu-system-x86_64 -m 4096 -smp 4 --enable-kvm -drive file=/home/zlcao/Workspace/iso/ps.img -device vfio-pci,sysfsdev=/sys/bus/mdev/devices/f422fd86-35c0-11ef-8e50-9342c1138a56 -device vfio-pci,sysfsdev=/sys/bus/mdev/devices/c04de378-35d8-11ef-95c3-339660dfc874
其它调试技巧
我们在使用GNU工具链(gcc/g++)编译器编译程序的时候,使用-g选项编译可调试的目标文件,有的时候,虽然目标文件不带调试信息,但是我们不想更换目标文件,仍然想在现有的不带调试信息的目标文件上编译,有什么办法么?
有的,方法简单来说,就是先编译生成一个带调试信息的目标文件,然后用这个目标文件中的调试信息调试原来不带调试信息的目标文件,示意图如下:
我们就以如下C++程序为例来说明:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void fn() { cout << "In Base class" << endl; }
};
class Sub :public Base
{
public:
virtual void fn() { cout << "In Sub class" << endl; }
};
int main(int argc, char **argv)
{
Base *p;
Base bc;
Sub sc;
Sub mc;
p=&bc;
p->fn();
p=≻
p->fn();
p=&mc;
p->fn();
return 0;
}
首先编译两个可执行文件版本,debug和不带debug的。
$ g++ cpp.cpp -O0 -g -o debug
$ g++ cpp.cpp -O0 -o nodebug
~/czl/cpp$ g++ cpp.cpp -O0 -g -o debug
~/czl/cpp$ g++ cpp.cpp -O0 -o nodebug
~/czl/cpp$ ls
cpp.cpp debug nodebug
可以看到nodebug的程序确实是无法调试的
我们用如下命令就可以实现用nodebug的调试信息调试debug.
$ gdb --symbol=$debugfile -exec=$nodebugfile
可以看到,确实可以i调试了,如下:
~/czl/cpp$ gdb --symbol=debug -exec=nodebug
GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from debug...done.
(gdb) b main
Breakpoint 1 at 0xaa9: file cpp.cpp, line 16.
(gdb) r
Starting program: /home/xxx/czl/cpp/nodebug
warning: Probes-based dynamic linker interface failed.
Reverting to original interface.
Breakpoint 1, main (argc=1, argv=0x7fffffffe278) at cpp.cpp:16
16 {
(gdb) l
11 public:
12 virtual void fn() { cout << "In Sub class" << endl; }
13 };
14
15 int main(int argc, char **argv)
16 {
17 Base *p;
18
19 Base bc;
20 Sub sc;
(gdb)
或者我们把debug文件中的符号表提取出来单独组成一个文件
$ objcopy --only-keep-debug debug debug.symbol
~/czl/cpp$ objcopy --only-keep-debug debug debug.symbol
~/czl/cpp$ ls
cpp.cpp debug debug.symbol nodebug
然后,在单独引用debug文件即可
~/czl/cpp$ gdb --symbol=debug.symbol -exec=nodebug
GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to c