gdb调试学习与实践笔记 -- 常用命令解析2

目录

info 和 thread 命令

 info args 查看当前函数的参数值

next 命令(简写为 n)让 GDB 调到下一条命令去执行

step 命令(简写为 s)遇到函数调用,进入函数内部

finish / return 命令 回到上一层调用处

ntil 命令(简写为 u)可以指定程序运行到某一行停下

jump 命令(简写为 j)跳转到指定位置执行

info 和 thread 命令

  • info 命令是一个复合指令,可以用来查看当前进程的所有线程运行情况。
  • 使用 run 命令重启一下 redis-server,等程序正常启动后,按快捷键 Ctrl+C 中断程序,然后使用 info thread 命令来查看当前进程有哪些线程,分别中断在何处:

  • 通过输出可以知道 redis-server 正常启动后,一共产生了 5个线程,包括一个主线程和四个工作线程,线程编号(Id 那一列)分别是1、2、3、4、5。
  • 四个工作线程(2、3、4、5)分别阻塞在 Linux API pthread_cond_wait 处,而主线程(1)阻塞在 epoll_wait 处。
    • 第一栏的名称叫 Id,但第一栏的数值不是线程的 Id,第三栏括号里的内容(如 LWP 24129)中,24129这样的数值才是当前线程真正的 Id。
    • LWP 含义:在早期的 Linux 系统的内核里面,其实不存在真正的线程实现,当时所有的线程都是用进程来实现的,这些模拟线程的进程被称为 Light Weight Process(轻量级进程),后来 Linux 系统有了真正的线程实现,这个名字仍然被保留了下来。
  • 线程编号前面的星号表示的是当前 GDB 作用于哪个线程,而不是主线程的意思
    • 现在有 5个线程,也就有 5 个调用堆栈,如果此时输入 backtrace 命令查看调用堆栈,由于当前 GDB 作用在线程 1,因此 backtrace 命令显示的一定是线程 1 的调用堆栈:

  • “thread 线程编号”切换到具体的线程上

 info args 查看当前函数的参数值

  • 堆栈 #2 调用处的函数是 aeProcessEvents() ,参数 eventLoop 是一个指针类型的参数,对于指针类型的参数,GDB 默认会输出该变量的指针地址值,如果想输出该指针指向对象的值,在变量名前面加上 * 解引用即可,使用 p *eventLoop 命令:

  • 如果要查看其成员值,继续使用 变量名 ->字段名 。

 help info查看更多关于 info 的组合命令

next 命令(简写为 n)让 GDB 调到下一条命令去执行

  • 下一条命令不一定是代码的下一行,而是根据程序逻辑跳转到相应的位置。
  • next 命令用调试的术语叫“单步步过”(step over),即遇到函数调用直接跳过,不进入函数体内部。
  • 在 GDB 命令行界面如果直接按下回车键,默认是将最近一条命令重新执行一遍
    • 当使用 next 命令单步调试时,不必反复输入 n 命令,直接回车就可以了

step 命令(简写为 s)遇到函数调用,进入函数内部

  • 函数调用方式,常用的函数调用方式有 _cdecl 和 _stdcall,C++ 非静态成员函数的调用方式是 _thiscall 。
    • 在这些调用方式中,函数参数的传递本质上是函数参数的入栈过程,而这三种调用方式参数的入栈顺序都是从右往左
    • 没有显式标明函数的调用方式,采用默认 _cdecl 方式。
    • 例如:c = func3(func1(1, 2), func2(8, 9));
      • step 先进入的是 func2() ,当从 func2() 返回时再次输入 step 命令会接着进入 func1() ,当从 func1 返回时,此时两个参数已经计算出来了,这时候会最终进入 func3() 。

finish / return 命令 回到上一层调用处

  • 在某个函数中调试一段时间后,不需要再一步步执行到函数返回处,希望直接执行完当前函数并回到上一层调用处,就可以使用 finish 命令。
  •  finish 命令类似的还有 return 命令,return 命令的作用是结束执行当前函数,还可以指定该函数的返回值。
  • 【注】:
    • finish 命令会执行函数到正常退出该函数.
    • return 命令是立即结束执行当前函数并返回,如果当前函数还有剩余的代码未执行完毕,也不会执行了。

ntil 命令(简写为 u)可以指定程序运行到某一行停下

  • 可快速执行完中间的代码,直接运行到指定行,也可以使用在改行添加断点,然后continue。

jump 命令(简写为 j)跳转到指定位置执行

  • jump <location> location 可以是程序的行号或者函数的地址
  • jump 会让程序执行流跳转到指定位置执行,当然其行为也是不可控制的
    • 例如跳过了某个对象的初始化代码,直接执行操作该对象的代码,那么可能会导致程序崩溃或其他意外行为。
  • jump 命令可以简写成 j,注意如果 jump 跳转到的位置后续没有断点,那么 GDB 会执行完跳转处的代码会继续执行。
int testfunc()
{
   //代码A
   //代码B
   //代码C
   //代码D
   //代码E
   //代码F
 }
  • 假设断点初始位置在行号 3 处(代码 A),这个时候我们使用 jump 6,那么程序会跳过代码 B 和 C 的执行,执行完代码 D( 跳转点),程序并不会停在代码 6 处,而是继续执行后续代码,因此如果我们想查看执行跳转处的代码后的结果,需要在行号 6、7 或 8 处设置断点。
  • jump可以执行一些我们想要执行的代码,而这些代码在正常的逻辑下可能并不会执行(可能也因此会产生一些意外的结果)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值