Linux篇gdb实战指南——调试奔溃内核

打印 上一主题 下一主题

主题 859|帖子 859|积分 2577

本篇紧张是从三点方面,介绍gdb工具,分别是Gdb基本概念、常用命令以及实战调试。
若文章存在偏差之处,望佬们指出
  Ⅰ 基本概念

gdb是什么?
  一款Linux下的步伐调试工具,可调试C、C++、go、java等多种编程语言,可追踪步伐运行过程,进行针对性的步伐优化和bug修复。
什么情况用?


  • 常用于C/C++,用于找出步伐运行中的奔溃原因和步伐逻辑问题
  • 内核奔溃,导致服务器重启
  • 段错误
  • 步伐优化
有没有雷同的调试工具
  有,crash+dump+vmlinux,这一个紧张用于服务器会出现重启情况,无法用gdb捕获错误的情况,将内核奔溃的一刹时,将日记转储起来,方便后续的调试。
什么是段错误?
  段错误是一种内存访问违规的保护机制,发生在步伐试图访问不允许访问的内存地区时,体系会发送一个sigsegv信号。
什么情况下,会出现段错误
  记住一点:访问了不应访问的东西,就会触发段错误,比如空内存、未授权内存等


  • 引用空指针变量
  • 访问了已释放的内存
  • 访问数组越界
  • 访问只读内存
  • 栈溢出
安装,用于
  1. apt install gdb -y   //ubuntu/debian
  2. yum install gdb -y   // centos
复制代码
Ⅱ 常用指令

直接进一个小demo,进行测试。
  1. #include <stdio.h>
  2. int AddToTop(int top)
  3. {
  4.     printf("Enter AddToTop\n");
  5.     int count = 0;
  6.     for(int i = 1;i <= top; ++i)
  7.     {
  8.        count += i;
  9.     }
  10.     printf("Quit AddToTop\n");                                                                        
  11.     return count;
  12. }
  13. int main(void)
  14. {
  15.     int top = 10;
  16.     int ret = AddToTop(top);
  17.     printf("ret = %d\n", ret);
  18.     return 0;
  19. }
复制代码
Makefile文件
  1. 01_gdb_debug:01_gdb.c
  2.     gcc -o 01_gdb_debug 01_gdb.c -std=c99 -g                                                           
  3. .PHONY:clean
  4. clean:
  5.     rm -rf 01_gdb_debug
复制代码
利用过程
  1. make //编译
  2. gdb 01_gdb_debug  //进入调试界面
复制代码
常用指令
  1. l 1  //从第一行获取代码信息
  2. b 5 // 断点标记
  3. info b //查看断点信息
  4. d 2 //删除断点编号,需要提前使用info b,获取断点的编号
  5. r //运行
  6. n //逐步调试断点输出信息
  7. print i // i为需要输出的变量名
  8. display i // 追踪变量i每次输出的结果,需要配合n使用
复制代码
三、实战环节—模仿C步伐空指针异常情况,通过gdb,找到空指针报错位置

限制条件:代码正在执行中,突然就中断了,出现"Segmentation fault",需要定位到具体代码位置
【已知】一个运行的c模块 + 一个报错信息"Segmentation fault",
【不知情】不知道什么时间中断,也不知道怎么触发的
【目的】找到具体代码报错位置
直接编写一份会触发空指针的c代码
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. // 学生结构体
  4. typedef struct Student {
  5.     char* name;
  6.     int age;
  7. } Student;
  8. // 初始化学生信息
  9. Student* initStudent(const char* name, int age) {
  10.     if (age < 0) {
  11.         // 当年龄小于0时,返回空指针
  12.         return NULL;
  13.     }
  14.    
  15.     Student* stu = (Student*)malloc(sizeof(Student));
  16.     stu->name = (char*)malloc(strlen(name) + 1);
  17.     strcpy(stu->name, name);
  18.     stu->age = age;
  19.     return stu;
  20. }
  21. // 打印学生信息
  22. void printStudent(Student* stu) {
  23.     // 这里会出现空指针解引用
  24.     printf("Student Name: %s, Age: %d\n", stu->name, stu->age);
  25. }
  26. // 释放学生内存
  27. void freeStudent(Student* stu) {
  28.     if (stu) {
  29.         if (stu->name) {
  30.             free(stu->name);
  31.         }
  32.         free(stu);
  33.     }
  34. }
  35. int main() {
  36.     // 创建一个空指针(传入负数年龄)
  37.     Student* stu1 = initStudent("Alice", -1);
  38.    
  39.     // 这里会触发空指针异常
  40.     printStudent(stu1);
  41.    
  42.     // 释放内存
  43.     freeStudent(stu1);
  44.    
  45.     return 0;
  46. }
复制代码
Makefile
  1. null_pointer_test: null_pointer.c
  2.     gcc -o null_pointer_test null_pointer.c -g -Wall
  3. .PHONY: clean
  4. clean:
  5.     rm -f null_pointer_test
复制代码
编译下
  1. make
  2. ./null_pointer_test  //执行下
复制代码
出现报错

开始定位
  1. gdb ./null_pointer_test   //启动
  2. r  //run 运行程序并等待段错误发生
复制代码

  在这里,已经显示出报错位置,实战环节中一样寻常是不能第一时间看出来的,现在演示排查流程
开始调试
  1. bt //查看报错调用栈
  2. list // 输出对应代码位置
  3. print stu //输出可能空指针的变量参数
复制代码

运行错误解析
  1. //接受到一个段错误
  2. Program received signal SIGSEGV, Segmentation fault.
  3. //发现程序出现空指针访问
  4. 0x0000555555555253 in printStudent (stu=0x0) at null_pointer.c:32
  5. 发生位置:printStudent 的stu=0x0,且再null_pointer.c的第32行
  6. 原因:stu是一个空指针
复制代码
更详细的栈帧信息
  1. info frame
复制代码

  1. //最顶层栈帧,当前执行函数,地址为0x7fffffffe2d0
  2. Stack level 0, frame at 0x7fffffffe2d0:
  3. // rip指向当前执行指令,位于printStudent 的32行
  4. rip = 0x555555555253 in printStudent (null_pointer.c:32);
  5.     saved rip = 0x5555555552e8
  6. //函数执行完后应该返回到这个地址继续执行
  7. called by frame at 0x7fffffffe2f0
  8. //c语言
  9. source language c.
  10. // 0x7fffffffe2c0地址出现参数stu NULL指针
  11. Arglist at 0x7fffffffe2c0, args: stu=0x0
  12. Locals at 0x7fffffffe2c0, Previous frame's sp is 0x7fffffffe2d0
  13. // 保存的寄存器信息,rbp (基址指针)保存在0x7fffffffe2c0
  14. Saved registers:
  15.   rbp at 0x7fffffffe2c0, rip at 0x7fffffffe2c8
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

耶耶耶耶耶

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表