当前位置:   article > 正文

【C/C++ 调试 GDB指南 】gdb调试基本操作_c++ gdb

c++ gdb


gdb 简介

GDB 全称“GNU symbolic debugger”,从名称上不难看出,它诞生于 GNU 计划(同时诞生的还有 GCC、Emacs 等),是 Linux 下常用的程序调试器。发展至今,GDB 已经迭代了诸多个版本,当下的 GDB 支持调试多种编程语言编写的程序,包括 C、C++、Go、Objective-C、OpenCL、Ada 等。实际场景中,GDB 更常用来调试 C 和 C++ 程序。


一般来说,GDB主要帮助我们完成以下四个方面的功能:
1. 启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
2. 在某个指定的地方或条件下暂停程序。
3. 当程序被停住时,可以检查此时你的程序中所发生的事。
4. 在程序执行过程中修改程序中的变量或条件,将一个bug产生的影响修正从而测试其他bug。

要使用GDB调试某个程序,该程序编译时必须加上编译选项 -g,否则该程序是不包含调试信息的; GCC编译器支持 -O 和 -g一起参与编译。GCC编译过程对进行优化的程度可分为5个等级.


重要快捷键:
ctrl+A+X:进入(TextUser Interface),它为GDB调试的文本用户界面,可以方便地显示源代码、汇编和寄存器文本窗口.

GDB调试步骤

  • 启动GDB
  • 直接调试目标程序:gdb ./hello_server
  • 附加进程id:gdb attach pid
  • 调试core文件:gdb filename corename
  • 退出GDB

使用命令:q(quit的缩写)或者 Ctr + d 退出GDB。
如果GDB attach某个进程,退出GDB之前要用命令 detach 解除附加进程。


GDB常用命令

命令名称命令缩写命令说明
runr运行一个待调试的程序
continuec让暂停的程序继续运行
nextn运行到下一行
steps单步执行,遇到函数会进入
untilu运行到指定行停下来
finishfi结束当前调用函数,回到上一层调用函数处
returnreturn结束当前调用函数并返回指定值,到上一层函数调用处
jumpj将当前程序执行流跳转到指定行或地址
printp打印变量或寄存器值
backtracebt查看当前线程的调用堆栈
framef切换到当前调用线程的指定堆栈
threadthread切换到指定线程
breakb添加断点
tbreaktb添加临时断点
deleted删除断点
enableenable启用某个断点
disabledisable禁用某个断点
watchwatch监视某一个变量或内存地址的值是否发生变化
listl显示源码
infoi查看断点 / 线程等信息
ptypeptype查看变量类型
disassembledis查看汇编代码
set argsset args设置程序启动命令行参数
show argsshow args查看设置的命令行参数

  • run命令

​默认情况下,以 gdb ./filename
方式启用GDB调试只是附加了一个调试文件,并没有启动这个程序,需要输入run命令(简写为r)启动这个程序

  • continue命令

​ 当GDB触发断点或者使用 Ctrl + C 命令中断下来后,想让程序继续运行,只要输入 continue(简写为c)命令即可。

  • break命令

​break命令(简写为b)用于添加断点,可以使用以下几种方式添加断点:
break FunctionName,在函数的入口处添加一个断点;
break LineNo,在当前文件行号为LineNo处添加断点;
break FileName:LineNo,在FileName文件行号为LineNo处添加一个断点;
break FileName:FunctionName,在FileName文件的FunctionName函数的入口处添加断点;
break -/+offset,在当前程序暂停位置的前/后 offset 行处下断点;
break … if cond,下条件断点;

  • info break、enable、disable和delete命令

​命令格式及作用:
info break,也可简写为 i b,作用是显示当前所有断点信息;
disable 断点编号,禁用某个断点,使得断点不会被触发;
enable 断点编号,启用某个被禁用的断点;
delete 断点编号,删除某个断点。

  • backtrace和frame命令

​命令格式及作用:
backtrace,也可简写为 bt,用于查看当前调用堆栈。
frame 堆栈编号,也可简写为 f 堆栈编号,用于切换到其他堆栈处。

  • list命令

​命令格式及作用:
list,输出上一次list命令显示的代码后面的代码,如果是第一次执行list命令,则会显示当前正在执行代码位置附近的代码;
list -,带一个减号,显示上一次list命令显示的代码前面的代码;
list LineNo,显示当前代码文件第 LineNo 行附近的代码;
list FileName:LineNo,显示 FileName 文件第 LineNo 行附近的代码;
list FunctionName,显示当前文件的 FunctionName 函数附近的代码;
list FileName:FunctionName,显示 FileName 文件的 FunctionName 函数附件的代码;
list from,to,其中from和to是具体的代码位置,显示这之间的代码;
list命令默认只会输出 10 行源代码,也可以使用如下命令修改:

show listsize#查看 list 命令显示的代码行数;
set listsize count#设置 list 命令显示的代码行数为 count;
  • 1
  • 2
  • print和ptype命令

命令格式及作用:
print param,用于在调试过程中查看变量的值;
print param=value,用于在调试过程中修改变量的值;
print a+b+c,可以进行一定的表达式计算,这里是计算a、b、c三个变量之和;
print func(),输出func函数执行的结果,常见的用途是打印系统函数执行失败原因:print > strerror(errno);
print *this,在c++对象中,可以输出当前对象的各成员变量的值;

  • whatis和ptype命令

命令格式及功能:
whatis val,用于查看变量类型;
ptype val,作用和 whatis 类似,但功能更强大,可以查看复合数据类型,会打印出该类型的成员变量。

  • thread命令

命令格式及作用:
info thread,查看当前进程的所有线程运行情况;
thread 线程编号,切换到具体编号的线程上去;

  • next、step命令

​next 和 step 都是单步执行,但也有差别:
next 是 单步步过(step over),即遇到函数直接跳过,不进入函数内部。
step 是 单步步入(step into),即遇到函数会进入函数内部。

  • return、finish命令

return 和 finish 都是退出函数,但也有差别:
return 命令是立即退出当前函数,剩下的代码不会执行了,return 还可以指定函数的返回值。
finish 命令是会继续执行完该函数剩余代码再正常退出。

  • until命令

该命令使得程序执行到指定位置停下来,命令参数和 break 命令一样。

  • jump命令

命令格式及作用:
jump LineNo,跳转到代码的 LineNo 行的位置;
jump +10,跳转到距离当前代码下10行的位置;
jump *0x12345678,跳转到 0x12345678 地址的代码处,地址前要加星号;
​jump 命令有两点需要注意的:
中间跳过的代码是不会执行的;
跳到的位置后如果没有断点,那么GDB会自动继续往后执行;

  • set args 和 show args命令

​ 很多程序启动需要我们传递参数,set args 就是用来设置程序启动参数的,show args 命令用来查询通过 set args 设置的参数,命令格式:
set args args1,设置单个启动参数 args1;
set args “-p” “password”,如果单个参数之间有空格,可以使用引号将参数包裹起来;
set args args1 args2 args3,设置多个启动参数,参数之间用空格隔开;
set args,不带参数,则清除之前设置的参数;

  • tbreak命令

该命令时添加一个临时断点,断点一旦被触发就自动删除,使用方法同 break。

  • watch命令

watch 命令用来监视一个变量或者一段内存,当这个变量或者内存的值发生变化时,GDB就会中断下来。被监视的某个变量或内存地址会产生一个 watch point(观察点)。
​ 命令格式:
watch 整型变量;
watch 指针变量,监视的是指针变量本身;
watch *指针变量,监视的是指针所指的内容;
watch 数组变量或内存区间;

  • call命令

​ 命令格式及作用:
call func(),执行 func() 函数,同 print func()。

  • help命令

通过 help 命令可以查看目标命令的具体用法。


GDB多线程调试

概述

​ 多线程程序的编写更容易产生异常或 Bug(例如线程之间因竞争同一资源发生了死锁、多个线程同时对同一资源进行读和写等等)。GDB调试器不仅仅支持调试单线程程序,还支持调试多线程程序。本质上讲,使用GDB调试多线程程序的过程和调试单线程程序类似,不同之处在于,调试多线程程序需要监控多个线程的执行过程。
​ 用GDB调试多线程程序时,该程序的编译需要添加 -lpthread 参数。

一些命令

​1. info thread,查看当前调试程序启动了多少个线程,并打印出各个线程信息;
​2. thread 线程编号,将该编号的线程切换为当前线程;
​3. thread apply 线程编号1 线程编号2 … command,将GDB命令作用指定对应编号的线程,可以指定多个线程,若要指定所有线程,用 all 替换线程编号;
​4. break location thread 线程编号,在 location 位置设置普通断点,该断点只作用在特定编号的线程上;

设置线程锁

使用GDB调试多线程程序时,默认的调试模式是:一个线程暂停运行,其他线程也随即暂停;一个线程启动运行,其他线程也随即启动。但在一些场景中,我们希望只让特定线程运行,其他线程都维持在暂停状态,即要防止线程切换,要达到这种效果,需要借助 set scheduler-locking 命令。
命令格式及作用:
set scheduler-locking on,锁定线程,只有当前或指定线程可以运行;
set scheduler-locking off,不锁定线程,会有线程切换;
set scheduler-locking step,当单步执行某一线程时,其他线程不会执行,同时保证在调试过程中当前线程不会发生改变。但如果在该模式下执行 continue、until、finish 命令,则其他线程也会执行;
show scheduler-locking,查看线程锁定状态;

结语

在我们的编程学习之旅中,理解是我们迈向更高层次的重要一步。然而,掌握新技能、新理念,始终需要时间和坚持。从心理学的角度看,学习往往伴随着不断的试错和调整,这就像是我们的大脑在逐渐优化其解决问题的“算法”。

这就是为什么当我们遇到错误,我们应该将其视为学习和进步的机会,而不仅仅是困扰。通过理解和解决这些问题,我们不仅可以修复当前的代码,更可以提升我们的编程能力,防止在未来的项目中犯相同的错误。

我鼓励大家积极参与进来,不断提升自己的编程技术。无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力。


阅读我的CSDN主页,解锁更多精彩内容:泡沫的CSDN主页
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/620902
推荐阅读
相关标签
  

闽ICP备14008679号