Linux调试器-gdb使用

news/2025/3/31 5:12:51/

目录

1. 背景

2. 开始使用

3. 理解

创建需要调试的代码

debug&&release

4 详细调试

 list/l 行号

list/l 函数名

r或run

break(b)

info b(reak)

d num

disable breakpoints

enable breakpoints

n (next)

s(step)

breaktrace(或bt)

p 变量

display 变量名

undisplay

until X行号

 finish

 c


调试器:核心工作,主要是为了定位问题
所有查看的指令不影响实际的调试指令

1. 背景

程序的发布方式有两种,debug模式和release模式
Linux gcc/g++出来的二进制程序,默认是release模式
要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项

2. 开始使用

  • gdb binFile 退出: ctrl + d 或 quit 调试命令:
  • list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
  • list/l 函数名:列出某个函数的源代码。
  • r或run:运行程序。
  • n 或 next:单条执行。
  • s或step:进入函数调用
  • break(b) 行号:在某一行设置断点
  • break 函数名:在某个函数开头设置断点
  • info break :查看断点信息。
  • finish:执行到当前函数返回,然后挺下来等待命令
  • print(p):打印表达式的值,通过表达式可以修改变量的值或者调用函数

  • p 变量:打印变量值。
  • set var:修改变量的值
  • continue(或c):从当前位置开始连续而非单步执行程序
  • run(或r):从开始连续而非单步执行程序
  • delete breakpoints:删除所有断点
  • delete breakpoints n:删除序号为n的断点
  • disable breakpoints:禁用断点
  • enable breakpoints:启用断点
  • info(或i) breakpoints:参看当前设置了哪些断点
  • display 变量名:跟踪查看一个变量,每次停下来都显示它的值
  • undisplay:取消对先前设置的那些变量的跟踪
  • until X行号:跳至X行
  • breaktrace(或bt):查看各级函数调用及参数
  • info(i) locals:查看当前栈帧局部变量的值
  • quit:退出gdb

3. 理解

创建需要调试的代码

[root@VM-12-17-centos lesson8]# mkdir gdb
[root@VM-12-17-centos lesson8]# cd gdb
[root@VM-12-17-centos gdb]# touch test.c
[root@VM-12-17-centos gdb]# ll
total 0
-rw-r--r-- 1 root root 0 Jan 17 19:39 test.c
[root@VM-12-17-centos gdb]# ls ../
gdb  Makefile  mytest  proc  test.c
[root@VM-12-17-centos gdb]# cp ../Makefile .
[root@VM-12-17-centos gdb]# ll
total 4
-rw-r--r-- 1 root root 71 Jan 17 19:40 Makefile
-rw-r--r-- 1 root root  0 Jan 17 19:39 test.c
[root@VM-12-17-centos gdb]# vim test.c
[root@VM-12-17-centos gdb]# cat test.c
#include <stdio.h>int addToTop(int top)
{printf("enter addToTop\n");int i=1;int sum=0;for( i=1;i<=top;i++){sum+=i;}printf("quit addToTop\n");return sum;
}int main()
{int top=100;int result=addToTop(top);printf("result:%d\n",result);return 0;
}
[root@VM-12-17-centos gdb]# cat Makefile
mytest:test.cgcc -o mytest test.c -std=c99.PHONY:clean
clean:rm -f mytest
[root@VM-12-17-centos gdb]# ll
total 8
-rw-r--r-- 1 root root  71 Jan 17 19:40 Makefile
-rw-r--r-- 1 root root 285 Jan 17 19:45 test.c

[root@VM-12-17-centos gdb]# vim Makefile
[root@VM-12-17-centos gdb]# make
gcc -o mytest test.c
test.c: In function ‘addToTop’:
test.c:8:3: error: ‘for’ loop initial declarations are only allowed in C99 modefor(int i=1;i<=top;i++)^
test.c:8:3: note: use option -std=c99 or -std=gnu99 to compile your code
make: *** [mytest] Error 1

如果出现这种报错,该语法在C99标准下被支持,在Makefile内添加-std=c99

mytest:test.cgcc -o mytest test.c -std=c99                                                                      .PHONY:clean                           clean:rm -f mytest

debug&&release

 

 我们对之前生成的mytest重命名,使我们观察的现象更明显

[root@VM-12-17-centos gdb]# mv mytest mytest-release
[root@VM-12-17-centos gdb]# ll
total 20
-rw-r--r-- 1 root root   83 Jan 17 20:12 Makefile
-rwxr-xr-x 1 root root 8440 Jan 17 19:49 mytest-release
-rw-r--r-- 1 root root  292 Jan 17 19:49 test.c
[root@VM-12-17-centos gdb]# ./mytest-release
enter addToTop
quit addToTop
result:5050

我们生成debug方式编译的文件

[root@VM-12-17-centos gdb]# make
gcc -o mytest test.c -g -std=c99
[root@VM-12-17-centos gdb]# ll
total 32
-rw-r--r-- 1 root root   83 Jan 17 20:12 Makefile
-rwxr-xr-x 1 root root 9672 Jan 17 20:18 mytest
-rwxr-xr-x 1 root root 8440 Jan 17 19:49 mytest-release
-rw-r--r-- 1 root root  292 Jan 17 19:49 test.c
[root@VM-12-17-centos gdb]# mv mytest mytest-debug
[root@VM-12-17-centos gdb]# ll
total 32
-rw-r--r-- 1 root root   83 Jan 17 20:12 Makefile
-rwxr-xr-x 1 root root 9672 Jan 17 20:18 mytest-debug
-rwxr-xr-x 1 root root 8440 Jan 17 19:49 mytest-release
-rw-r--r-- 1 root root  292 Jan 17 19:49 test.c
[root@VM-12-17-centos gdb]# ./mytest-debug
enter addToTop
quit addToTop
result:5050

release、debug都能正常运行

debug版本内有很多的调试信息,其体积比release版本大

[root@VM-12-17-centos gdb]# readelf -S mytest-debug | grep -i debug[27] .debug_aranges    PROGBITS         0000000000000000  00001069[28] .debug_info       PROGBITS         0000000000000000  00001099[29] .debug_abbrev     PROGBITS         0000000000000000  00001191[30] .debug_line       PROGBITS         0000000000000000  0000121c[31] .debug_str        PROGBITS         0000000000000000  00001273
[root@VM-12-17-centos gdb]# readelf -S mytest-release | grep -i debug
[root@VM-12-17-centos gdb]# 

4 详细调试

 list/l 行号

显示binFile源代码,接着上次的位置往下列,每次列10行。

[root@VM-12-17-centos gdb]# gdb mytest-debug
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 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-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/lesson8/gdb/mytest-debug...done.
(gdb) l
11	
12	  }
13	  printf("quit addToTop\n");
14	  return sum;
15	}
16	
17	
18	int main()
19	{
20	  int top=100;
(gdb) l 0
1	#include <stdio.h>
2	
3	int addToTop(int top)
4	{
5	  printf("enter addToTop\n");
6	  int i=1;
7	  int sum=0;
8	  for( i=1;i<=top;i++)
9	  {
10	    sum+=i;
(gdb) l
11	
12	  }
13	  printf("quit addToTop\n");
14	  return sum;
15	}
16	
17	
18	int main()
19	{
20	  int top=100;
(gdb) l
21	
22	  int result=addToTop(top);
23	  printf("result:%d\n",result);
24	  return 0;
25	}
(gdb) l
Line number 26 out of range; test.c has 25 lines.
(gdb) 

list/l 函数名

列出某个函数的源代码,函数名居中
(gdb) l main
14	  return sum;
15	}
16	
17	
18	int main()
19	{
20	  int top=100;
21	
22	  int result=addToTop(top);
23	  printf("result:%d\n",result);

r或run

运行程序

(gdb) r
Starting program: /root/lesson8/gdb/mytest-debug 
enter addToTop
quit addToTop
result:5050
[Inferior 1 (process 480) exited normally]

break(b)

插入断点

(gdb) b 19
Breakpoint 1 at 0x4005d2: file test.c, line 19.

info b(reak)

查看断点信息

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004005d2 in main at test.c:19
(gdb) r
Starting program: /root/lesson8/gdb/mytest-debug Breakpoint 1, main () at test.c:20
20	  int top=100;
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004005d2 in main at test.c:19breakpoint already hit 1 time

d num

删除断点(num是断点的序号)

(gdb) d 19
No breakpoint number 19.
(gdb) d 1
(gdb) info b
No breakpoints or watchpoints.
(gdb) b 19
Breakpoint 2 at 0x4005d2: file test.c, line 19.
(gdb) r
Starting program: /root/lesson8/gdb/mytest-debug Breakpoint 2, main () at test.c:20
20	  int top=100;
(gdb) info b
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x00000000004005d2 in main at test.c:19breakpoint already hit 1 time

        我们重新设置断点,然后发现当我们还未退出这一次gdb时,我们即便删除之前的断点,我们重新设置的断点的num会增加,这里提一个功能,就是打开/关闭断点,我们看到enb下是yes,说明该断点是打开的,尤其是当我们不确定代码哪里出现问题,我们设置多个但是不一定同时使用的断点时,num的递增计数方式及断点的打开/关闭结合的功能会很好地帮助我们解决问题。

disable breakpoints

禁用断点
(gdb) disable breakpoint 2
(gdb) info b
Num     Type           Disp Enb Address            What
2       breakpoint     keep n   0x00000000004005d2 in main at test.c:19breakpoint already hit 1 time
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/lesson8/gdb/mytest-debug 
enter addToTop
quit addToTop
result:5050
[Inferior 1 (process 4066) exited normally]

enable breakpoints

启用断点
(gdb) enable breakpoint 3
(gdb) info b
Num     Type           Disp Enb Address            What
3       breakpoint     keep y   0x00000000004005d2 in main at test.c:19

n (next)

逐过程

(gdb) r
Starting program: /root/lesson8/gdb/mytest-debug Breakpoint 1, main () at test.c:20
20	  int top=100;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64
(gdb) n
22	  int result=addToTop(top);
(gdb) n
enter addToTop
quit addToTop
23	  printf("result:%d\n",result);
(gdb) l 22
17	
18	int main()
19	{
20	  int top=100;
21	
22	  int result=addToTop(top);
23	  printf("result:%d\n",result);
24	  return 0;
25	}
(gdb) 
Line number 26 out of range; test.c has 25 lines.
(gdb) n
result:5050
24	  return 0;
(gdb) n
25	}
(gdb) n
0x00007ffff7a2f555 in __libc_start_main () from /lib64/libc.so.6

s(step)

逐语句

(gdb) b 22
Breakpoint 2 at 0x4005d9: file test.c, line 22.
(gdb) d 1
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/lesson8/gdb/mytest-debug Breakpoint 2, main () at test.c:22
22	  int result=addToTop(top);
(gdb) s
addToTop (top=100) at test.c:5
5	  printf("enter addToTop\n");

调用函数实现压栈的过程,main函数在栈底,addToTop在其之上

 

 

 

breaktrace(或bt)

查看各级函数调用及参数

p 变量

打印变量值

(gdb) p sum
$1 = 3
(gdb) p i
$2 = 2
(gdb) p &sum
$3 = (int *) 0x7fffffffe438
(gdb) p &i
$4 = (int *) 0x7fffffffe43c

但是要一次一次地显示,非常麻烦

display 变量名

        常显示(内置类型,结构体等自定义类型,stl);

        跟踪查看一个变量,每次停下来都显示它的值

(gdb) display sum
1: sum = 3
(gdb) display i
2: i = 2
(gdb) display &sum
3: &sum = (int *) 0x7fffffffe438
(gdb) display &i
4: &i = (int *) 0x7fffffffe43c
(gdb) s
10	    sum+=i;
4: &i = (int *) 0x7fffffffe43c
3: &sum = (int *) 0x7fffffffe438
2: i = 3
1: sum = 3
(gdb) s
8	  for( i=1;i<=top;i++)
4: &i = (int *) 0x7fffffffe43c
3: &sum = (int *) 0x7fffffffe438
2: i = 3
1: sum = 6

undisplay

取消对先前设置的那些变量的跟踪

(gdb) s
8	  for( i=1;i<=top;i++)
4: &i = (int *) 0x7fffffffe43c
3: &sum = (int *) 0x7fffffffe438
2: i = 3
1: sum = 6
(gdb) undisplay &sum
warning: bad display number at or near '&sum'
(gdb) undisplay 3
(gdb) n
10	    sum+=i;
4: &i = (int *) 0x7fffffffe43c
2: i = 4
1: sum = 6

until X行号

跳至X行,执行完区间代码


(gdb) l 0
1	#include <stdio.h>
2	
3	int addToTop(int top)
4	{
5	  printf("enter addToTop\n");
6	  int i=1;
7	  int sum=0;
8	  for( i=1;i<=top;i++)
9	  {
10	    sum+=i;
(gdb) l
11	
12	  }
13	  printf("quit addToTop\n");
14	  return sum;
15	}
16	
17	
18	int main()
19	{
20	  int top=100;
(gdb) until 13
addToTop (top=100) at test.c:13
13	  printf("quit addToTop\n");
4: &i = (int *) 0x7fffffffe43c
2: i = 101
1: sum = 5050

 finish

执行到当前函数返回,然后停下来等待命令

(gdb) finish
Run till exit from #0  addToTop (top=100) at test.c:7
quit addToTop
0x00000000004005e3 in main () at test.c:22
22	  int result=addToTop(top);
Value returned is $5 = 5050
(gdb) n
23	  printf("result:%d\n",result);
(gdb) p result
$6 = 5050

c

从一个 断点处,直接运行至下一个断点处

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/lesson8/gdb/mytest-debug Breakpoint 3, main () at test.c:20
20	  int top=100;
(gdb) c
Continuing.Breakpoint 2, main () at test.c:22
22	  int result=addToTop(top);


http://www.ppmy.cn/news/12912.html

相关文章

关于浮点数使用的两个注意事项(C/C++)

目录 一.回顾浮点数的存储与读取 二.浮点数使用的第一个注意事项 三.浮点数使用的第二个注意事项 附&#xff1a; 观察内存中的FLT_MAX和FLT_MIN 一.回顾浮点数的存储与读取 http://t.csdn.cn/oVwte 浮点数的存入与读取流程总览&#xff1a; 二.浮点数使用的第一个注意事…

Linux中ssh实现免密登录

Linux中ssh实现免密登录sshpass工具安装sshpass使用sshpass命令选项用于sshpass通过SSH登录到远程服务器。假设用户名和密码都为raypick。以下是使用sshpass选项的几种方法。sshpass expect实现交互式shell脚本安装expect操作系统&#xff1a; Ubuntu18.04 需求背景&#xff1…

前端学习路线(包括计算机基础,算法,项目开发等学习路径)

1.html和CSS 推荐pink老师的学习路线: html/css 2.js和js高级 推荐pink老师学习js基础: js基础 推荐尚硅谷学习学习js高级部分:js高级 3.小项目练习 在学习完html/css/js前端三件套之后&#xff0c;建议做以下两个小项目&#xff0c;加强练习 页面练习1:项目 js小案例练…

Spring Boot自动装配原理详解

目录 1.环境和依赖 1.1.spring boot版本 1.2.依赖管理 2.自动装配 2.1.流程概述 2.2.三大步前的准备工作 2.2.1.注解入口 2.2.2.获取所有配置类 2.3.获取过滤列表 2.3.1.目的 2.3.2.过程 2.4.装载 2.4.1.目的 2.4.2.过程 2.5.自动配置 3.启动过程 3.1.整体流程…

【Java】流式编程学习笔记

文章目录一、流简介二、创建流2.1 由值创建流&#xff1a;of2.2 由列表创建流&#xff1a;stream2.3 由 Builder 创建流&#xff1a;build2.4 由文件生成流&#xff1a;lines2.5 由函数生成流2.5.1 迭代&#xff08;如果不做限制&#xff0c;就是创建无限流&#xff09;&#x…

【初阶数据结构】——二叉树OJ练习

文章目录前言1. 单值二叉树思路分析思路1. 遍历对比思路2. 递归代码实现2. 判断两棵二叉树是否相同思路分析代码实现3. 另一棵树的子树思路分析代码实现4. 返回二叉树结点的前序遍历数组思路分析代码实现5. 对称二叉树思路分析代码展示前言 上一篇文章我们刚刚学完二叉树初阶的…

Java技能树-操作符(一)-练习篇

算术运算符 执行完下面的代码&#xff0c;变量b的值是&#xff1a; java int a 1; int b a; 答案是&#xff1a;D 在后,先赋值再运算 自动递增和递减 下面代码执行后的结果是&#xff1a; int a 0; a a; int b 0; b b; System.out.println("a " a); S…

MyBatis -- 多表查询

MyBatis -- 多表查询一、准备工作二、多表查询属性名与字段名不匹配一、准备工作 博客系统场景。 创建库、表&#xff1a; -- 创建数据库 drop database if exists mycnblog; create database mycnblog DEFAULT CHARACTER SET utf8mb4;-- 使用数据数据 use mycnblog;-- 创建…