Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3115085
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: LINUX

2014-09-13 16:35:28

原文地址:http://blog.csdn.net/blizmax6/article/details/6747601

linux内核调试指南

大海里的鱼有很多,而我们需要的是鱼钩一只

本文档由大家一起自由编写,修改和扩充,sniper负责维护。引用外来的文章要注明作者和来处。本文档所有命令都是在ubuntu/debian下的操作。选取的内核源码从文档开始编写时最新的内核版本–2.6.26开始,而且会随着linux的更新而不断更换新的版本。所以文档的内容可能前后不一致。相信大家有能力克服这个问题。

本文档的字符图示在linux环境下显示正常,在window下显示有细微的错乱。

本文档唯一的更新网址是: 转载请保留此网址。

有任何建议请发邮件:

有任何问题请到邮件列表提问:

一些前言

作者前言

一个人默默地敲打这篇文章也有段时间了。在这个过程里,没有收到任何的赞誉,也没接到任何的板砖,没有任何的反馈。就这么敲打着,修理着。但是本人从没怀疑这篇文档的价值,这是因为,本人就是这篇文档的亲身收益者。在这里把它“无私”奉献出来,乃是出于对于某类同道者锲而不舍孜孜以求的“德性”的认同和“同情”,你的痛苦我表示感同身受,你的迷茫我愿意一起分担。一定有人能从个文档受益,这便已让我知足。其实,写这个文档并非是件苦差,而是字字都是有感而发的,不吐不快的结果。这里的句句都是本人教训和经验的记录。

谈到调试器,世上存在两种截然不同的看法。其中一种,是超级解霸的作者,他认为“程序不是写出来的,好程序绝对是调试出来的”。对于这个观点,虽然本人学识浅陋,也很崇拜“ ”他的为人,但是本人还是持着极不认同的态度。而第二种相反观点的人,便是linux之父linus了。他认为调试器只会“误人子弟”,只会导致人们迷于表象而不去真正理解源码本身。并以此为由,长期没把kgdb内置到内核中。对于调试器调试bug会引入错误的修正这个观点,我认为还是有点道理的。但是他以此为由而不把它集合到内核中,这个做法我就认为是毫无道理了。因为linus本人就说过:“我只使用GDB,而且我总是并不把它作为调试器来使用,只是将其作为一个可以用来分析程序的分解器来使用。”既然他可以这样做,为什么就认定他人使用gdb的目的一定就是用来调试bug而不是另有所用呢?本人之所以这样说,这是因为本人正也是使用gdb主要是用来辅助分析内核代码而不是主要用来调试错误的。这也正就是本文的主题。

世上从不缺少解决问题的答案,缺少的是解决问题的方法。现在,linux的世界里已经不缺少牛书了,将尽一千页一本的满载答案的砖头书接踵而来,但是渐渐地发现,看书看到后面就忘了前面,回到前面有忘了后面,甚至一个章节还没看完,那个子系统已经被完全重写了。慢慢地,就会怀疑“我是不是真的变老了?真的不行了?”但是我们从没想过:“凭什么我们就如此受制于人?他就能搞懂,而我就不行呢?”。其实,我们需要的是一种重其意而忘其形的根本之道,需要的是一种兵来将挡,火来水淹的通用解决方法。而绝不是淹没于牛人们的结论中。否则,遇到一个新的问题,就只能埋怨牛人的书还不够厚,以至于没把你需要的东西也包括进去了。牛人一定有一套牛方法,而他在书中不详说,我不认为是他故意“留一手”,而是认为这是对自身觉得习以为常的事物的一种疏忽。牛人的研究结果其实不是最重要的,他的研究方法和手段才是最重要的事情。而我,也渐渐地发现,调试器能带给我们很多有用的提示,使得我们能不断的寻找到思考的灵感和方向,也使得学习变得非常的有趣性和有目的性。我想,利用调试器辅助源码分析,是不是正是很多牛人正在做的而没有说出来的事情呢?无论答案如何,本人还是觉得,调试器是个好东西,不要轻易把它搁置在一旁。虽然很多高人也许已经是深安此道,甚至已经不需要它的提示了,但是它依然有益于我等功力尚浅的人。把这种经验和技巧记录下来,让需要这项技巧的人少化时间去摸索,这绝对不是一件坏事。

正是因为这个原因,随着文档慢慢地变大,也更加的觉得文档的题目起得有点不恰当了,题目起作“内核动态分析指南”更恰当点。文档的主旨是利用调试器动态分析内核,调试错误只是这个过程的副产品罢了。不过,这个新的名字实在是不够现在名字“刺眼”,所以也就没有启用它。

说了这么多的废话和出格的话,无非是有两个目的:这个文章慢慢的变得这么长了,如果没有半句的“人”话,没有半句的现实世界中的语句。那估计本人不是变成了机器人,阅读的人也会变成了机器人。顺便借这段文字交交朋友。另一个目的呢,是说不应拘束于工具,工具是死的,人是活的。如果某些工具确能带给我们某些有益的提示,我们就可以去尝试它,取起优点而舍其糟粕。

引用的原文:

Linus 谈调试器和内核如何发展: 

知识从哪里来

1. 永远不要忘记的三大帮助命令

  • XXX -h(xxx –help)
  • man -a XXX
  • info XXX

2. 如何安装帮助文档

  • $ sudo synaptic 界面出来后,在“组别”->“文档”选取你要的文档进行安装
  • 或$ apt-cache search Documentation | grep XXX 搜索需要的文档进行安装

3. 从软件/工具的官方网站阅读/下载文档

4. 从irc获取帮助 irc.freenode.net

5. 从邮件列表获取帮助 mailist  

6. 发行版社区文档或社区  

7. 利用google搜索文档或阅读他人文章

8. 利用google搜索lkml

 网域那里填上lkml.org

9. 获取内核文档

  • 源码本身
  • 源码中的注释
  • 内核源码附带的文档 Documentation
  • 相关的教科书
  • 论文 免费论文引擎 
  • 内核子系统的官方网站
  • 获取内核源码目录Documentation/DocBook/ 下已经编译好的书籍
找到最新版本的文档 $ apt-cache search linux-doc 安装最新的文档 $ sudo apt-get install linux-doc-2.6.24 阅读Documentation/DocBook/ 下已经编译好的书籍(html格式) $ firefox /usr/share/doc/linux-doc-2.6.24/html/index.html

10. 买书

11. 书籍最后面的参考书目

12. 文章末尾的参考文章

为什么撰写本文档

todo:学习方法,学习曲线,参考书籍的特点和不足,本文档的任务

内核学习曲线

1.只读书不看源码

参考书籍:Linux Kernel Development

2.参考源码读书(读书为主)

参考书籍:understanding the linux kernel

3.参考书读源码(看源码为主)

参考书籍:情景分析

4.只看源码不/少读书(提交补丁为主)

参考:lkml,main-tree, mm-tree

linux内核分析方法:

按分析的对象分:

1.代码: 分析的对象是源代码

2.数据: 分析的对象是内核运行时产生的数据

按观察对象的状态分:

1.静态: 观察的目标对象是静止不动的

2.动态: 观察的目标对象是动态变化的

所以综合地看,分析方法的种类有:

1.静态代码:

最原始的方式,阅读源代码

2.动态代码:

利用某些工具或手段,动态分析源代码。又分为

a. 利用lxr, cscope, source insight等工具交叉索引源代码

b. 利用git,web-git通过阅读增量patch等形式观察源码的进化

c. 利用调试器跟随内核的运行动态观察内核正在运行的代码片段

3.静态数据:

观察的对象是内核在运行时产生或收集汇总出来的数据。又分为

a. 代码中printk语句打印出来的内核信息

b. 系统出错产生的oops,panic信息

c. 借助systemtap等类似工具提取的内核数据汇总

4.动态数据:

借助内核调试器实时观察内核不断产生的数据

可见内核调试器是最强大的内核分析工具,但它也不是“全功能”的工具。

1. 主要地,本文档聚焦于描述如何利用gdb对内核进行源码级别和汇编级别的观察和调试。

而这种调试的目的有两个:

  • 确定bug产生的引入点。这部分内容放于本文档第一部分。
  • 配合源码阅读工具(source insight,kscope等),观察内核实时运行的状况,观察内核数据的产生和变化,以及观察各个函数的动态调用关系,从而以一种精确的动态的和验证性的方式来理解内核运作的原理。这部分内容放于本文档第二部分

前者是调试器应用的主要价值,而后者却是本文档的兴趣所在。

2. 因为需要观察用户层和内核层的交互,演示调试工具的全面功能等原因,本文档内容不完全局限于内核层。

3. 另外,为了提供内核调试知识的全面叙述,我们对其他调试工具,其他调试的问题比如检测内存泄露等内容,也会进行说明。此部分内容放于本文档的第三部分。

为什么需要汇编级调试

  • 逆向工程的需要

例子1:NT 内核的进程调度分析笔记 

例子2: NT 下动态切换进程分析笔记 

在windows的世界里,内核源码和具体原理是不公开的。但很多牛人就凭一个破烂调试器阅读反汇编代码就能得到内部真相,可见调试器汇编级调试威力之大。但是在linux是源码公开的情况下,就没必要干那样的辛苦活了。但是因为以下原因,汇编级调试还是必要的。

  • 汇编比C语言更低层

有时(比如代码优化)情况下,因为C代码经过了编译器的处理,调试器在c源码调试这个级别下给出的信息是无法理解的,甚至看起来是错误的。但是如果直接对调试器给出的反汇编代码进行分析,就不会受到那类问题的束缚。也就是说,进行汇编级别的调试能最大程度的利用调试器的功能。

  • 汇编是C语义的解释

当你对某句C语言不是很理解时,看看编译器是怎么想的,是个很不错的办法。

  • 能锻炼汇编源码的阅读能力

另一方面,内核中本来存在很多汇编源代码,进行汇编级调试也是锻炼阅读汇编源码能力的最有效方法。

当然,汇编级调试虽然强大,但代价也是很昂贵。和源码级调试相比,分析汇编代码花的时间要多上几十倍。所以,在源码公开的情况下,应该以源码级调试为主,特殊情况下才需要汇编级调试。

***第一部分:基础知识***

总纲:内核世界的陷阱

也是阅读理解其他任何大型代码会遇到的问题。下面各节的内容都是围绕这些小项展开的。如果有的内容不知所云,先看后面内容,再回头看这里。

[先从其他地方复制过来,等待充实]

源码阅读的陷阱

源码不但是越来越大,更是越来越“刁”了。“刁”到了就是借助源码交叉索引工具也有它索引不到的地方。所以目前,即使是从源码阅读的角度而不是从调试的角度,只利用阅读工具不借助调试工具的话,源码都无法阅读。

源码“刁”到源码解析工具都无法解析的因素有:

1. 汇编源码包括内嵌汇编 可能无法被你的源码阅读工具所解析

2. 汇编代码和C代码之间的调用关系 无法被被源码阅读工具解析

3. 利用函数指针的函数调用 无法被被源码阅读工具解析



阅读(1011) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~