不落辰

知不可乎骤得,托遗响于悲风

0%

gdb调试

调试可执行文件

  • 编译项目时添加-g选项,二进制会带有调试信息

  • gdb + 二进制名字 开始调试程序

  • 打断点

    • break main:就是在要调试的程序入口设置断点
    • break 文件名:行号 chatservice.cpp:91
    • break 类名称::方法名 ChatService::login
  • 启动调试

    • start:从main函数第一行代码开始执行
    • run:程序开始执行直到命中断点
    • continue:从当前指令向下执行直到下一个断点
  • layout split 很好看啊。今天才知道。

    • focus src / asm / cmd 鼠标聚焦在哪个窗口
      1
      2
      3
      4
      5
      6
      (gdb) focus src
      Focus set to src window.
      (gdb) focus asm
      Focus set to asm window.
      (gdb) focus cmd
      Focus set to cmd window.
  • back trace : bt

    • 查看当前调用堆栈
  • print + 变量名/reg名/值 m : p m

    • 查看变量值
  • x + 变量名m/reg名/值 : x m

    • 查看以m的值作为地址处的内存所存储的值
  • watch + 变量名x : 监控变量x

    • 向下运行 直到该值改变时会停住
  • info inferiors : 查看当前process

    1
    2
    3
    (gdb) info inferiors
    Num Description Executable
    * 1 process 6542 /home/shc/Code/try/lock/pmap
  • info threads : 查看所有 thread

  • thread n : 切换线程

  • si , ni , s , n

    • n/s都是C语言级的断点定位。
      • s会进入C函数内部,但是不会进入没有定位信息的函数(比如没有加-g编译的代码,因为其没有C代码的行数标记,没办法定位)。
      • n不会进入C函数内部。
    • ni/si都是汇编级别的断点定位。
      • si会进入函数内部的第一条汇编一句(C语言的函数 和 通过汇编跳转的函数都会进入)
      • ni不会进入汇编跳转的函数内部。
    • 归纳:
      • 当要进入没有调试信息的库函数调试的时候,用si是我已知的唯一的方法。
      • 如果要进入汇编跳转到的函数比如callq addr,那么si是我已知的唯一的方法
      • 当进入有调试信息的函数,用si和s都可以,但是他们不同,si是定位到汇编级别的第一个语句,但是s是进入到C级别的第一个语句
  • x/20i $pc : 显示当前PC后面的20条指令
  • disas $pc, $pc+20 : 显示接下来20byte的汇编指令
  • display/10i $pc : gdb持续自动显示从pc起的10条指令
  • 命令行工具:
    • pmap + pid
      • 查看一个process的所有地址空间
    • cat /proc/pid/maps
      • 查看一个process的所有地址空间。比pmap更详细。

调试core dump文件

  • 专业的描述是segmentfault,通俗的讲就是程序挂掉了

  • ulimit -c:查看允许生成的core文件大小

  • ulimit -c unlimited:打开core文件开关

  • 开始执行程序,程序挂掉之后发现二进制目录下面有core文件

  • gdb executableFile core文件 :gdb调试core文件,快速发现程序出错代码

    • 会直接显示出程序在哪里挂掉
    • core文件是死去程序的遗言。调试core文件并不是调试我们编写的可执行文件,而是遗言,只读不写。
  • 所以遇到挂掉的程序,根本不用加日志,直接gdb调试core文件,就可以知道在哪里挂掉

  • 知道在那里挂掉之后,就可以直接gdb调试可执行文件,设置断点。