gdb调试器(三)

        File/file 装入想要调试的可执行文件     run(r) 执行当前被调试的程序     kill(k) 终止正在调试的程序       quit(q)  退出gdb   shell 使用户不离开gdb就可以执行Linux的shell命令                  backtrace(bt) 回溯跟踪(当对代码进行调试时,run后出现错误,则可以使用bt命令查出详细的错误信息         frame n  定位到发生错误的代码段,n为backtrace命令的输出结果中的行号(位于行首)。   

(1) 设置断点(break)  

break <function>          在进入指定函数时被停住。C++可以使用class::function或function<type,type>格式来指定函数名。 //在该处停止(断点),该处不执行,下同

break <linenum> 在指定行号停住

break filename:linenum   在源文件filename的linenum行处停止

break filename:function   在源文件filename的function函数的入口处停止

break    没有参数,表示在下一条指令处停止

break *address 在程序运行的内存地址处停止

break与step结合使用时,step(s)确认后,执行上一次显示的未执行命令,并且显示出将要执行的下一行程序。使用单步调试命令step来跟踪程序,它一次只执行程序中的一行代码。

info break(i b)  命令  可以显示所有断点的信息

(2) 查看运行时的数据

在调试程序的过程中,需要查看程序中某些表达式或变量的值,以判断程序运行是否正确。

  •         print命令(p)

在调试程序时,当程序被停住时(如在断点处),可以使用print(p)命令或其同义命令inspect来查看当前程序的运行数据。

print <expr>  //输出表达式的值

print /<f> <expr>  //按某种格式输出表达式的值,如/x 则为16进制

(gdb) print n1

$1 = 4

(gdb) inspect n1

$2 = 4

(gdb) print n1

$3 = 4

(gdb) print n2

$4 = 5

(gdb) print $2

$5 = 4     //$2的值

(gdb) print $   //$5的值

$6 = 4

(gdb) print $ $  //$5的值    注意之间没有空格  这是防止CSDN编辑器转义而加上的空格

$7 = 4

(gdb) print $ $6 //$4的值

$8 = 5

每一个print都会被gdb记录下来,并且会以$1、$2、$3······这样的方式为每一个print命令编号。于是,可以使用这个编号访问以前的表达式。

另外要注意print命令的表达式中两个具有特殊意义的符号:$、$ $。print $表示显示当前序号的前一个序号的值;$ $表示给定序号的前两个序号,如果未给定序号,则默认当前序号为给定序号。

另外,info local命令可以显示当前本地的所有变量的值。

print命令的功能除了打印表达式或变量的值以外,还有对变量进行赋值和打印内存中某个变量开始的一段区域的内容。

  •         gdb的数据输出格式

x 十六进制格式     d 十进制格式   u 十六进制格式无符号整型

o 八进制格式       t 二进制格式    a 十六进制格式(等价x)

c  ASCII字符格式     f 浮点数格式     s字符串格式   i指令地址(指令文件)

p /x n1    //以十六进制格式显示n1的值

  •         自动显示命令display

当程序停住时,或单步跟踪时,这些变量会自动显示。

display <expr>        display /<f> <expr>   

display /<f> <addr>  addr表示内存地址

display /i $pc  $pc为gdb的环境变量,表示指令的地址,/i则表示输出格式为机器指令码,也就是汇编。该句指令表示,当程序停下后,就会出现源代码和机器指令码相对应的情形。 即输出当前指令的地址(程序运行到当前处),以机器指令码的格式输出,从而出现源代码和机器指令码(汇编代码)相对应的情形。

  •         查看内存examine(x)

examine(简写为x)指令可以查看内存地址中的值,格式:

x /<n/f/u> <addr>

n、f、u为可选的参数,可以独立使用,也可以联合使用。

n为一个正整数,表示显示内存的长度,即从当前地址向后显示几个地址的内容。

f表示显示的格式(即地址所指内容以什么样的格式显示出),s为字符串,如果所指的内容为指令地址,则为i。

u表示从当前地址往后请求的字节数,如果不指定则默认为4个Bytes。u参数可以用下面的字符代替:b表示单字节,h表示双字节,w表示四字节,g表示八字节。

<addr>表示一个内存地址

x /4uh 0x48723  // 从内存地址0x48723读取内容,h表示以双字节为1个单位,4表示4个单位,u表示按16进制显示。

  •         gdb的环境变量

可以在gdb的调试环境中定义自己的变量,用来保存一些调试程序中的运行数据。set命令用于定义gdb的环境变量,gdb的环境变量与Linux一样,都是以$起始。

set $foo=*object_ptr

第一次使用环境变量时,需要创建这个变量(set),以后使用直接对其赋值即可,环境变量没有类型,可以给环境变量定义任意的类型,包括结构体和数组。

在gdb的调试过程中,show convenience 命令用于查看当前设置的所有环境变量

  •         查看寄存器

在调试程序的过程中,有时需要查看某些寄存器中的值。寄存器存放了程序运行时的数据,比如程序当前运行时的指令地址(IP),程序的当前堆栈地址(SP)等。可以使用info命令来查看寄存器中的值。

info registers //查看寄存器的情况(不包括浮点寄存器)

info all-registers //查看所有寄存器的情况(包括浮点寄存器)

info registers<name1,name2,······>  //查看指定寄存器的情况(name表示寄存器名)

也可以使用print命令来访问寄存器的情况,只需要在寄存器名字前加一个$就可以了,如:print $ip。

  •         查看源程序list(l)

在程序的调试过程中,有时需要查看源程序的内容,以及源代码在内存中的情况。用list命令可以显示程序的源代码。

list linenum 显示程序第linenum行周围的源程序

list filename:linenum  显示某个.c文件中的第linenum行周围的源程序(对于多个源文件的编译)

list function 显示函数名为function的函数的源程序

list filename:function

list 显示当前行后面的源程序

list - 显示当前行前面的源程序

list first,last 显示从first行到last行之间的源代码

list ,last 显示从当前行到last行之间的源代码

可以使用info line命令来查看源代码在内存中的地址,info line命令后面也可以跟行号、函数名、文件名:行号、文件名:函数名等,从而显示指定的源代码在内存中的地址。如要显示zsx.c源文件中calculate( )函数在内存中的地址:

info line zsx.c:calculate 

(3) 改变程序的执行

修改变量的值。print命令还可以修改被调试程序中运行时的变量值。如:

print x=9

跳转执行。可以修改程序的执行顺序,让程序执行随意跳跃。

jump <linespec>  <linespec>可以是文件的行号,可以是file:linenum格式,表示下一条运行语句从哪里开始。

jump <address>  <address>是代码行的内存地址

注意jump命令不会改变当前的程序栈中的内容。

程序运行时,有一个寄存器用于保存当前代码所在的内存地址,所以jump命令也就是改变了这个寄存器中的值。可以使用set $pc来更改跳转执行的地址:set $pc=0x485。

(4) 具体事例

15           for (i = 0; i < len; ++i)

(gdb) b 15 if i==5

Breakpoint 1 at 0x4008d3: file ../src/main.c, line 15.

(gdb) b 27

Breakpoint 2 at 0x400936: file ../src/main.c, line 27.

(gdb) i b

Num     Type           Disp Enb               Address                      What

1       breakpoint     keep y        0x00000000004008d3  in main at ../src/main.c:15

                          stop only if i==5

2       breakpoint     keep y        0x0000000000400936  in main at ../src/main.c:27

//断点编号(id 断点类型    断点是否可用(y表示可用,n表示不可用) 断点地址  断点的详细信息

(5) 总结(重点内容)

运行程序:start(开始运行,只执行一步就停住);run(开始运行,在断点处停住);continue(c)继续运行,到下一个断点处停止,step(s)单步执行,进入函数内部;next(n)单步执行,不进入函数内部;u跳出循环体,执行循环体后面的第一个语句。

set var i=10  //将变量i的值设为10,比如在一个循环体中,i为控制变量,当单步执行时,i依次增加,如果想让变量i循环到10时,才停住,则可以:set var i = 10。

gdb调试:

              1. 启动gdb

                            start -- 只执行一步

                                   n -- next

                                   s -- step(单步) -- 可以进入到函数体内部

                                   c - continue -- 直接停在断点的位置

              2. 查看代码:

                            l -- list

                            l 10(或者函数名)

                            l filename:行号(或者函数名)

              3. 设置断点:

                            设置当前文件断点:

                                   b -- break

                                   b 10(或函数名)

                            设置指定文件断点:

                                b fileName:行号(或函数名)

                            设置条件断点:

                                   b 10 if value==19

                            删除断点:

                                   d 断点编号

                                获取编号:i b

              4. 查看设置的断点

                    info break   i b

              5. 开始 执行gdb调试

                            执行一步操作:  start

                                   继续执行:  n s

                            执行多步, 直接停在断点处:  continue

              5. 单步调试

                            进入函数体内部: s

                                   从函数体内部跳出: finish(如果在循环处有断点, 需要将断点删掉)

                            不进入函数体内部:n

                            退出当前循环: u //该退出是指,直接一次性执行完该循环体

              6. 查看变量的值: p -- print

              7. 查看变量的类型: ptype 变量名

              8. 设置变量的值:  set var 变量名 = 赋值  //注意,同理,不是硬性的

              9. 设置追踪变量

                            display

                            取消追踪变量

                            undisplay 编号

                            获取编号: info display

              10. 退出gdb调试

                                   quit

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/385423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

makefile文件的书写规则(make和makefile)

对于makefile&#xff0c;掌握一个规则&#xff0c;两个变量和三个函数。下面介绍一个规则。 makefile的作用&#xff1a;一个项目代码的管理工具。当一个项目的代码文件数&#xff08;如.c文件&#xff09;太多&#xff0c;用gcc编译会太麻烦&#xff0c;如果全部文件一次性编…

makefile的两个变量(自动变量和普通变量)

(1)普通变量 如&#xff1a; objmain.o add.o sub.o mul.o div.o //将后面的值赋值给obj&#xff0c;obj就是一个普通变量 targetzsx //将zsx赋值给target makefile中已经定义的一些普通变量&#xff08;通常格式都是大写&#xff0c;类似环境变量&#xff0c;它们都是普通…

【C++ Priemr | 15】虚函数表剖析(二)

一、多重继承&#xff08;无虚函数覆盖&#xff09; 下面&#xff0c;再让我们来看看多重继承中的情况&#xff0c;假设有下面这样一个类的继承关系。注意&#xff1a;子类并没有覆盖父类的函数。 测试代码&#xff1a; class Base1 { public: virtual void f() { cout <…

makefile中的两个函数(wildcard和patsubst)

(1) wildcard函数 作用是查找指定目录下指定类型的文件&#xff0c;并最终返回一个环境变量&#xff0c;需要用$取值赋值给另一个环境变量&#xff01;该函数只有一个参数&#xff0c;如取出当前目录下的所有.c文件&#xff0c;并赋值给allc普通变量&#xff1a; allc$(wildc…

C库函数

Linux的系统I/O函数&#xff08;read、write、open、close和 lseek等&#xff09;与C语言的C库函数&#xff08;libc.so库文件中&#xff09;都是相对应的&#xff0c;它们都是动态库函数。如下图所示&#xff0c;C库函数有fopen、fclose、fwrite、fread和fseek等。这些C库函数…

C库函数与Linux系统函数之间的关系

由上小节知道&#xff0c;C库函数是借助FILE类型的结构体来对文件进行操作的&#xff0c;其本身只是在用户空间&#xff08;I/O缓冲区&#xff09;进行读写操作&#xff0c;而数据在内核与用户空间之间的传递、以及将内核与I/O设备之间的数据传递都是该C库函数进行一系列的系统…

open函数和errno全局变量

&#xff08;1&#xff09;open函数 man man 查看man文档的首页 其中DESCRIPTION部分描述了man文档的每一章的章节内容 第2章System calls为系统调用&#xff0c;即Liunx系统函数。 man 2 open 查看第二章的open函数的详细帮助文件。 open函数用于打开一个已经的文件或者创…

open函数和close函数的使用

学习几个常用的Linux系统I/O函数&#xff1a;open、close、write、read和lseek。注意&#xff0c;系统调用函数必须都考虑返回值。 &#xff08;1&#xff09;open函数的使用 首先&#xff0c;需要包含三个头文件&#xff1a;<sys/types.h> <sys/stat.h> <…

1091. Acute Stroke (30)

One important factor to identify acute stroke (急性脑卒中) is the volume of the stroke core. Given the results of image analysis in which the core regions are identified in each MRI slice, your job is to calculate the volume of the stroke core. Input Speci…

stat函数(stat、fstat、lstat)

#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> //需包含头文件 有如下三个函数的函数原型&#xff1a; int stat(const char *path, struct stat *buf); 第一个形参&#xff1a;指出文件&#xff08;文件路径&#xff09;&…

【Leetcode | 235】 235. 二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以是它自己…

CPU和MMU(内存管理单元)

CPU的架构&#xff1a;要求能够理解从源程序到微指令的整个经历过程&#xff1a;存储器的层次结构&#xff08;网络资源下载到硬盘、磁盘缓存、内存、Cache、寄存器&#xff09;&#xff1b;CPU的四大部分&#xff1a;ALU、CU、中断系统和寄存器&#xff1b;程序执行的整个过程…

【C++ Primer | 09】容器适配器

一、stack s.push(): 向栈内压入一个成员&#xff1b; s.pop(): 从栈顶弹出一个成员&#xff1b; s.empty(): 如果栈为空返回true&#xff0c;否则返回false&#xff1b; s.top(): 返回栈顶&#xff0c;但不删除成员&#xff1b; s.size(): 返回栈内元素…

进程控制块PCB(进程描述符)

&#xff08;1&#xff09;PCB 每个进程在内核中都有一个进程控制块&#xff08;PCB&#xff09;来维护进程相关的信息&#xff0c;Linux内核的进程控制块是task_struct结构体。grep -r “task_struct” / 可以查找根目录下&#xff0c;包含task_struct的文件文件。或者 find…

【C++ Primer | 19】控制内存分配

1. 测试代码&#xff1a; #include <iostream> #include <new> #include <cstring> #include <cstdlib> using namespace std;void* operator new(size_t size) {cout << "global Override operator new" << endl;if (void* p…

【第15章】虚函数

一、为什么基类中的析构函数要声明为虚析构函数&#xff1f; 直接的讲&#xff0c;C中基类采用virtual虚析构函数是为了防止内存泄漏。具体地说&#xff0c;如果派生类中申请了内存空间&#xff0c;并在其析构函数中对这些内存空间进行释放。假设基类中采用的是非虚析构函数&am…

【C++ Primer | 08】IO库

一、istringstream类 描述&#xff1a;从流中提取数据&#xff0c;支持 >> 操作 这里字符串可以包括多个单词&#xff0c;单词之间使用空格分开 #include <iostream> #include <sstream> using namespace std; int main() {istringstream istr(&quo…

EXEC函数族的一般规律

事实上&#xff0c;只有execve是真正的系统调用&#xff0c;其它五个函数最终都调用execve&#xff0c;所以execve在man手册第2节&#xff0c;其它函数在man手册第3节。这些函数之间的关系如下图所示。

进程间通信的方法

Linux环境下&#xff0c;进程地址空间相互独立&#xff0c;每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到&#xff0c;所以进程和进程之间不能相互访问&#xff0c;要交换数据必须通过内核&#xff0c;在内核中开辟一块缓冲区&#xff0c;进…

pipe函数

#include <unistd.h> int pipe(int pipefd[2]); 作用&#xff1a;创建管道 成功&#xff1a;0&#xff1b;失败&#xff1a;-1&#xff0c;设置errno 函数调用成功返回r/w两个文件描述符。无需open&#xff0c;但需手动close。规定&#xff1a;fd[0] …