目录

一.准备工作

二.调试命令

(一).查看代码内容(l)

 (二).开始调试(r)

(三).查看当前调试位置(where)

(四).断点(b、info b、d、c、disable、enable)

1.打断点

2.显示断点

 3.删除断点

4.调试至下一个断点

5.关闭断点

​编辑 6.打开断点

(五).打印变量和数组(p、display、undisplay)

1.打印某变量值

 2.常显示某变量

3.删除常显示

 (六).逐语句、逐过程调试(s、n)

1.逐语句调试(step)

2.逐过程调试(next)

 (七).函数(bt、finish、until)

1.查看当前堆栈调用

2.直接跑完当前函数

3.执行至指定行

(八).反汇编(disassemble)

 (九).在gdb界面执行linux指令(shell)

(十).退出gdb(quit)


一.准备工作

首先,我们需要将文件编译为debug版本。因为在linux系统下,默认生成的可执行程序是release版,但是调试需要debug版本。

我们需要在gcc或g++命令后加上限定符-g。这样生成的程序就是debug版本的。

方式如下:

gcc/g++ -g test.c/test.cpp -o test

二.调试命令

*gdp会自动记录最近的命令,如果没有输入其他命令,可以按enter键继续执行最近命令。

(一).查看代码内容(l)

l  命令是用来查看代码内容的。使用方式为

l 行号        默认生成10行,当指定行号时,会生成以指定行号为中间的共10行代码

默认不指定行号时: 

(gdb) l
1	#include<iomanip>
2	#include<stdio.h>
3	#include<string.h>
4	#include<iostream>
5	#include<stdlib.h>
6	#include<unistd.h>
7	using namespace std;
8	int main()
9	{
10	  char arr[102] = { 0  };
(gdb) 

 指定行号:

(gdb) l 10
5	#include<stdlib.h>
6	#include<unistd.h>
7	using namespace std;
8	int main()
9	{
10	  char arr[102] = { 0  };#会以第10行为中心
11	  const char* Lop = "|/-\\";
12	  memset(arr, 0, sizeof(arr));
13	  int i = 0;
14	  for(i = 0; i <= 100; i++)
(gdb) 

 (二).开始调试(r)

r命令用来开始代码调试工作,使用方式如下:

r        开始调试,直到程序结束或遇到断点暂停。在调试过程中,再次使用r命令会重新开始调试。

 

(三).查看当前调试位置(where)

where        查看此时执行位置

 

(四).断点(b、info b、d、c、disable、enable)

1.打断点

b 行号        在指定行打断点

2.显示断点

info b        显示全部断点信息,也可以在b后加编号显示指定断点

(gdb) b 10  #打断点
Breakpoint 3 at 0x400ac8: file cdl.cpp, line 10.
(gdb) b 15
Breakpoint 4 at 0x400b23: file cdl.cpp, line 15.
(gdb) info b  #显示断点
Num     Type           Disp Enb Address            What
3       breakpoint     keep y   0x0000000000400ac8 in main() at cdl.cpp:10
4       breakpoint     keep y   0x0000000000400b23 in main() at cdl.cpp:15
(gdb) 

 3.删除断点

d 断点编号        删除指定断点,不加编号则删除全部

注意断点编号不是行号,可以使用info来查看。 

(gdb) info b
Num     Type           Disp Enb Address            What
5       breakpoint     keep y   0x0000000000400ac8 in main() at cdl.cpp:7
6       breakpoint     keep y   0x0000000000400ac8 in main() at cdl.cpp:10
7       breakpoint     keep y   0x0000000000400b23 in main() at cdl.cpp:15
8       breakpoint     keep y   0x0000000000400b39 in main() at cdl.cpp:17
(gdb) d 5   #删除指定断点
(gdb) d     #删除全部断点
Delete all breakpoints? (y or n) y
(gdb) info b
No breakpoints or watchpoints.
(gdb)

4.调试至下一个断点

c        从当前调试位置直接执行到下一个断点处

#断点为10、17、18行
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400ac8 in main() at cdl.cpp:10
2       breakpoint     keep y   0x0000000000400b39 in main() at cdl.cpp:17
3       breakpoint     keep y   0x0000000000400c04 in main() at cdl.cpp:20
(gdb) r  #执行到第10行暂停

Breakpoint 1, main () at cdl.cpp:10
10	  char arr[102] = { 0  };
(gdb) c   #执行到第17行暂停
Continuing.

Breakpoint 3, main () at cdl.cpp:17
17	    cout << '[' << setw(100) << arr << ']' << '[' << i << '%' << ']' << Lop[i % 4] << '\r';
(gdb)

5.关闭断点

disable 断点编号        关闭断点 

注意,关闭断点并不是删除断点。只是在调试时不会在该处暂停,但是断点依旧存在。 

使用info b即可看断点关闭与否。

 6.打开断点

enable 变量编号        打开断点

同样的,指令需要输入的也是断点编号

 

(五).打印变量和数组(p、display、undisplay)

1.打印某变量值

p 变量        打印对应的变量值,打印地址直接加取地址符&即可

需要注意的是,这种方法只能显示一次变量值,当继续调试时变量不再显示。

(gdb) p i
$5 = 4
(gdb) n
14	  for(i = 0; i <= 100; i++)
(gdb)     #变量i没有再次显示

如果我们需要打印数组的值,输入数组名即可。

 2.常显示某变量

如果我们需要在调试中一直显示某个变量的值,那么就需要display命令了。

display 变量        常显示指定变量值,使用方式与p一致 

(gdb) display arr
3: arr = "---------", '\000' <repeats 92 times>
(gdb) c
Continuing.
[---------                                                                 ][9%]/
Breakpoint 1, main () at cdl.cpp:17
#arr数组常显示
3: arr = "----------", '\000' <repeats 91 times>
(gdb) 

3.删除常显示

undisplay 常显示变量编号        删除指定常显示变量 

 需要注意的是,不能直接写变量名,变量编号使用info display即可知道。

 

 (六).逐语句、逐过程调试(s、n)

1.逐语句调试(step)

s        逐语句调试。相当于vs中的F11

2.逐过程调试(next)

n        逐过程调试。相当于vs中的F10 

 

 (七).函数(bt、finish、until)

1.查看当前堆栈调用

bt        查看当前堆栈调用 

主要用于调试至函数内部或者递归调用函数时。 

 我们以一个递归程序举例:

#include<stdio.h>
void func(int i);
void func(int i)
{
  if(i == 0)  return;
  printf("hello world\n");
  func(i - 1);
}

int main()                                                                                                      
  3 {                                                                                                                                              
  4   func(3);                                                                                                                                       
  5   return 0;                                                                                                      
  6 }           

当我们执行至i == 1时: 

2.直接跑完当前函数

finish        可以直接跑完当前函数,若函数只有一层则直接跑完函数。 

如果是函数递归调用,当还没开始递归时,finish会执行完整个函数,自动走完全部递归过程(前提无断点)。

当已经递归调用后,在哪一层递归finish就会返回至它的前一层。 

我们依旧以上一个递归程序为例: 

3.执行至指定行

until 行号        执行至指定行

1	#include"head.h"
2	 void func(int i)
3	{
4	  if(i == 0)  return;
5	  printf("hello world\n");
6	  func(i-1);
7	}
(gdb) until 5
func (i=3) at function.c:5
5	  printf("hello world\n");
1: i = 3
(gdb) 

until也可以在main函数中使用,但一般until用于小范围跳动。

 

(八).反汇编(disassemble)

disassemble        查看指令附近区域的反汇编

 

 

 (九).在gdb界面执行linux指令(shell)

shell 指令        在gdb界面中执行linux指令

 

(十).退出gdb(quit)

(gdb) quit

(gdb) quit
A debugging session is active.

	Inferior 1 [process 10341] will be killed.

Quit anyway? (y or n) y
[cdl@VM-16-9-centos ~]$ 

 

  • “一名优秀的程序员,在穿越单行道时也会确认双向的来车情况。”——道格拉斯·林德(Doug Linder)

 如有错误,敬请斧正

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐