gdb

前言

本文参考的资料

https://blog.csdn.net/ithomer/article/details/5929720
core的原理和例子:https://blog.csdn.net/furzoom/article/details/50443092
https://blog.csdn.net/furzoom/article/details/50443116
gdb用法简介:https://blog.csdn.net/ithomer/article/details/5929720 

gdb调试的应用场景

前提:在编译时加入-g选项,把调试信息加到可执行文件中,例如g++ -g hello.cpp –o hello或是在CMakeLists.txt文件的编译参数中加入-g,常见的应用如下

  • gdb
    program也就是你的执行文件,一般在当前目录下。
  • gdb core
    用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。
  • gdb
    如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试它。program应该在PATH环境变量中搜索到。
    参见:https://www.cnblogs.com/chaoyazhisi/p/5396096.html,本文暂不讨论此应用

1. gdb调试执行文件

gdb ./test(可执行文件)后进入gdb模式,常见命令如下:
设置断点:
b function(在function函数入口处设置断点)
b number(在第number行设置断点)
b (在当前行设置断点)
layout 多窗口查看相应信息:https://blog.csdn.net/zhangjs0322/article/details/10152279
layout src 查看源码
layout reg:查看寄存器信息
单步(finish跳出):
n (next)下一步,逐过程  n 3 下行三步
s (step)进函数,逐步
run 运行程序
p (print)  变量名/地址
bt 或者where ( 查看当前函数堆栈)
quit 退出gdb模式


查看调试:http://www.cnblogs.com/jiangzhaowei/p/8987069.html

2.gdb调试core文件

2.1 segmentation fault简介

当程序运行过程中出现Segmentation fault (core dumped)错误时,程序停止运行,并产生core文件。core文件是程序运行状态的内存映象。使用gdb调试core文件,可以帮助我们快速定位程序出现段错误的位置。当然,可执行程序编译时应加上-g编译选项,生成调试信息。

当程序访问的内存超出了系统给定的内存空间,就会产生Segmentation fault (core dumped),因此,段错误产生的情况主要有:

  • 内存访问越界
    由于使用错误的下标,导致数组访问越界
    搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符
    使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。
  • 多线程程序使用了线程不安全的函数。
    多线程读写的数据未加锁保护。对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成core dump
  • 非法指针
    使用空指针
    随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它时就很容易因为bus error而core dump.
  • 堆栈溢出.不要使用大的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误。
    首先通过ulimit命令查看一下系统是否配置支持了dump core的功能。通过ulimit -c或ulimit -a,可以查看core file大小的配置情况,如果为0,则表示系统关闭了dump core。可以通过ulimit -c unlimited来打开。若发生了段错误,但没有core dump,是由于系统禁止core文件的生成。

2.2 gdb生成core文件的过程

  • 修改CMakeLists.txt文件,将CMAKE_BUILD_TYPE设为Debug(如果不需要添加调试信息,就直接修改CMAKE_BUILD_TYPE的值),并设置debug版本的参数,如下所示:
SET(CMAKE_BUILD_TYPE "Debug")

SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS}  -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -O0 -w -g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -O3 -w")
  • 建立一个debug文件夹,进入文件夹,执行:cmake –DCMAKE_BUILD_TYPE=Debug ..(..为CMakeLists.txt所在目录)
  • make -j10 //生成二进制文件
  • 先执行: ulimit -c unlimited(打开dump core的功能),再sh run.sh(执行相应的二进制文件)
  • gdb bin(promotion_tag) core.txt

2.3 生成core文件例子:空指针

main.cpp

#include 
int main(void)
{
    printf("hello world! dump core for set value to NULL pointer/n");
    *(char *)0 = 0;
    return 0;
}
  • 修改CMakeLists.txt文件,其中为了支持gdb调试而做了修改的是三个set语句.
[chengliying@localhost null_ptr]$ vim CMakeLists.txt 
PROJECT(hello_word_debug)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
SET(CMAKE_BUILD_TYPE "Debug")
add_executable(hello_word_debug main.cpp)

SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS}  -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -O0 -w -g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -O3 -w")
  • 建立debug文件目录并编译
[chengliying@localhost null_ptr]$ mkdir debug
[chengliying@localhost null_ptr]$ ls
CMakeLists.txt  debug  main.cpp
[chengliying@localhost null_ptr]$ cd debug
[chengliying@localhost debug]$ cmake –DCMAKE_BUILD_TYPE=Debug ..
-- The C compiler identification is GNU 4.4.7
-- ...
-- Build files have been written to: /home/chengliying/gdb/null_ptr/debug
  • 生成可执行二进制文件
[chengliying@localhost debug]$ make -j10
Scanning dependencies of target hello_word_debug
[ 50%] Building CXX object CMakeFiles/hello_word_debug.dir/main.cpp.o
[100%] Linking CXX executable hello_word_debug
[100%] Built target hello_word_debug
  • 打开core开关,生成core文件
[chengliying@localhost debug]$ ulimit -c unlimited
[chengliying@localhost debug]$ ./hello_word_debug 
Segmentation fault (core dumped)
[chengliying@localhost debug]$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  core.7835  hello_word_debug  Makefile
  • 查看core文件,可以发现bug在第5行,输入bt进一步查看堆栈信息
[chengliying@localhost debug]$ gdb ./hello_word_debug core.7835
Core was generated by `./hello_word_debug'.
Program terminated with signal 11, Segmentation fault.
#0  0x000000000040077c in main () at /home/chengliying/gdb/null_ptr/main.cpp:5
5           *(char *)0 = 0;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6.x86_64 libgcc-4.4.7-3.el6.x86_64 libstdc++-4.4.7-3.el6.x86_64
(gdb) bt
#0  0x000000000040077c in main () at /home/chengliying/gdb/null_ptr/main.cpp:5
(gdb) 

2.4栈溢出示例

有的错误不会直接显示源码,此时可以gdb模式下输入bt查看堆栈信息,从下堆栈信息中,调``frame n```显示相应的源码至找到bug所在。源码链接:https://blog.csdn.net/ithomer/article/details/5945152
类似的例子还有:https://www.cnblogs.com/luhouxiang/p/6830316.html

  • 未显示源码的gdb调试信息
Core was generated by `./test'.
Program terminated with signal 11, Segmentation fault.
#0  0x00007ff24cc23283 in vfprintf () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6.x86_64
  • 输入bt查看堆栈信息
(gdb) bt
#0  0x00007ff24cc23283 in vfprintf () from /lib64/libc.so.6
#1  0x00007ff24cc2e40a in printf () from /lib64/libc.so.6
#2  0x00000000004005e0 in test (s=0x0) at test.c:9
#3  0x000000000040060a in test (s=0x0) at test.c:13
  • frame 查看相应的源码
(gdb) frame 2
#2  0x000000000040060a in test (s=0x0) at test.c:9
9          test(s); 

你可能感兴趣的:(gdb)