本篇紧张是从三点方面,介绍gdb工具,分别是Gdb基本概念、常用命令以及实战调试。
若文章存在偏差之处,望佬们指出
Ⅰ 基本概念
gdb是什么?
一款Linux下的步伐调试工具,可调试C、C++、go、java等多种编程语言,可追踪步伐运行过程,进行针对性的步伐优化和bug修复。
什么情况用?
- 常用于C/C++,用于找出步伐运行中的奔溃原因和步伐逻辑问题
- 内核奔溃,导致服务器重启
- 段错误
- 步伐优化
有没有雷同的调试工具
有,crash+dump+vmlinux,这一个紧张用于服务器会出现重启情况,无法用gdb捕获错误的情况,将内核奔溃的一刹时,将日记转储起来,方便后续的调试。
什么是段错误?
段错误是一种内存访问违规的保护机制,发生在步伐试图访问不允许访问的内存地区时,体系会发送一个sigsegv信号。
什么情况下,会出现段错误
记住一点:访问了不应访问的东西,就会触发段错误,比如空内存、未授权内存等
- 引用空指针变量
- 访问了已释放的内存
- 访问数组越界
- 访问只读内存
- 栈溢出
安装,用于
- apt install gdb -y //ubuntu/debian
- yum install gdb -y // centos
复制代码 Ⅱ 常用指令
直接进一个小demo,进行测试。
- #include <stdio.h>
- int AddToTop(int top)
- {
- printf("Enter AddToTop\n");
- int count = 0;
- for(int i = 1;i <= top; ++i)
- {
- count += i;
- }
- printf("Quit AddToTop\n");
- return count;
- }
- int main(void)
- {
- int top = 10;
- int ret = AddToTop(top);
- printf("ret = %d\n", ret);
- return 0;
- }
复制代码 Makefile文件
- 01_gdb_debug:01_gdb.c
- gcc -o 01_gdb_debug 01_gdb.c -std=c99 -g
- .PHONY:clean
- clean:
- rm -rf 01_gdb_debug
复制代码 利用过程
- make //编译
- gdb 01_gdb_debug //进入调试界面
复制代码 常用指令
- l 1 //从第一行获取代码信息
- b 5 // 断点标记
- info b //查看断点信息
- d 2 //删除断点编号,需要提前使用info b,获取断点的编号
- r //运行
- n //逐步调试断点输出信息
- print i // i为需要输出的变量名
- display i // 追踪变量i每次输出的结果,需要配合n使用
复制代码 三、实战环节—模仿C步伐空指针异常情况,通过gdb,找到空指针报错位置
限制条件:代码正在执行中,突然就中断了,出现"Segmentation fault",需要定位到具体代码位置
【已知】一个运行的c模块 + 一个报错信息"Segmentation fault",
【不知情】不知道什么时间中断,也不知道怎么触发的
【目的】找到具体代码报错位置
直接编写一份会触发空指针的c代码
- #include <stdio.h>
- #include <stdlib.h>
- // 学生结构体
- typedef struct Student {
- char* name;
- int age;
- } Student;
- // 初始化学生信息
- Student* initStudent(const char* name, int age) {
- if (age < 0) {
- // 当年龄小于0时,返回空指针
- return NULL;
- }
-
- Student* stu = (Student*)malloc(sizeof(Student));
- stu->name = (char*)malloc(strlen(name) + 1);
- strcpy(stu->name, name);
- stu->age = age;
- return stu;
- }
- // 打印学生信息
- void printStudent(Student* stu) {
- // 这里会出现空指针解引用
- printf("Student Name: %s, Age: %d\n", stu->name, stu->age);
- }
- // 释放学生内存
- void freeStudent(Student* stu) {
- if (stu) {
- if (stu->name) {
- free(stu->name);
- }
- free(stu);
- }
- }
- int main() {
- // 创建一个空指针(传入负数年龄)
- Student* stu1 = initStudent("Alice", -1);
-
- // 这里会触发空指针异常
- printStudent(stu1);
-
- // 释放内存
- freeStudent(stu1);
-
- return 0;
- }
复制代码 Makefile
- null_pointer_test: null_pointer.c
- gcc -o null_pointer_test null_pointer.c -g -Wall
- .PHONY: clean
- clean:
- rm -f null_pointer_test
复制代码 编译下
- make
- ./null_pointer_test //执行下
复制代码 出现报错
开始定位
- gdb ./null_pointer_test //启动
- r //run 运行程序并等待段错误发生
复制代码
在这里,已经显示出报错位置,实战环节中一样寻常是不能第一时间看出来的,现在演示排查流程
开始调试
- bt //查看报错调用栈
- list // 输出对应代码位置
- print stu //输出可能空指针的变量参数
复制代码
运行错误解析
- //接受到一个段错误
- Program received signal SIGSEGV, Segmentation fault.
- //发现程序出现空指针访问
- 0x0000555555555253 in printStudent (stu=0x0) at null_pointer.c:32
- 发生位置:printStudent 的stu=0x0,且再null_pointer.c的第32行
- 原因:stu是一个空指针
复制代码 更详细的栈帧信息
- //最顶层栈帧,当前执行函数,地址为0x7fffffffe2d0
- Stack level 0, frame at 0x7fffffffe2d0:
- // rip指向当前执行指令,位于printStudent 的32行
- rip = 0x555555555253 in printStudent (null_pointer.c:32);
- saved rip = 0x5555555552e8
- //函数执行完后应该返回到这个地址继续执行
- called by frame at 0x7fffffffe2f0
- //c语言
- source language c.
- // 0x7fffffffe2c0地址出现参数stu NULL指针
- Arglist at 0x7fffffffe2c0, args: stu=0x0
-
- Locals at 0x7fffffffe2c0, Previous frame's sp is 0x7fffffffe2d0
- // 保存的寄存器信息,rbp (基址指针)保存在0x7fffffffe2c0
- Saved registers:
- rbp at 0x7fffffffe2c0, rip at 0x7fffffffe2c8
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |