0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

浅论Linux 内核函数调用关系的验证方法

电子工程师 来源:微型机与应用第21期 刘志 作者:微型机与应用第 2021-04-02 11:30 次阅读

摘 要: 作为最流行的开源操作系统Linux在各行各业得到了广泛的应用。因此了解Linux 内核的架构及工作机制就显得非常重要。然而目前对Linux 内核的主要学习途径是各种教科书以及经验博客,而对于Linux内核的实时动态监控技术却很少有人了解。本文提供一种动态监视内核运行过程的方法。通过此方法可以动态地观察Linux内核的函数调用情况,以及CPU寄存器值等动态信息

0 引言

众所周知Linux是目前公认的最好的开源操作系统。它被广泛应用于各行各业。因此对Linux内核的学习就显得尤为重要。目前对于Linux内核的学习一般都是通过以下几个途径。

⑴通过经典教材,这些教材一般由著名的Linux 内核开发者编写。比较常用的如参考文献[1-3] 。通过这些教材读者可以从宏观的角度去了解Linux内核的整体架构以及运行机制。但是由于教科书只能提供基于作者理解的内核架构,读者无法从中获得直观的内核的动态运行状况,而这点对加深内核的理解是非常有益的。

⑵通过Linux内核的邮件列表,Linux 的开发者可以从这些列表中与其他开发者交流遇到的问题。

⑶Linux内核的源代码。Linux 的源代码涵盖了Linux的所有实现细节,但由于源代码的数量非常巨大,所以开发者往往需要在了解了相关机制以后才可以定位代码片段的位置。

以上提到的是目前了解和学习Linux内核的一些主要途径,通过这些途径可以了解内核的大体运行机制。然而这些方法都存在一个相同的问题就是无法动态实时地反应内核的运行情况。而在分析Linux内核的运行机制尤其是在遇到通过函数指针的赋值调用的情况时能够动态实时地检测内核的运行情况是非常必要的。

本文将介绍一种基于 DDD (Data Display Debugger)[4]、 BusyBox [5]、QEMU(Quick Emulator)[6]工具来对Linux内核代码运行进行动态检测的方法。

1 相关实验工具简介

本文将利用QEMU[7]搭建一个虚拟机,同时用BusyBox[5]在虚拟机上搭建一个小型Linux文件系统,然后用命令行调试程序DDD[4]来监视Linux内核的运行情况。

1.1 QEMU简介

QEMU[7]是一套由Fabrice Bellard所编写的模拟处理器的自由软件。QEMU能模拟至接近真实电脑的速度。通过QEMU可以建立一个运行目标内核的轻量级的虚拟机,并可以像调试普通应用程序一样对虚拟机中的内核代码进行单步调试,从而可以很清楚地看到代码跳转过程、CPU寄存器的变化、内核堆栈的变化等内核动态运行信息。

1.2 DDD简介

DDD(Data Display Debugger)是命令行调试程序,它特有的图形数据显示功能可以把数据结构按照图形的方式显示出来。DDD的功能非常强大,可以调试用C\C++Ada、Fortran、Pascal、Modula-2和Modula-3编写的程序。可以超文本方式浏览源代码;同时可以进行断点设置、显示各种数据结构之间的关系并由此将数据结构以图形化形式显示。

1.3 BusyBox简介

BusyBox集成压缩了 Linux 的许多工具和命令,也包含了 Android 系统的自带的shell。BusyBox将许多具有共性的小版本的Unix工具结合到一个单一的可执行文件。BusyBox提供了一个比较完善的环境,可以运行任何小的系统或嵌入式系统

2 验证流程

2.1 实验环境

本文将在Linux发行版Ubuntu 12.04上搭建实验工具。

2.2 实验工具搭建说明

这个工具套件的环境搭建由以下几个步骤组成:

⑴编译内核

选用Linux Kernel 3.5.4的内核版本。在进行内核代码的验证之前先要对目标内核进行编译,用wget命令从内核服务器下载3.5.4版本的内核,在对其编译之后就能获得内核镜像文件bzImage。

⑵安装QEMU

从QEUM的官方网站[5]上下载QEMU的最新源码文件。而后切换到 QEMU 的源码目录输入./configure生成 makefile 文件。在完成后输入编译命令make 开始编译QEMU。最后用make install命令将QEMU安装到系统中。

⑶制作根文件系统

利用DD 命令建立一个大小为10 MB的磁盘镜像文件。本实验内核将运行在这个系统上。在完成后挂载刚刚生成的镜像。在镜像中建立Linux根目录下的文件夹dev、proc、sys。

⑷安装 BusyBox 到根文件系统

在BusyBox的官方网站[8]上下载最新的BusyBox 源码。切换到BusyBox的源码目录,输入命令 make menuconfig 配置编译选项。

在弹出的配置菜单中勾选静态编译的选项(BusyBox Settings→Build options→Build BusyBox as a static binary)。

完成后输入命令make 开始编译。最后用命令make install 把编译好的BusyBox文件系统安装到刚刚生成的镜像根文件系统中。

通过以上4个步骤就可以完成Linux内核运行验证系统的搭建。

3 验证演示实例

3.1 验证的内核模块

在本文中将演示验证Linux 内核中虚拟终端(TTY)子系统open操作的运行流程。通过阅读源代码,总结出TTY子系统open操作的主要流程如图1所示。

6357782753806600002796520.jpg

3.2 DDD中显示的内核运行结果

⑴因为在Linux内核中TTY设备被归于字符型设备,所以TTY初始化的第一步是将申请的设备描述结构体的open操作函数指针(def_chrfops->chrdec_open)赋值成字符设备open函数(chrdev_open)的函数指针。 程序代码如下:

const struct file_operations def_chr_fops = {

.open = chardev_open,

.llseek = nop_llseek,

};

⑵调用字符设备子系统的open函数进入char_open函数。相关代码如下:

static int chardev_open(struct *inode,struct file *filp){

struct dev *p;

struct cdev *new =NULL;

int ret = 0;

}

⑶检测内核kobject链表是否有TTY设备,如果找不到这个设备,则返回错误。其内核代码如下所示:

if(!kobj)

return -ENXIO;

new = container_of(kobj, struct codec,kobj);

spin_lock(&cdev_lock);

p = inode->i_cdev;

⑷运行内核 filip结构体的open函数。以下为相关代码:

if(filp->f_op->open){

ret = filp->f_op->open(inode,filp);

if(ret)

goto out_cdev_put;

}

通过DDD对Linux内核运行的检测结果发现,Linux内核中TTY子系统的打开操作的流程与我们通过源代码分析出来的结论是一致的。从而验证了我们流程图的正确性。

4 结束语

本文介绍了一个基于DDD、QEMU、BusyBox工具套件,对Linux内核进行动态检测的方法。通过该方法能够对这个Linux内核的实时运行情况进行监测,从而使内核学习者和研究者对Linux 的整个运行机制有了立体的了解,对内核的运行有直观深刻的印象。本文还以虚拟终端(TTY)子系统open操作为例进行了完整的分析。展示了这个方法对一个具体的应用场景进行动态分析的过程及通过这个套件捕捉到Linux内核函数指针的动态赋值及调用过程。

参考文献

[1] Bovet D P, Cesati M. Understanding the Linux Kernel [M]. O'Reilly,2006.

[2] Wolfgang Mauerer.Professional Linux Kernel Architecture [M]. Wiley India Pvt. Limited, 2008.

[3] Robert Love. Linux Kernel Development [M]. Addison-Wesley Professional, 2010.

[4] Zeller A, Lütkehaus D. DDD-a free graphical front-end for UNIX debuggers [J]. ACM Sigplan Notices [C]. 1996, 31(1): 22-27.

[5] Bellard, Fabrice. QEMU open source processor emulator [OL]. (2007-04-03)[2014-07-15] (2007).

[6] Wells N. BUSYBOX: A swiss army knife for Linux [J]. Linux Journal, 2000, 2000(78es): 10.

[7] Fabrice B. QEMU, a fast and portable dynamic translator[C]. USENIX Annual Technical Conference, FREENIX Track, 2005.

[8] Andersen, Erik. BusyBox[OL]. (2008-01-19)[2014-07-15] BusyBox.net (2008).

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • LINUX内核
    +关注

    关注

    1

    文章

    311

    浏览量

    21389
  • ddd
    ddd
    +关注

    关注

    0

    文章

    21

    浏览量

    2733
  • 函数调用
    +关注

    关注

    0

    文章

    19

    浏览量

    2558
  • qemu
    +关注

    关注

    0

    文章

    54

    浏览量

    5210
收藏 人收藏

    评论

    相关推荐

    linux用gdb调试遇到函数调用怎么办?

    linux用gdb调试遇到函数调用怎么办? 在Linux上使用GDB调试时,遇到函数调用是一个常
    的头像 发表于 01-31 10:33 199次阅读

    Linux系统中调用脚本的常见方法

    linux系统中有多种方法可以在系统启动后调用脚本,接下来介绍几种常见的方法
    的头像 发表于 12-13 18:16 518次阅读

    Linux内核自解压过程分析

    uboot完成系统引导以后,执行环境变量bootm中的命令;即,将Linux内核调入内存中并调用do_bootm函数启动内核,跳转至kern
    的头像 发表于 12-08 14:00 411次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>内核</b>自解压过程分析

    malloc在Linux上执行的是哪个系统调用

    malloc底层为什么是内存池 malloc大家都用过,其是库函数。我们都知道库函数在不同的操作系统中其实执行的是系统调用,那么malloc在Linux上执行的是哪个系统
    的头像 发表于 11-13 10:36 499次阅读
    malloc在<b class='flag-5'>Linux</b>上执行的是哪个系统<b class='flag-5'>调用</b>

    ES32F36xx芯片发生HardFault异常时的函数调用关系及问题定位

    ES32F36xx芯片发生HardFault异常时的函数调用关系及问题定位
    的头像 发表于 11-06 17:13 418次阅读
    ES32F36xx芯片发生HardFault异常时的<b class='flag-5'>函数</b><b class='flag-5'>调用</b><b class='flag-5'>关系</b>及问题定位

    OP-TEE的内核初始化函数调用

    OP-TEE内核组件等操作。该函数的执行流程如图所示。 generic_boot_init_primary函数执行流程 generic_boot_init_primary函数
    的头像 发表于 11-02 18:18 357次阅读
    OP-TEE的<b class='flag-5'>内核</b>初始化<b class='flag-5'>函数</b><b class='flag-5'>调用</b>

    python函数函数之间的调用

    函数函数之间的调用 3.1 第一种情况 程序代码如下: def x ( f ): def y (): print ( 1 ) return y def f (): print
    的头像 发表于 10-04 17:17 355次阅读

    Linux内核如何使用结构体和函数指针?

    我将结合具体的Linux内核驱动框架代码来展示Linux内核如何使用结构体和函数指针。
    的头像 发表于 09-06 14:17 571次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>内核</b>如何使用结构体和<b class='flag-5'>函数</b>指针?

    Linux系统调用的具体实现原理

    文我将基于 ARM 体系结构角度,从 Linux 应用层例子到内核系统调用函数的整个过程来梳理一遍,讲清楚linux系统
    的头像 发表于 09-05 17:16 762次阅读
    <b class='flag-5'>Linux</b>系统<b class='flag-5'>调用</b>的具体实现原理

    Linux内核中系统调用详解

    Linux内核中设置了一组用于实现各种系统功能的子程序,称为系统调用。用户可以通过系统调用命令在自己的应用程序中调用它们。从某种角度来看,系
    发表于 08-23 10:37 619次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>内核</b>中系统<b class='flag-5'>调用</b>详解

    万千设备,linux内核如何知道?

    linux内核设备的注册由device_register()函数完成,这个函数linux设备驱动模型的核心
    的头像 发表于 07-12 08:52 506次阅读
    万千设备,<b class='flag-5'>linux</b><b class='flag-5'>内核</b>如何知道?

    linux操作系统中的进程创建和销毁函数解析

    第一次遇见创建进程是在Linux启动流程中,reset_init函数调用kernel_thread函数创建了2个内核进程:kernel_in
    发表于 06-26 09:12 414次阅读
    <b class='flag-5'>linux</b>操作系统中的进程创建和销毁<b class='flag-5'>函数</b>解析

    Linux系统调用的实现与应用

    在计算机科学中,系统调用(System Call)是一种操作系统提供的服务,它允许应用程序通过软件中断的方式访问操作系统内核中的函数。这些函数提供了一系列与硬件相关的服务,例如文件系统
    发表于 06-14 11:46 366次阅读

    Linux内核模块间通讯方法

    Linux内核模块间通讯方法非常的多,最便捷的方法莫过于函数或变量符号导出,然后直接调用。默认情
    发表于 06-07 16:23 1702次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>内核</b>模块间通讯<b class='flag-5'>方法</b>

    SCL中调用函数的示例

    在此,可插入函数 (FC) 调用函数块 (FB) 调用函数块可作为单实例、多重实例或参数实例进行调用
    的头像 发表于 06-06 10:18 1352次阅读