浅谈Linux内核源码分析方法( 四 )

GNUC语法和铺天盖地的宏定义会令人很绝望 。 此时只要沉下心来 , 弄清每个关键的难点 , 才能保证以后碰到类似的难点不会再被困住 。 而且 , 我们对内核相关的其他知识会不断的像树一样扩展开来 。
比如在cpufreq.c文件开始就会出现“DEFINE_PER_CPU”宏的使用 , 我们通过查阅资料可以基本弄清这个宏的含义和功能 。 这里使用的手段和之前搜集资料使用的方法基本一致 , 另外我们也可以使用sourceinsight提供的转到定义等功能查看它的定义 , 或者使用LKMLLinux Kernel Mail List)查阅 。 总之利用所有可能的手段 , 我们总能得到这个宏的含义——为每个CPU定义一个独立使用的变量 。
我们也不要强求一次就能把注释描述的很准确(我们甚至都没必要弄清每个函数的具体实现流程 , 只要弄清大致功能含义即可) , 我们结合搜集到的资料和后边代码的分析不断的完善注释的含义(源码中原有的注释和标识符命名在此很有利用价值) 。 通过不断的注释 , 不断的查阅资料 , 不断的修改注释的含义 。
浅谈Linux内核源码分析方法文章插图
当我们把所有涉及的源码文件简单注释完毕后我们可以达到如下效果:
1.基本弄清了源码中代码元素存在的含义 。
2.找出了该模块所涉及的基本上全部的关键源码文件 。
结合之前搜集到的信息和资料对该待分析代码的整体或者架构描述 , 我们可以将分析的结果和资料对比 , 以确定和修正我们对代码的理解 。 这样 , 通过一遍的简单注释 , 我们就可以从整体上把握了源码模块的主要结构 。 这也达到了我们简单注释的基本目的 。
第四步:详细注释
完成代码的简单注释后 , 可以认为对模块的分析工作完成了一半了 , 剩下的内容就是对代码的深入分析和彻底理解 。 简单注释总是不能将代码元素的具体含义描述的十分精确 , 因此详细注释是十分有必要的 。 这一步中 , 我们需要弄清以下内容:
1.变量定义在何时被使用 。
2.宏定义的代码何时被使用 。
3.函数的参数和返回值的含义 。
4.函数的执行流程和调用关系 。
5.结构体字段的具体含义和使用条件 。
我们甚至可以把这一步称为函数详细注释 , 因为函数之外的代码元素的含义基本上在简单注释中已经比较明确了 。 而函数本身的执行流程、算法等是这部分注释和分析的主要任务 。
比如cpufreq_ondemand策略的实现算法(函数dbs_check_cpu中)是如何实现的 。 我们需要逐步分析该函数使用的变量和调用的函数等信息 , 弄清算法的来龙去脉 。 最好的结果 , 我们需要这些复杂函数的执行流程图和函数调用关系图 , 这是最直观的表达方式 。
浅谈Linux内核源码分析方法文章插图
通过这一步的注释 , 我们基本上能完全把握待分析代码整体的实现机制了 。 而所有的分析工作可以认为完成了80% 。 这一步工作尤其关键 , 我们必须尽量让注释的信息足够的准确 , 才能更好的理解待分析代码的内部模块的划分 。 虽然Linux内核中使用了宏语法“module_init”和“module_exit”声明模块文件 , 但是对模块内部子功能的划分是建立在充分了解模块的功能基础上的 。 只有正确划分好模块 , 我们才能弄清模块提供了哪些外部函数和变量(使用EXPORT_SYMBOL_GPL或者EXPORT_SYMBOL导出的符号) 。 才能继续下一步的模块内标识符依赖关系分析 。
第五步:模块内部标识符依赖关系


推荐阅读