《电子技术应用》
您所在的位置:首页 > 可编程逻辑 > 设计应用 > 基于编译选项的Linux内核交互式图解软件设计*
基于编译选项的Linux内核交互式图解软件设计*
2015年微型机与应用第8期
潘朋飞,李素科,荆 琦
(北京大学 软件与微电子学院,北京 102600)
摘要: Linux内核庞大并且可定制性非常高,而且目前市场上并没有学习内核的指导软件。针对Linux内核学习难、配置难等问题,对Linux内核模块进行了重新的逻辑划分,提出了“虚目录”的概念,并在此基础上,围绕Linux内核的编译选项设计并开发了一款学习指导软件。该软件为一套内核编译配置的辅助工具,虚目录的划分清晰地展示了内核功能模块的逻辑划分,展开虚目录后,会显示与此虚目录功能配置相关的所有编译配置选项,使用户了解到该目录项的功能是通过哪些编译选项来配置的。编译配置选项之间存在着编译依赖关系,本软件可以从源码的层次(如函数调用、变量引用等)来解释编译依赖关系的具体实现。
Abstract:
Key words :

  摘  要: Linux内核庞大并且可定制性非常高,而且目前市场上并没有学习内核的指导软件。针对Linux内核学习难、配置难等问题,对Linux内核模块进行了重新的逻辑划分,提出了“虚目录”的概念,并在此基础上,围绕Linux内核的编译选项设计并开发了一款学习指导软件。该软件为一套内核编译配置的辅助工具,虚目录的划分清晰地展示了内核功能模块的逻辑划分,展开虚目录后,会显示与此虚目录功能配置相关的所有编译配置选项,使用户了解到该目录项的功能是通过哪些编译选项来配置的。编译配置选项之间存在着编译依赖关系,本软件可以从源码的层次(如函数调用、变量引用等)来解释编译依赖关系的具体实现。
  关键词: Linux内核;虚目录;编译选项;交互式图解软件
0 引言
  Linux操作系统以其开源源码、高性能和高可靠性等诸多优势在商业服务器和个人桌面系统中得到日益广泛的应用。近年来,随着Linux内核的不断发展和完善,内核变得日趋庞大,想深入了解其模块的划分以及各个模块的功能机制,也变得相对困难。在对Linux体系结构及内核功能模块间关系分析的基础上,对Linux内核进行了重新的逻辑架构划分,形成“虚目录”,并且将所有内核源码分配到相应的虚目录下。同时,Linux内核的可定制性也是非常高的,它有着数以万计的编译配置选项,针对不同的需求可以进行相应的配置。但是,如此大数目的编译配置选项也正是问题的所在,不管是初学者,还是内核的精通者,都无法保证能了解到每个编译配置选项处于内核的哪个大模块中,以及编译选项配置所涉及的文件,等等。通过对内核Kconfig文件的语法分析,识别出所有的编译选项;通过对Makefile文件的语法分析,解析出每个编译所需要的源码文件;根据之前划分好的虚目录,以源码文件作为中介,将编译选项划分到相应的虚目录中。这样就可以很清楚地知道内核的哪些功能(虚目录)需要哪些配置选项去配置,以及每个配置选项配置需要涉及哪些文件。为了深入到最底层来了解每个功能以及配置的实现,对文件进行解析,提取出具体函数以及变量的调用关系。虚目录与编译选项的关系,通过逐层细化,可以很清晰地体现到底层的函数与变量的关系上,对各个模块功能的具体实现进行了很好的展示。
  使用本交互式图解软件可以从细节上理清Linux的代码,从宏观上的逻辑模块(虚目录)层层细化到小模块、编译选项、文件、函数来快速地认识Linux内核以及内核各个模块间的关系。
1 虚目录
  1.1 虛目录概念
  本软件是对于Linux内核架构、编译选项以及各层次关系的详细展示。Linux内核架构也是整个软件依托的基础。但是Linux内核源码的固有架构(目录划分)是相对工程化的,不便于用户的理解,比如:(1)/kernel文件夹意义不明确,包括多个功能模块中的内容;(2)对于arch文件夹,实际运行的Linux内核只对应一个架构,并且arch文件夹下的内容与许多其他功能模块紧密相关;(3)/mm、/virt/kvm等目录需要继续细化。
  于是本文提出了虚目录的思想,虚目录是与实目录(即内核源码的相对路径)相对应的说法。本文将内核源代码根据其功能及逻辑关系进行了重新划分。与实目录相比,虚目录体现了内核的逻辑结构,虚目录按照内核的功能对源码进行了重新的组织,更人性化,更体现了源码的相关性和功能性。
  1.2 虛目录划分
  对于虚目录的划分,主要是从以下4个方面来综合考虑的:
  (1)重点阅读了Linux内核源码[1-6]。众所周知,功能相关联或者类似的内核代码大多都在相同目录下(比如ext4和btrfs都在fs目录下),因此Linux内核源码的组织方式可以作为模块划分的一个重要参考;
  (2)参考关于内核的经典书籍(如:《Understanding the Linux Kernel》[1]、《Professional Linux Kernel Architecture》[2]、《Linux内核源代码情景分析》[3]、《Linux操作系统内核分析》[4]、《Linux内核分析及高级编程》[5]、《Linux内核完全注释》[6]等),这些书籍的各个章节(比如进程、内存管理、虚拟文件系统)既可作为各个子模块来进行单独分析,同时排版上相邻的章节(比如进程、中断等)关联比较紧密,可以考虑划分到大的模块中来进行分析;
  (3)参考现有的一些模块划分手段,比如主流的五大子系统的划分:内存管理、进程调度、进程间通信、虚拟文件系统、网络子系统,以及kernel map图;
  (4)查看了Linux内核的维护者列表,由相同人员来维护的内容,往往是同一个子模块,或者是同一模块的不同子模块,这可以作为模块划分辅助手段,来帮助确定各个模块的划分;
  (5)与红帽、阿里等内核小组负责人进行交流,对于存在疑问、分歧的划分点进行讨论,以保证划分的合理性。
  虚目录相对于实目录,最大的改变在于以下几点:
  (1)/kernel文件夹:实目录中,此文件夹的意义并不是很明确,所包含的文件功能涉及很多模块,需要将其划分到多个模块中;
  (2)/arch文件夹:实际运行的Linux系统中只有一种体系架构,任一体系结构中包含的文件也是涉及内核中的各个大模块的,为了保证其他各个模块功能的完整性,需要将/arch文件夹下的各个体系架构所包含的文件细分到其他各大模块中,剩余的common文件应该隶属于系统管理;
  (3)/mm、/virt/kvm等目录:内核中有一些这样的模块,从它的机制来理解,它应该是架构分层的,但是在实际的源码中却并非如此,它将包含的所有文件平级地放在了一个大文件夹下,对于这样的模块,本文按照架构和功能对其重新做了划分;
  (4)将Linux内核分成以下8大模块:进程管理、内存管理、系统运行、文件系统、网络模块、安全模块、设备管理和虚拟化(各个模块具体内容可以参看下面的模块图);同时,由于各个大模块的功能和复杂程度各不相同,为了较好地对各模块进行分析,并没有拘泥于严格的模块分层,而是针对每个特定的模块进行了适当的分层,从而更好地完成对各个模块的分析。
  图1为Linux内核虚目录。

Image 002.png

2 软件架构设计
  本软件采用B/S架构,系统架构图如图2所示。

Image 003.png

  根据上面的架构设计,可以把系统分为图3所示的几个模块。
  各模块设计如下:

Image 004.png

  展示模块:负责前台数据的展示,可以分为如下两个子模块:
  (1)布局模块:用来计算各个矢量图的坐标位置布局,以及拖拽、放大、缩小等之后的布局。
  (2)渲染模块:将布局模块计算好之后的坐标,使用Raphael的库来渲染到界面上。
  数据交互模块:
  (1)数据获取模块:从MySQL数据库中获取数据,经过格式化之后,转换成json格式。
  (2)数据持久化模块:提供数据持久化接口,可以将数据持久化到数据库中。
  数据爬取模块:
  (1)数据实体(虚目录、模块、文件、函数、变量)爬取:①爬取虚目录、模块以及文件并存储到数据库之中;②爬取文件中函数及变量的数据,并存储到数据库中。
  (2)关系爬取:爬取(1)中的元素之间的关系,并存储到数据库中。
  2.1 展示模块
  前端采用Jquery和Raphael在Web界面上画出所需要的矢量图,用来表示模块及模块之间的关系,以及函数/变量之间的关系。
  2.2 数据交互模块
  交互式图解软件中,使用PHP作为中间层,连接前端界面与后端数据库,前端使用的JavaScript绘图引擎会向PHP发出getJSON请求,PHP解析参数,完成指定类型的数据查询工作,最后形成与前端统一标准json结构,利用回调函数的形式返回给前端绘图引擎。其整个过程如图4所示。

Image 005.png

  2.3 数据爬取模块
  数据爬取模块主要负责数据实体(虚目录、模块、文件、函数、变量)爬取以及这些实体之间关系的爬取。爬取模块逻辑如图5所示。

Image 006.png

  整体思想:
  (1)根据Linux内核文档kconfig-language.txt的说明,了解Kconfig语法规则。在此基础上,对Linux内核的Kconfig文件做语法分析,爬取出Linux定义的编译选项及其之间的关系。
  (2)根据Linux内核文档makefile.txt和modules.txt的说明,了解Makefile文件中,定义编译选项对应文件的规则。在此规则基础上,对Linux内核的Makefile文件进行语法分析,爬取出编译选项与文件关系。
  (3)函数与文件关系的数据爬取方面,可用的现成开源工具较多,经过调研,可以使用到的工具主要有:Clang编译器、ctags、cscope、eclipse CDT插件、pycparser等。互补的运用这些工具,对Linux内核源码文件进行AST或者符号标记的生成并输出为中间文件,然后对这些文件进行读取,可以解析获得变量、函数、宏的定义与它们之间的调用关系。
  在爬取完上述关系之后,存在一个比较大的疑问,即虚目录如何与编译选项对应虚目录与编译选项的对应,可以通过文件巧妙的连接起来。对于划分好的虚目录的爬取,得到了虚目录与文件的层次结构;对于Makefile的爬取,得到了编译选项与文件的对应关系。从而,通过一个编译选项包含了哪些文件,这些文件位于哪些虚目录下,就可以确定编译选项位于哪些虚目录下了。
3 软件展示
  3.1 实例场景
  内核的输入和输出都属于设备驱动的范畴。在进行虚目录划分时,将其划分为设备驱动下输入子系统。内核的输入子系统是对分散、多种不同类别的输入设备(如键盘、鼠标、操纵杆、触摸屏、加速计和手写板)进行统一处理的驱动程序。
  内核输入子系统的顶层核心编译选项配置是CONFIG_INPUT,Kconfig中说明如图6所示。

Image 007.png

  可以看出,此编译选项默认为打开状态,任何输入设备(mouse、keyboard…)需要连接到系统,必须保证其为打开状态,不然输入设备是无法加载驱动的。
  相应Makefile的定义如图7所示。

Image 008.png

  可以看出,配置该选项后,将编译input.c、input-compat.c、input-mt.c、ff-core.c,通过实际分析文件可以了解到,这些文件中实现了诸如input_register_handler(),input_unregister_handler()等INPUT子系统的核心函数。
  而mosue dev很显然属于输入设备中的一部分。既然CONFIG_INPUT是输入子系统的顶层核心编译选项,那么实际的输入设备的配置必然是依赖于它的,从Kconfig的定义中发现/drivers/input/Kconfig片段如图8所示。

Image 009.png

  INPUT_MOUSEDEV编译选项确实处于INPUT配置的IF条件中(为了方便截图,用省略号省去了其他配置说明)。

Image 010.png

  从相应的Makefile的定义(如图9所示)中可以看出,配置该选项后,将编译mousedev.c文件,通过实际分析文件可以了解到,文件中实现了诸如mousedev_init()、mousedev_exit()等与mouse dev相关的核心函数。
  实际分析文件中的函数如图10所示。

Image 011.png

  mousedev_init()在进行鼠标设备初始化时,需要调用input.c的函数input_register_handler()注册一个鼠标类型的Handler,这里的Handler是鼠标类设备的统一处理接口,如图11所示。

Image 012.png

  同样,mousedev_exit()在进行鼠标设备的退出时,需要调用文件input.c的函数input_unregister_handler()来注销初始化时注册的鼠标Handler。从最低层的函数调用中体现出了INPUT_MOUSEDEV对于INPUT编译选项的依赖性。
  3.2 实际演示
  图解软件首页如图12所示。

Image 013.png

  对上述机制进行说明,当进行虚目录划分时,INPUT子系统被划分到了设备驱动中,并且由于input.c和mousedev.c中实现的函数都是输入输出中通用的机制,因此二者都被划分到了虚目录input-common中,由于虚目录和编译选项的包含关系是通过文件联系的,从而包含文件input.c和mousedev.c的编译选项INPUT和INPUT_MOUSEDEV会出现在虚目录input-common中。接下来通过图解软件进行展示(具体编译选项位置:设备驱动->iput->input-common),展开后可以看到(注:以下展示过程中,为了使得所展示的模块间关系突出,均使用过滤操作滤除了其他不相关线条):
  (1)INPUT_MOSUEDEV到INPUT编译选项的依赖关系如图13所示。


Image 014.png


  (2)展开编译选项INPUT,可以看到INPUT_ MOUSEDEV对于INPUT编译选项包含的文件drivers/input/input.c的依赖关系,如图14所示。

Image 015.png

  (3)展开INPUT_MOUSEDEV编译选项,可以看到,INPUT_MOUSEDE编译选项包含的文件drivers/input/mousedev.c对于INPUT编译选项包含的文件drivers/input/input.c的依赖关系,如图15所示。

Image 001.png

  (4)展开文件drivers/input/mousedev.c,可以看到drivers/ input/mousedev.c包含的函数mouse_init和mouse_exit对于文件drivers/input/input.c的依赖关系,如图16所示。

Image 016.png

  (5)展开文件drivers/input/input.c,可以看到drivers/input/mousedev.c包含的函数mouse_init和mouse_exit对于文件drivers/input/input.c包含的函数input_register_handler和input_unregister_handler的依赖关系,如图17所示。

Image 017.png

4 结论
  本文在虚目录的基础上,围绕着编译选项提出了一套完整的开发交互式图解软件的设计方案。一方面,此交互式图解软件为Linux学习者提供了准确而便捷的途径,同时也为高级用户提供了深入探讨Linux内核的平台;另一方面,此软件可以与“在线源码协同分析平台”和社区进行集成,将Linux体系构架的分析成果作为软件中的编译选项、文件以及函数和变量的注释说明来在线展示,有着非常广泛的应用前景。
  参考文献
  [1] DANIEL P B, MARCO C. Understanding the Linux Kernel(3rd Edition)[M]. O′Reilly,2005.
  [2] MAUERER W. Professional Linux Kernel Architecture[M]. Wiley, 2008.
  [3] 胡希明,毛德操. Linux内核源代码情景分析[M].杭州:浙江大学出版社,2001.
  [4] 陈莉君.Linux 操作系统内核分析[M].北京:人民邮电出版社,2000.
  [5] 吴国伟,李张,任广臣.Linux内核分析及高级编程[M].北京:电子工业出版社,2008.
  [6] 赵炯.Linux内核完全注释[M].北京:机械工业出版社,2004.

此内容为AET网站原创,未经授权禁止转载。