调试linux内核(1): 环境准备和原理介绍
开篇
现在流行的开源项目经历了长时间的开发, 积累了大量的代码, 想要一行一行地阅读代码去学习开源项目, 需要的时间成本是巨大的. 所以, 我们也需要用一种高效的方式去"阅读"代码. 计算机科学发展到现在, 产生了很多高效成熟的工具, 调试器就是其中之一(扯句题外话, 那些大牛程序员似乎就是喜欢琢磨怎么制造各种工具哈), 调试器能够帮程序员定位代码的bug, 理解代码的运行机制. 这篇文章总结了如何搭建一个调试linux内核源码的开发环境, 并简单介绍了一些调试器的实现原理.
问题1
调试内核和调试用户态程序有什么区别?
问题2
使用qemu调试内核, 原理是什么?
问题3
如何搭建调试linux内核源码的开发环境?
回答1
我们把讨论限定在使用c语言写的程序上, 一个程序想在linux运行, 大致会经过下面几个步骤:
- 你首先会编译源代码得到一个ELF文件, 这个文件中包含了用户程序的二进制指令和数据, 它具有可执行的权限;
- 接下来你在shell中运行这个ELF文件, shell会使用fork, exec等系统调用生成一个子进程去运行你的程序, 系统调用进入内核之后, 编译得到的ELF文件被用来构造这个子进程在内存中的初始状态, 内核还需要为这个进程返回用户态之后的寄存器设置合适的初始状态. 可以说, 一个进程就像一个状态机, 它的状态包括内存和寄存器的状态, 在这一步内核对这个状态机作了初始化;
- 子进程得到调度, 它从内核态返回用户态, 每执行一条指令, 伴随的是内存和寄存器状态的变化, 也就是状态机的状态转移;
以上是用户态进程的运行过程, 如果想调试一个用户态程序, 可以使用gdb工具, gdb之所以能够调试程序, 是借助了内核的帮助. 如果理解了进程是一个状态机这样的观点, 理解gdb调试程序的原理就比较容易了, 调试程序无非就是运行几条指令,观察或者修改一下内存和寄存器的状态. 内核提供了ptrace系统调用, 可以让一个进程去"跟踪(trace)"另一个进程的状态, 使用ptrace系统调用, gdb可以修改被调试进程的内存和寄存器, 比如修改原来内存中的某条指令为另一条特殊的指令, 就可以实现"打断点"的功能, 具体的细节会在其他文章中讨论, 手写一个简单的调试器体会一下ptrace系统调用.
调试用户态程序依赖内核提供的系统调用, 但是调试内核本身, 就不能再依赖它本身提供的系统调用了, 我们需要一种仿真器软件, 也就是接下来要介绍的qemu.
回答2
qemu是一种仿真器软件, 用软件的方式模拟了一整个硬件平台, 支持不同类型的CPU架构, 众多的IO设备. 使用qmeu, 可以运行完整的linux操作系统, 通过qemu的启动参数可以方便地添加修改硬件的配置, 比如CPU的数量, 增加硬盘, 网卡等设备. 对于调试内核来说, 我们需要把编译好的内核镜像传递给它, 依赖qemu提供的gdb调试服务支持, 改变启动参数, 可以让qemu启动内核的同时启动一个gdb server服务, 在特定的端口上等待gdb client的连接, 并执行gdb client的命令.
以上就是使用qemu调试内核的基本原理. 从操作系统的角度看, qemu也是一个普通的用户进程, 只不过它可以仿真一台真实的机器, 并且能够接受另外的gdb client进程的命令, 从而控制其中运行的linux内核的执行. 这个gdb client进程既可以和qemu在统一台机器上运行, 也可以通过网络连接到qemu的gdb server服务, 使用起来比较方便.
回答3
以下均在ubuntu系统上完成, 需要准备的内容包括:
- 交叉编译工具链
- 这里使用arm或者riscv平台
- 交叉编译工具用来编译linux内核源码和busybox源码
- linux内核源码
- 可以使用5.4或者之后的版本
- 编译得到内核镜像文件, 通过启动参数传递给qemu
- busybox源码
- 可以使用1.36或者之后的版本
- 编译之后用于制作根文件系统, 供内核使用
- 安装好的qemu
- 启动linux内核
- 等待gdb的连接
- 其他软件
- gdb-multiarch
- guestfs-tools
- 其他
具体的调试环境准备可以参考下面的视频:
结尾
按照视频的步骤操作下来, 实现调试linux内核应该不会有什么问题. 但是qemu的一些启动参数, 传递给内核的启动参数, 以及这些参数为什么要这样设置, 是否可以改成其他的值, 可能还是会有疑惑的. 我的建议是, 先把环境搞起来, 等对qemu和内核源码熟悉一点了, 很多问题自然就明白了.
- 比如你想知道内核的启动参数有什么用? 就可以通过调试代码的方式, 找到内核解析启动参数的部分, 分析出它在做什么.
- 对于qmeu的问题, 最好是找官方文档, 这里放个链接, 每个参数的含义在文档中都可以找到.
- 文档中没说清楚的, 你可以把qemu的源码拿来看, 自己编译一下, 然后用gdb调试qemu, 并且在qemu启动时加上 -s -S参数, 这个时候, 你就成功实现了一个两层的gdb套娃, qemu在被调试, 同时qemu里的内核也在被调试, 如果你愿意, 你还可以在qemu虚拟机里面在起一个gdb去调试用户进程, 这样就得到了一个三层的gdb套娃.
- 三层gdb套娃不是为了炫技, 这能够帮你在更高的层次上理解这一整套软件栈时如何协同工作的. 比如你在qemu虚拟机里的进程访问了一个硬件设备, 会触发到qemu中的运行的linux内核的驱动代码, 驱动代码的执行, 又会触发到qemu对某个设备的模拟代码上, 有了三层gdb套娃, 你就有机会了解你想知道的任何实现细节, 从而帮助你解决遇到的各种问题.
- 以上是一些学习和工作经验的总结, 详细的讨论会在其他文章中展开, 这里先挖个坑.
总而言之, 源码之下没有秘密. 读文档, 读源码能够解决你的大部分问题.
建了个QQ群: 838923389. 有想法的老铁可以加一下, 一起交流linux内核的使用和学习经验. 后续也会在b站发一些技术视频, 老铁们觉得有需要可以先关注一下, 视频和文章肯定会给各位带来一些启发和帮助. 更多文章还可以参考我的csdn.
调试linux内核(1): 环境准备和原理介绍的更多相关文章
- Linux内核驱动开发之KGDB原理介绍及kgdboe方式配置
接博文<Linux内核驱动开发之KGDB单步调试内核(kgdboc方式)>.上篇博文中,仅简单介绍使用串口的Kgbd的流程(kgdboc方式),本文将重点介绍KGDB调试Linux内核的原 ...
- 在qemu环境中用gdb调试Linux内核
简介 对用户态进程,利用gdb调试代码是很方便的手段.而对于内核态的问题,可以利用crash等工具基于coredump文件进行调试.其实我们也可以利用一些手段对Linux内核代码进行gdb调试,qem ...
- 学习构建调试Linux内核网络代码的环境MenuOS系统
构建调试Linux内核网络代码的环境MenuOS系统 一.前言 这是网络程序设计的第三次实验,主要是学习自己编译linux内核,构建一个具有简易功能的操作系统,同时在系统上面进行调试linux内核网络 ...
- Gdb远程调试Linux内核遇到的Bug
知识共享许可协议本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/gdb-bug 本博客同步在http://www.cn ...
- 用qemu+gdb tcp server+CDT调试linux内核启动-起步
用qemu+gdb tcp server+CDT调试linux内核启动-起步 说明: 环境信息与 用virtualbox+模拟串口+CDT调试linux内核 TCP IP协议栈-起步 提到的一样,并且 ...
- 使用QEMU调试Linux内核代码
http://blog.chinaunix.net/uid-20729583-id-1884617.html http://www.linuxidc.com/Linux/2014-08/105510. ...
- 【转】TI-Davinci开发系列之六CCS5.2调试Linux内核
上转博文<TI-Davinci开发系列之五CCS5.2使用gdbserver远程调试应用程序> 使用CCS5.2远程调试内核时,只需导入Linux内核源码,而不需要编译内核,也就不会用到交 ...
- linux内核编译环境配置
linux内核编译环境配置 如果不是编译内核,只需要安装与内核相匹配的kernel-devel开发包即可.即是/lib/modules/`uname -r`/build -> /usr/src/ ...
- VELT-0.1.5开发:使用kgdb调试Linux内核【转】
转自:http://demo.netfoucs.com/lights_joy/article/details/44106589 VELT的全称是Visual EmbedLinuxTools,它是一个与 ...
- 跟踪调试Linux内核的启动过程
跟踪调试Linux内核的启动过程---使用gdb 符钰婧 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/UST ...
随机推荐
- 通过空间占用和执行计划了解SQL Server的行存储索引
1 索引介绍 索引是一种帮助查询语句能够快速定位到数据的一种技术.索引的存储方式有行存储索引.列存储索引和内存优化三种存储方式: 行存储索引,使用B+树结构,行存储指的是数据存储格式为堆.聚集索引和内 ...
- 2020-12-29:mysql中,innodb表里,某一条数据删除了之后,这条数据会被真实的擦掉吗,还是删除了关系?
福哥答案2020-12-29:[答案来自此链接,答案相当详细:](https://www.zhihu.com/question/436957843)面试的时候受 <MySQL技术内幕 InnoD ...
- 2021-12-14:根据身高重建队列。 假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个
2021-12-14:根据身高重建队列. 假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序).每个 people[i] = [hi, ki] 表示第 i 个 ...
- 2021-08-08:自由之路。电子游戏“辐射4”中,任务“通向自由”要求玩家到达名为“Freedom Trail Ring”的金属表盘,并使用表盘拼写特定关键词才能开门。给定一个字符串 ring,表
2021-08-08:自由之路.电子游戏"辐射4"中,任务"通向自由"要求玩家到达名为"Freedom Trail Ring"的金属表盘,并 ...
- Solon v2.2.17 发布,Java 新的生态型应用开发框架
相对于 Spring Boot 和 Spring Cloud 的项目: 启动快 5 - 10 倍. (更快) qps 高 2- 3 倍. (更高) 运行时内存节省 1/3 ~ 1/2. (更少) 打包 ...
- 2013年蓝桥杯C/C++大学A组省赛真题(颠倒的价牌)
题目描述: 小李的店里专卖其它店中下架的样品电视机,可称为:样品电视专卖店. 其标价都是4位数字(即千元不等). 小李为了标价清晰.方便,使用了预制的类似数码管的标价签,只要用颜色笔涂数字就可以了(参 ...
- MYSQL数据库的创建和删除
打开Windows命令行,输入登录用户和密码 mysql -h localhost -u root -p 创建新数据 CREATE DATABASE zoo; 查看系统中的数据库 SHOW DATAB ...
- js有关dom操作学习
dom对象就是操作网页的document dom节点: 整个文档是一个文档节点(document对象) 每个 HTML 元素是元素节点(element 对象) HTML 元素内的文本是文本节点(tex ...
- 值得推荐的Blazor UI组件库
前言 本文主要是推荐一些开源.免费.实用.美观的Blazor UI组件库,提供给广大C#/.NET开发者们学习和使用(注意:排名不分先后,都是十分优秀的开源框架和项目).本文中的所有框架都已经收录到适 ...
- PE 结构的三种地址
三种地址 (一)VA(虚拟地址):PE 文件被 Windows 加载到内存后的地址. (二) RVA(相对虚拟地址):PE 文件虚拟地址相对于映射基地址(对于 EXE 文件来说,映射基地址是 ...