调试可执行文件
编译项目时添加-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.
- focus src / asm / cmd 鼠标聚焦在哪个窗口
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/pmapinfo 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级别的第一个语句
- n/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更详细。
- pmap + pid
调试core dump文件
专业的描述是segmentfault,通俗的讲就是程序挂掉了
ulimit -c:查看允许生成的core文件大小
ulimit -c unlimited:打开core文件开关
开始执行程序,程序挂掉之后发现二进制目录下面有core文件
gdb executableFile core文件 :gdb调试core文件,快速发现程序出错代码
- 会直接显示出程序在哪里挂掉
- core文件是死去程序的遗言。调试core文件并不是调试我们编写的可执行文件,而是遗言,只读不写。
所以遇到挂掉的程序,根本不用加日志,直接gdb调试core文件,就可以知道在哪里挂掉
知道在那里挂掉之后,就可以直接gdb调试可执行文件,设置断点。