GDB调试方法

来源:互联网 发布:禅道数据库配置 编辑:程序博客网 时间:2024/05/16 05:21

目录

  • 1. 安装
  • 2. gbd帮助信息
  • 3. 启动退出gdb
    • 3.1. 启动:
    • 3.2. 退出:q
  • 4. 显示源文件
  • 5. 设置程序启动时的命令行参数
  • 6. segment fault和源程序assert造成的程序运行中断
    • 6.1. 中断时,是不能打印变量的信息的,因为不是处于用户层程序处。
    • 6.2. 打印动态分配的指针的空间大小
  • 7. 查看某个函数被谁调用的过程
  • 8. 断点
  • 9. 观察点
  • 10. 程序执行流程控制
  • 11. 查看程序运行状态
  • 12. 多进程多线程调试
    • 12.1. 想要调试多线程,必须先插入断点,让程序在断点处中断。
    • 12.2. 插入断点
    • 12.3. 设置调试进程和线程模式(可选)
    • 12.4. 调试进程
      • 12.4.1. 使用top查看杀死上次调试的进程
      • 12.4.2. 在fork位置处中断
      • 12.4.3. 显示进程信息
      • 12.4.4. 切换调试的进程
      • 12.4.5. 添加新的调试进程
      • 12.4.6. 其他
    • 12.5. 调试线程
      • 12.5.1. 显示线程信息
      • 12.5.2. 只调试某一线程,切换到线程
      • 12.5.3. 断点
      • 12.5.4. 线程执行顺序控制
      • 12.5.5. cont
      • 12.5.6. 显示某线程执行处的代码
    • 12.6. 调试实例
      • 12.6.1. 分析死锁
      • 12.6.2. 调试多进程和多线程
    • 12.7. 遇到的问题
  • 13. 其他使用方法

安装

mac下需要授权,不然不能使用

gbd帮助信息

  1. 进入gdb,显示所有帮助信息:help
  2. 针对1中显示的某项,显示所有的帮助信息:help breakpoints

启动退出gdb

启动:

  1. gcc –g file.c
  2. gdb a.out 或者 gdb,file a.out

退出:q

显示源文件

  1. 不能正常显示源文件
    解决方案: run一遍程序
  2. 设置一次显示的源码行数:set listsize 数字。显示刚才的设置:show listsize
  3. 显示程序源码:list(l)
    1. 不加参数[当前行后面]
    2. 上次显示源码的第一行的前面listsize行:-
    3. 上次显示源码的最后一行的后面listsize行:+或者不加参数
    4. 上次显示源码中间那行减offset行开始,之后的listsize行:-offset
    5. 上次显示源码中间那行加offset行开始,之后的listsize行:+offset
    6. 开始行号[开始行号为空,表示从当前行开始],结束行号
    7. 文件名:行号
    8. 文件名:函数名
    9. 函数名
  4. 搜索关键字:search 正则表达式
  5. 显示当前程序执行到哪一句
    where

设置程序启动时的命令行参数

1 直接跟在run后面
(gdb) run arg1 arg2 …
2 用命令,以后运行程序时都是这些参数
(gdb) set args arg1 arg2 …
清空2设置的args参数,为了运行不带命令行参数的程序
(gdb) set args

segment fault和源程序assert造成的程序运行中断

中断时,是不能打印变量的信息的,因为不是处于用户层程序处。

解决方法:

  1. bt显示栈帧
  2. 使用frame 1/2/3…切换到用户层栈帧处
  3. 就可以通过打印栈帧中的变量

打印动态分配的指针的空间大小

介绍几个关于C/C++程序调试的函数_rhdfcgj_新浪博客
malloc_usable_size(p)

查看某个函数被谁调用的过程

  1. 在函数内部设置断点
  2. 断点处输入bt打印被谁调用
  3. 重复观察该断点处的bt情况

断点

  1. 增加断点:
    1. 在某一行设置断点:break 行号
    2. 函数定义处设置断点:break 函数名
    3. 条件断点:b 行号 if strcmp(指针a,”temp”)==0。效果:指针a所指字符串等于temp时,在行号处插入断点并中断。tip:tab键不能自动补全,自己确认输入的正确就行了。
  2. 删除断点:delete(d) 断点编号[不加该参数默认删除所有断点,该参数使用显示断点命令显示的Num号]
  3. 显示断点信息:info break
  4. 禁用断点
    1. 禁用特定的断点
      disable breakpoint 断点编号
    2. 禁用所有的断点
      disable
  5. 打开断点
    1. 打开指定的断点
      enable breakpoint 断点编号
    2. 打开所有断点
      enable
  6. 执行到某个断点处

观察点

  1. 功能:运行到断点处,在该断点处设置某一个变量为观察点。然后continue命令会在断点或者观察点的值发生变化时,中断。
  2. 增加观察点:
    • 对要观察的变量处设置断点
    • 运行到断点处
    • 在断点处设置观察点: watch 变量名。设置完观察点后不用删除该变量所在行的断点
    • continue就会在该变量的值发生变化时停下来
  3. 显示观察点:info(或i) watchpoints
  4. 删除观察点:delete 该Num号(显示观察点命令显示的观察点有个Num序号)
  5. 规律:重新run之后,设置的观察点消失

程序执行流程控制

  1. 没有断点运行完整程序,有断点运行到第一个断点处:run(r) [命令行参数1] [命令行参数2]
  2. 执行run命令之后使用,运行到下一个断点:continue(c)
  3. 执行run命令之后使用,执行下一条指令(不进入函数):next(n).
    n 3,执行3条
  4. 执行下一条指令(进入函数):step(s)。退出被调用函数:finish(f)
  5. 在函数内部跳出函数
    finish
  6. 跳转到指定行号处执行
    1. 先在要跳转到的指定行号处设置断点!!!
    2. jump 指定行号

查看程序运行状态

  1. 打印指针变量内容:print(p) 指针变量名
  2. 打印指针变量指向变量的内容:print(p) *指针变量名
  3. 查看变量类型:ptype或者whatis 变量名
  4. 查看堆栈:backtrace(bt),然后用frame 号 查看某一层栈
  5. 查看系统变量:print(p)系统变量名


    1. $pc : 程序计数器
    2. $fp : 帧指针(当前堆栈帧)
    3. $sp : 栈指针
    4. $ps : 处理器状态

多进程多线程调试

想要调试多线程,必须先插入断点,让程序在断点处中断。

  1. 如果在main函数的第一行,插入断点。info threads显示只有main进程。
  2. 如果运行到第一个pthread_create之后。info threads显示main线程和该thread。
  3. 如果运行到第二个pthread_create之后。info threads显示main线程、thread、该thread。

插入断点

b 行号

设置调试进程和线程模式(可选)

只需要设置follow-fork-mode(默认值:parent)和detach-on-fork(默认值:on)即可。

detach-on-fork(是否同时调试父进程和子进程)follow-fork-mode(调试父进程或者子进程)说明onparent只调试主进程(GDB默认)onchild只调试子进程offparent同时调试两个进程,gdb跟主进程,子进程block在fork位置offchild同时调试两个进程,gdb跟子进程,主进程block在fork位置

设置方法:set follow-fork-mode [parent|child] set detach-on-fork [on|off]

调试进程

使用top查看杀死上次调试的进程

在fork位置处中断

catch fork

catch event
Stop when event occurs. event can be any of the following:

throw
The throwing of a C++ exception.
catch
The catching of a C++ exception.
exec
A call to exec. This is currently only available for HP-UX.
fork
A call to fork. This is currently only available for HP-UX.
vfork
A call to vfork. This is currently only available for HP-UX.

显示进程信息

info inferiors

切换调试的进程

inferior

添加新的调试进程

add-inferior [-copies n] [-exec executable] ,可以用file executable来分配给inferior可执行文件。

其他

remove-inferiors infno, detach inferior

调试线程

显示线程信息

  1. 线程ID,后面用来切换线程
  2. 每个线程执行到哪一句

  3. 显示所有线程的信息

    info threads

  4. 显示某个线程的信息

    info threads 线程ID

只调试某一线程,切换到线程

thread threadID

断点

  1. 断点对所有线程生效

    break

  2. 断点对指定线程生效

    break thread

线程执行顺序控制

  1. 进程间执行顺序控制

    1. 只让当前被调试线程执行

      set scheduler-locking on

    2. 不锁定任何线程,也就是所有线程都执行,这是默认值

      set scheduler-locking off

    3. 在单步的时候,除了next过一个函数的情况以外,只有当前线程会执行

  2. 让所有被调试线程执行GDB命令command

    thread apply ID1 ID2 command
    让一个或者多个线程执行GDB命令command

    thread apply all command
    让所有被调试线程执行GDB命令command

  3. 中断UI进程

    C-c 中断的是gdb的UI进程。后台如果有死锁的进程在运行,那么还像以前一样运行。
    Finding multi-threading bugs with gdb

  4. 中断每一个在运行的进程,看看他们在做什么

    (gdb) interrupt -a
    (gdb) bt

cont

显示某线程执行处的代码

  1. 先切换到线程上。
  2. 然后l

l显示的是当前线程执行处的代码

调试实例

分析死锁

Finding multi-threading bugs with gdb

调试多进程和多线程

gdb调试多进程和多线程命令 - 高科的专栏 - 博客频道 - CSDN.NET

遇到的问题

子线程在正常运行模式下不打印信息,在gdb下打印
原因是,正常运行模式下main线程运行的快

其他使用方法

  1. ctrl+r 搜索输入历史
  2. 自动补全输入的命令:CapsLock建
  3. 重复执行上一条命令:回车
  4. 显示输入历史:上方位键
  5. 输入命令的缩写形式
  6. gdb脚本
    • 启动gdb时候
      gdb在启动的时候,会在当前目录下查找”.gdbinit”这个文件,并把它的内容作为gdb命令进行解释,所以如果我把脚本命名为”.gdbinit”,这样在启动的时候就会处理这些命令。
    • gdb运行期间
      可以使用 source script-file 来解释gdb命令脚本script-file
      把设置参数set args等下入下面文件,启动gdb就行
      .gdbinit
    • 语法
      define nn
      n
      l
      end
      在gdb里,输入nn,程序执行到下一句,并显示语句