Linux内核源码分析方法(3)

按照搜索出的信息流动方向,我们完全可以定位到需要分析的源码文件。源码定位这一步并非十分关键,因为我们不需要找出所有源码文件,我们可以把部分工作推迟到分析代码的过程中。源码定位也比较关键,找到一部分源码文件是分析源码的基础。

第三步:简单注释

在已定位好的源码文件中,分析每个变量、宏、函数、结构体等代码元素的大致含义和功能。之所以称此为简单注释,并非指这部分的注释工作很简单,而是指这部分的注释可以不必过分细化,只要大致描述出相关代码元素的含义即可。相反,这里的工作其实是整个分析流程中最困难的一步。因为这是第一次深入到内核代码的内部,尤其是对于首次分析内核源码的人来说,大量的生疏GNU的C语法和铺天盖地的宏定义会令人很绝望。此时只要沉下心来,弄清每个关键的难点,才能保证以后碰到类似的难点不会再被困住。而且,我们对内核相关的其他知识会不断的像树一样扩展开来。

比如在cpufreq.c文件开始就会出现“DEFINE_PER_CPU”宏的使用,我们通过查阅资料可以基本弄清这个宏的含义和功能。这里使用的手段和之前搜集资料使用的方法基本一致,另外我们也可以使用sourceinsight提供的转到定义等功能查看它的定义,或者使用LKML(Linux Kernel Mail List)查阅,实在不行我们还可以到提问寻求解答(想了解什么是LKML和stackoverflow?搜集资料吧!)。总之利用所有可能的手段,我们总能得到这个宏的含义——为每个CPU定义一个独立使用的变量。

我们也不要强求一次就能把注释描述的很准确(我们甚至都没必要弄清每个函数的具体实现流程,只要弄清大致功能含义即可),我们结合搜集到的资料和后边代码的分析不断的完善注释的含义(源码中原有的注释和标识符命名在此很有利用价值)。通过不断的注释,不断的查阅资料,不断的修改注释的含义。

当我们把所有涉及的源码文件简单注释完毕后我们可以达到如下效果:

1.基本弄清了源码中代码元素存在的含义。

2.找出了该模块所涉及的基本上全部的关键源码文件。

结合之前搜集到的信息和资料对该待分析代码的整体或者架构描述,我们可以将分析的结果和资料对比,以确定和修正我们对代码的理解。这样,通过一遍的简单注释,我们就可以从整体上把握了源码模块的主要结构。这也达到了我们简单注释的基本目的。

第四步:详细注释

完成代码的简单注释后,可以认为对模块的分析工作完成了一半了,剩下的内容就是对代码的深入分析和彻底理解。简单注释总是不能将代码元素的具体含义描述的十分精确,因此详细注释是十分有必要的。这一步中,我们需要弄清以下内容:

1.变量定义在何时被使用。

2.宏定义的代码何时被使用。

3.函数的参数和返回值的含义。

4.函数的执行流程和调用关系。

5.结构体字段的具体含义和使用条件。

我们甚至可以把这一步称为函数详细注释,因为函数之外的代码元素的含义基本上在简单注释中已经比较明确了。而函数本身的执行流程、算法等是这部分注释和分析的主要任务。

比如cpufreq_ondemand策略的实现算法(函数dbs_check_cpu中)是如何实现的。我们需要逐步分析该函数使用的变量和调用的函数等信息,弄清算法的来龙去脉。最好的结果,我们需要这些复杂函数的执行流程图和函数调用关系图,这是最直观的表达方式。

通过这一步的注释,我们基本上能完全把握待分析代码整体的实现机制了。而所有的分析工作可以认为完成了80%。这一步工作尤其关键,我们必须尽量让注释的信息足够的准确,才能更好的理解待分析代码的内部模块的划分。虽然Linux内核中使用了宏语法“module_init”和“module_exit”声明模块文件,但是对模块内部子功能的划分是建立在充分了解模块的功能基础上的。只有正确划分好模块,我们才能弄清模块提供了哪些外部函数和变量(使用EXPORT_SYMBOL_GPL或者EXPORT_SYMBOL导出的符号)。才能继续下一步的模块内标识符依赖关系分析。

第五步:模块内部标识符依赖关系

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/16268.html