GDB调试①:断点设置与分步执行
GDB是符合GPL*公共许可证的GNU体系下调试工具,功能简洁易用,可以随心所欲的查看程序运行过程中的信息。
一个app程序:
#include<iostream>
using namespace std;
int func(int a,int b)
{
return a+b;
}
int main()
{
int* arr=new int[3];
arr[0]=1;
arr[1]=2;
arr[2]=func(arr[0],arr[1]);
int c=arr[2];
cout<<c<<endl;
delete [] arr;
return 0;
}
首先编译生成带调试信息的可执行目标文件(elf格式 可以通过readelf查看)
linux> g++ -o app -g app.cpp # -g 带调试信息(目标文件中包含源代码等信息,以用于调试)
通过gdb命令打开一个应用程序:
linux>gdb ./app # ./app指定调试的程序 因此可以指定 gdb ls 调试内置命令 ls
执行gdb后,转入gdb交互终端。
【显示代码】
gdb>list #显示源代码 但默认只能显示10行
gdb>set listsize 100 #修改显示行数为100 unlimited 无限制
gdb>list 10,15 #显示10=>15行的源代码
【采取-tui方式显示】
tui:text user interface 文本用户接口,将更加清晰的显示程序源代码
linux>gdb ./app -tui #以文本gui方式显示源代码,gdb交互终端在下方
【断点设置】
调试程序最关键的操作是设置断点:当程序执行到断点时将暂停,此时可以查看各部分变量是否符合预期。
gdb>break 5 #在第5行设置断点 break可以简写为b
gdb>rbreak fun #在func函数调用处设置断点
另外支持启动/关闭断点 以及删除断点
gdb>disable #禁用断点
gdb>enable #启用断点
gdb>clear #删除所有断点
gdb>delete 2 #删除断点2
【执行与查看】
gdb>run #程序执行到下一个断点 若没有设置断点,将完整执行程序
gdb>next #单步执行(但不会进入被调函数) 可简写为:n
gdb>next 2 #执行2步
gdb>step #单步执行(但会进入被调函数内部) 可简写为:s
通过在第9行设置断点,执行next将跳转到下一步
通过print命令可以查看程序执行过程对应变量的值:
gdb>print i #查看当前变量i的值
gdb>print &i #查看当前变量i的地址值
gdb>print arr #查看数组arr的值
gdb>print arr[1] #查看数组arr[1]处的值
可以看到打印出arr的值(动态申请的内存地址) 以及arr[0]的值(印证了:动态堆内存申请是请求二进制0的方式获取虚拟内存页)
gdb>print *aaa@qq.com #打印arr指针开始的数组前3个变量的值
另外在程序执行过程中如果希望,一直查看某个值的变化,可以采取watch命令达到对变量的监视:
gdb>break 9 #设置断点
gdb>run #程序执行到断点处
gdb>watch arr[1] #监视arr[1] 注意一定要程序运行之后才能watch设置监视
gdb>next #单步
gdb>next #单步
.....
一旦执行过程arr[1]发生变化,将显示前后变化值
【内存查看与寄存器查看】
print方式可以查看对应变量的值,以文本方式显示,但有时候需要分析具体对应bit位的信息,可以采取二进制方式查看内存:x/tb 命令
gdb>x/4tb arr #以二进制方式查看4字节的内存数据
#其中t指明二进制 b表面字节单位 arr是内存起始地址
程序执行过程中,可能某些情况下还需要知道寄存器的内容,gdb提供对寄存器内容的查看:
gdb>info registers #查看寄存器内容 可以简写为 info r
可以看到当函数func执行完到达第6行(采取step命令) 此时info r 显示:
- rax寄存器内容为3 即存放着被调函数的返回值。
- rdx rsi寄存器内容则存放着函数调用过程中的参数传递
上一篇: angular-cli styles 全局样式引用无效
下一篇: K8S 升级