嵌入式设备使用GDB及coredump文件查找崩溃问题

2019-07-13 07:35发布

背景:1.运行目标为MIPS机器,FLASH及RAM资源都非常紧张,无法运行带调试信息的程序2.程序有一定概率崩溃,从表现上难以分析目标:直接定位到崩溃目标代码说明:1、2在运行环境中操作,3、4在编译环境中操作

1.设置内核转储

内核转储可以保存程序崩溃时的内存状态。是系统级别的实现。查看运行机器当前内核转储的设置:#ulimit -a -f: file size (blocks) unlimited -t: cpu time (seconds) unlimited -d: data seg size (kb) unlimited -s: stack size (kb) 8192 -c: core file size (blocks) 0 -m: resident set size (kb) unlimited -l: locked memory (kb) 64 -p: processes 986 -n: file descriptors 1024 -v: address space (kb) unlimited -w: locks unlimited -e: scheduling priority 0 -r: real-time priority 0当前“core file size”为0,即未开启。设置为不限制,修改运行机器的/etc/profile#添加 ulimit -c unlimited应用配置,在运行机器中执行:#source /etc/profile

2.指定崩溃文件生成路径

默认崩溃文件会生成在程序运行路径下。程序占用的内存越大,生成的崩溃文件会越大。如果只需要部分内存段信息,可以通过coredump_filter文件指定。文件位于/proc//coredump_filter,默认值为0x23,数值含义如下:(bit 0) anonymous private memory(匿名私有内存段) (bit 1) anonymous shared memory(匿名共享内存段) (bit 2) file-backed private memory(file-backed 私有内存段) (bit 3) file-backed shared memory(file-bakced 共享内存段) (bit 4) ELF header pages in file-backed private memory areas (it is effective only if the bit 2 is cleared)(ELF 文件映射,只有在bit 2 复位的时候才起作用) (bit 5) hugetlb private memory(大页面私有内存) (bit 6) hugetlb shared memory(大页面共享内存)这里我们不做修改,我们去压缩崩溃文件来减小占用体积。修改运行机器的/etc/sysctl.conf:#添加 kernel.core_pattern = | /usr/sbin/core_gzip %e %p kernel.core_uses_pid = 0 创建/usr/sbin/core_gzip脚本:#!/bin/sh exec gzip -> /tmp/$1_$2.core.gz #注意路径必须存在 修改文件属性:#chmod +x /usr/sbin/core_gzip这样程序崩溃的时候会在运行机器的/tmp下生成例如prog_1480.core.gz文件,文件名格式是由前面的%e %p指定的,具体参数含义如下:%c 转储文件的大小上限 %e 所dump的文件名 %g 所dump的进程的实际组ID %h 主机名 %p 所dump的进程PID %s 导致本次coredump的信号 %t 转储时刻(由1970年1月1日起计的秒数) %u 所dump进程的实际用户ID应用配置,在运行机器中执行:#sysctl –p /etc/sysctl.conf

3.程序编译注意事项

在本机使用交叉工具链编译的时候需要生成2个文件,一个是带调试信息的,另外一个是我们实际运行的。方法如下:
  1. 编译选项加上-g生成了体积巨大的程序prog,我们备份为prog_debug,prog_debug是用来分析崩溃文件的。
  2. 在交叉工具链中找到mips_xxx_strip工具,执行#mips_xxx_strip prog得到去掉了调试信息的正常大小的prog
另外需要注意的是,为了让程序能够产生崩溃文件,我们不能处理SIGQUIT,SIGILL,SIGABRT, SIGFPE和SIGSEGV这5个信号。

4.定位崩溃

前面我们已经准备好了运行机器环境和带调试信息的程序。等待程序崩溃后,我们从运行机器中拿到prog_1480.core.gz,#gzip -d prog_1480.core.gz解压后得到prog_1480.core原始崩溃文件。使用交叉工具链的mips_gdb工具执行:#mips_xxx_gdb -ex bt prog_debug prog_1480.core不出意外的话我们会看到崩溃代码和堆栈信息(-ex bt表示在mips_gdb中执行bt指令)Core was generated by `/tmp/prog'. Program terminated with signal 11, Segmentation fault. #0 manmade_crash(this=this@entry=0x8fdf50) at /mnt/d/workspace/crash/main.cpp:250 250 *i = 12; #0 xxx1.cpp:123 #1 xxx2.cpp:86 #2 xxx.h:66 Backtrace stopped: frame did not save the PC问题找到了。可能我们会在mips_gdb的时候看到不能加载共享库文件的提示warning: Could not load shared library symbols for 9 libraries, e.g. /lib/libpthread.so.0.在gdb中输入(gdb) info sharedlibrary查看下共享库的加载情况
From To Syms Read Shared Object Library No /lib/libpthread.so.0 No /usr/lib/libstdc++.so.6 No /lib/libm.so.0 No /lib/libgcc_s.so.1 No /lib/libc.so.0 No /lib/ld-uClibc.so.0在本机用户目录下我们新建一个.gdbinit文件把我们程序用到的交叉编译链的库路径包涵进去:set solib-search-path ~/sdk/staging_dir/toolchain-mipsel/lib这样使用mips_gdb分析的时候就可以加载程序使用的共享库了。