一种在线调试Linux内核的方法与流程
未命名
09-29
阅读:135
评论:0

技术领域
1.本发明涉及操作系统技术领域,具体提供一种在线调试linux内核的方法。
背景技术:
2.linux操作系统的开发,可以分为内核开发和用户空间开发,内核开发比用户空间开发更加困难,很重要的一个因素就是内核调试比较困难。用户空间的程序在线调试工具可以用gdb,或者直接在代码中添加打印信息,重新编译运行。而内核添加打印信息重新编译可能需要耗时更长,还有可能需要重启机器。很多时候对于在线系统,希望内核探测运行时的情况,其实就是探测某个函数,尤其是状态机比较复杂的时候,更希望做分支的判断,探测内核函数执行走的那个分支,以及函数中某个变量的值。
3.现有技术中对于操作系统内核的调试方法存在诸多缺点,例如:(1)中国发明专利“mips 架构操作系统内核的调试方法和装置”(专利号:cn104077220a)。该专利提供了一种基于mips架构操作系统内核的调试方法。其调试方法为:在操作系统内核的指定地址插入探测点,将探测点处理函数与探测点关联;在内核执行至探测点时,执行探测点处理函数;由内核预置的调试工具钩住mips架构处理器并收集内核调试信息;在探测点处理函数执行完毕后,返回执行操作系统内核。其原理是基于linux内核的kprobe的探测技术,一般用于探测函数的开头和返回值,尽管也可以探测函数内部,但是缺点也是很明显的,需要在被探测函数的地址基础上加上被探测点的偏移地址。要想知道偏移地址,就需要阅读被探测函数的汇编代码,找到被探测点,然后计算出偏移地址,这需要使用者熟悉被调试机器所属架构的指令集,难度较高,对使用者不友好。
4.(2)中国发明专利“一种操作系统内核调试方法和虚拟调试服务模块”(专利号:cn102301344b)。该专利提供的调试方法为:虚拟调试服务模块接收主控操作系统中的调试模块发送的插入至少一个断点的断点插入请求,断点插入请求中包括插入断点的位置信息;虚拟调试服务模块根据断点插入请求中的插入断点的位置信息,在被调试操作系统中的相应位置处插入断点,并将插入断点的位置记录在调试断点信息表中;虚拟调试服务模块捕获被调试操作系统执行过程中触发的断点异常,并将捕获到的断点异常的特征与调试断点信息表中记录的断点的位置进行比较,如果匹配,则暂停被调试操作系统的运行。其原理就是在一台主机上构建两台虚拟机来实现类似gdb的调试。但是这种方法构建比较繁琐,另外不能模拟在线内核的环境,所以不能调试在线内核。
5.(3)中国发明专利“linux操作系统的内核调试方法”(专利号:cn101281488)。该专利提出了采用动态替换和恢复技术对linux 操作系统的内核进行调试。将需要修改和调试的内核函数以内核模块的方式编译为临时内核模块;然后利用内核装载工具加载到内核的用户空间,对被调试函数入口放置了函数跳转表,截获对原始函数的调用,从而调试对原始函数的临时改写函数,调试完毕后,利用模块的卸载机制,来恢复原始函数,从而使得内核恢复为原始状态,其核心是模块装载工具。这种方法的缺点是,模块装载工具实现较为复杂,并且将被替换函数被编译为模块的过程也是很复杂的,实际实施可能需要经过多次编
译试错。
6.相应地,本领域需要一种新的调试linux内核方案来解决上述问题。
技术实现要素:
7.为了克服上述缺陷,提出了本发明,以提供解决或至少部分地解决现有技术中对于linux内核的调试存在实施复杂、处理繁琐、无法在线调试内核的技术问题。
8.本发明提供一种在线调试linux内核的方法,包括步骤:根据待探测函数,处理得到探测模块;将所述探测模块加载到在线内核中;使用跳转指令替换待探测函数开头预设的空指令,所述跳转指令用于跳转到所述探测模块,且在所述探测模块执行结束后返回到所述待探测函数被调用处的下一条指令;在所述探测模块执行结束后,将所述跳转指令还原为所述空指令;从所述在线内核中卸载所述探测模块。
9.在上述方法的一个技术方案中,所述根据待探测函数,处理得到探测模块,包括:编写源代码,所述源代码包括待探测函数的全部执行体、探测点以及调试信息;编译所述源代码,得到探测模块。
10.在上述方法的一个技术方案中,所述编译所述源代码,得到探测模块,包括:提取所有的内核头文件,汇总到vmlinux.h文件中;将所述vmlinux.h文件添加到所述源代码中;编译添加所述vmlinux.h文件后的源代码,得到探测模块。
11.在上述方法的一个技术方案中,所述提取所有的内核头文件,汇总到vmlinux.h文件中,包括:登录linux系统,使用ls命令得到vmlinux文件;使用bpftool工具将所述vmlinux文件中的内核头文件信息提取出来,汇总到vmlinux.h文件中。
12.在上述方法的一个技术方案中,所述将所述探测模块加载到在线内核中,包括:使用所述linux系统中的insmod命令将所述探测模块加载到在线内核中。
13.在上述方法的一个技术方案中,所述从所述在线内核中卸载所述探测模块,包括:使用所述linux系统中的rmmod命令从所述在线内核中卸载所述探测模块。
14.在上述方法的一个技术方案中,所述使用跳转指令替换待探测函数开头预设的空指令,和所述将所述跳转指令还原为所述空指令,均通过设置的文件系统接口在用户空间控制。
15.本发明上述技术方案的工作原理为:在实施本发明的技术方案中,先把待探测函数进行改写,封装为一个内核模块,通过加载内核模块到在线内核,再借助跳转指令替换空指令,实现了在运行待探测函数时能够替换执行内核模块中处理后的函数,探测结束后再将空指令替换回来并卸载内核模块来恢复现场,不影响后续内核运行。
附图说明
16.参照附图,本发明的公开内容将变得更易理解。本领域技术人员容易理解的是:这些附图仅仅用于说明的目的,而并非意在对本发明的保护范围组成限制。此外,图中类似的数字用以表示类似的部件,其中:图1是根据本发明中一种在线调试linux内核的方法主要步骤流程示意图;图2是根据本发明一种在线调试linux内核的方法中步骤s3执行前的函数运行示意图;图3是根据本发明一种在线调试linux内核的方法中步骤s3执行后的函数运行示意图;图4是根据本发明一种在线调试linux内核的方法中步骤s4执行后的函数运行示意图。
具体实施方式
17.为了对本发明的技术方案及有益效果有更进一步的了解,下面结合附图详细说明本发明的技术方案及其产生的有益效果。
18.本发明主要针对上述调试方法的缺点提出的一种方法,使得内核可以被在线探测调试,不需要理解特定架构的汇编,不需要额外的辅助机器;并且可以深入到内核函数的任意位置,不需要手动计算偏移地址,使用c语言实现源码级别的在线调试。
19.本发明在内核探测工具的基础上,参考了内核探测技术及指令替换技术,基本构思在于借助跳转指令,通过蹦床实现被探测函数的替换,同时借助内核模块这一通用的做法,把要探测的函数进行该些,封装为一个探测模块,通过记载和卸载该探测模块实现调试和恢复现场。
20.图1是根据本发明中一种在线调试linux内核的方法主要步骤流程示意图。如图1所示,本发明实施例中的一种在线调试linux内核的方法主要包括下列步骤s1-步骤s5。
21.步骤s1:待探测函数编写探测模块,该探测模块以内核模块的形式存在。
22.内核代码以两种方式存在于linux内核中:一种是静态编译进内核,另外一种是以模块的方式存在于内核,称之为内核模块。
23.比如一个功能被编写为代码后,就可以通过上述两种方式存在于内核中。当以静态方式编译进内核后,需要把在线内核整个替换,重启机器后才能生效;但是以内核模块的存在方式,就不需要替换整个内核,也不需要重启机器,只需要通过命令把对应这个功能的内核模块加载到内核就可以。同样的,如果不需要这个功能,可以通过命令来把对应这个功能的内核模块从内核中卸载即可。
24.探测模块可以通过命令insmod安装到内核,也可以通过rmmod命令从内核中被卸载。
25.一个实施方式中,步骤s1进一步包括:步骤s11:编写源代码,所述源代码包括待探测函数的全部执行体、探测点以及调试信息。
26.本实施例中,需要先得到初始的源代码debug_.c文件,通过对源代码debug_.c文件进行编译才能得到用于探测模块debug_.ko。初始的源代码
debug_.c文件编写方法,需要先在其中拷贝待探测函数的全部执行体,再添加待探测函数内部需要的探测点,使用c语言根据需要编写源码级的调试信息。其中,调试信息的用途在于,比如我们想查看函数中某处某个变量的值,可以加入打印信息,通过打印到终端的方式来获取该变量的值。
27.为了便于区分,此时可以将经过步骤s11处理后的函数重命名为fake_ 。后续待探测函数将会被重命名函数fake_ 所替换(后文详述),重命名函数fake_和待探测函数拥有一样的功能,只是在其基础上增加了需要调试的内容。
28.其中,debug是调试的意思,表示待探测函数,假设待调试的被探测函数是pipe_write这个内核函数,那么对应的源代码文件为debug_ pipe_write.c,对应编译后的内核模块为debug_pipe_write.ko,经过步骤s11处理后的pipe_write函数重命名为fake_pipe_write。步骤s12:编译所述源代码,得到探测模块。
29.本实施例中,如果直接编译上述得到初始的源代码debug_.c,虽然能得到用于探测相应内核函数的探测模块,但是由于头文件缺失的问题会出现很多报错,为解决头文件的包含问题,本实施例中步骤s12进一步包括:步骤s121:提取所有的内核头文件,汇总到vmlinux.h文件中。
30.具体的提取方法为:借助内核的工具bpftool btf dump file /sys/kernel/btf/vmlinux format c 》 vmlinux.h来提取待探测函数涉及的数据结构类型。bpftool btf dump file /sys/kernel/btf/vmlinux format c 》 vmlinux.h,这个动作就是使用bpftool工具将所述vmlinux文件中的内核头文件信息提取出来,汇总到vmlinux.h文件中。
31.其中vmlinux文件主要指/sys/kernel/btf/vmlinux,它是操作系统中的一个文件,这个文件存储了内核头文件的信息,可以使用bpftool工具将文件中的内核头文件的信息提取出来。
32.[root@fedora linux]# ls /sys/kernel/btf/vmlinux,登录linux系统,使用ls命令得到vmlinux文件;步骤s122:将所述vmlinux.h文件添加到所述源代码中。
[0033]
当探测/调试不同的内核函数时,需要加载不同的内核头文件,本实施例中把所有的内核头文件都集中到vmlinux.h中,那么以后无论探测/调试哪个内核函数,都只需要在源代码中包含vmlinux.h即可,而且vmlinux.h这个文件只需要提取这一次即可。
[0034]
步骤s123:编译添加所述vmlinux.h文件后的源代码,得到探测模块。
[0035]
步骤s2:将所述探测模块加载到在线内核中。
[0036]
本实施例中,使用所述linux系统中的insmod命令将所述探测模块加载到在线内核中。
[0037]
步骤s3:探测模块被安装到内核后,并没有把待探测的函数替换为探测模块中的函数,因此,本发明于此步骤中通过内核文件系统接口来使能函数替换,也即使用跳转指令替换待探测函数开头预设的空指令,所述跳转指令用于跳转到所述探测模块,这样当执行函数pipe_write函数的时候,走到跳转指令处,就会通过这个跳转指令执行到fake_pipe_write函数上去,且在所述探测模块执行结束后返回到所述待探测函数被调用处的下一条
指令。
[0038]
以pipe_write内核函数为例,通过执行开关指令echo 1 》 /sys/kernel/debug/pipe_write/enabled,使跳转指令替换掉pipe_write内核函数前的空指令,内核开始正常运行,当内核运行到待探测函数pipe_write的时候,会通过被替换的空指令,在正常执行待探测函数pipe_write前,跳转到提前加载的探测模块,执行探测模块中的重命名fake_pipe_write函数,此时可以通过调试信息来观察探测点的信息,同时也可以向终端打印出所添加的debug调试信息,实现在线内核的调试。
[0039]
图2是根据本发明一种在线调试linux内核的方法中步骤s3执行前的函数运行示意图。如图2所示,内核函数被探测前,待探测函数的开头为空指令,空指令是在编译的时候插入的。正常情况下,待探测函数执行后,会返回到被调用处的下一条指令,继续执行。
[0040]
图3是根据本发明一种在线调试linux内核的方法中步骤s3执行后的函数运行示意图。如图3所示,探测模块安装后,待探测函数替换后以及执行重命名函数的情景,空指令被替换为了跳转指令,该跳转指令会先跳转到蹦床,所谓蹦床就是起一个中间站的作用,蹦床为执行重命名函数以及重命名函数的返回做了设置,然后通过蹦床来执行重命名函数,最后重命名函数返回到待探测函数被调用处的下一条指令。
[0041]
步骤s4:在所述探测模块执行结束后,将所述跳转指令还原为所述空指令。
[0042]
图4是根据本发明一种在线调试linux内核的方法中步骤s4执行后的函数运行示意图。如图4所示,当执行完待探测函数的调试工作后,为了不影响内核的后续使用,通过执行开关指令echo 0 》 /sys/kernel/debug/pipe_write/enabled,使pipe_write内核函数前的空指令替换回跳转指令,恢复原来的工作场景。
[0043]
本实施例中,所述使用跳转指令替换待探测函数开头预设的空指令,和所述将所述跳转指令还原为所述空指令,均通过设置的文件系统接口在用户空间控制,从而进一步使能内核函数替换。
[0044]
步骤s5:从所述在线内核中卸载所述探测模块。
[0045]
本实施例中,使用所述linux系统中的rmmod命令从所述在线内核中卸载所述内核模块。
[0046]
基于上述步骤s1-步骤s5,先把待探测函数进行改写,封装为一个探测模块,通过加载探测模块到在线内核,再借助跳转指令替换空指令,实现了在运行待探测函数时能够替换执行探测模块中处理后的函数,探测结束后再将空指令替换回来并卸载探测模块来恢复现场,不影响后续内核运行。
[0047]
本发明的有益效果包括:1.本发明在实施内核调试时,可以在线内核现场编写探测模块,源码级别加入调试信息,不需要重启内核。
[0048]
2.本发明对于模块编译的过程进行了优化,通过工具提取了内核需要的所有头文件,这些头文件放在vmlinux.h中,模块的编写只需要包含这一个头文件即可。不需要通过一次次编译试错来找出编译探测模块到底要包含哪些头文件的问题,使得模块编译顺利进行。
[0049]
3.通过文件系统接口将空指令替换为跳转指令,实现运行函数的使能替换,从而实现待探测函数的调试功能。
[0050]
4.在调试完成后,通过文件系统接口替换会空指令,恢复原来的函数执行,卸载探测模块,恢复原始的在线内核。
[0051]
需要指出的是,尽管上述实施例中将各个步骤按照特定的先后顺序进行了描述,但是本领域技术人员可以理解,为了实现本发明的效果,不同的步骤之间并非必须按照这样的顺序执行,其可以同时(并行)执行或以其他顺序执行,这些变化都在本发明的保护范围之内。
[0052]
至此,已经结合附图所示的优选实施方式描述了本发明的技术方案,但是,本领域技术人员容易理解的是,本发明的保护范围显然不局限于这些具体实施方式。在不偏离本发明的原理的前提下,本领域技术人员可以对相关技术特征作出等同的更改或替换,这些更改或替换之后的技术方案都将落入本发明的保护范围之内。
技术特征:
1.一种在线调试linux内核的方法,其特征在于,包括步骤:根据待探测函数,处理得到探测模块;将所述探测模块加载到在线内核中;使用跳转指令替换待探测函数开头预设的空指令,所述跳转指令用于跳转到所述探测模块,且在所述探测模块执行结束后返回到所述待探测函数被调用处的下一条指令;在所述探测模块执行结束后,将所述跳转指令还原为所述空指令;从所述在线内核中卸载所述探测模块。2.根据权利要求1所述的在线调试linux内核的方法,其特征在于,所述根据待探测函数,处理得到探测模块,包括:编写源代码,所述源代码包括待探测函数的全部执行体、探测点以及调试信息;编译所述源代码,得到探测模块。3.根据权利要求2所述的在线调试linux内核的方法,其特征在于,所述编译所述源代码,得到探测模块,包括:提取所有的内核头文件,汇总到vmlinux.h文件中;将所述vmlinux.h文件添加到所述源代码中;编译添加所述vmlinux.h文件后的源代码,得到探测模块。4.根据权利要求3所述的在线调试linux内核的方法,其特征在于,所述提取所有的内核头文件,汇总到vmlinux.h文件中,包括:登录linux系统,使用ls命令得到vmlinux文件;使用bpftool工具将所述vmlinux文件中的内核头文件信息提取出来,汇总到vmlinux.h文件中。5.根据权利要求1所述的在线调试linux内核的方法,其特征在于,所述将所述探测模块加载到在线内核中,包括:使用所述linux系统中的insmod命令将所述探测模块加载到在线内核中。6.根据权利要求1所述的在线调试linux内核的方法,其特征在于,所述从所述在线内核中卸载所述探测模块,包括:使用所述linux系统中的rmmod命令从所述在线内核中卸载所述探测模块。7.根据权利要求1所述的在线调试linux内核的方法,其特征在于,所述使用跳转指令替换待探测函数开头预设的空指令,和所述将所述跳转指令还原为所述空指令,均通过设置的文件系统接口在用户空间控制。
技术总结
本发明涉及操作系统技术领域,具体提供一种在线调试Linux内核的方法,旨在解决现有技术中对于Linux内核的调试存在实施复杂、处理繁琐、无法在线调试内核的技术问题。为此目的,本发明包括步骤:将所述内核模块加载到在线内核中;使用跳转指令替换待探测函数开头预设的空指令,所述跳转指令用于跳转到所述内核模块,且在所述内核模块执行结束后返回到所述待探测函数被调用处的下一条指令;在所述内核模块执行结束后,将所述跳转指令还原为所述空指令;从所述在线内核中卸载所述内核模块。从所述在线内核中卸载所述内核模块。从所述在线内核中卸载所述内核模块。
技术研发人员:郭东太 张铎 刘云 姜浩然 胡松
受保护的技术使用者:麒麟软件有限公司
技术研发日:2023.08.25
技术公布日:2023/9/23
版权声明
本文仅代表作者观点,不代表航家之家立场。
本文系作者授权航家号发表,未经原创作者书面授权,任何单位或个人不得引用、复制、转载、摘编、链接或以其他任何方式复制发表。任何单位或个人在获得书面授权使用航空之家内容时,须注明作者及来源 “航空之家”。如非法使用航空之家的部分或全部内容的,航空之家将依法追究其法律责任。(航空之家官方QQ:2926969996)
航空之家 https://www.aerohome.com.cn/
飞机超市 https://mall.aerohome.com.cn/
航空资讯 https://news.aerohome.com.cn/