李迟按:

调试是程序员的一项基本能力,经历过大大小小的实战,随着见识的增长,只要用心留意并做总结,相信调试的能力会越来越好。写程序不可能没有bug,只是bug容易不容易被发现,bug的危害大不大。笔者使用coredump调试很多年了,也有部分的工作笔记,无奈事多人懒,一直没有好好总结。直到最近帮同学排查bug时,才真正下定决心写几篇文章。本文为开篇,主要描述coredump作用及配置的一些注意事项,并给出简单示例。

一、介绍

程序运行过程中,难免会出现这种或那种错误导致其异常崩溃。如果使能了coredump,则操系统在程序出现异常时生成一个文件,一般名称为core。该文件有大量可以帮助我们分析程序状态的信息——比如可回溯函数栈帧。与gdb实时运行程序调试不同,coredump是一种事后分析的手段。特别适合一些错误很难重现的程序,例如设备运行三天后,挂掉了,可能是内存泄漏导致内存不够用了,可能哪个模块在一个条件语句中出现了指针非法。使用gdb对coredump文件可以分析程序崩溃之前执行的代码片段,可以帮助我们快速定位错误。

二、配置coredump

2.1 使用调试版本

一般地,在软件开发阶段,都会使用调试版本。亦即程序使用-g来编译,另外要注意,不能用strip命令对生成的可执行文件进行精简。这一切均是为了可执行文件保留着调试信息,以方便使用gdb进行调用。

2.2 设置ulimit

为了在程序崩溃时产生coredump文件,要设置coredump大小。先进行查看:

root@latelee:~# ulimit -a
time(seconds)        unlimited
file(blocks)         unlimited
data(kb)             unlimited
stack(kb)            8192
coredump(blocks)     0
memory(kb)           unlimited
locked memory(kb)    64
process              545
nofiles              1024
vmemory(kb)          unlimited
locks                unlimited

可以看到,其中coredump一行值为0,此时无法产生coredump文件。因此要设置其文件为无限大,命令:

# ulimit -c unlimited

结果如下:

root@latelee:~# ulimit -a

time(seconds)        unlimited
file(blocks)         unlimited
data(kb)             unlimited
stack(kb)            8192
coredump(blocks)     unlimited
memory(kb)           unlimited
locked memory(kb)    64
process              545
nofiles              1024
vmemory(kb)          unlimited
locks                unlimited

另外,要程序运行的同一环境下执行。比如,不能在一个终端设置ulimit,而在另一个终端运行程序,这样不能生成coredump文件的。

为了保证coredump文件名称的唯一性,可以用下面命令设置:
# echo 'core.%e.%s.%t' > /proc/sys/kernel/core_pattern  # 设置生成的coredump文件名称

2.3 万一程序因段错误等原因崩溃,则会生成core文件。

2.4 3、有了coredump文件,就可以结合可执行文件,使用gdb进行调试了,命令形式如下:
# gdb hello core

(注:需保证编译器一致)

三、实例演示

下面使用李迟当年参考uboot源码实现的命令行解析代码为例。

首先,代码编译时必须带-g选项。
然后,在命令行中设置core文件:
[latelee@latelee creadline]$ ulimit -c unlimited

运行程序:
[latelee@latelee creadline]$ ./a.out
Hit any key to stop autoboot:  0
You abort.
NotAShell> print
in print ...
Segmentation fault (core dumped)

(已经产生了coredump文件)

下面使用gdb调试:
[latelee@latelee creadline]$ gdb a.out core.2896

gdb打印信息如下:
GNU gdb Fedora (6.8-29.fc10)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /usr/lib/libstdc++.so.6...done.
Loaded symbols for /usr/lib/libstdc++.so.6
Reading symbols from /lib/libm.so.6...done.
Loaded symbols for /lib/libm.so.6
Reading symbols from /lib/libgcc_s.so.1...done.
Loaded symbols for /lib/libgcc_s.so.1
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
[New process 2896]
#0  0x0084d626 in memcpy () from /lib/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.9-2.i686 libgcc-4.3.2-7.i386 libstdc++-4.3.2-7.i386
(gdb)

使用bt命令查看函数调用的栈帧(用where命令也可以):
(gdb) bt
#0  0x0084d626 in memcpy () from /lib/libc.so.6
#1  0x08048660 in ?? ()
#2  0x08049f5d in do_print (argc=1, argv=0xbf8935dc) at my_command.c:31
#3  0x08048cc2 in run_command (cmd=0x804cca0 "print") at command.c:380
#4  0x08049e93 in readline_test ()
#5  0x08049ee6 in main ()
(gdb)
 可以看到最后出现的可疑的代码函数为do_print,里面使用到了memcpy,具体是哪里,可以用frame NUM查看栈帧。比如,查看第2个栈帧:
(gdb) frame 2
#2  0x08049f5d in do_print (argc=1, argv=0xbf8935dc) at my_command.c:31
31          memcpy(p, buffer, 5);
(gdb)

可以看到,已经输出了文件名称、行号、函数等重要信息。
至此,就可以根据信息修改代码了。

下面给出错误函数代码片段:
int do_print(int argc, char * const argv[])
{
    printf("in print ...\n");
    char* p = NULL;
    char* buffer = "hello";
    memcpy(p, buffer, 5);     //  注:拷贝到空指针,错误!!!
    return 0;
}

下面在某款嵌入式平台上进行同时的演示,这里只给出最后gdb调用的过程。

latelee@latelee:creadline$ arm_v5t_le-gdb readline_arm readline_arm.core.11.1941
GNU gdb 6.3 (MontaVista 6.3-20.0.66.0600975 2006-07-06)
...
Core was generated by `./readline_arm'.
Program terminated with signal 11, Segmentation fault.
...
#0  0x4020f164 in memcpy ()
   from /opt/mv_pro_4.0.1/montavista/pro/devkit/arm/v5t_le/target/lib/libc.so.6
(gdb) bt
#0  0x4020f164 in memcpy ()
   from /opt/mv_pro_4.0.1/montavista/pro/devkit/arm/v5t_le/target/lib/libc.so.6
#1  0x0000b660 in do_print (argc=1, argv=0xbefffcd0) at my_command.c:242
#2  0x00009574 in run_command (cmd=0x16c64 "print") at command.c:380
#3  0x0000af7c in readline_test () at main.c:78
#4  0x0000b20c in main (argc=1, argv=0xbefffe64) at main.c:139
(gdb) frame 1
#1  0x0000b660 in do_print (argc=1, argv=0xbefffcd0) at my_command.c:242
242         memcpy(p, buf, 5);
(gdb)

注:行文不特别区别交叉编译,对于交叉版本,自行补充交叉前缀即可。文中“gdb”表示gdb调用器,在x86-linux上其文件为gdb,而在不同的arm-linux上,文件名称不同,如可能是arm_v5t_le-gdb,也可能是arm-linux-gdb,还可能是arm-arago-linux-gnueabi-gdb,甚至哪天李迟自己编译了一个交叉编译器前缀为arm-latelee-,则对应调试器名称为arm-latelee-gdb。

下一篇文章将演示几个实际中遇到过的bug的排查实例。

李迟

2016.5.31 周二 晚

Linux下coredump调试1:使用相关推荐

  1. Linux下coredump调试3:补录

    本篇文章记录在coredump调试过程中记录的其它事项. 一般地,调试的方式多种多样,不可能将其一网打尽.就笔者而言,一般喜欢用print大法,分段注解法,版本回退法,等等.实在无招,则用coredu ...

  2. Linux下coredump调试2:实例

    前面文章只是给出简单演示,实际的程序运行中会遇到这样或那样的问题.所以,本文结合笔者实际编程经历,给出一些曾经遇到过的实际例子. 笔者遇到的大多数程序崩溃原因,基本上都是段错误:非法内存使用,越界.这 ...

  3. gdb 调试_一文入门Linux下gdb调试(二)

    点击"蓝字"关注我吧 作者:良知犹存 转载授权以及围观:欢迎添加微信号:Conscience_Remains 总述     今天我们介绍一下core dump文件,Core dum ...

  4. linux gdb网络调试,一文入门Linux下gdb调试(二)

    本文转载自[微信公众号:羽林君,ID:Conscience_Remains] 总述 今天我们介绍一下core dump文件,Core dump叫做核心转储,它是进程运行时在突然崩溃的那一刻的一个内存快 ...

  5. linux下gdb调试方法和技巧详解

    linux下gdb调试方法和技巧整理 简介 UNIX或者UNIX-like下调试工具 启动gdb # 1. 在可执行程序不需要输入参数时,我们可以使用 gdb + 可执行程序 gdb ./typeid ...

  6. Linux下串口调试及使用shell编程接收数据

    串口简介 串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是 RS-232-C 接口(又称 EIA RS-232-C)它是在 1970 年由美国电子工业协会(EIA)联 ...

  7. UART和RS232/RS485的关系是什么?RS485在linux下的调试 ubuntu串口调试工具

    串口通讯是电子工程师和嵌入式开发工程师面对的最基本问题,RS232则是其中最简单最常用的通讯方式.但是初学者往往搞不清有关的名词如UART和RS232或RS485之间是什么关系,因为它们经常被放到语句 ...

  8. C++(Qt)软件调试---linux下生成/调试Core文件(3)

    #软件调试 C++(Qt)软件调试-linux下生成/调试Core文件(3) 文章目录 C++(Qt)软件调试---linux下生成/调试Core文件(3) 前言 1.C++生成Core和使用GDB调 ...

  9. Linux下gdb调试用法

    稍微小小介绍一下 gdb是GUN组织开发的Linux下的调试利器.一般用于调试C/C++程序. GDB主要有以下4个功能: 1.启动你的程序,可以按照你的自定义的要求随心所欲的运行程序. 2.可让被调 ...

最新文章

  1. BZOJ 2157 「国家集训队」旅游(树链剖分,线段树,边权转点权)【BZOJ计划】
  2. 模板 - 2 - SAT问题
  3. 对服务器文件夹写,服务器文件夹写入权限设置
  4. 解决NGUI中sprite的边缘会出现黑线的问题
  5. 安卓 外部存储/ExternalStorage 的使用
  6. 银行利率是5.45%,房贷是4.9%,有钱该提前还房贷还是存款?
  7. 一步步编写操作系统 60 cpu的IO特权级2 什么是驱动程序
  8. Java面向对象之object类自带的方法解析(equals与==、toString方法、instanceof方法、参数传递问题)
  9. Reflexer Labs将于4月15日进行首次FLX代币分配
  10. SQL Server数据库技术大全——08讲 PD的使用
  11. 普通计算机用的是什么屏幕,笔记本屏幕的色域 72%NTSC和100%sRGB有什么区别
  12. linux推流软件推荐,Linux直播推流
  13. android 投屏,华为手机的电脑模式是如何实现的
  14. Cassandra启动过程详解【原创】
  15. 大学生应该懂得。。。葡萄酒知识
  16. 切换白天黑夜模式系统切换语言回调
  17. UCenter单点登录,同步登录,同步登出原理
  18. 浅谈高内聚与松耦合,各人自扫门前雪,莫管他人瓦上霜
  19. 前端水印生成方案(网页水印+图片水印)
  20. 【项目】智能WiFi远程灯光控制系统

热门文章

  1. 国产游戏版号时隔8个月重启 游戏公司董事长喜极而泣
  2. 叮咚买菜大裁员?回应:消息不实 目前业务都在正常运转
  3. 数字人民币App正式上线 京东子钱包推送量峰值增长超过20倍
  4. 百度Apollo开通上海自动驾驶示范路线 落地第5城
  5. 雷军:到了40岁觉得自己一事无成
  6. 天猫双11第一波今晚开启 预计2天内1亿人收到货
  7. 低价iPhone 12彻底没戏了?苹果严控渠道:给拼多多等电商供货罚款40万元/台
  8. 拼多多股价创历史新高:市值再度逼近京东
  9. 疫情下的“双11”,品牌逆势增长背后的数字化变革
  10. iPhone 9又要鸽了?