gdb调试core dump入门实践(顺便复习一下之前介绍过的addr2line命令调试)

本文主要是介绍gdb调试core dump入门实践(顺便复习一下之前介绍过的addr2line命令调试),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        调试技能是软件开发的必备技能, 不会调试, 就抓不到bug, 就很痛苦。 本文我们来一起聊聊gdb调试core

 

         Part 1:

        在前面的博文中, 我们聊过重要的addr2line调试, 现在再来一起看看, 就当是复习吧。

        程序如下:

 

#include <stdio.h>int main()
{int *p = NULL;*p = 0;printf("bad\n");return 0;
}

       几乎所有的码农都能一眼看出错在哪里, 但在大型项目中, 光靠肉眼怎行? 必须借助工具, 我们用addr2line来搞起,编译并运行:

 

 

[taoge@localhost test]$ cat main.c -n1  #include <stdio.h>23  int main()4  {5          int *p = NULL;6          *p = 0;78          printf("bad\n");9          return 0;10  }11
[taoge@localhost test]$ gcc -g main.c 
[taoge@localhost test]$ ./a.out 
Segmentation fault (core dumped)
[taoge@localhost test]$ 
[taoge@localhost test]$ 
[taoge@localhost test]$ 
[taoge@localhost test]$ dmesg | grep a.out 
virtual kernel memory layout:
a.out[2282]: segfault at 0 ip 080483c9 sp bfacd460 error 6 in a.out[8048000+1000]
a.out[2303]: segfault at 0 ip 080483c9 sp bfadc1a0 error 6 in a.out[8048000+1000]
a.out[2307]: segfault at 0 ip 080483c9 sp bfef76e0 error 6 in a.out[8048000+1000]
a.out[4153]: segfault at 0 ip 080483c9 sp bf9f2490 error 6 in a.out[8048000+1000]
a.out[4932]: segfault at 0 ip 080483c9 sp bfcfd2a0 error 6 in a.out[8048000+1000]
a.out[5408]: segfault at 0 ip 080483c9 sp bf894b40 error 6 in a.out[8048000+1000]
[taoge@localhost test]$ addr2line -e a.out 080483c9
/home/taoge/test/main.c:6
[taoge@localhost test]$ 

        可以看到, 程序core dump了, 用dmesg命令查出程序core对应的地址为:080483c9, 然后呢, 利用addr2line命令转换为对应的代码行, 可以看到问题出在第6行, 回头看代码, 果真如此。

 

        在实际开发中, dmesg命令用的不多, 那怎么知道像080483c9这样的地址呢? 通常来讲, 程序core dump之后, 在日志中会记录堆栈信息的, 可以在日志文件中搜索backtrace这个字段, 然后查找地址。

 

 

       Part 2:

       接下来先预热一下, 搞点前戏, 我们来用gdb的r命令来玩玩, 如下:

 

[taoge@localhost test]$ rm a.out
[taoge@localhost test]$ gcc -g main.c 
[taoge@localhost test]$ ./a.out 
Segmentation fault (core dumped)
[taoge@localhost test]$ gdb a.out 
GNU gdb (GDB) Red Hat Enterprise Linux (7.1-29.el6)
Copyright (C) 2010 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 "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/taoge/test/a.out...done.
(gdb) r
Starting program: /home/taoge/test/a.out Program received signal SIGSEGV, Segmentation fault.
0x080483c9 in main () at main.c:6
6               *p = 0;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.i686
(gdb) quit
A debugging session is active.Inferior 1 [process 5489] will be killed.Quit anyway? (y or n) y
[taoge@localhost test]$ 

        可以看到, 在gdb调试的时候, 用r命令让程序再跑起来, 同样可以定位到问题出在第6行。还没完, 我们来看bt命令:

 

 

[taoge@localhost test]$ rm a.out
[taoge@localhost test]$ gcc -g main.c 
[taoge@localhost test]$ ./a.out 
Segmentation fault (core dumped)
[taoge@localhost test]$ gdb a.out 
GNU gdb (GDB) Red Hat Enterprise Linux (7.1-29.el6)
Copyright (C) 2010 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 "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/taoge/test/a.out...done.
(gdb) bt
No stack.
(gdb) r
Starting program: /home/taoge/test/a.out Program received signal SIGSEGV, Segmentation fault.
0x080483c9 in main () at main.c:6
6               *p = 0;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.i686
(gdb) bt
#0  0x080483c9 in main () at main.c:6
(gdb) 

        可以看到, 第一个bt显示no stack, 因为程序a.out还没有跑起来。 好, 用r让程序run起来,继续bt,  就可以看到函数堆栈, 也能定位到第6行。 我们仔细看一下, gdb也找到了080483c9这个地址,进而找到了第6行,  所以完全可以认为, gdb里面内置了addr2line命令。


 

Part 3:

        好的, 还是来说我们的重头戏------gdb调试core

 

        我们先来看如下操作:

 

[taoge@localhost test]$ rm a.out 
[taoge@localhost test]$ ls
main.c
[taoge@localhost test]$ gcc -g main.c 
[taoge@localhost test]$ ls
a.out  main.c
[taoge@localhost test]$ ./a.out 
Segmentation fault (core dumped)
[taoge@localhost test]$ ls
a.out  main.c
[taoge@localhost test]$ 

        可以看到, 程序core dump后, 并没有生成什么core文件, 原因是ulimit对应的开关没有打开, 我们来看看:

 

 

[taoge@localhost test]$ ulimit -c
0
[taoge@localhost test]$ ulimit -c 999
[taoge@localhost test]$ ulimit -c
999
[taoge@localhost test]$ rm a.out 
[taoge@localhost test]$ gcc -g main.c 
[taoge@localhost test]$ ls
a.out  main.c
[taoge@localhost test]$ ./a.out 
Segmentation fault (core dumped)
[taoge@localhost test]$ ls
a.out  core.5911  main.c
[taoge@localhost test]$ gdb a.out core.5911 
GNU gdb (GDB) Red Hat Enterprise Linux (7.1-29.el6)
Copyright (C) 2010 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 "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/taoge/test/a.out...done.
[New Thread 5911]
Missing separate debuginfo for 
Try: yum --disablerepo='*' --enablerepo='*-debuginfo' install /usr/lib/debug/.build-id/74/d23352fd770753e375bd0caecf375bd77bded5
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  0x080483c9 in main () at main.c:6
6               *p = 0;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.i686
(gdb) bt
#0  0x080483c9 in main () at main.c:6
(gdb) quit
[taoge@localhost test]$

        看上面的过程, ulimit -c是用来查询所设定的core文件大小的, 可以看到, 在默认情况下为0, 所以执行./a.out的时候, 并没有core文件生成。 我们把它设置为999, 然后在执行./a.out, 可以看到, 有core文件(core.5911)生成。 然后利用gdb来调试core, 刚执行gdb a.out core.5911的之后, 就看出了问题出在第6行, 此时如果用bt命令来看堆栈, 也可以看出问题出在第6行。
 

 


        那上述调试各有什么特点呢? 

        我们知道,在实际中, 有很多问题是概率发生的, 很难重现。 此时, 如果用gdb的r命令(实际相当于重新运行程序)则是不可能的, 所以,本文part 2中的方法不太实用。

 

        对于概率性问题, 我们通常采用的是part 1和 part 3的方法。

        先说part 1方法:当程序出现堆栈错误时, 我们可以从日志中看到出错的地址, 然后用part 1中介绍的方法来查询, 以前经常这么玩。

        再说part 3方法:当程序出现堆栈错误时, 如果产生了core文件, 我们一定要视之为宝贝, 记得保存, 否则很可能被冲掉。 拿到core文件后, 我们可以用part 3中介绍的方法来调试core, 以前也这么玩过。

 

        有一个重要的问题必须指出, 在本文中, 所有的编译都加了-g这个选项, 主要是为了调试(保存了调试所需的调试信息), 如果没有-g, 那么只能知道程序出错的堆栈地址, 却无法知道对应的代码行, 前功尽弃, 抓狂不已抓狂

        在实际项目开发中(比如嵌入式开发), 真正的可执行文件/动态库等都都不能太大, 比如说,生成的xxx.so库有10M,  嵌入式那点小设备哪能奢侈地装这么大的东西啊?

所以要对xxx.so文件进行脱衣服操作(strip xxx.so), 去掉一些调试信息, 形成对应的yyy.so,  真正发布的时候, 只发布yyy.so就行了, 如果出了问题, 需要定位的时候, 再用对应的xxx.so来定位, 因为xxx.so中有调试信息, 而yyy.so的衣服被脱了, 没有对应的调试信息了。   而且, 嵌入式设备生成了core文件, 但设备一般不支持gbd调试, 所以要把设备中的core文件拷贝到linux机器上进行调试, 千万要记得保存编译的环境哦。

 

         OK, gdb调试core dump的入门介绍就到此为止, 在后续的博文中, 我会继续介绍更多有关gdb调试的内容, 到时再一起嗨。

 

 

 

 

 

 

这篇关于gdb调试core dump入门实践(顺便复习一下之前介绍过的addr2line命令调试)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/684558

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

30常用 Maven 命令

Maven 是一个强大的项目管理和构建工具,它广泛用于 Java 项目的依赖管理、构建流程和插件集成。Maven 的命令行工具提供了大量的命令来帮助开发人员管理项目的生命周期、依赖和插件。以下是 常用 Maven 命令的使用场景及其详细解释。 1. mvn clean 使用场景:清理项目的生成目录,通常用于删除项目中自动生成的文件(如 target/ 目录)。共性规律:清理操作

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题: