面试官都在问 | Linux命令之gdb怎么使用?

面试官都在问 | Linux命令之gdb

在这里插入图片描述

0. 简述

GDB(GNU symbolic debugger)简单地说就是一个调试工具。它是一个受通用公共许可证即GPL保护的自由软件。

一般来说,GDB主要帮助你完成下面四个方面的功能:

1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。

2、可让被调试的程序在你所指定的调置的断点处停住。

3、当程序被停住时,可以检查此时你的程序中所发生的事。

4、你可以改变你的程序,将一个BUG产生的影响修正从而测试其他BUG

正因为GDB是linux下最常使用的程序调试器,因此,在我们面试各大公司的时候,使用GDB调试程序,又是相对比较容易被问到的。因为对GDB的了解,最能直观反映应聘者对Linux环境编程是否熟悉。因此我们结合海量面经,提取出了几个最容易被问到的GDB使用问题,供大家参考。

  • 使用gdb调试程序的前提是什么
  • 使用gdb如何在程序中逐步调试
  • 使用gdb如何在程序中打断点
  • 使用gdb如何查看函数调用栈

1 Linux命令之GDB

1.1 使用规则及高频选项
gdb [选项] 程序名称
-p 	#指定一个pid,调试正在运行的程序
1.2 高频调试指令
命令名称说明简写使用示例
run直接运行程序r -l -p
start开始逐步调试start -l -p
list显示调试行附近代码l main.c:10
next执行当前行代码,进入下一行,
若当前行是函数则直接将函数运行完毕
n
step执行当前行代码,进入下一行,
若当前行是函数,则进入函数进行调试。
s
continue从当前停止的位置开始继续运行c
break打断点,程序运行到断点位置停下来b main.c:10
info break查看断点信息i b
deletes删除断点d 2
backtrace查看程序运行调用栈信息backtrace
print打印变量数据p var_name
quit退出调试q
run [运行参数]
start [运行参数]
list 
1.3 调试代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int gval = 100;
int mycopy(char *buf)
{
    strcpy(buf, "我爱我的祖国");
    return gval;
}
int main()
{
    int i = 0;

    printf("gval:%d\n", gval);
    for (i = 0; i < 10; i++) {
        gval += i;
        printf("gval:%d\n", gval);
    }   
    char *buf = "我爱我家";
    printf("%s\n", buf);
    buf = NULL;
    mycopy(buf);
    printf("%s\n", buf);

    return 0;
}
1.4 gdb 调试之调试前提

并非所有的程序都可以直接调试,gdb 程序的前提是即将调试的程序中必须包含有调试符号信息。因此在程序编译生成时必须指定生成debug版本的程序,因为只有debug版本的程序在编译生成的时候才会加入程序的调试符号信息。

[san@San doc]$ ls -l test.c
-rw-rw-r-- 1 san san 460 Apr 20 15:40 test.c
[san@San doc]$ gcc -g test.c -o test
[san@San doc]$

注意: gcc -g 选项的功能为在编译生成可执行程序时,向程序中添加调试符号信息。

1.5 加载程序

直接运行gdb,将可执行程序文件名称以空格间隔,紧跟其后即可

[san@San doc]$ gdb ./test
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-114.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 /home/san/doc/test...done.
(gdb) 

若要调试正在运行中的程序,则使用 gdb -p 选项指定进程id来连接到这个程序

[san@San doc]$ sleep 60
[san@San ~]$ ps -ef|grep sleep
UID        PID  PPID  C STIME TTY          TIME CMD
san       8712 29712  0 16:04 pts/2    00:00:00 sleep 60
san       8746  8717  0 16:04 pts/1    00:00:00 grep --color=auto sleep
[san@San ~]$ gdb -p 8712

注意: 这里的ps -ef|grep sleep 为查看进程信息,并过滤出名称为 sleep 的进程。

1.6 开始调试:runstart
[san@San doc]$ gdb ./test
Reading symbols from /home/san/doc/test...done.
(gdb) run
Starting program: /home/san/doc/./test 
gval:100
gval:100
gval:101

注意: 这里run 命令敲击后,则直接开始运行程序,直到断点位置停下或者程序结束。

(gdb) start 
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Temporary breakpoint 1 at 0x4005a7: file test.c, line 13.
Starting program: /home/san/doc/./test 
Temporary breakpoint 1, main () at test.c:13
13	    int i = 0;

注意: 这里start 命令敲击后,则程序从main函数的起始位置停下,开始逐步调试。

1.7 查看调试行附近代码: list
(gdb) list
8	    strcpy(buf, "我爱我的祖国");
9	    return gval;
10	}
11	int main()
12	{
13	    int i = 0;
14	
15	    printf("gval:%d\n", gval);
16	    for (i = 0; i < 10; i++) {
17	        gval += i;

注意: 这里list 命令敲击后,查看的是调试行上下五行内的代码

(gdb) list test.c:20
15	    printf("gval:%d\n", gval);
16	    for (i = 0; i < 10; i++) {
17	        gval += i;
18	        printf("gval:%d\n", gval);
19	    }
20	    char *buf = "我爱我家";
21	    printf("%s\n", buf);
22	    buf = NULL;
23	    mycopy(buf);
24	    printf("%s\n", buf);

注意: 这里list test.c:20 命令敲击后,表示查看test.c文件的第20行附近代码

1.8 逐步调试之 step
(gdb) step
15	    printf("gval:%d\n", gval);
(gdb) step
gval:100
16	    for (i = 0; i < 10; i++) {
(gdb) step
17	        gval += i;
23	    mycopy(buf);
(gdb) step
mycopy (buf=0x0) at test.c:8
8	    strcpy(buf, "我爱我的祖国");
(gdb) list
3	#include <stdlib.h>
4	#include <string.h>
5	int gval = 100;
6	int mycopy(char *buf)
7	{
8	    strcpy(buf, "我爱我的祖国");
9	    return gval;
10	}
1.9 逐步调试之 next
(gdb) next
18	        printf("gval:%d\n", gval);
(gdb) next
gval:100
16	    for (i = 0; i < 10; i++) {
(gdb) next
17	        gval += i;

注意: 这里示例中stepnext 命令敲击后都是运行当前行代码,进入下一行。

main () at test.c:23
23	    mycopy(buf);
(gdb) next

Program received signal SIGSEGV, Segmentation fault.

注意: 从示例中可以看出stepnext 命令的区别在于,当调试行为函数时,step会进入函数内部继续逐步调试,而next则是直接将函数运行完毕(我这里的代码函数的运行直接出错了)。

1.10 逐步调试之 until
(gdb) start
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Temporary breakpoint 3 at 0x4005a7: file test.c, line 13.
Starting program: /home/san/doc/./test 

Temporary breakpoint 3, main () at test.c:13
13	    int i = 0;
(gdb) until test.c:23
gval:100
gval:100
gval:101
gval:103
gval:106
gval:110
gval:115
gval:121
gval:128
gval:136
gval:145
我爱我家
main () at test.c:23
23	    mycopy(buf);

注意: 从示例中可以看出until test.c:23 这一步的指令的功能为直接运行到test.c文件的第23行。

1.11 逐步调试之 continue
(gdb) n
gval:100
16	    for (i = 0; i < 10; i++) {
(gdb) n
17	        gval += i;
(gdb) continue
Continuing.
gval:100
gval:101
gval:103

注意: continue 的功能是从当前位置开始运行,直到遇到下一个断点或者程序运行结束。

1.12 断点添加之break
(gdb) break test.c:21
Breakpoint 6 at 0x400608: file test.c, line 21.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/san/doc/./test 
gval:100
gval:100
gval:101
gval:103
...
Breakpoint 6, main () at test.c:21
21	    printf("%s\n", buf);

注意: break test.c:21 的功能是给test.c文件的第21行打断点,程序运行至第21行就会停下来。

1.13 查看并删除断点之info breeakdelete
(gdb) info break
Num     Type           Disp Enb Address            What
6       breakpoint     keep y   0x0000000000400608 in main at test.c:21
	breakpoint already hit 1 time
(gdb) delete
Delete all breakpoints? (y or n) n
(gdb) delete 6
(gdb) info break
No breakpoints or watchpoints.
(gdb) 

注意: info break 用于查看断点信息, 能够看到示例中有一个断点ID为6的断点信息; 使用delete删除断点时,默认为删除所有断点信息,可以使用yn 决定是否删除。同时也可以直接使用delete删除断点的时候直接通过断点ID删除指定的断点。

1.14 查看程序中函数调用栈信息之backtrace
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/san/doc/./test 
gval:100
gval:100
....
Program received signal SIGSEGV, Segmentation fault.
0x000000000040057c in mycopy (buf=0x0) at test.c:8
8	    strcpy(buf, "我爱我的祖国");
(gdb) backtrace
#0  0x000000000040057c in mycopy (buf=0x0) at test.c:8
#1  0x0000000000400628 in main () at test.c:23

注意: backtrace 用于查看调用栈信息,从示例中可以看出在程序因为异常错误退出时,调用栈顶函数为mycopy 函数,则可以认为程序退出是在mycopy 函数中出现了某个错误(因为程序运行在这个函数中的时候还没有来得及运行完函数然后出栈函数,就退出了)。

1.15 查看并设置变量数据
(gdb) list
3	#include <stdlib.h>
4	#include <string.h>
5	int gval = 100;
6	int mycopy(char *buf)
7	{
8	    strcpy(buf, "我爱我的祖国");
9	    return gval;
10	}
11	int main()
12	{
(gdb) print gval
$1 = 145
(gdb) print gval=300
$2 = 300
(gdb) print gval
$3 = 300
(gdb) 

注意: print 用于查看变量的数据内容以及可以设置变量的数据,这在我们调试程序的时候非常的实用。

2. 总结
  • gdb调试程序运行的前提
  • gdb如何调试加载程序以及连接正在运行的程序
  • gdb常见的调试指令

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值