用gdb分析core文件及常见gdb命令操作示例

开发 开发工具
本文以一个实际的程序为例,介绍了用gdb分析core文件的方法和步骤,同时演示了常见gdb命令的操作方法。

1.概述

在实际的软件开发项目中,程序出现问题是在所难免的。遥想本人参加工作之后***遇到程序的情景,至今还历历在目。之前的经验告诉我,我们越是惊慌失措,问题就越是解决不了。我们要先让自己平静下来,然后再寻找解决程序问题的办法。

软件开发

Linux下做开发的朋友,想必都与core文件打过交道。当看到自己的程序运行之后出现core时,很多人都慌乱了,仿佛天快要塌下来一样。其实,我们大可不必如此,只要我们掌握了用gdb调试core文件的办法,依然可以很快定位程序问题,一举将bug消灭掉。有关Linux core文件的更多介绍,请阅读此文:http://www.cnblogs.com/dongzhiquan/archive/2012/01/20/2328355.html

本文以一个实际的程序为例,介绍了用gdb分析core文件的方法和步骤,同时演示了常见gdb命令的操作方法。如果大家想对相关gdb命令有更多的了解,请自行百度之。

2.示例程序

  1. /********************************************************************** 
  2. * 版权所有 (C)2015, Zhou Zhaoxiong。 
  3. * 文件名称:GdbDebug.c 
  4. * 文件标识:无 
  5. * 内容摘要:Gdb命令演示程序 
  6. * 其它说明:无 
  7. * 当前版本:V1.0 
  8. * 作    者:Zhou Zhaoxiong 
  9. * 完成日期:20151008 
  10. **********************************************************************/ 
  11. #include <stdio.h> 
  12. #include <stdlib.h> 
  13. #include <string.h> 
  14.  
  15. // 数据类型重定义 
  16. typedef unsigned char       UINT8; 
  17. typedef signed   int        INT32; 
  18. typedef unsigned int        UINT32; 
  19.  
  20.  
  21. // 函数声明 
  22. void Sleep(UINT32 iCountMs); 
  23. void PrintInfo(void); 
  24. INT32 main(); 
  25.  
  26.  
  27. /********************************************************************** 
  28. * 功能描述:主函数 
  29. * 输入参数:无 
  30. * 输出参数:无 
  31. * 返 回 值:无 
  32. * 其它说明:无 
  33. * 修改日期        版本号     修改人            修改内容 
  34. * ------------------------------------------------------------------- 
  35. * 20151008       V1.0     Zhou Zhaoxiong      创建 
  36. ***********************************************************************/ 
  37. INT32 main() 
  38.     PrintInfo();   // 在屏幕上输出消息 
  39.  
  40.     return 0; 
  41.  
  42.  
  43. /********************************************************************** 
  44.  * 功能描述: 在屏幕上输出消息 
  45.  * 输入参数: 无 
  46.  * 输出参数: 无 
  47.  * 返 回 值: 无 
  48.  * 其它说明: 无 
  49.  * 修改日期            版本号            修改人           修改内容 
  50.  * ---------------------------------------------------------------------- 
  51.  * 20151008            V1.0        Zhou Zhaoxiong        创建 
  52.  ************************************************************************/ 
  53. void PrintInfo(void) 
  54.     UINT32 iLoopFlag = 0
  55.     UINT32 iSum      = 0
  56.     UINT32 iLen      = 0
  57.     UINT8 *pCtrStr   = NULL
  58.  
  59.     iLen = strlen(pCtrStr); 
  60.  
  61.     for (iLoopFlag = 0; iLoopFlag < iLen; iLoopFlag ++)      // 打印消息iLen次 
  62.     { 
  63.         printf("PrintInfo: hello, world!\n"); 
  64.  
  65.         iSumiSum = iSum + iLoopFlag; 
  66.  
  67.         Sleep(10 * 1000);   // 每10s打印一次 
  68.     } 
  69.  
  70.     return; 
  71.  
  72.  
  73. /********************************************************************** 
  74. * 功能描述: 程序休眠 
  75. * 输入参数: iCountMs-休眠时间(单位:ms) 
  76. * 输出参数: 无 
  77. * 返 回 值: 无 
  78. * 其它说明: 无 
  79. * 修改日期          版本号       修改人              修改内容 
  80. * ------------------------------------------------------------------ 
  81. * 20151008         V1.0     Zhou Zhaoxiong          创建 
  82. ********************************************************************/ 
  83. void Sleep(UINT32 iCountMs) 
  84.     struct timeval t_timeout = {0}; 
  85.  
  86.     if (iCountMs < 1000
  87.     { 
  88.         t_timeout.tv_sec = 0
  89.         t_timeout.tv_usec = iCountMs * 1000; 
  90.     } 
  91.     else 
  92.     { 
  93.         t_timeout.tv_sec = iCountMs / 1000; 
  94.         t_timeout.tv_usec = (iCountMs % 1000) * 1000; 
  95.     } 
  96.     select(0, NULL, NULL, NULL, &t_timeout);   // 调用select函数阻塞程序 

3.用gdb分析core文件

在Linux上用“gcc -g -o GdbDebug GdbDebug.c”命令对程序进行编译之后,运行“GdbDebug”命令,发现在当前目录下出现了core文件。利用gdb命令对core文件进行分析的过程如下所示:

  1. ~/zhouzhaoxiong/zzx/GdbDebug> gdb GdbDebug core     -- 启动gdb对core文件的分析 
  2. GNU gdb (GDB) SUSE (7.3-0.6.1) 
  3. Copyright (C) 2011 Free Software Foundation, Inc. 
  4. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
  5. This is free software: you are free to change and redistribute it. 
  6. There is NO WARRANTY, to the extent permitted by law.  Type "show copying" 
  7. and "show warranty" for details. 
  8. This GDB was configured as "x86_64-suse-linux". 
  9. For bug reporting instructions, please see: 
  10. <http://www.gnu.org/software/gdb/bugs/>... 
  11. Reading symbols from /home/zhou/zhouzhaoxiong/zzx/GdbDebug/GdbDebug...done. 
  12. Core was generated by `GdbDebug'. 
  13. Program terminated with signal 11, Segmentation fault. 
  14. #0  0x00007f4a736f9812 in __strlen_sse2 () from /lib64/libc.so.6 
  15. (gdb) where          -- 查看程序出问题的地方 
  16. #0  0x00007f4a736f9812 in __strlen_sse2 () from /lib64/libc.so.6 
  17. #1  0x000000000040061a in PrintInfo () at GdbDebug.c:64   -- 可以看到,在GdbDebug.c文件的第64行出的问题 
  18. #2  0x00000000004005e5 in main () at GdbDebug.c:41 
  19. (gdb) b 41           -- 在GdbDebug.c文件第41行设立断点 
  20. Breakpoint 1 at 0x4005e0: file GdbDebug.c, line 41. 
  21. (gdb) b 64           -- 在GdbDebug.c文件第64行设立断点 
  22. Breakpoint 2 at 0x400611: file GdbDebug.c, line 64. 
  23. (gdb) info b         -- 显示断点信息 
  24. Num     Type           Disp Enb Address            What 
  25. 1       breakpoint     keep y   0x00000000004005e0 in main at GdbDebug.c:41 
  26. 2       breakpoint     keep y   0x0000000000400611 in PrintInfo at GdbDebug.c:64 
  27. (gdb) r              -- 运行GdbDebug 
  28. Starting program: /home/zhou/zhouzhaoxiong/zzx/GdbDebug/GdbDebug  
  29.  
  30. Breakpoint 1, main () at GdbDebug.c:41 
  31. 41          PrintInfo();   // 在屏幕上输出消息 
  32. (gdb) n             -- 执行下一步 
  33.  
  34. Breakpoint 2, PrintInfo () at GdbDebug.c:64 
  35. 64              iLen = strlen(pCtrStr); 
  36. (gdb) p iLen        -- 打印(输出)iLen的值 
  37. $1 = 0 
  38. (gdb) p iLoopFlag   -- 打印(输出)iLoopFlag的值 
  39. $2 = 0 
  40. (gdb) c             -- 继续执行      
  41. Continuing. 
  42.  
  43. Program received signal SIGSEGV, Segmentation fault.    -- 程序core掉了 
  44. 0x00007ffff7ae9812 in __strlen_sse2 () from /lib64/libc.so.6 
  45. (gdb) q             -- 退出gdb 
  46. A debugging session is active. 
  47.  
  48.         Inferior 1 [process 26640] will be killed. 
  49.  
  50. Quit anyway? (y or n) y 
  51. ~/zhouzhaoxiong/zzx/GdbDebug> 

从以上分析可知,执行GdbDebug.c文件的第64行时程序core掉了。此时仔细分析程序,发现pCtrStr指针为空。当对一个不存在的指针取长度时,由于找不到地址,程序便崩溃了。修改的办法也非常的简单,只需要让pCtrStr指针指向具体的地址即可。

4.常见gdb命令操作示例

修改之后的代码如下:

  1. /********************************************************************** 
  2. * 版权所有 (C)2015, Zhou Zhaoxiong。 
  3. * 文件名称:GdbDebug.c 
  4. * 文件标识:无 
  5. * 内容摘要:Gdb命令演示程序 
  6. * 其它说明:无 
  7. * 当前版本:V1.0 
  8. * 作    者:Zhou Zhaoxiong 
  9. * 完成日期:20151008 
  10. **********************************************************************/ 
  11. #include <stdio.h> 
  12. #include <stdlib.h> 
  13. #include <string.h> 
  14.  
  15. // 数据类型重定义 
  16. typedef unsigned char       UINT8; 
  17. typedef signed   int        INT32; 
  18. typedef unsigned int        UINT32; 
  19.  
  20.  
  21. // 函数声明 
  22. void Sleep(UINT32 iCountMs); 
  23. void PrintInfo(void); 
  24. INT32 main(); 
  25.  
  26.  
  27. /********************************************************************** 
  28. * 功能描述:主函数 
  29. * 输入参数:无 
  30. * 输出参数:无 
  31. * 返 回 值:无 
  32. * 其它说明:无 
  33. * 修改日期        版本号     修改人            修改内容 
  34. * ------------------------------------------------------------------- 
  35. * 20151008       V1.0    Zhou Zhaoxiong       创建 
  36. ***********************************************************************/ 
  37. INT32 main() 
  38.     PrintInfo();   // 在屏幕上输出消息 
  39.  
  40.     return 0; 
  41.  
  42.  
  43. /********************************************************************** 
  44.  * 功能描述: 在屏幕上输出消息 
  45.  * 输入参数: 无 
  46.  * 输出参数: 无 
  47.  * 返 回 值: 无 
  48.  * 其它说明: 无 
  49.  * 修改日期            版本号            修改人           修改内容 
  50.  * ---------------------------------------------------------------------- 
  51.  * 20151008           V1.0         Zhou Zhaoxiong        创建 
  52.  ************************************************************************/ 
  53. void PrintInfo(void) 
  54.     UINT32 iLoopFlag = 0
  55.     UINT32 iSum      = 0
  56.     UINT32 iLen      = 0
  57.     UINT8 *pCtrStr   = "hello, world!";  // 修改了这行代码 
  58.  
  59.     iLen = strlen(pCtrStr); 
  60.  
  61.     for (iLoopFlag = 0; iLoopFlag < iLen; iLoopFlag ++)      // 打印消息iLen次 
  62.     { 
  63.         printf("PrintInfo: hello, world!\n"); 
  64.  
  65.         iSumiSum = iSum + iLoopFlag; 
  66.  
  67.         Sleep(10 * 1000);   // 每10s打印一次 
  68.     } 
  69.  
  70.     return; 
  71.  
  72.  
  73. /********************************************************************** 
  74. * 功能描述: 程序休眠 
  75. * 输入参数: iCountMs-休眠时间(单位:ms) 
  76. * 输出参数: 无 
  77. * 返 回 值: 无 
  78. * 其它说明: 无 
  79. * 修改日期          版本号       修改人              修改内容 
  80. * ------------------------------------------------------------------ 
  81. * 20151008         V1.0     Zhou Zhaoxiong          创建 
  82. ********************************************************************/ 
  83. void Sleep(UINT32 iCountMs) 
  84.     struct timeval t_timeout = {0}; 
  85.  
  86.     if (iCountMs < 1000
  87.     { 
  88.         t_timeout.tv_sec = 0
  89.         t_timeout.tv_usec = iCountMs * 1000; 
  90.     } 
  91.     else 
  92.     { 
  93.         t_timeout.tv_sec = iCountMs / 1000; 
  94.         t_timeout.tv_usec = (iCountMs % 1000) * 1000; 
  95.     } 
  96.     select(0, NULL, NULL, NULL, &t_timeout);   // 调用select函数阻塞程序 

编译并运行之后,程序正常,说明问题已被我们解决掉。下面是常见的gdb命令的操作示例:

  1. ~/zhouzhaoxiong/zzx/GdbDebug> gdb GdbDebug    -- 启动gdb调试 
  2. GNU gdb (GDB) SUSE (7.3-0.6.1) 
  3. Copyright (C) 2011 Free Software Foundation, Inc. 
  4. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
  5. This is free software: you are free to change and redistribute it. 
  6. There is NO WARRANTY, to the extent permitted by law.  Type "show copying" 
  7. and "show warranty" for details. 
  8. This GDB was configured as "x86_64-suse-linux". 
  9. For bug reporting instructions, please see: 
  10. <http://www.gnu.org/software/gdb/bugs/>... 
  11. Reading symbols from /home/zhou/zhouzhaoxiong/zzx/GdbDebug/GdbDebug...done. 
  12. (gdb) b 64     -- 在GdbDebug.c文件第64行设立断点 
  13. Breakpoint 1 at 0x400611: file GdbDebug.c, line 64. 
  14. (gdb) b 72     -- 在GdbDebug.c文件第72行设立断点 
  15. Breakpoint 2 at 0x400637: file GdbDebug.c, line 72. 
  16. (gdb) info b   -- 显示断点信息 
  17. Num     Type           Disp Enb Address            What 
  18. 1       breakpoint     keep y   0x0000000000400611 in PrintInfo at GdbDebug.c:64 
  19. 2       breakpoint     keep y   0x0000000000400637 in PrintInfo at GdbDebug.c:72 
  20. (gdb) r        -- 运行GdbDebug 
  21. Starting program: /home/zhou/zhouzhaoxiong/zzx/GdbDebug/GdbDebug  
  22.  
  23. Breakpoint 1, PrintInfo () at GdbDebug.c:64 
  24. 64              iLen = strlen(pCtrStr); 
  25. (gdb) p iLen    -- 打印(输出)iLen的值 
  26. $1 = 0 
  27. (gdb) n         -- 执行下一步 
  28. 66              for (iLoopFlag = 0; iLoopFlag < iLen; iLoopFlag ++)      // 打印消息iLen次 
  29. (gdb) n         -- 执行下一步 
  30. 68              printf("PrintInfo: hello, world!\n"); 
  31. (gdb) p iLoopFlag   -- 打印(输出)iLoopFlag的值 
  32. $2 = 0 
  33. (gdb) p iLen    -- 打印(输出)iLen的值 
  34. $3 = 13 
  35. (gdb) n         -- 执行下一步 
  36. PrintInfo: hello, world!    -- 程序的输出结果 
  37. 70                      iSumiSum = iSum + iLoopFlag; 
  38. (gdb) p iSum    -- 打印(输出)iSum的值 
  39. $4 = 0 
  40. (gdb) n        -- 执行下一步 
  41.  
  42. Breakpoint 2, PrintInfo () at GdbDebug.c:72 
  43. 72                      Sleep(10 * 1000);   // 每10s打印一次 
  44. (gdb) n       
  45. 66              for (iLoopFlag = 0; iLoopFlag < iLen; iLoopFlag ++)      // 打印消息iLen次 
  46. (gdb) p iLoopFlag 
  47. $5 = 0 
  48. (gdb) n 
  49. 68              printf("PrintInfo: hello, world!\n"); 
  50. (gdb) p iLoopFlag 
  51. $6 = 1 
  52. (gdb) n 
  53. PrintInfo: hello, world! 
  54. 70                      iSumiSum = iSum + iLoopFlag; 
  55. (gdb) p iSum 
  56. $7 = 0 
  57. (gdb) n 
  58.  
  59. Breakpoint 2, PrintInfo () at GdbDebug.c:72 
  60. 72                      Sleep(10 * 1000);   // 每10s打印一次 
  61. (gdb) p iSum 
  62. $8 = 1 
  63. (gdb) finish        -- 一直运行到函数返回 
  64. Run till exit from #0  PrintInfo () at GdbDebug.c:72 
  65. PrintInfo: hello, world! 
  66.  
  67. Breakpoint 2, PrintInfo () at GdbDebug.c:72 
  68. 72                      Sleep(10 * 1000);   // 每10s打印一次 
  69. (gdb) c           -- 继续执行  
  70. Continuing. 
  71. PrintInfo: hello, world! 
  72.  
  73. Breakpoint 2, PrintInfo () at GdbDebug.c:72 
  74. 72                      Sleep(10 * 1000);   // 每10s打印一次 
  75. (gdb) bt            -- 打印当前的函数调用栈的所有信息 
  76. #0  PrintInfo () at GdbDebug.c:72 
  77. #1  0x00000000004005e5 in main () at GdbDebug.c:41 
  78. (gdb) q              -- 退出gdb 
  79. A debugging session is active. 
  80.  
  81.         Inferior 1 [process 26685] will be killed. 
  82.  
  83. Quit anyway? (y or n) y 
  84. ~/zhouzhaoxiong/zzx/GdbDebug>  

作为Linux下调试C/C++程序的工具,大家一定要熟练掌握gdb的用法。

【本文是51CTO专栏作者周兆熊的原创文章,作者微信公众号:周氏逻辑(logiczhou)】

戳这里,看该作者更多好文

责任编辑:赵宁宁 来源: 51CTO专栏
相关推荐

2017-05-10 15:30:30

skynet崩溃程序

2015-10-09 16:42:16

GDB 排查Python程序故障

2010-06-04 17:48:20

Linux编程工具

2022-12-19 10:10:07

GDB命令

2009-07-27 08:50:29

2021-03-15 06:23:40

GDB调试代码编程语言

2015-08-14 09:21:09

gdb工具调试 Go

2021-07-28 08:53:53

GoGDB调试

2021-07-05 11:00:43

GDB栈空间编程语言

2011-07-22 17:05:56

IOS 控制台 GDB

2023-05-04 12:39:27

GDB命令程序

2022-09-15 14:56:12

GDB调试鸿蒙

2016-03-29 10:32:34

2009-12-18 16:08:17

Fedora proc

2024-09-13 17:06:54

EF Core分组查询

2017-02-06 18:42:37

Linuxgdb程序

2010-01-20 10:39:52

Linuxcore

2012-05-21 10:13:05

XCode调试技巧

2018-04-16 10:12:46

Linux命令gunzip

2012-08-08 14:33:32

IBMdW
点赞
收藏

51CTO技术栈公众号