gdb - 实践

gdb - 实践

gdb是什么?

https://www.gnu.org/software/gdb/ 中介绍到,gdb是GNU project debugger,它让我们洞察正在运行的程序,或观测另一个程序在崩溃时正在干嘛。

gdb调试前,我们的代码应做什么?

编译过程,编译器做了大量的优化工作。代码原来的顺序,一些变量等都不保留。
因此要使用gdb调试,就在编译时指定-g选项,告诉编译器,将一行一行地代码留下来,供调试时使用。

代码1:简单正常的代码

/* Filename: basic1.cc */
#include <iostream>

int main() {
	int j = 3;
	int k = 7;

	j += k;
	k = j * 2;
	std::cout << "Hello there" << std::endl;
}

编译

thesre@HP-Z420-Workstation:~/gdb$ g++ -g -std=c++14 basic1.cc -o basic1

gdb调试

thesre@HP-Z420-Workstation:~/gdb$ gdb ./basic1 
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 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 "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./basic1...
(gdb) run #Run it.
Starting program: /home/thesre/gdb/basic1 
Hello there
[Inferior 1 (process 7822) exited normally]
(gdb) break main #设置断点。其中,断点可以设置行号,也可以设置函数名。
Breakpoint 1 at 0x5555555551a9: file basic1.cc, line 3.
(gdb) run #运行,到断点停止
Starting program: /home/thesre/gdb/basic1 

Breakpoint 1, main () at basic1.cc:3
3	int main() {
(gdb) next #下一条指令
4		int j = 3;
(gdb) next #下一条指令
5		int k = 7;
(gdb) list #打印代码上下文
1	#include <iostream>
2	
3	int main() {
4		int j = 3;
5		int k = 7;
6	
7		j += k;
8		k = j * 2;
9		std::cout << "Hello there" << std::endl;
10	}
(gdb) print j #打印变量值
$1 = 3
(gdb) next #下一条指令
7		j += k;
(gdb) n #n为next的缩写
8		k = j * 2;
(gdb) p j #p为print的缩写
$2 = 10
(gdb) p j + k #p能打印表达式(计算后的值)
$3 = 17
(gdb) p ((j * 3) + k * 2) - 2
$4 = 42
(gdb) quit #退出当前gdb实例
A debugging session is active.

	Inferior 1 [process 7851] will be killed.

Quit anyway? (y or n) y
thesre@HP-Z420-Workstation:~/gdb$ 

代码2:定位空指针

源码文件

/* Filename: example1.cc */
#include "black_box.h"

void crash(int *i) {
	*i = 1;
}

void f(int *i) {
	int *j = i;
	j = sophisticated(j);
	j = complicated(j);
	crash(j);
}

int main() {
	int i;
	f(&i);
}

头文件(假设头文件的内容,不被用户知道)

thesre@HP-Z420-Workstation:~/gdb$ cat black_box.h 
#ifndef FUNCTIONS_H_INCLUDED
#define FUNCTIONS_H_INCLUDED

int sophisticated(int a) {
	return a;
}

int complicated(int a) {
	return 0;
}

#endif

编译,加上-fpermissive忽略错误。

thesre@HP-Z420-Workstation:~/gdb$ g++ -g -std=c++14 ./example1.cc -o ./example1 -fpermissive
./example1.cc: In function ‘void f(int*)’:
./example1.cc:9:20: warning: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
    9 |  j = sophisticated(j);
      |                    ^
      |                    |
      |                    int*
In file included from ./example1.cc:1:
./black_box.h:4:23: note:   initializing argument 1 of ‘int sophisticated(int)4 | int sophisticated(int a) {
      |                   ~~~~^
./example1.cc:9:19: warning: invalid conversion from ‘int’ to ‘int*’ [-fpermissive]
    9 |  j = sophisticated(j);
      |      ~~~~~~~~~~~~~^~~
      |                   |
      |                   int
./example1.cc:10:18: warning: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
   10 |  j = complicated(j);
      |                  ^
      |                  |
      |                  int*
In file included from ./example1.cc:1:
./black_box.h:8:21: note:   initializing argument 1 of ‘int complicated(int)8 | int complicated(int a) {
      |                 ~~~~^
./example1.cc:10:17: warning: invalid conversion from ‘int’ to ‘int*’ [-fpermissive]
   10 |  j = complicated(j);
      |      ~~~~~~~~~~~^~~
      |                 |
      |                 int

运行程序,得到段错误的报错。

thesre@HP-Z420-Workstation:~/gdb$ ./example1 
Segmentation fault (core dumped)

调试

thesre@HP-Z420-Workstation:~/gdb$ gdb ./example1 
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 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 "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./example1...
(gdb) break crash #设置断点
Breakpoint 1 at 0x116d: file ./example1.cc, line 3.
(gdb) r #Run
Starting program: /home/thesre/gdb/example1 

Breakpoint 1, crash (i=0xc2) at ./example1.cc:3
3	void crash(int *i) {
(gdb) n
4		*i = 1;
(gdb) up #在栈中往上移动一帧
#1  0x00005555555551cc in f (i=0x7fffffffde14) at ./example1.cc:11
11		crash(j);
(gdb) up
#2  0x00005555555551f6 in main () at ./example1.cc:16
16		f(&i);
(gdb) down #在栈中往下移动一帧
#1  0x00005555555551cc in f (i=0x7fffffffde14) at ./example1.cc:11
11		crash(j);
(gdb) down
#0  crash (i=0x0) at ./example1.cc:4
4		*i = 1;
(gdb) break f
Breakpoint 2 at 0x555555555186: file ./example1.cc, line 7.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/thesre/gdb/example1 

Breakpoint 2, f (i=0x55555555526d <__libc_csu_init+77>) at ./example1.cc:7
7	void f(int *i) {
(gdb) n
8		int *j = i;
(gdb) p j
$1 = (int *) 0x555555555220 <__libc_csu_init>
(gdb) display j #往表达式列表中(表达式列表在每次暂停时显示)添加一个表达式。此处,以达到每次都显示j变量值的效果。
1: j = (int *) 0x555555555220 <__libc_csu_init>
(gdb) n
9		j = sophisticated(j);
1: j = (int *) 0x7fffffffde14
(gdb) list
4		*i = 1;
5	}
6	
7	void f(int *i) {
8		int *j = i;
9		j = sophisticated(j);
10		j = complicated(j);
11		crash(j);
12	}
13	
(gdb) n
10		j = complicated(j);
1: j = (int *) 0x7fffffffde14
(gdb) n #执行完j = complicated(j);后j变成了空指针。Bingo,找到你了!就是你导致了段错误。
11		crash(j);
1: j = (int *) 0x0
(gdb) display i
2: i = (int *) 0x7fffffffde14
(gdb) undisplay 1 #是display expr的反向操作。该命令也可以写成delete display 1
(gdb) n

Breakpoint 1, crash (i=0xc2) at ./example1.cc:3
3	void crash(int *i) {
(gdb) n
4		*i = 1;
(gdb) backtrace #打印整个栈的backtrace
#0  crash (i=0x0) at ./example1.cc:4
#1  0x00005555555551cc in f (i=0x7fffffffde14) at ./example1.cc:11
#2  0x00005555555551f6 in main () at ./example1.cc:16
(gdb) q
A debugging session is active.

	Inferior 1 [process 8757] will be killed.

Quit anyway? (y or n) y

代码3:定位递归

#include <iostream>

int factorial(const int &n) {
	if (n) {
		return n * factorial (n - 1);
	} else {
		return 1;
	}
}

int main() {
	int n;
	
	std::cout << "Please enter a positive integer: ";
	if (std::cin >> n && n >= 0) {
		std::cout << n << "! = " << factorial(n) << std::endl;
	} else {
		std::cout << "That's not a positive integer!" << std::endl;
	}
}

编译

thesre@HP-Z420-Workstation:~/gdb$ g++ -g -std=c++14 -o recursive recursive.cc

运行

thesre@HP-Z420-Workstation:~/gdb$ ./recursive 
Please enter a positive integer: 4
4! = 24

调试

thesre@HP-Z420-Workstation:~/gdb$ gdb ./recursive
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 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 "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./recursive...
(gdb) break factorial
Breakpoint 1 at 0x1229: file recursive.cc, line 3.
(gdb) r
Starting program: /home/thesre/gdb/recursive 
Please enter a positive integer: 4

Breakpoint 1, factorial (n=<error reading variable>) at recursive.cc:3
3	int factorial(const int &n) {
(gdb) n
4		if (n) {
(gdb) n
5			return n * factorial (n - 1);
(gdb) step #继续运行程序,直到控制到达了不同的源代码行,然后停止它,并将控制交回给GDB。

Breakpoint 1, factorial (n=@0x555555558040: -134560816) at recursive.cc:3
3	int factorial(const int &n) {
(gdb) continue #从上一个停止点恢复运行,并且任何在那个停止点设置的断点,都被bypassed掉。
Continuing.

Breakpoint 1, factorial (n=<error reading variable>) at recursive.cc:3
3	int factorial(const int &n) {
(gdb) c
Continuing.

Breakpoint 1, factorial (n=@0x555555556032: 540876833) at recursive.cc:3
3	int factorial(const int &n) {
(gdb) c
Continuing.

Breakpoint 1, factorial (n=@0x7ffff7c737b2: 1307312461) at recursive.cc:3
3	int factorial(const int &n) {
(gdb) finish #继续运行,直到选中的栈帧的函数返回,打印返回值。
Run till exit from #0  factorial (n=@0x7ffff7c737b2: 1307312461) at recursive.cc:3
factorial (n=@0x7fffffffdd74: 1) at recursive.cc:5
5			return n * factorial (n - 1);
Value returned is $1 = 1
(gdb) finish
Run till exit from #0  factorial (n=@0x7fffffffdd74: 1) at recursive.cc:5
factorial (n=@0x7fffffffddb4: 2) at recursive.cc:5
5			return n * factorial (n - 1);
Value returned is $2 = 1
(gdb) finish
Run till exit from #0  factorial (n=@0x7fffffffddb4: 2) at recursive.cc:5
factorial (n=@0x7fffffffddf4: 3) at recursive.cc:5
5			return n * factorial (n - 1);
Value returned is $3 = 2
(gdb) finish
Run till exit from #0  factorial (n=@0x7fffffffddf4: 3) at recursive.cc:5
factorial (n=@0x7fffffffde24: 4) at recursive.cc:5
5			return n * factorial (n - 1);
Value returned is $4 = 6
(gdb) finish
Run till exit from #0  factorial (n=@0x7fffffffde24: 4) at recursive.cc:5
0x0000555555555337 in main () at recursive.cc:16
16			std::cout << n << "! = " << factorial(n) << std::endl;
Value returned is $5 = 24
(gdb) 
"finish" not meaningful in the outermost frame.
(gdb) 
"finish" not meaningful in the outermost frame.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/thesre/gdb/recursive 
Please enter a positive integer: 4

Breakpoint 1, factorial (n=<error reading variable>) at recursive.cc:3
3	int factorial(const int &n) {
(gdb) c
Continuing.

Breakpoint 1, factorial (n=@0x555555558040: -134560816) at recursive.cc:3
3	int factorial(const int &n) {
(gdb) c
Continuing.

Breakpoint 1, factorial (n=<error reading variable>) at recursive.cc:3
3	int factorial(const int &n) {
(gdb) c
Continuing.

Breakpoint 1, factorial (n=@0x555555556032: 540876833) at recursive.cc:3
3	int factorial(const int &n) {
(gdb) bt #打印整个函数栈的backtrace,可以看到递归函数的传参值。
#0  factorial (n=@0x555555556032: 540876833) at recursive.cc:3
#1  0x0000555555555271 in factorial (n=@0x7fffffffddb4: 2) at recursive.cc:5
#2  0x0000555555555271 in factorial (n=@0x7fffffffddf4: 3) at recursive.cc:5
#3  0x0000555555555271 in factorial (n=@0x7fffffffde24: 4) at recursive.cc:5
#4  0x0000555555555337 in main () at recursive.cc:16
(gdb) q
A debugging session is active.

	Inferior 1 [process 9198] will be killed.

Quit anyway? (y or n) y
thesre@HP-Z420-Workstation:~/gdb$

代码4

TODO

总结

参考资料

https://sourceware.org/gdb/current/onlinedocs/gdb.pdf
https://www.youtube.com/watch?v=svG6OPyKsrw

https://gcc.gnu.org/onlinedocs/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王万林 Ben

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值