利用Yocto工程生成debug符号

实现目的 #

嵌入式设备在进行gdb调试时,由于存储容量限制,文件系统中一般不会包含debug版本的libc库,导致总是会提示找不到符号表,如下

(gdb) n

Program received signal SIGABRT, Aborted.
0xb6c0fbe6 in ?? ()
(gdb) bt
#0  0xb6c0fbe6 in ?? ()
#1  0xb6c1ebce in ?? ()

如果程序需要依赖多个库,就需要单独去编译每一个依赖的库为debug版本,不太现实,可以利用yocto工程一次性解决,轻松实现目标,生成debug版本的安装包或者debug版本的文件系统。

利用Yocto工程生成debug符号 #

默认SDK包中并不包含debug版本的库和源码文件,为了让gdb找到符号表,需要重新编译SDK,开启debug相关选项,通过如下两步,可以获得一个debug安装包,安装之后,会在原有SDK安装目录下添加debug版本的库和源码文件,这样在执行GDB调试时,指定好相应的目录就能找到符号表了

1、修改conf/local.conf文件 #

新增如下:

#debug时添加以下选项
EXTRA_IMAGE_FEATURES ?= "tools-debug ssh-server-openssh"

#解决bitbake执行到打包时失败
RDEPENDS_packagegroup-core-standalone-sdk-target_remove = "libatomic-dev"

2、执行如下bitbake命令,生成带debug符号的SDK安装包 #

MACHINE=am335x-evm bitbake -c populate_sdk tisdk-base-image

在~/tool/tisdk/build/arago-tmp-external-arm-glibc/deploy/sdk/目录下,会生成arago-2020.09-toolchain-2020.09.sh和arago-2020.09-toolchain-2020.09.sharago-2020.09-armv7a-linux-gnueabi-tisdk.sh两个安装包,如下

qq@ubuntu:~/tool/tisdk/build/arago-tmp-external-arm-glibc/deploy/sdk$ ls -lth
total 1.2G
-rwxr-xr-x 2 qq qq 646M Apr  2 02:36 arago-2020.09-armv7a-linux-gnueabi-tisdk.sh
-rw-r--r-- 2 qq qq 7.5K Apr  2 02:32 arago-2020.09-armv7a-linux-gnueabi-tisdk.host.manifest
-rw-r--r-- 2 qq qq  49K Apr  2 02:30 arago-2020.09-armv7a-linux-gnueabi-tisdk.target.manifest
-rw-r--r-- 2 qq qq 332K Apr  2 02:30 arago-2020.09-armv7a-linux-gnueabi-tisdk.testdata.json
-rwxr-xr-x 2 qq qq 499M Feb 25 17:29 arago-2020.09-toolchain-2020.09.sh
-rw-r--r-- 2 qq qq   66 Feb 25 16:54 arago-2020.09-toolchain-2020.09.host.manifest
-rw-r--r-- 2 qq qq  81K Feb 25 16:53 arago-2020.09-toolchain-2020.09.target.manifest
-rw-r--r-- 2 qq qq 361K Feb 25 16:53 arago-2020.09-toolchain-2020.09.testdata.json

3、安装生成的两个debug包 #

3.1、安装后,安装目录中会包含sysroot目录,并且sysroot目录中包含所有程序和库对应的debug symbols

3.2、所有可执行文件的源码保存到/usr/src/debug/,相对于sysroot目录

The SDK contains a copy of GDB.

It also contains a sysroot for the target with debug symbols for all the programs and libraries that are part of the target image.

Finally, the SDK contains the source code for the executables.

In each of these directories, you will find a subdirectory named .debug/ that contains the symbols for each program and library.

GDB knows to look in .debug/ when searching for symbol information.

需要将路径指向上一步中生成的linux-devkit目录, /home/ubuntu/test_ti_sdk/linux-devkit

ubuntu:~/tool/tisdk/build/arago-tmp-external-arm-glibc/deploy/sdk$./arago-2020.09-toolchain-2020.09.sh 
Arago SDK installer version 2020.09
===================================
Enter target directory for SDK (default: /tmp/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy): /home/ubuntu/test_ti_sdk/linux-devkit                
The directory "/home/ubuntu/test_ti_sdk/linux-devkit" already contains a SDK for this architecture.
If you continue, existing files will be overwritten! Proceed [y/N]? y
Extracting SDK....................................................................................done
Setting it up...done
SDK has been successfully set up and is ready to be used.
Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.
 $ . /home/ubuntu/test_ti_sdk/linux-devkit/environment-setup-armv7at2hf-neon-linux-gnueabi

安装完成后,可以找到.debug相关目录,如下

ubuntu:~/test_ti_sdk$find ./linux-devkit -name  ".debug" -type d
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/bin/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/share/Linux-PAM/xtests/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/bin/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/libexec/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/libexec/mtd-utils/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/lib/python3.8/site-packages/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/lib/bash/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/lib/systemd/user-environment-generators/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/lib/engines-1.1/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/lib/audit/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/lib/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/lib/xtables/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/sbin/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/lib/systemd/system-generators/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/lib/systemd/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/lib/udev/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/lib/security/pam_filter/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/lib/security/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/lib/.debug
./linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/sbin/.debug

同时会在usr/src/debug/目录下包含源码,The source code for the executables is stored in /usr/src/debug/, relative to the sysroot.

ubuntu:~/test_ti_sdk$ls linux-devkit/sysroots/armv7at2hf-neon-linux-gnueabi/usr/src/debug/
acl         base-passwd  dosfstools  flac       iptables    libcap         libnss-mdns  libpng          libusb1    mtd-utils  opkg     shared-mime-info  usbutils
alsa-lib    bzip2        e2fsprogs   freetype   kbd         libcap-ng      libogg       libsamplerate0  libvorbis  ncurses    phytool  strace            util-linux
alsa-utils  cifs-utils   elfutils    glib-2.0   kmod        libdaemon      libpam       libsndfile1     libxml2    netperf    psplash  systemd           xz
attr        dbus         ethtool     i2c-tools  less        libffi         libpcap      libsolv         ltrace     nfs-utils  rpcbind  tcpdump           zlib
avahi       devmem2      expat       iperf3     libarchive  libjpeg-turbo  libpcre      libtirpc        lzo        openssl    shadow   tcp-wrappers

开启debug选项编译程序 #

makfile编译开启debug选项 #

#-g生成调试信息,-Og开启优化但是不影响GDB
LOCAL_CFLAGS += -g -Og

On some architectures, GCC will not generate stack-frame pointers with the higher levels of optimization (-O2 and above). If you find yourself in a situation where you really have to compile with -O2, but still want backtraces, you can override the default behavior with -fno-omit-frame-pointer

 -fno-omit-frame-pointer  

cmake编译开启debug选项 #

SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0  -g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
add_compile_options(-O0  -g -ggdb)

Qt工程设置debug选项 #

QMAKE_CXXFLAGS += -g -Og
QMAKE_CXXFLAGS_RELEASE += -O1

遇到错误 #

1、C库函数符号找不到 #

https://stackoverflow.com/questions/48278881/gdb-complaining-about-missing-raise-c/48287761#48287761

Program received signal SIGABRT, Aborted.
0x76cd0f70 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56  ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
#查看当前运行的源文件
(gdb) info source
Current source file is ../sysdeps/unix/sysv/linux/raise.c
Compilation directory is /build/glibc-S7Ft5T/glibc-2.23/signal
Source language is c.
Producer is GNU C11 5.4.0 20160609 -mtune=generic -march=x86-64 -g -O2 -O3 -std=gnu11 -fgnu89-inline -fno-stack-protector -fmerge-all-constants -frounding-math -fPIC -ftls-model=initial-exec.
Compiled with DWARF 2 debugging format.
Does not include preprocessor macro info.

解决办法

sudo mkdir /opt/src
cd /opt/src/
sudo apt source libc6
find $PWD -maxdepth 1 -type d -name "glibc*"
ls /opt/src/glibc-2.23/sysdeps/unix/sysv/linux/raise.c 

设置库路径

(gdb) set substitute-path /build/glibc-S7Ft5T/glibc-2.23 /opt/src/glibc-2.23

2、查找不到库文件 #

https://stackoverflow.com/questions/16254546/gdb-can-not-open-shared-object-file

(gdb) r
Starting program: /home/ubuntu/targetNFS/test/build/test_main 
/home/ubuntu/targetNFS/test/build/test_main: error while loading shared libraries: libiconv.so.2: cannot open shared object file: No such file or directory
[Inferior 1 (process 39876) exited with code 0177]
(gdb) set env LD_LIBRARY_PATH /usr/local/lib/
(gdb) set environment LD_LIBRARY_PATH /usr/local/lib/

gdb多线程及动态库调试,需要手动导入带符号表的库路径,可以查看当前已导入的库:

set solib-absolute-prefix ../out/target/product/tiny4412/symbols
set solib-search-path ../out/target/product/tiny4412/symbols/system/lib
info sharedlibrary

中间有链接静态库需要调试时,在编译静态库时需要去掉编译优化,否则单步调试会乱跳;

LOCAL_CFLAGS += -g -O0

3、找不到自己的代码文件 #

解决方法1:修改gcc 选项

-fdebug-prefix-map=/full/build/path=.
-fdebug-prefix-map=old_path=new_path

解决方法2:修改gdb配置

#利用如下命令设置替换路径规则
set subsitute-path from  to

#举个例子如下
/home/ubuntu/test/src/xxx.cpp   #编译到程序中的代码路径
/mnt/nfs/test/src/xxx.cpp		#NFS目录下实际真正的代码文件所在路径
#那么应该如下设置
(gdb) set subsitute-path /home/ubuntu  /mnt/nfs

推荐使用方法2

https://stackoverflow.com/questions/9607155/make-gcc-put-relative-filenames-in-debug-information

参考链接 #

Using Qt Creator to cross-compile and debug Raspberry Pi Qt5 apps

Qt creator gdb remote debugging with debug helpers