前言
gdb server运行于嵌入式设备,比如arm或arm64体系结构,体积小,占用资源少,相当于一个前端。gdb server可以attach到一个strip的进程。
gdb运行于性能更高的主机,如x86设备上,需要有带符号表的相应进程。
以下分别以aarch64和x86来指带被调试进程运行设备(也就gdbserver运行设备)和gdb运行的设备。
关于gdb编译参数–target
我是使用ubuntu docker编译的gdb和gdb server,之前去简单看了下gdb的官方文档,不过也没咋看明白,之前在automake中文手册中提到过–target=target选项,我一直以为这个只有在交叉编译编译器的时候才会用到,但编译gdb时也用到了。
首先确认一下,需要编译的至少有两个进程,gdb与gdbserver,分别运行于x86和arm平台,gdbserver运行于进程真正运行的设备上,毫无疑问,指定–host=aarch64就可以了。
而gdb需要怎么编译呢?若指定–host=aarch64,则变成了arm平台的程序,但是若不指定host,那么变成了x86平台的普通gdb了,经过亲身实践,不带参数指定编译完的gdb在远程连接gdbserver后是不能正常调试的。
但是当使用同一源码编译gdb时携带–target=aarch64,则可以正常调试。
这里引用一句话:
target:表示需要处理的目标平台名称,若无指定使用 host 相同名称,gcc、binutils, gdb
等与平台指令相关的软件都有此参数,多数软件此参数无用处。
因此之前对target参数的理解可能偏狭隘,target参数不只是给编译器用的,指明编译出的编译器编译出的程序运行的平台,而是编译出的程序需要处理的目标的平台。
编译
编译过程还好,可能问题都是由于我这个ubuntu是被简化过的,过程中有不报不支持c++11,实际上是g++没安。
一个编译gdb常见的问题可能是缺少libtermcap库,实际这个库很老了,之前编译也不好编,只能编出静态库,而且指定了也不好用,可以去下载ncurses源码,交叉编译使用之。
还有就是报缺少gmp,我当时用apt在装,可能是脑子不清醒了,实际交叉编译缺库,安装自己平台的库是没用的,因此去下载了gmp源码交叉编译,指定-I和-L就可以了。
最后把编译好的gdbserver拷贝到arm设备就可以了。
连接
arm设备:
先编个程序:
pi@link:~/project$ cat test.cpp
#include<iostream>
using namespace std;
int main()
{
cout<<"hello world!"<<std::endl;
}
pi@link:~/project$g++ -g -O2 test.cpp
然后做个strip的版本,把原版拷贝到x86设备,然后运行
gdbserver link.local:6000 a_strip.out
x86设备:
/opt/bentutucopy/bin/aarch64-linux-gnu-gdb a.out
之后在gdb里执行:
(gdb) target remote link.local:6000
然后这两个就连上了,可以开始使用了。
使用
1)远程获取/上传/删除文件
remote get/put/delete命令
这样在测试的时候,在嵌入式设备上编译的带符号表版本的进程可以直接下载到本地设备。
2)运行进程
- 用gdbserver attach已经运行的进程
- 运行时命令行指定要调试的进程,然后用gdb连接后运行continue(不让运行run)。
- 不指定任何进程启动gdbserver:
$ gdbserver --multi localhost:6000
,然后在gdb指定要调试的进程,但客户端必须要用target extended-remote命令连接。连接后使用set remote exec-file a.out
指定要调试进程的名字,然后就可以运行run了。需要注意的是以–multi启动的gdbserver不会主动退出,需要在gdb端连接后使用monitor exit
显式退出,除非一种情况,在启动gdbserver时还指定了–onece。