GDB调试(调试的本质)??栈、堆,虚拟地址布局

调试的本质:确认错误的存在。

调试的原则:

1)从简单工作开始调试

(如果代码由大型循环组成,最容易出现错误的是第一次或第二次迭代引发的错误)

2)自顶向下的方法

举例:当遇到对f()的调用时,选择跟在函数调用后的语句;执行调用,然后检查依赖调用结果的变量的值,从而了解该函数是否正确运行。如果正确运行,一般就可避免单步调试。

3)使用调试工具确定段错误位置

发生段错误时,执行的第一步操作应该是在调试器中运行程序并重新产生段错误。调试器将指出发生这种错误的代码行。然后通过调用调试器的反向跟踪获得其他有用信息。

4)通过发出中断确定无限循环的位置

如果怀疑程序有无限循环,进入调试器运行程序,让该程序执行足够长的时间进入循环,然后,使用调试器的中断命令挂起该程序,并且执行反向跟踪,了解到达循环体的位置。

5)使用二分搜索

可用于迭代错误查询(二分迭代次数);用于代码段错误查询(折半删除代码查询)



GDB的 tui模式:

在GDB中使用ctrl+X+A组合键,进入tui模式。

TUI模式中,GDB窗口划分为两个子窗口

ctrl + p和ctrl + N组合键浏览以前GDB命令

使用list更改TUI的源代码子窗体显示代码的区域


基本操作

启动 GDB的方法有以下几种: 

1、gdb <program> 
program也就是你的执行文件,一般在当然目录下。 

(有参数时,set arg XXX)

2、gdb <program> core 
用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生 
的文件。 

3、gdb <program> <PID> 
如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。gd 
b会自动attach上去,并调试他。program应该在 PATH环境变量中搜索得到。 

run 运行程序

break 行号 设置断点

break [可选/行号]   if  (条件)   组合命令

break function 在函数function()的入口指定断点

disable breakpoint-list 禁用断点(不带参数,禁用所有断点)

enable breakpoint-list 启用断点(不带参数,启用所有断点)


break filename:line_number 在源代码文件的line_number处设置断点(如果文件不再当前路径则给出全路径)

break filename.cpp:line_number 在源文件中设置断点

tbreak 行号 设置断点(首次到达时起作用)

clear 行号 删除断点(适用于已经到达断点)

delete 断点编号 删除断点、监视点及捕获点

info break 查找断点

next  可选参数 下一/几步

step 可选参数 下一/几步(会进入调用函数体)

finish(简写fin) 恢复执行,直到当前栈帧完成之后止

until(简写u) 恢复执行,退出循环体内部止

continue 恢复执行操作,直到下一个断点

print j 查看变量j的值

print *pointer@number_of_elements 打印动态数组

display 变量 (简写disp)每次有暂停时输出指定条目(适当时候可使用类型强制转换)

info breakpoints 列出所有断点命令

监视点设置

watch z 在变量z值改变时查看

watch (z>18) 通过设置表达式设置监视点

调用栈

frame 1 查看以前的帧(调用的函数的存储)

//执行frame命令时,当前正在执行的函数的帧被编号为0,其父帧编号为1,依次类推。

up 转到下一个父帧

backtrace 命令显示整个栈(当前存在的所有帧的集合)

联机帮助使用:

help breakpoints 显示关于断点的文档

break *address 在虚拟内存地址处设置断点。对于没有调试信息的部分(比如源代码不可用时,或者共享库文件)是必需的。

(缩写,b ->break,cond->condition,r->run,n->next,s->step,c->continue,p->print,bt->backtrace)


GDB启动文件:

默认名为:.gdbinit

启动文件1:放在主目录中,一般

启动文件2:放在包含该项目特有用途的特定目录中

gdb -command=z  x表示要在可执行文件x上运行GDB,首先从文件z中读取命令

启动调试会话:

第一步:break main,在主函数设置断点

第二步:break function,调用函数设置断点,list列出需要看的代码

commands断点命令列表设置

commands 1 执行断点1列表

silent 静默执行

continue 命令列表中最后一个命令时continue,将继续自动执行程序

GDB的define命令创建宏


show user可以得到所有宏的列表

info locals 得到当前栈帧中所有局部变量列表

call printtree(结构体地址) 打印出结构体

x 命令,直接检查给定地址的内存

undisplay 编号 删除显示条目

set 变量=XXX 设置变量

info args检查当前函数参数

方便变量定义: set $gdb变量 = 程序变量



程序崩溃的处理:

访问禁止访问内存->导致segfault(linux,unix)/general protection fault(windows)

Unix平台上,虚拟地址布局:


箭头显示堆和栈的增长方向;

文本区域:由程序源代码中的编译器产生的机器指令组成。例如main()

数据区域:编译时分配的所有程序变量,即全局变量。

      第一个数据子区域:.data,由初始化过的变量组成;

      第二个数据子区域:.bss,未初始化的数据。

堆区域:当动态分配内存时(malloc()和new结构),从堆中分配,堆空间不够通过调用brk()来扩展堆。

栈区域:用来动态分配数据的空间。函数调用的数据(包括参数、局部变量和返回地址)都存储在栈上。每次进行函数调用时栈都会增长,每次返回到调用者,栈都会收缩。

cat 过程号,查看执行程序内存分布


段错误分析查找:

第一步:分析core文件

$ gdb cstring core

第二步:回溯输出

$ backtrace

第三步:把当前帧改为发生错误的帧

$ frame number(帧号)

第四步:输出我们的猜测

$ print XX (变量)


客户端、服务器调试

第一步:确认客户机是否成功连接到了服务器

print function(参数1,参数2...),去掉其中的强制转换,否则会输出错误

第二步:跟踪程序做过的所有系统调用,strace


调试多线程代码

info threads 获得每个线程运行信息(星号表示在当前进程中)

backtrace 查看当前线程在做什么

thread 线程号  切换到其他线程

backtrace 查看其他线程做什么

break Y  thread X  线程X到达源代码Y行时停止

break Y  thread X if i==j  线程X到达源代码Y行,并且变量i 和 j相等时停止执行

(调试多线程需要耐心和创意)


并行应用程序

并行架构:共享内存和消息传递

消息传递程序调试

$ ps ax 确定正在执行应用程序的进程(直接在命令行)

$ gdb 程序名 pid(进程号)   将GDB附加到正在运行的节点上

(gdb) backtrace  查看代码运行到何处

(gdb) frame  #number 移动到问题栈帧处



无法编译或加载调试

1、“幽灵行号”问题

第一步:确认错误代码大概位置,方法:注释掉可能出问题代码;

第二步:恢复代码,重新编译,使错误再次出现;

第三步:二分搜索,反复缩小函数搜索区,直到找到出错点。

2、缺少库

$ ldd 程序 检查程序需要哪些库

第一步:创建或查找所需库文件

第二步:

解决问题方式之一:

添加库坐在搜索路径/Debug/z

%setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/Debug/z

对于bash,执行如下命令:

$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/Debug/z

$ export LD_LIBRARY_PATH

解决开源软件库找不到问题:设置环境变量

% setenv PKG_CONFIG_PATH /usr/lib/pkgconfig:/usr/local/lib/pkgconfig


调试GUI程序

$ tty 查看当前窗口终端号


如何使用splint

splint 有很多开关,可以打开或关闭某个功能(+打开,-关闭)

























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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值