【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

在linux kernel调试的时候,有一种很方便的调试方法,那就是kgdb。kgdb的本质,就是在kernel内部建立一个gdb server,通过串口,它就可以和gdb进行通信来调试了。kgdb的代码和kernel是独立开来的,也就是说,除了极少数的情况,kgdb不会调用kernel的函数。这样就保证kgdb可以任意在kernel中设置断点进行调试。

1、gdb调试

gdb调试时kgdb的基础。一般来说,我们怎么用gdb调试呢,如下所示

shell> gcc hello.c -g -o hello

shell> gdb hello

编译的时候,一般先添加-g选项。添加这个选项的好处是什么,那就是在编译的时候会在执行文件中添加调试信息。有了这些调试信息之后,查看变量、设置函数断点都非常方便。因为关于函数地址、变量地址的相关信息都保存在了调试信息当中。

那么如果没有-g选项,能不能调试呢,其实也是可以的,

shell> gcc hello.c -o hello

shell> gdb hello

没有-g本身并不会影响调试,只是gdb种的部分选项无法使用而已。这时候调试,一般需要把执行文件反汇编处理,利用地址和阅读汇编语言的方法进行调试和分析。

2、gdb server & gdb

对于嵌入式来说,硬件本身的性能决定了很多软件不能运行在嵌入式设备上。这个时候,人们就想出来了gdb server的方法。gdb server就相当于一个服务器,它接受pc 上gdb的命令,将gdb要做的动作做完,并反馈相应的结果就可以了。

shell> gdbserver ./hello :7070

shell> gdb ./hello

gdb> target remote 127.0.0.1:7070

上面的demo是为了说明gdb server的用法,在实际使用的使用,只需要将ip设置成对应的嵌入式设备ip就可以了。那么,如果gdb想要调试一个嵌入式板子上正在运行的程序怎么办?也不难,

shell> gdbserver :7070 --attach 12345

shell> gdb

gdb> target remote 127.0.0.1:7070

修改的方法就是在gdbserver运行的时候添加一个attach的编译选型就可以了。

3、kgdb

有一本书籍叫《软件调试》的,内容非常好,它主要就是讲软件调试基本原理的。一般来说,软件调试离不开cpu、操作系统、编译器和gdb等调试软件的帮助。cpu决定了什么指令本身会产生中断、操作系统帮助我们收集被调试程序的所有信息、编译器产生调试信息、gdb则完成调试者和系统的交互工作。前面,我们谈到了gdb server& gdb,这里的kgdb完成的就是gdb server的工作。kgdb的使用其实非常简单,

a、打开kernel下面的kgdb调试开关

b、修改kernel启动参数

c、打开gdb命令,设置target选项,完成和gdb的沟通工作,准备开始调试

关于上面kgdb的详细操作,可以参考这一篇文章,或者这一篇。 那kgdb本身是怎么完成的,大家可以参考kernel/debug下的代码,比如这,kernel本身最早是在2.6.35才正式引入kgdb的。之前kgdb都只能作为patch自己添加到kerne里面,十分不方便。

整个目录下面,最重要的文件就是debug_core.c和gdbstub.c两个文件。中间主要包括了两个流程,

a、设置断点的流程,在debug_core.c中有如下的代码

early_param("kgdbwait", opt_kgdb_wait);

,它说明了opt_kgdb_wait是在什么时候调用的。事实上,这个函数最重要的设计就是调用arch_kgdb_breakpoint,人为产生一个断点,让cpu进入异常,从而可以让kdgb可以与gdb进行交互处理。

b、处理异常

int
kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
{struct kgdb_state kgdb_var;struct kgdb_state *ks = &kgdb_var;int ret;ks->cpu           = raw_smp_processor_id();ks->ex_vector      = evector;ks->signo     = signo;ks->err_code        = ecode;ks->kgdb_usethreadid    = 0;ks->linux_regs      = regs;if (kgdb_reenter_check(ks))return 0; /* Ouch, double exception ! */kgdb_info[ks->cpu].exception_state |= DCPU_WANT_MASTER;ret = kgdb_cpu_enter(ks, regs);kgdb_info[ks->cpu].exception_state &= ~(DCPU_WANT_MASTER |DCPU_IS_SLAVE);return ret;
}

这段代码就是kgdb异常的入口点。从kgdb_handle_exception-> kgdb_cpu_enter-> gdb_serial_stub函数,一条龙完成kgdb交互之前的准备工作,gdb_serial_stub函数如下所示,

/** This function performs all gdbserial command procesing*/
int gdb_serial_stub(struct kgdb_state *ks)
{int error = 0;int tmp;/* Clear the out buffer. */memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));if (kgdb_connected) {unsigned char thref[8];char *ptr;/* Reply to host that an exception has occurred */ptr = remcom_out_buffer;*ptr++ = 'T';ptr = pack_hex_byte(ptr, ks->signo);ptr += strlen(strcpy(ptr, "thread:"));int_to_threadref(thref, shadow_pid(current->pid));ptr = pack_threadid(ptr, thref);*ptr++ = ';';put_packet(remcom_out_buffer);}kgdb_usethread = kgdb_info[ks->cpu].task;ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid);ks->pass_exception = 0;while (1) {error = 0;/* Clear the out buffer. */memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer));get_packet(remcom_in_buffer);switch (remcom_in_buffer[0]) {case '?': /* gdbserial status */gdb_cmd_status(ks);break;case 'g': /* return the value of the CPU registers */gdb_cmd_getregs(ks);break;case 'G': /* set the value of the CPU registers - return OK */gdb_cmd_setregs(ks);break;case 'm': /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */gdb_cmd_memread(ks);break;case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */gdb_cmd_memwrite(ks);break;case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */gdb_cmd_binwrite(ks);break;/* kill or detach. KGDB should treat this like a* continue.*/case 'D': /* Debugger detach */case 'k': /* Debugger detach via kill */gdb_cmd_detachkill(ks);goto default_handle;case 'R': /* Reboot */if (gdb_cmd_reboot(ks))goto default_handle;break;case 'q': /* query command */gdb_cmd_query(ks);break;case 'H': /* task related */gdb_cmd_task(ks);break;case 'T': /* Query thread status */gdb_cmd_thread(ks);break;case 'z': /* Break point remove */case 'Z': /* Break point set */gdb_cmd_break(ks);break;
#ifdef CONFIG_KGDB_KDBcase '3': /* Escape into back into kdb */if (remcom_in_buffer[1] == '\0') {gdb_cmd_detachkill(ks);return DBG_PASS_EVENT;}
#endifcase 'C': /* Exception passing */tmp = gdb_cmd_exception_pass(ks);if (tmp > 0)goto default_handle;if (tmp == 0)break;/* Fall through on tmp < 0 */case 'c': /* Continue packet */case 's': /* Single step packet */if (kgdb_contthread && kgdb_contthread != current) {/* Can't switch threads in kgdb */error_packet(remcom_out_buffer, -EINVAL);break;}dbg_activate_sw_breakpoints();/* Fall through to default processing */default:
default_handle:error = kgdb_arch_handle_exception(ks->ex_vector,ks->signo,ks->err_code,remcom_in_buffer,remcom_out_buffer,ks->linux_regs);/** Leave cmd processing on error, detach,* kill, continue, or single step.*/if (error >= 0 || remcom_in_buffer[0] == 'D' ||remcom_in_buffer[0] == 'k') {error = 0;goto kgdb_exit;}}/* reply to the request */put_packet(remcom_out_buffer);}kgdb_exit:if (ks->pass_exception)error = 1;return error;
}

当然,除了第一次交互是人为设置断点之外,后面的断点主要是依靠kgdb的命令设置来完成的。在交互模式下,你可以完成很多操作,比如查看内存、寄存器、设置断点,甚至可以扩展kgdb的功能都可以。目前kgdb支持最好的是x86 cpu,其他cpu只是完成gdb server的一些基本工作而已。

随想录(kgdb的基本原理)相关推荐

  1. 随想录(systemtap中的基本原理)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] systemtap中的probe功能非常令人着迷.这种类似hook的方法对于我们调试性能和分析 ...

  2. Computer OS系统基本原理

    Computer OS系统基本原理 第一章 绪论(考概念) 什么是OS? o 操作系统是一组控制和管理计算机软硬件资源.合理地对各类作业进行调度以及方便用户使用的程序集合. o 操作系统是位于硬件层( ...

  3. XGBoost4J-Spark基本原理

    XGBoost4J-Spark基本原理 XGBoost4J-Spark是一个项目,旨在通过使XGBoost适应Apache Spark的MLLIB框架,无缝集成XGBoost和Apache Spark ...

  4. Docker基本原理概述

    Docker基本原理概述 Docker是一个用于开发,交付和运行应用程序的开放平台.Docker能够将应用程序与基础架构分开,从而可以快速交付软件.借助Docker,可以以与管理应用程序相同的方式来管 ...

  5. 多机多卡训练基本原理

    多机多卡训练基本原理 在工业实践中,许多较复杂的任务需要使用更强大的模型.强大模型加上海量的训练数据,经常导致模型训练耗时严重.比如在计算机视觉分类任务中,训练一个在ImageNet数据集上精度表现良 ...

  6. MindSpore基本原理

    MindSpore基本原理 • MindSpore介绍 o 自动微分 o 自动并行 • 安装 o pip方式安装 o 源码编译方式安装 o Docker镜像 • 快速入门 • 文档 MindSpore ...

  7. Docker Context基本原理

    Docker Context基本原理 介绍 本指南介绍了上下文如何使单个Docker CLI轻松管理多个Swarm集群.多个Kubernetes集群和多个单独的Docker节点. 单个Docker C ...

  8. 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?...

    一.垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?   1.对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址.大小以及使用情况. 通常, ...

  9. g-git 相关命令 及其 基本原理探索(二):git 在工作中的常用命令操作 ,超级实用!!!

    上一篇git 基本原理对git的使用以及文件分布已经有了一个整体的了解. 本篇将对工作中常用的一些git 操作命令的操作进行总结归纳,方便今后查阅. 文章目录 1. 分离头指针 2. 通过HEAD 来 ...

最新文章

  1. Python进阶之递归函数的用法及其示例
  2. windows套接字IOCP模型
  3. 启明云端分享|LVGL官方认证的开发板,到底有多牛
  4. 直播预告 | 长文本知识抽取:基于语义分割的文档级三元组关系抽取
  5. Hadoop集群规划
  6. 收藏本站html,加入收藏代码_加入收藏代码 -收藏本站的代码
  7. 编程技术越来越被看中 编程到底是什么?
  8. 源代码 到 可执行程序的过程
  9. 前端工程师应该怎么发展?
  10. 惹怒程序员的下场!阿里达摩院大神受不了骚扰电话,业余发起“二哈”AI,315后爆红...
  11. 轻松看懂概率论与图论基础数学知识
  12. Qt-textEdit 滚顶条设置只读模式
  13. Chrome 开发者工具(DevTools)中所有快捷方式列表
  14. python倒排索引
  15. Java private方法访问
  16. 盘点世界十大软件外包公司排名是哪些公司
  17. 为何需要物联网设备管理平台
  18. 2.4g语音遥控器小结
  19. getchar() 和 getch()
  20. Android系统中的Binder通信机制分析(7)- Java 层的 Binder 机制

热门文章

  1. Jquery获取列表中的值和input单选、多选框控制选中与取消
  2. 将数据库中一张表中数据复制到另一张表
  3. 更改tomcat的根目录路径
  4. 网站时间显示——基于Date
  5. 工作那些事(三十一)怎样带好一个项目团队
  6. 关于JS中和||用法技巧
  7. [No000004]在WIN7/8任务栏创建快捷方式
  8. Unity3D SceneView Camera
  9. Python学习笔记_文件读写,目录遍历类封装
  10. EF with (LocalDb)V11.0