前言
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参数不只是给编译器用的,指明编译出的编译器编译出的程序运行的平台,而是编译出的程序需要处理的目标的平台。
还有一个有意思的地方是这两种参数编译出来的产物也不同,如果指定了host(交叉编译),那么产物是gcore gdb gdb-add-index gdbserver run,而指定target,产物是gdb gdb-add-index run,少了gcore和gdbserver。
编译
具体编译过程可参照Building GDB and GDBserver for cross debugging。
编译过程还好,可能问题都是由于我这个ubuntu是被简化过的,过程中有不报不支持c++11,实际上是g++没安。
一个编译gdb常见的问题可能是缺少libtermcap库,实际这个库很老了,之前编译也不好编,只能编出静态库,而且指定了也不好用,可以去下载ncurses源码,交叉编译使用之。
还有就是报缺少gmp,我当时用apt在装,可能是脑子不清醒了,实际交叉编译缺库,安装自己平台的库是没用的,因此去下载了gmp源码交叉编译,指定-I和-L就可以了。
最后把编译好的gdbserver拷贝到arm设备就可以了。
如果只编译嵌入式设备的gdbserver的话应该不需要额外的库,看编译完的依赖:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-aarch64.so.1]
很明显是不需要 额外库的。看了本节开头的链接后,编译gdbserver只需要:
../configure --host=aarch64-linux-gnu --prefix=/opt/linkcopy/ CPPFLAGS="-Wno-error"
make -j4 all-gdbserver
跟本不需要去交叉编译那些库。
使用源码包版本记录,全部下载于http://ftp.gnu.org
gdb-12.1.tar.gz
gmp-6.2.1.tar.xz
ncurses-6.4.tar.gz
连接
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。
编译脚本
说明
#mipsel-buildroot-linux-uclibc-gdb runs on x86_64 PC as a client, and gdb,gdbserver runs on mipsel as a server
$ file mipsel-buildroot-linux-uclibc-gdb
mipsel-buildroot-linux-uclibc-gdb: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=af78561b1581d8d27e1d21133c2a3899240e9b02, stripped
$ file gdbserver
gdbserver: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked (uses shared libs), stripped
定义
${CROSS}定义为交叉编译工具链前缀,例如mips-rtl83xx-linux
:
$ CROSS=mips-rtl83xx-linux
#CROSS=aarch64-linux-gnu
#CROSS=aarch64-none-linux-gnu
$ echo $CROSS
mips-rtl83xx-linux
脚本
拷贝注意换行符!!!
拷贝注意换行符!!!
拷贝注意换行符!!!
pc端gdb:
#mipsel-buildroot-linux-uclibc-gdb(x86_64)
mkdir -p build_x86_64 && cd build_x86_64
../configure \
--target=${CROSS} \
--prefix=$(pwd)/../out_x86_64 \
--enable-shared
make -j4 all-gdb
make install-gdb
嵌入式设备端gdb以及gdbserver编译,以下二选一:
- 只编译gdbserver,无需任何额外的库
#gdbserver(嵌入式平台)
mkdir -p build_${CROSS} && cd build_${CROSS}
../gdb/gdbserver/configure \
--host=${CROSS} \
--prefix=$(pwd)/../out_${CROSS} \
--enable-shared
make -j4
make install
- 编译gdb与gdbserver,需要ncurses库
#前置依赖,
#ncurses(嵌入式平台)
mkdir -p build_${CROSS} && cd build_${CROSS}
../configure \
--host=${CROSS} \
CC=${CROSS}-gcc \
AR=${CROSS}-ar \
--prefix=$(pwd)/../out_${CROSS} \
--without-shared \
--without-normal \
--without-cxx \
--without-cxx-binding \
--without-cxx-shared \
--disable-db-install \
--without-pkg-config \
--disable-pc-files \
--without-manpages \
--without-tack \
--without-tests \
--without-ada \
--without-progs \
--without-debug
make -j4
make install.libs
#gdb&&gdbserver(嵌入式平台)
mkdir -p build_${CROSS} && cd build_${CROSS}
../configure \
--host=${CROSS} \
--prefix=$(pwd)/../out_${CROSS} \
CPPFLAGS="-I$(pwd)/../../ncurses-6.4/out_${CROSS}/include" \
LDFLAGS="-L$(pwd)/../../ncurses-6.4/out_${CROSS}/lib -lncurses" \
--disable-libquadmath \
--disable-libquadmath-support \
--disable-libada \
--disable-libssp \
--disable-libstdcxx \
--disable-bootstrap \
--disable-isl-version-check \
--disable-cloog-version-check \
--disable-lto \
--disable-objc-gc \
--disable-maintainer-mode \
--disable-werror \
--disable-host-shared
make -j4 all-gdb
make install-gdb