gdb调试core dump文件
1 随时收录
-
gdb 调试时符号文件在哪里?
若是指定为
CMAKE_BUILD_TYPE=Debug
,那么符号文件会嵌入到可执行文件中;
如Debug编译产生的文件不能显示源代码,可以再执行以便cmake和make,因为有可能在某种情况下,编译会出错。 -
如何定位动态库中的代码
在gdb调试时,只有让程序运行起来之后,才会加载动态库,之后,b到某一个行之后,使用
i sharedlibrary
查看已经加载的动态库。之后,就可以b 动态库中的代码所在文件:行号
,来定位具体的代码; 之后再执行c
,就可以在运行过程中,当触发对应的条件,就可以定位到断点处; -
如何设置条件断点
condition开头,后面跟上断点号,之后对期望的变量进行条件判断,如下所示:
#gdb条件断点 condition 1 value==1 # (C语言风格),只有再value为1时才命中 #忽略前几次命中,在ignore之后紧跟断点号,之后是数据表示忽略前几次 ignore 1 4 # 忽略断点1的前4次命中
-
d br
: 删除所有的断点 -
p /t var-name
: 打印变量var-name
的二进制内容 -
i args
: 显示当前和函数的参数
2 core dump
文件处理和分析
将core文件,统一放到一个固定的目录下,如/corefile
,方便统一管理;
sudo mkdir /corefile
sudo chmod /corefile
将/proc/sys/kernel/core_pattern
中的内容改为:/corefile/core-%e-%p%t
;
一个小方法测试产生core文件, 直接输入命令:kill -s SIGSEGV $$
产生coredump一般都是在进程收到某个信号的时候,Linux下大概有60多个信号,可以使用kill -l
命令全部列出来.
2.1 产生和配置core文件
-
ulimit -c
: 检查和设置core文件生成的限制,输出为0,表示不生成core文件,使用ulimit -c unlimited
,设置为无限制; -
/proc/sys/kernel/core_pattern
: 默认情况下,core文件会生成再程序运行所在的目录,可以修改此文件来指定core文件的存放位置和命名方式,例如:sudo echo "/tmp/core.%e-%p-%t-%s" > sudo /proc/sys/kernel/core_pattern
该命令改变
code dump
位置说明:
%e: 程序文件的完整路径(路径中的/会被!替换)
%p: 进程ID
%t: 进程崩溃的时间戳
%s: 哪个信号让程序崩溃
2.2 永久生效可生成core dump
的方法
2.2.1 方法一
使用2.1
的方法,只能对当前的终端环境有效,要永久生效,可以修改文件/etc/security/limits.conf
文件.
-
关闭服务apport:默认自动开启,功能是自动生成崩溃报告,官方为来自动收集错误的软件,即
automatic crash report generation.
经验证同时开启coredump功能,对debug版本带-g编译产生的c++程序,不能自动生成崩溃文件.
解决方案:关闭apport服务
service apport status
: 查看该服务sudo service apport stop
: 关闭apport.service服务程序
2.2.2 方法一
vim ~/.bashrc
# 添加如下信息
ulimit -c unlimited
source ~/.bashrc
2.3 分析core文件
-
启动gdb
将可执行文件和core文件一起传给gdb
gdb /executable /path/to/core
-
在gdb中分析
进入gdb后,可以使用一些命令来分析文件
bt
: 查看崩溃位置list
: 查看代码上下文print variable_name
: 查看变量值- other command:
info locals
: 显示当前函数的局部变量;info args
: 显示当前函数的输入参数;info registers
: 显示CPU寄存器的内容;
3 在Ubuntu上调试ARMv7的core文件
3.1 预备
-
uname -a
: 获得目前嵌入式系统Linux (none) 3.8.11-xilinx #40 SMP PREEMPT Thu Jan 12 17:02:11 CST 2023 armv7l GNU/Linux
-
安装armv7的交叉编译工具链:
sudo apt-get udpate sudo apt-get install gcc-arm-linux-gnueabihf gdb-multiarch
gcc-arm-linux-gnueabihf
: 是交叉编译器,用于在Ubuntu上编译ARMv7架构程序;gdb-multiarch
: 支持多种架构的GDB版本,可以用来调试ARMv7程序;
安装
gcc-arm-linux-gnueabihf
之后,相关的文件在如下目录中:/usr/local/ti-sdk-am335x-evm/linux-devkit/sysroots/i686-arago-linux/usr/bin/
将ARMv7下的可执行文件和core dump文件拷贝到如上文件夹下
若如上文件夹下没有
arm-linux-gnueabihf-gdb
文件,可以使用gdb-multiarch
替代.为方便gdb调试时使用
set solib-search-path
设置库文件,可以将可执行文件所需要引用的库文件也一同放在如上目录下,不过建议还是同一放到一个固定的地方,方便调试,如:~/crash/
下,可以存放,如下文件:可执行文件
: 执行该文件产生了如下的core dump文件;core
: 即core dump文件library
: 该可执行文件依赖的库文件
而将对应的ARMv7的系统库文件可以放在
/opt/
下,如:/opt/arm_lib
: 该文件夹下存放ARMv7系统/lib
下的系统库文件和C运行库;/opt/arm_usr_lib
: 该文件夹下存放ARMv7系统/usr/lib
下的用户级运行库;
以上这5个文件,当使用
gdb-multiarch
调试时,需要使用set solib-search-path
来设置,各个文件夹以:
隔开; -
获取ARMv7上的系统库文件
分别有/lib
和/usr/lib
-
/lib
: 包含基本系统程序使用的共享库文件,例如: C库, 内核模块等 -
/usr/lib
: 包含用户级应用程序使用的库文件并将该库存放到当前ubuntu下的
/opt/下
,如/opt/arm_lib
和/opt/arm_usr_lib
-
将Arm下运行的可执行文件所依赖的库,存放到指定位置,如
/opt/arcs/librarys/
当
gdb-multiarch
调试时,需要使用set solib-search-path
来设置所引用库的全部文件;
3.2 直接在非ARM的主机上调试ARM下生成的core文件
sudo gdb-mulitarch ./ARCS ./core
set solib-search-path /opt/arm_lib/:/opt/arm_usr_libs/:Libraries/:Libraries/lib1/:Libraries/lib2/
: 设置so的库文件搜索路径, 注意这里的Libraries/:Libraries/lib1/:Libraries/lib2/
这三个文件夹是当前可执行文件所需要使用的库文件,且都存放在/usr/local/ti-sdk-am335x-evm/linux-devkit/sysroots/i686-arago-linux/usr/bin/
下,推荐放在和可执行文件、core文件的同一级目录,方便调试。(gdb) set sysroot /opt/arm_lib
: 设置root目录,并回车之后,就会开始加载有符号文件的动态库;之后,就可以运行bt查看崩溃堆栈信息;bt
: 查看堆栈信息i sharedlibrary
: 查看哪些动态库有符号文件;f num
: 切换堆栈层;l
: 查看相关代码;
3.3 注意事项
- 产生core文件的可执行文件,最好使用debug版本,这样可以更好的进行排查问题;
- 最好将可执行文件,core文件,当前可执行文件所依赖的本地库文件放到同一个文件夹下,方便
gdb-mutliarch
进行set solib-search-path
设置; - 若执行以上的
2.
操作之后,没有分析堆栈信息,可以使用set sysroot /opt/arm_lib
来强制分析;
4 在Ubuntu上远程调试ARMv7上的可执行文件
4.1 在ARM目标设备上安装gdbserver
可以多种方法安装gdbserver
-
通过
sudo apt
直接在目标设备上安装gdbserver,如下所示sudo apt update
sudo apt install gdbserver
-
通过
sudo apt
先在Ubuntu上安装gdbserver,如下所示sudo apt update
sudo apt install gdbserver
: 安装gdbserverwhich gdbserver
: 查找到gdbserver的安装位置,找到该文件之后,将它拷贝到ARM系统中,假如在/usr/bin/gdbserver
下;scp /usr/bin/gdbserver root@target_device_id:/home/user
: 将Ubuntu下的gdbserver拷贝到ARM设备上;-
可能遇到的问题:
gdbserver: line 1: syntax error: unexpected "("
- 原因分析: 拷贝到ARMv7上的
gdbserver
可执行文件并不是ARM架构的二进制文件,而是x86/x86_64
架构的二进制文件,导致在ARMv7设备上无法运行;
要解决该问题,需要获取适用于ARMv7架构的
gdbserver
,有以下几种方法:- 从ARMv7的软件源安装
sudo apt update
sudo apt install gdbserver
若该方法不可用,使用以下方法
-
交叉编译gdbserver
-
安装必要工具
sudo apt install gcc-arm-linux-gnueabi
sudo apt install g++-arm-linux-gnueabi
(也可直接安装gcc-arm-linux-gnueabihf
)
-
获取gdbserver源码
git clone git://sourceware-org/git/binutils-gdb.git cd binutils-gdb
-
配置和编译
cd binutils-gdb ./config --host=arm-linux-gnueabi make
-
将编译好的
gdbserver
拷贝到ARMv7设备scp gdbserver user@target_device_ip:/path/to/targe
-
在目标设备上设置权限
ssh user@target_device_ip chmod +x /path/to/target/gdbserver
-
-
下载预编译的gdbserver
一些嵌入式Linux发行版(例如:Linar或Yoctor Project)提供适用于ARM的预编译
gdbserver
-
注意项
无论使用哪种方法,都可以使用
file
命令检查gdbserver
可执行文件的架构.file /path/to/targe/gdbserver
输出应该包含
ARM
- 原因分析: 拷贝到ARMv7上的
-
4.2 在目标设备上设置权限
ssh user@target_device_ip
: 通过ssh登录可以登录ARM系统;target_device_ip
为ARM系统的IP地址,user
为ARM系统的用户;chmod +x /home/user/gdbserver
: 设置gdbserver为可执行文件;
4.3 在目标设备上启动gdbserver
在目标设别上,通过gdbserver
启动我的可执行文件,并指定调试的端口,假设我的可执行文件位于/home/user
下
/home/user/gdbserver :1234 /home/user/my_program
4.5 连接
在Ubuntu主机上启动gdb-multiarch
并连接gdbserver
gdb-multiarch my_program
在GDB提示符下,连接到目标设备上的gdbserver
(gdb) target remote target_device_ip:1234
4.6 开始调试
现在已经连接到目标设备,可以使用GDB进行调试, 一下是一些常用命令:
(gdb) break main
(gdb) continue
(gdb) step
(gdb) print variable_name
(gdb) bracetrace