linux c之gdb调试

gdb概述

gdb是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会发现gdb这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。

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

1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
3、当程序被停住时,可以检查此时你的程序中所发生的事。
4、动态的改变你程序的执行环境。

从上面看来,GDB和一般的调试工具没有什么两样,基本上也是完成这些功能,不过在细节上,你会发现GDB这个调试工具的强大,大家可能比较习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。让我们一一看来。

gdb调试实例

源程序gdb_test1.c

  1 #include<stdio.h>                                                                                      
  2 
  3 int func(int n)
  4 {
  5     int sum=0,i;
  6     for(i=1;i<=n;i++)
  7     {
  8         sum+=i;
  9     }
 10     return sum;
 11 }
 12 
 13 
 14 main()
 15 {
 16     int i;
 17     long result=0;
 18     for(i=1;i<=100;i++)
 19     {
 20         result+=i;
 21     }
 22 
 23     printf("result[1-100]=%d \n",result);
 24     printf("result[1-250]=%d \n",func(250));
 25 }

一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,我们必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数可以做到这一点。如:

>g++ -g gdb_test1.c -o gdb_test1
>cc -g gdb_test1.c -o gdb_test1

编译生成执行文件。这里我们使用

> g++ -g gdb_test1.c -o gdb_test1

使用gdb调试:

root@f49:/home/fhj/mycode# gdb gdb_test1  <---------- 启动GDB
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 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 gdb_test1...done.
(gdb) l   <-------------------- l命令相当于list,从第一行开始例出原码。
3	int func(int n)
4	{
5		int sum=0,i;
6		for(i=1;i<=n;i++)
7		{
8			sum+=i;
9		}
10		return sum;
11	}
12	
(gdb)    <-------------------- 直接回车表示,重复上一次命令
13	
14	main()
15	{
16		int i;
17		long result=0;
18		for(i=1;i<=100;i++)
19		{
20			result+=i;
21		}
22	

(gdb) break 16   <-------------------- 设置断点,在源程序第16行处。
Breakpoint 1 at 0x40055c: file gdb_test1.c, line 16.
(gdb) break func  <-------------------- 设置断点,在函数func()入口处。
Breakpoint 2 at 0x40052d: file gdb_test1.c, line 5.
(gdb) info break   <-------------------- 查看断点信息。
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000040055c in main() at gdb_test1.c:16
2       breakpoint     keep y   0x000000000040052d in func(int) at gdb_test1.c:5
(gdb) r  <--------------------- 运行程序,run命令简写
Starting program: /home/fhj/mycode/gdb_test1 

Breakpoint 1, main () at gdb_test1.c:17  <---------- 在断点处停住
17		long result=0;
(gdb) n  <--------------------- 单条语句执行,next命令简写。
18		for(i=1;i<=100;i++)
(gdb) n
20			result+=i;
(gdb) n
18		for(i=1;i<=100;i++)
(gdb) n
20			result+=i;
(gdb) c   <--------------------- 继续运行程序,continue命令简写(结束本次循环)
Continuing.
result[1-100]=5050  <----------程序输出。

Breakpoint 2, func (n=250) at gdb_test1.c:5
5		int sum=0,i;
(gdb) n
6		for(i=1;i<=n;i++)
(gdb) p i  <--------------------- 打印变量i的值,print命令简写。
$1 = 32767
(gdb) n
8			sum+=i;
(gdb) n
6		for(i=1;i<=n;i++)
(gdb) p sum
$2 = 1
(gdb) n
8			sum+=i;
(gdb) p i
$3 = 2
(gdb) n
6		for(i=1;i<=n;i++)
(gdb) p sum
$4 = 3
(gdb) bt  <--------------------- 查看函数堆栈。
#0  func (n=250) at gdb_test1.c:6
#1  0x00000000004005a0 in main () at gdb_test1.c:24
(gdb) finish   <--------------------- 退出函数
Run till exit from #0  func (n=250) at gdb_test1.c:6
0x00000000004005a0 in main () at gdb_test1.c:24
24		printf("result[1-250]=%d \n",func(250));
Value returned is $5 = 31375

(gdb) c  <--------------------- 继续运行。
Continuing.
result[1-250]=31375   <----------程序输出
[Inferior 1 (process 2907) exited normally]  <--------程序退出,调试结束

(gdb) quit   <--------------------- 退出gdb。

使用gdb

  • 编译调试

一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,我们必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数可以做到这一点。如:

> cc -g hello.c -o hello
> g++ -g hello.cpp -o hello

如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。当你用-g把调试信息加入之后,并成功编译目标代码以后,让我们来看看如何用gdb来调试他。

  • 启动
对C/C++程序的调试,需要在编译前就加上-g选项:
$g++ -g hello.cpp -o hello
       program也就是你的执行文件,一般在当前目录下。
$gdb <program> <core dump file>
$gdb program core.11127
       用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。
 $gdb <program> <PID>
 $gdb hello 11127
	如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试他。program应该在PATH环境变量中搜索得到。

gdb交互命令

启动gdb后,进入到交互模式,通过以下命令完成对程序的调试;注意高频使用的命令一般都会有缩写,熟练使用这些缩写命令能提高调试的效率;

运行

  • run:简记为 r ,其作用是运行程序,当遇到断点后,程序会在断点处停止运行,等待用户输入下一步的命令。
  • continue (简写c ):继续执行,到下一个断点处(或运行结束)
  • next:(简写 n),单步跟踪程序,当遇到函数调用时,也不进入此函数体;此命令同 step 的主要区别是,step 遇到用户自定义的函数,将步进到函数中去运行,而 next 则直接调用函数,不会进入到函数体内。
    step (简写s):单步调试如果有函数调用,则进入函数;与命令n不同,n是不进入调用的函数的
  • until:当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
    -until+行号: 运行至某行,不仅仅用来跳出循环
  • finish: 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。
  • call 函数(参数):调用程序中可见的函数,并传递“参数”,如:call gdb_test(55)
  • quit:简记为 q ,退出gdb

设置断点

  • break n (简写b n):在第n行处设置断点
    (可以带上代码路径和代码名称: b OAGUPDATE.cpp:578)
  • b fn1 if a>b:条件断点设置 b 13 if i=3在第13行如果i=3设置断点
  • break func(break缩写为b):在函数func()的入口处设置断点,如:break cb_button
  • delete 断点号n:删除第n个断点
  • disable 断点号n:暂停第n个断点
  • enable 断点号n:开启第n个断点
  • clear 行号n:清除第n行的断点
  • info b (info breakpoints) :显示当前程序的断点设置情况
  • delete breakpoints:清除所有断点:

查看源代码

  • list :简记为 l ,其作用就是列出程序的源代码,默认每次显示10行。
  • list 行号:将显示当前文件以“行号”为中心的前后10行代码,如:list 12
  • list 函数名:将显示“函数名”所在函数的源代码,如:list main
  • list :不带参数,将接着上一次 list 命令的,输出下边的内容。

打印表达式

  • print 表达式:简记为 p ,其中“表达式”可以是任何当前正在被测试程序的有效表达式,比如当前正在调试C语言的程序,那么“表达式”可以是任何C语言的有效表达式,包括数字,变量甚至是函数调用。
  • print a:将显示整数 a 的值
  • print ++a:将把 a 中的值加1,并显示出来
  • print name:将显示字符串 name 的值
  • print gdb_test(22):将以整数22作为参数调用 gdb_test() 函数
  • print gdb_test(a):将以变量 a 作为参数调用 gdb_test() 函数
  • display 表达式:在单步运行时将非常有用,使用display命令设置一个表达式后,它将在每次单步进行指令后,紧接着输出被设置的表达式及值。如: display a
  • watch 表达式:设置一个监视点,一旦被监视的“表达式”的值改变,gdb将强行终止正在被调试的程序。如: watch a
  • whatis :查询变量或函数
  • info function: 查询函数
  • 扩展info locals: 显示当前堆栈页的所有变量

查询运行信息

  • where/bt :当前运行的堆栈列表;
  • bt backtrace 显示当前调用堆栈
  • up/down 改变堆栈显示的深度
  • set args 参数:指定运行时的参数
  • show args:查看设置好的参数
  • info program: 来查看程序的是否在运行,进程号,被暂停的原因。

分割窗口

  • layout:用于分割窗口,可以一边查看代码,一边测试:
  • layout src:显示源代码窗口
  • layout asm:显示反汇编窗口
  • layout regs:显示源代码/反汇编和CPU寄存器窗口
  • layout split:显示源代码和反汇编窗口
  • Ctrl + L:刷新窗口

notes

交互模式下直接回车的作用是重复上一指令,对于单步调试非常方便;

转载自:https://blog.csdn.net/haoel/article/details/2879
https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html

猜你喜欢

转载自blog.csdn.net/qq_35429629/article/details/90348792