GDB

What is GDB?

GDB, the GNU Project debugger, allows you to see what is going on `inside’ another program while it executes – or what another program was doing at the moment it crashed.

GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:

  • Start your program, specifying anything that might affect its behavior.
  • Make your program stop on specified conditions.
  • Examine what has happened, when your program has stopped.
  • Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.

Those programs might be executing on the same machine as GDB (native), on another machine (remote), or on a simulator. GDB can run on most popular UNIX and Microsoft Windows variants, as well as on Mac OS X.

现代操作系统中,用core dump 表示当程序异常终止或崩溃时,将进程此时的内存中的内容拷贝到磁盘文件中存储,以方便编程人员调试。core dump 中包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息等。

Core is like a black box which is use to get the last moment information about the crashed plane.

core dump文件的生成方法

通过ulimit -c查看是否打开生成core dump

1
ulimit -c unlimited

产生core dump的原因

内存访问越界

  1. 使用错误的下标,导致数组访问越界
  2. 搜索字符串时,依靠字符串结束结束符来判断字符串是否结束,但是字符串没有正常的使用结束符。
  3. 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。

多线程程序使用了线程不安全的函数

多线程读写的数据未加锁保护

对于会被多个线程同事访问的全局数据,应该注意加锁保护,否则很容易造成core dump

非法指针

  1. 使用空指针
  2. 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型 的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它 时就很容易因为bus error而core dump.

堆栈溢出

不要使用大的局部变量(局部变量分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误。

如何使用

“next” - causes the debugger to execute the current command, and stop again, showing the next command in the code to be executed.

“step” - causes the debugger to execute the current command, and if it is a function call - break at the beginning of that function. This is useful for debugging nested code.

command: ctrl+x+a\ctrl+x+2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
┌──demo.c──────────────────────────────────────────────────────────────────────────┐
│8 int main(){ │
│9 int res=getSum(100); │
│10 printf("1+2+...+100=%d\n",res); │
│11 } │
│12 │
│13 │
│14 │
│15 │
│16 │
│17 │
│18 │
│19 │
│20 │
│21 │
│22 │
│23 │
└─────────────────────────────────────────────────────────────────────────────────────┘
│0x100000f50 <main()> push %rbp │
│0x100000f51 <main()+1> mov %rsp,%rbp │
│0x100000f54 <main()+4> sub $0x10,%rsp │
│0x100000f58 <main()+8> mov $0x64,%edi │
│0x100000f5d <main()+13> callq 0x100000f10 <getSum(int)> │
│0x100000f62 <main()+18> lea 0x3d(%rip),%rdi # 0x100000fa6 │
│0x100000f69 <main()+25> mov %eax,-0x4(%rbp) │
│0x100000f6c <main()+28> mov -0x4(%rbp),%esi │
│0x100000f6f <main()+31> mov $0x0,%al │
│0x100000f71 <main()+33> callq 0x100000f84 │
│0x100000f76 <main()+38> xor %esi,%esi │
│0x100000f78 <main()+40> mov %eax,-0x8(%rbp) │
│0x100000f7b <main()+43> mov %esi,%eax │
│0x100000f7d <main()+45> add $0x10,%rsp │
│0x100000f81 <main()+49> pop %rbp │
│0x100000f82 <main()+50> retq │
└─────────────────────────────────────────────────────────────────────────────────────┘
exec No process In: L?? PC: ??
(gdb)

设置观察点(WatchPoint)

观察点一般来观察某个表达式的值是否有变化了,如果有变化,马上停止程序。

查看栈信息

当程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的。当你的程序调用了一个函数,函数的地址,函数参数,函数内的局部变量都会被压入“栈”(Stack)中。

1
backtrace frame

查看内存

可以使用examine命令来查看内存地址中的值

跳转执行

Ctrl+z 挂起 会像进程发出SIGTSTP信号,该信号的默认操作为暂停进程(Stop Process)

Ctrl+c 结束 会向进程发出SIGINT信号,该信号默认操作为终止进程(Terminate Process)

###Error

Segment fault

Stackoverflow

Runtime error

Reference

https://www.gnu.org/software/gdb/

https://coolshell.cn/articles/3643.html

https://www.youtube.com/watch?v=PorfLSr3DDI

http://yusufonlinux.blogspot.com/2010/11/debugging-core-using-gdb.html

More than your eyes can see