推广 热搜:   中国  公司  企业  服务  未来  政策  行业  设备  基金 

linux内核调试指南

   日期:2023-10-12       caijiyuan   评论:0    移动:http://skally.gawce.com/news/4666.html
核心提示:大海里的鱼有很多,而我们需要的是鱼钩一只本文档由大家一起自由编写,修改和扩充,sniper负责维护。引用外来

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

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

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

本文档唯一的更新网址是:http://wiki.zh-kernel.org/sniper?转载请保留此网址。

有任何建议请发邮件:s3c24xx@gmail.com

有任何问题请到邮件列表提问:http://zh-kernel.org/mailman/listinfo/linux-kernel

一些和内核调试分析有关的小工具放在

http://code.google.com/p/root-kit/

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

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

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

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

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

引用的原文

Linus 谈调试器和内核如何发展:?http://www.bitscn.com/linux/kernel/200604/7493.html

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?http://lkml.org/?http://marc.info/

6. 发行版社区文档或社区?https://help.ubuntu.com/community/?http://wiki.ubuntu.org.cn/

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

8. 利用google搜索lkml

http://www.google.cn/advanced_search?hl=zh-CN?网域那里填上lkml.org

9. 获取内核文档

  • 源码本身
  • 源码中的注释
  • 内核源码附带的文档 documentation
  • 相关的教科书
  • 论文 免费论文引擎??http://citeseerx.ist.psu.edu/
  • 内核子系统的官方网站
  • 获取内核源码目录documentation/DocBook/ 下已经编译好的书籍

10. 买书

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

12. 文章末尾的参考文章

13. 电子书搜索网站

emule: 只要知道书名,windows下用emule基本可以找到所有的英文版电子书。

但在linux不行,可能是我的设置问题。

http://rapidshare.com/index.html

http://www.netbks.com/

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 内核的进程调度分析笔记?http://www.whitecell.org/list.php?id=11

例子2: NT 下动态切换进程分析笔记?http://www.whitecell.org/list.php?id=13

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

  • 汇编比C语言更低层

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

  • 汇编是C语义的解释

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

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

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

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

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

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

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

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

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

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

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

4. 宏“假函数” 可能无法被被源码阅读工具解析(SI不能解析,lxr能)

5. 利用宏在编译时动态生成的函数体 无法被被源码阅读工具解析

6. 函数/变量的某类c扩展属性标记, 可能导致该函数/变量无法被被源码阅读工具解析

7. 其他语种的保留关键字,可能无法被你的源码阅读工具所解析

但是借助调试器,就能直接而轻易地解决上述源码解析工具难以解决的问题。

搭建调试环境

gdb调试器的陷阱

1. 宏“假函数”

2. 内嵌函数

3. 代码优化

4. 汇编码

5. 进程切换

6. 中断处理

7. 系统调用

0. 链接器脚本和make语法

1. C与汇编代码的相互调用

2. 各子系统间的接口互动

3. 内核的设计思想及其代码编写和运行形式

a) 基于对象的思想

例子:文件系统,设备模型

b) “发布—订阅”模型

例子:notification chain

为什么选debian

[如题]?http://www.debian.org/?http://www.emdebian.org/

为什么本人选择debian?因为:引用内容来之www.debian.org

“Debian 计划 是一个致力于创建一个自由操作系统的合作组织。...屁话省略...屁话..N多屁话之后: 当然,人们真正需要的是应用软件,也就是帮助他们完成工作的程序: 从文档编辑,到电子商务,到游戏娱乐,到软件开发。Debian 带来了超过 18733 个 软件包 (为了能在您的机器上轻松的安装,这些软件包都已经被编译包装为一种方便的格式) — 这些全部都是 自由 软件。”

原因终于看到了,选择debian是因为本人比较懒,比较笨。而debian正好迎合了我这种人的需求。

1. 它”带来了超过 18733 个 软件包”。18733这个数目非常不直观,而且或许是N年前的数据了。我们可以到debian的ftp看看,现在它可供安装的软件和工具达到了5个DVD的容量。难以想象,在这5个DVD容量的工具库中,还会找不到我所想要的东西。

2. debian有一个非常出名的安装包管理机制。你需要做的就是,打开“立新得”软件,然后在一个小方框里写上你需要东西的相关信息,然后再点点一个叫做“ 搜索”的小方块。接着,debian就会在它5个DVD大的工具库中寻找你想要的工具。在结果返回后,选择好你的工具,再点点一个叫做“应用”的小方块, 过一会,就可以使用你的工具了。

再也没有了“缺少什么什么包”的烦人提示了,一切都这么简单,又这么强大。这,正是我想要的。

debian与ubuntu

[两者区别,版本外号,支持社区,source list等] 1. ubuntu的易用性比debian要好。尤其是中文支持,还有ubuntu国内有活跃的社区。 2. 虽然ubuntu是基于debian的,apt 软件库也能获取到debian的软件,但它毕竟是不同的系统环境,理念不同,对于一些偏门或太旧或太新的软件时,ubuntu往往不支持,安装不了。比 如,gcc-3.4-arm-linux-gnu这个包,发行时间已久,ubuntu下安装不了,但在debian下则可以。http://www.ubuntu.com/community/ubuntustory/debian

如不特别说明,本文档所有命令都是在ubuntu Hardy Heron8.04版本 和debian testing版本下的操作。

从0安装debian

[如果想领教古典linux相对于windows的特色,请安装一次debian吧。尽管和以前比,已经很智能了。但安装了debian,选了中文环境, 发现汉字都是歪歪倒倒的。而且没有汉字输入法,装了汉字输入法后,却用不了。不知道是我笨还是程序有bug.所以不得不用英文写下本烂文,怕把安装过程给 忘了。需要翻译回中文

How to install and configure a debian system from zero

1.install the system with one CD

Download CD iso file from debian official website, and burn it into a CD. Note that, we can just download the first CD iso but not DVDs or the whole serials of CDs, because the first CD has already contained all the basis components of dedian system and many other most common applications. We can use the first CD to install debian system, and then to install some other needed programs from it if needed. In this way, you can save much time spent on touching many inrelatived things.

2.install application & tool from CD

ou can install some common apllications from the CD with the following commnad: apt-get install expected-application. Why can we do that without any more configuration? Why is it not need to has a ability to access internet? Well, Let’s look at the file named sourse.list which idenifying where to get software’s pakage?? deb cdrom:[Debian GNU/Linux testing _Lenny_ - Official Snapshot i386 CD Binary-1 20080605-15:01]/ lenny main It means that system try to get somethig from your CD, so obviously that you can get some the most common but not all the tools available in debian official apllication repository.

3.try to access the internet

Thank to the first CD, we can do that easily. Fist, install the tool ppp contained in CD and its’ configuration tool pppoeconfig. All these steps are described in file ADSL(PPPOE)接入指南.txt

4.search any useful information through the internet

now, we have built a base debian system, but it is too simple. I want to do some some thing, for example, to chat with some other people with pidgin, but it is not contained in the first CD, which just downloaded by you. And you may want to search some helps with google,etc. Just to do it, google is a most useful tool.

5.search the internet updating source

I think you have get much thing through the google. But the most important thing is to get a available update source for your system, and change the source.list–that is /etc/apt/source.list. Now, I have got a good one, and it seems good. Don’t forget to turn on the security entry in the orgion file source.list. That file looks like following after my updataion:

You should note that the internet address is debian office’s, but It takes some while to get it. And my searching tool is google. :) Oh, we shoul run a command to update the new configuration to system before using it, don’t ferget: apt-get update

6.get help from?IRC

Well, we have already been able to get some applications or tools from internet with command apte-get or wget,etc.. But I think the first thing to do is to get and install a very valuable tool named pidgin which can bring you into?IRC?world. Because Many experiance and kind person live in channel #debian of irc.freenode.net. You can get help from it very quickly. How to configure pidgin? Sorry, I don’t like to answer such a problem , please just to google it or try it by yourselft. I am not so kind as some guys living in?IRC?: )

7.get and install synaptic

If you ever used ubuntu, you should agree that synaptic is good tool to update you system. It can save you much time of searching tools, typing commnad, or managing the downloaded tools. But Unfortunately, such a important tool is not installed in the default system, and it is not contained in the first CD. So, We can just to get it with command “apt-get install synaptic”. After doing that successfully, I don’t want to type that command anymore. It’s so tedious to me.

8.get more tools with the help of synaptic

synaptic is my GOD in the linux world. Without it, I will become crazy. But now, I have owned it, so I can fly very freely in the internet sky. Just to search any tools and to update your system. And now, the CD used to install debian can be discarded, if you will never reinstall or rescure the system with it in future.

Now, the sun has raise up, and you have found the road to reback to civilization. Why? Just to ask your google and synaptic. :)

debian重要命令

[来源]《APT and Dpkg 快速参考表》?http://i18n.linux.net.cn/others/APT_and_Dpkg.php

Apt 不止是 apt-get

http://www.erwinwang.com/node/10

中文环境设置

debian的键盘设置更改

默认安装的debian,键盘的设置可能有问题。比如“|”打不出来。值得一提的是,这个设置甚至是和qemu的monitor模式相关联的。也就是说,qemu下有的字符也打不出来。如果有这个问题,按下面步骤设置

System→Preferences→Keyboard→Layouts

然后通过“Add”增加China,并设置它为默认,或者同时把其他的删除掉。

英文Locale下使用中文输入法

说明,中文环境比英文环境有很多缺点。比如编译时编译器的提示都给汉化了,有如,minicom的中文汉化界面是错乱的,而且minicom无法设置。本 人一般是英文环境+中文输入法。先安装好好中文环境,系统中就有了中文输入法和其他一些和中文有关的东西。然后转到英文环境下,按照下面做法更改scim 的配置文件即可。

来自:http://wiki.ubuntu.org.cn/index.php?title=%E8%8B%B1%E6%96%87Locale%E4%B8%8B%E4%BD%BF%E7%94%A8%E4%B8%AD%E6%96%87%E8%BE%93%E5%85%A5%E6%B3%95&variant=zh-cn

编辑 /etc/gtk-2.0/gtk.immodules(如果存在的话) 或者 /usr/lib/gtk-2.0/2.10.0/immodule-files.d/libgtk2.0-0.immodules 文件,在xim 的 local 增加 en 也就是说

pdf乱码的解决

参考

http://wiki.ubuntu.org.cn/PDF%E6%96%87%E6%A1%A3%E7%9A%84%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98

建立编译环境

其余的根据出错的提示,利用“立新得”搜索,然后进行安装。没有“立新得”界面程序的可以在终端下利用以下命令来搜索和安装。

双硬盘系统切换设置的grub设置, 私人备忘用

交叉编译工具下载网址

下面是几个交叉编译工具下载网址,需要手动安装时,对比一下编译器的名称可以找到合适的下载地址。debian维护有自己的已经打包成.deb形式安装包,在debian软件库中。

安装arm-linux-gnueabi-XXX 工具集

debian有自己维护的一套交叉编译工具集

[参考]http://www.emdebian.org/tools/crosstools.html

工具库:?http://www.emdebian.org/debian/pool/main/

步骤

1. 往/etc/apt/sources.list文件加入下面软件源

然后

2. 安装交叉编译器

注意,在ubuntu8.04下,只能安装4.2版。把上面文字中的4.3全部换为4.2即可。

3. 安装交叉调试器

注意:

a. 安装时使用名称:gdb-arm-linux-gnueabi,调用时使用命令名是:arm-linux-gnueabi-gdb

b. ubuntu下,arm-linux-gnueabi-gdb和gdb有冲突。

解决方法

需要使用arm-linux-gnueabi-gdb时先卸载gdb,记下卸载gdb时与gdb一起被卸载的软件名,然后安装arm-linux- gnueabi-gdb。 想换回gdb时,在反操作。apt-install remove arm-linux-gnueabi-gdb 然后 apt-get install gdb以及之前和gdb一起被卸载包。可以写个脚本自动完成这些操作。本人环境下的脚本是

脚本1. install-armgdb.sh

脚本2. install-gdb.sh

什么是EABI

: 来自AAPCS

ABI: Application Binary Interface:

1). The specifications to which an executable must conform in order to execute in a specific execution environment. For example, the Linux ABI for the ARM Architecture.

2). A particular aspect of the specifications to which independently produced relocatable files must conform in order to be statically linkable and executable. For example, the C++ ABI for the ARM Architecture, the Run-time ABI for the ARM Architecture, the C Library ABI for the ARM Architecture.

ARM-based … based on the ARM architecture …

EABI: An ABI suited to the needs of embedded (sometimes called free standing) applications.

参考

ABI/EABI/OABI?http://blog.csdn.net/hongjiujing/archive/2008/07/21/2686556.aspx

Re: 关于kernel ARM_EABI?http://zh-kernel.org/pipermail/linux-kernel/2008-January/002793.html

Why ARM’s EABI matters?http://www.linuxdevices.com/articles/AT5920399313.html

Why switch to EABI??http://www.applieddata.net/forums/topic.asp?TOPIC_ID=2305

ArmEabiPort?http://wiki.debian.org/ArmEabiPort

安装arm-elf-XXX 工具集

:arm-elf-XXX 工具集是用于uclinux的

1. 依据要求搜索下载相应的arm-elf-tools安装包。比如arm-elf-tools-20030315.sh

2. 安装: $ https://www.ngui.cc/zz/arm-elf-tools-20030315.sh

3. 如果,该安装包年代过老,比如arm-elf-tools-20030315.sh,会出现下面的错误提示 “tail: 无法打开“ 43” 读取数据: 没有那个文件或目录。”。 这时需要修改安装包源码。方法:vi arm-elf-tools-20030315.sh, 搜索tail,在它后面加 -n .比如 把tail ${SKIP} ${script} | gunzip | tar xvf -改成如下:tail -n ${SKIP} ${script} | gunzip | tar xvf -

4.如何卸载已安装的arm-elf-tools? 答,重新安装一次,注意看终端提示。或直接vi arm-elf-tools-20030315.sh,看脚本的内容

[该怎么称呼这类工具?待详述

如何获取这些工具的命令选项? 看章节“知识从哪里来” 一般是用命 xxxxxx –help就能得到简单的命令选项列表

下载arm-linux-gnueabi- 手册地址?http://www.codesourcery.com/gnu_toolchains/arm/portal/release324

然后搜索”arm”,便能找到处理器相关的特殊命令选项

arm-linux-gnueabi-gcc

查看arm处理器相关的编译选项

$ vi arch/arm/Makefile

阅读Makefile文件,并联系源码根目录下的.config文件,便能知道arm-linux-gnueabi-gcc用了哪些编译选项。再到手册中 查找,便能知道这些选项是干什么用的,但手册中说的不是很详细。另外查找有用解释的方法的是,利用make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig,找到与命令选项有关联的CONFIG_XXX的菜单项,看它的帮助说明.比如

再查看CONFIG_AEABI的帮助文档 $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig 找到CONFIG_AEABI相关的菜单,看它的帮助文档,便能知道选项-mabi=aapcs-linux -mno-thumb-interwork的整体效果怎样的。

arm-linux-gnueabi-gcc的主要编译选项有如下几个。但是在编译内核时,这些选项是不需要手工去写的,而是通过make menuconfig生成包含了编译选项配置信息的.config文件。在make编译内核时,再利用Makefile文件中的规则结合.config文 件提取出那些选项。

arm-linux-gnueabi-gdb

注意它的默认选项设置

但是,如果如果在命令后有参数vmlinux的话,它会自动识别出内核的abi,从而自动设置了gdb的abi。比如,在编译内核时,如果选了CONFIG_AEABI,则gdb的提示如下

参考手册

http://bellard.org/qemu/user-doc.html

http://wiki.debian.org.tw/index.php/QEMU

http://www.h7.dion.ne.jp/~qemu-win/

http://bellard.org/qemu/

邮件列表

http://lists.gnu.org/archive/html/qemu-devel/

参考文章

“QEMU安装使用全攻略”?http://forum.ubuntu.org.cn/viewtopic.php?p=248267&sid=f4e95025bdaf6a24a218315d03ad9933

[补充命令]引用自http://bbs.chinaunix.net/viewthread.php?tid=779540

[扩展,原理,相关命令。下面的skyeye可能需要这部分知识

“Linux2.6 内核的 Initrd 机制解析”?http://www.ibm.com/developerworks/cn/linux/l-k26initrd/

“Introducing initramfs, a new model for initial RAM disks”?http://www.linuxdevices.com/articles/AT4017834659.html

””深入理解 Linux 2.6 的 initramfs 機制 (上)“?http://blog.linux.org.tw/~jserv/archives/001954.html

MKINITRAMFS?http://www.manpage.org/cgi-bin/man/man2html?8+mkinitramfs

安装与使用

参考

“debugging-linux-kernel-without-kgdb”?http://memyselfandtaco.blogspot.com/2008/06/debugging-linux-kernel-without-kgdb.html

“使用 KGDB 调试 Linux 内核”?http://blog.chinaunix.net/u/8057/showart_1087126.html

“透過虛擬化技術體驗 kgdb (1)”?http://blog.linux.org.tw/~jserv/archives/002045.html

基于qemu和内核内置kgdb

缺点:相对于下节的“基于qemu和qemu内置gdbstub”,这个方法配置麻烦。

优点:真机远程调试时只能使用内置kgdb这个方法。

[等待扩展,,,,

终极参考

“Using kgdb and the kgdb Internals”?http://www.kernel.org/pub/linux/kernel/people/jwessel/kgdb/index.html

参考文章

“使用 KGDB 调试 Linux 内核”?http://blog.chinaunix.net/u/8057/showart_1087126.html

基于qemu和qemu内置gdbstub

  • 参考文章

“Debugging Linux Kernel Without KGDB Patch (Qemu + GDB)”?http://memyselfandtaco.blogspot.com/2008/06/debugging-linux-kernel-without-kgdb.html

  • 优缺点

优点:相对上节,优点是操作简单,几乎不需要什么配置

缺点:真机的远程调试,就只能利用内核的内置kgdb了

说明

如果长时间调试固定版本的内核,采取下面的把调试用内核安装的虚拟机内部就可以了。但是如果是要频繁地更换新内核或修改被调试内核,就需要采取把内核挂在 虚拟机外部的形式。也就是用 -kernel 在虚拟机外面挂个内核, 再利用-append 传递起内核启动参数等。[待研究

[太概过了,待扩展...

  • 调试用内核的安装过程

1. 利用qemu安装一个系统.

2. 在真机中配置并编译一个用于安装到虚拟系统中的新内核,注意配置时的选择

3. 在真机下编译好虚拟机新内核的源码

4. 结束qemu,用以下命令在真机上挂载虚拟硬盘。然后把编译好的整个源码目录都拷贝到挂载好的虚拟硬盘上(真机上保留一份源码)。

拷贝完后,在真机上卸载虚拟硬盘

5.启动虚拟机,进入旧系统,在新内核源码根目录下用以下命令给qemu的虚拟系统安装一个新的内核

6.用以下命令重启虚拟系统,并选择进入新系统,确认新系统是否安装成功。

  • 调试

1. 在真机新内核源码目录下建立一个文件 .gdbinit 内容是

注意我把c注释掉是因为ddd和gdb有切换的需要。见”gdb技巧”

2. 用以下命令启动虚拟机

3. 在真机新内核源码目录下运行

[实验记录]

实验过了,.config中不选择kgdb,利用qemu照样能调试。也不能调试start_kernel以前的代码。比如head_32.S中的代码。

但是不知CONFIG_HAVE_ARCH_KGDB是在menuconfig菜单的哪里。想试试把这项去了qemu还能不能调试。

经测试,取消CONFIG_HAVE_ARCH_KGDB后,qemu也能进行调试。情况不变。看来qemu能完全脱离内核中的kgdb就能调试内核。

  • 调试截图

利用qemu

利用qemu安装debian linux

目标

本节在qemu虚拟机上安装一个基于arm的“桌面“系统,可以有X桌面,该虚拟系统能利用apt-get从debian的软件库下载数不完的用交 叉编译已经编译好的arm下的程序和工具。除了虚拟处理器是arm外,简直就是PC机。可以进行应用程序的本机(在虚拟机内进行)调试。但是,本人装的时 候,如果选了安装桌面环境,内核就启动失败,好像是提示文件系统出错。[成功的麻烦把过程贴出来

过程是:

Debian on an emulated ARM machine?http://www.aurel32.net/info/debian_arm_qemu.php

下面是过程的提炼步骤,方便查看。

1.创建虚拟硬盘

$ qemu-img create -f qcow hda.img 40G

2.下载必要文件

2.安装系统

3. 第一次启动系统

4. 把旧的内核,intrd.img制作工具安装到虚拟机的系统内(操作在虚拟机内

5.其他更多的玩法请看原文http://www.aurel32.net/info/debian_arm_qemu.php

参考

Debian ARM Linux on Qemu

http://909ers.apl.washington.edu/~dushaw/ARM/#SYSTEM

Running Linux for ARM processors under QEMU

http://iomem.com/index.php?archives/2-Running-Linux-for-ARM-processors-under-QEMU.html&serendipity[entrypage]=2

Debian on an emulated ARM machine

http://www.aurel32.net/info/debian_arm_qemu.php

利用qemu安装能进行内核调试的系统

[暂时没法子,期待扩展。下面这个例子可以,但没尝试。估计这个方法与下节的利用skyeye的方法相比,没有优势。因为这个方法可能也是不能进行全程调试。但是下面网站的资料还是有一定参考价值的。

使用qemu-jk2410做為學習環境

http://wiki.jk2410.org/wiki/%E4%BD%BF%E7%94%A8qemu-jk2410%E5%81%9A%E7%82%BA%E5%AD%B8%E7%BF%92%E7%92%B0%E5%A2%83

另外:看看下面这个站点

Firmware Linux:?http://landley.net/code/firmware/

利用skyeye

skyeye虚拟机的内核调试

相对于利用qemu的方式,用skyeye虚拟机调试内核有个很重要的

优点是

调试可以从第一条机器指令开始。这对研究系统启动过程提供了极大的便利。

skyeye的安装与使用

该文非常好,好像没啥要扩充的

SkyEye硬件模拟平台,第二部分: 安装与使用

http://www.ibm.com/developerworks/cn/linux/l-skyeye/part2/

SkyEye User Manual?http://www.skyeye.org/wiki/UserManual

http://skyeye.wiki.sourceforge.net/

参考文档

Linux-2.6.20 on XXX platform

http://skyeye.wiki.sourceforge.net/Linux

uClinux-dist-20070130 on XXX platform

http://skyeye.wiki.sourceforge.net/uClinux

http://www.linuxfans.org/bbs/thread-182101-1-1.html

安装:

1. 安装主程序

在ubuntu系统能进行在线安装,但版本是v1.2,不是最新的

2. 测试套件

测试套件下载后解压开即可

地址:http://sourceforge.net/project/showfiles.php?group_id=85554

快速试玩

目的:

尽可能快的成功运行一个arm linux虚拟机。如果您化了很长时间也无法编译出一个能运行的内核,或写不出一个恰当的skyeye.conf时,在你的热情受到打击之前,我想这节是你急需的。

操作步骤

1.依照上节说明安装好主程序,下载并解压好测试套件

2.进入测试套件的目录 skyeye-testsuite-1.2.5/linux/s3c2410/s3c2410x-2.6.14

可以看到有三个文件initrd.img skyeye.conf vmlinux

3.运行虚拟机

$skyeye -e vmlinux

注意下面的提示,说明平时要注意在启动命令前加上sudo

4.可以看到,一个2.6.14 版本的linux跑起来了,还带有一个lcd.

快速配置能调试的环境

参考

http://skyeye.wiki.sourceforge.net/linux_2_6_17_lubbock

环境条件

1. ubuntu hardy 8.04

2. 安装了debian提供的交叉编译工具套件 arm-linux-gnueabi- (4.2版本)

目标

这小节能得到基于pxa平台(类似s3c2410,也基于arm核心)的linux2.6.20内核的虚拟系统,具备调试功能。相比“基于qemu 和qemu内置gdbstub”该节,利用skyeye的调试有那节所没有的优点:调试时可以从内核运行的第一条指令开始[这就是模拟硬件调试]。

参考手册

XScale PXA250开发手册?http://soft.laogu.com/download/intelpxa250.pdf

ARMv5 体系结构参考手册?http://www.arm.com/community/university/eulaarmarm.html

操作步骤

1. 下载linux-2.6.20 (由于交叉编译器太新,如果利用linux-2.6.17则编译不过)

2. 修改文件include/asm-arm/arch-pxa/memory.h 第18行

3. 下载内核配置选项,放置于linux-2.6.20源码的根目录下?http://skyeye.wiki.sourceforge.net/space/showimage/skyeye_2.6.17_lubbock.config

这个下载好的配置文件已经帮我们做了的两件事

首先,在block device菜单下配置了ramdisk和initrd的支持

其次,把内核原来的启动参数改为

4. 把下载到的skyeye_2.6.17_lubbock.config更名为.config

5. 编译内核

6. 创建文件 skyeye.conf,内容如下

7. 从skyeye的测试套件中拷贝initrd.img到linux-2.6.20源码根目录下。该initrd.img的路径是

8. 运行内核看看,在linux-2.6.20源码根目录下运行下面的命令。可以看到,内核成功运行

调试

1. 在linux-2.6.20源码根目录下运行命令

2. 在源码根目录下新开一个终端,并运行

gdb界面出来后

之后可以看到,下断点,查看汇编等一切调试功能和x86下都一样。

3. ddd下如何调用arm-linux-gnueabi-gdb ? 答

为s3c2410配置2.6.26内核

[启动过程中有若干错误提示,但内核能启动成功并运行。有待研究

目标

得到一个基于s3c2410cpu的2.6.26最新稳定内核的虚拟系统,能进行全程的内核调试,即调试能从第一条机器指令开始进行。

参考

http://skyeye.wiki.sourceforge.net/Linux

http://www.linuxfans.org/bbs/thread-182101-1-1.html

环境条件

1. ubuntu hardy 8.04

2. 安装了debian提供的交叉编译工具套件 arm-linux-gnueabi- (4.2版本)

操作步骤

1.依据“安装交叉编译工具”这节,安装好交叉编译工具

2.修改源码

3.把默认.config替换为s3c2410版本

3.修改配置文件

4.修改内核启动命令

5.编译

6.从skyeye的测试套件中拷贝相应的文件initrd.img和skyeye.conf到linux-2.6.26源码根目录下。这两个文件的位于

7.启动虚拟机

8.启动完成后那激动人心的logo如下

调试

1. 在linux-2.6.26源码根目录下新建文件”.gdbinit”,内容是

2. 在linux-2.6.26源码根目录下命令

3. 在源码根目录下新开一个终端,并运行

之后可以看到,下断点,查看汇编等一切调试功能和x86下都一样。

4. ddd下如何调用arm-linux-gnueabi-gdb ? 答

截图

使用最新的skyeye

1. 新版本的改进

在ubuntu下利用在线安装命令所安装的skyeye是旧的版本,新版本修正了旧版本的一些小问题。比如,旧版本在调试时会出现下面一些烦人的小提示。

但是,两个版本并不是完全兼容的,主要是skyeye.conf的处理上。不过,幸好这些都是很容易解决的问题。

2. 新版本的安装

http://sourceforge.net/project/showfiles.php?group_id=85554

到上面的网站下载最新版本,目前是skyeye-1.2.6_rc1。解压后用下面命令编译就可以了

然后把在源码根目录下生成的skyeye拷到内核目录下运行即可。这样系统中的老版本skyeye还照样可以使用。

3. 新老版本的兼容问题

主要是skyeye.conf的格式识别上。老版本要求load_address,load_address_mask不能写在 skyeye.conf文件内部,只能用-l选项指定。如果运行老版本时提示skyeye.conf出错,你就得去查查那里,并手动修改处理一下即可。

基于串口

为qq2440平台移植2.6.26或更新内核,并建立kgdb调试环境

进行中...

[移植中的一些零碎的笔记]

1.内核版本

使用linus的git,但是已知2.6.25中arm已经支持kgdb了。

2.

基于网口

推荐这篇,内容很全: gdb 使用手册?http://blog.chinaunix.net/u/11240/showart.php?id=340632

终极参考: Debugging with GDB?http://sourceware.org/gdb/current/onlinedocs/gdb.html#SEC_Top

网址

cgdb:http://cgdb.sourceforge.net/

kgdb:http://www.kdbg.org/screenshot.php

ddd:http://www.gnu.org/software/ddd/

insight:http://sourceware.org/insight/

这些工具在ubuntu下都有编译好的.deb安装包,利用“立新得”就直接搜索然后在线安装。

这篇短文是我的浅陋之见,我接触这些gui的时间也不久。错误难免。 虚拟机:qemu

内核内置kgdb

developer machine: 运行gdb

除了只用命令行gdb外,还可以用gdb的gui,有

1.cgdb 缺点:界面简陋,自动化程度低,只是把terminal分为两部分,上面部分显示源码,下面打命令。由于没有显示反汇编的窗体,不适合要求使用到 stepi命令的场合。优点:运行快,锻炼手指头. 最大的优点是,它有完美的代码着色功能。其他几款调试器中都没有。

2.ddd: 缺点:与kdbg相比,界面凌乱。优点:代码显示效果比kdbg好,c和反汇编代码分开在两个窗口。 可以随时暂停程序的运行。data windows 这个功能非常强大灵活。提示 ddd –tty 2>/dev/null https://www.ngui.cc/zz/vmlinux ; remote target localhost:1234

3. kdbg: 缺点:功能比ddd弱。字体太小,c和反汇编代码交错显示,反汇编代码折叠隐藏在C代码之间,要显示反汇编代码要手动展开,不可忍受。太过界面化,居然找 不到是在哪里手动打gdb命令。致命缺点是,内核跑起来后,如果没有断点拦截,就没法把内核的运行暂停下来,kdbg成了没事姥,源码窗口的显示不更新。 另一个致命缺点是,如果没有源码只有二进制文件,虽然可以下断点,但无法显示反汇编代码,没意义。据说kdbg是用来调试kde程序的,实际上也能调试内 核。优点:窗口可以整合到一块,稳定。有变化的寄存器会显示红色。提示 kdbg -r localhost:1234 https://www.ngui.cc/zz/vmlinux

4. insight: 和ddd都是基于TCL/TK,比较相似。优点:源码显示功能最强,可以选择C和反汇编代码分开和交叉显示。可以选择反汇编代码使用intel还是 at&t格式。可以列出当前有哪些源文件,当前文件有哪些函数。变化的寄存器有改变颜色的功能,ddd则没有。缺点:和ddd一样,小窗口无法整 合到到窗口中,但比ddd差的是,主窗口最大化后小窗口无法保持置顶。相对ddd的大劣势是没有一个强大的data windows。感觉界面比ddd强大,但灵活性比ddd差点。对于调试内核来说,还有一个和kdbg相同的大缺点,内核只能通过断点暂停运行,而ddd 下还可以用ctrl+c暂停内核。另外它有个SB错误,显示backtrace的窗口,标题居然是stack. 提示: insight https://www.ngui.cc/zz/vmlinux

5. xxgdb: 古董级别。没事干的时候可以玩玩

6. 其实,gdb自带了一个基于curses的gui。启动方式是gdbtui xxx; 或者在gdb启动之后用命令layout启动gui。很好用,可以至多同时显示三个分窗口。要是代码有着色功能就好了。

针对内核调试的总结

1. kdbg不适合调试内核

3. 如果想复习gdb强大的命令,选cgdb或纯gdb。

4. 如果想学习汇编,insight是不二选择。

5 如果倾向于把调试器当作浏览器使用,作为source insight等工具的辅助工具,在内核运行中拦截函数,分析函数的调用关系,不需要反汇编的话,则cgdb是不错的选择 .(source insight等源码分析工具有个共同的缺点,因为体系和内核配置不同,一个函数有很多的定义,借助调试器可以在内核运行的时候找出实际调用的那个)

6.insight和ddd很接近,各有千秋。但如果侧重于追溯数据结构体间的联系,ddd更好一点,因为它有data window,它的强项是数据和数据结构关系分析并用图像方式显示出来(What is DDD? Data Display Debugger)。如果侧重于分析汇编指令是怎么在cpu中跑的,推荐用insight,因为它汇编代码显示功能更细致。

7.可惜目前在ubuntu8.04下,ddd+qemu组合用来调试驱动时有bug:驱动函数被拦截时如果正在qemu的系统下操作,鼠标就会冻结在qemu的屏幕中。其实调试单个驱动,用gdb就足够了。ddd等gui一般用来调试理解内核原理。

另外有用的命令 ptype, whatis

更多相关技巧

1. 获取struct page结构的大小

2.

打印前从指针mem_map所指起的5个page结构体

用ddd的图形显示命令是 (gdb) graph display *mem_map@5

参考 p *array@len

@的左边是数组的首地址的值,也就是变量array所指向的内容,右边则是数据的长度,其保存在变量len中

3.

每运行一次stepi/next等命令后显示下一步要将要运行的反汇编指令

提示:display的管理

undisplay delete display disable display enable display info display

4.使结构体的显示更漂亮

(注:6.7.条来自http://techcenter.dicder.com/2006/0906/content_173.html)

5. 使用自定义命令。

6. 纯gdb的多窗口显示 GUI调试器可以同时打开多个小窗口,分别显示寄存器、汇编和源代码等。在gdb里也可以做到,但同时最多只能显示两个窗口,试了一下也很方便的。基本命令如下

a) `layout src’ 仅显示源代码窗口。

b) `layout asm’ 仅显示汇编代码窗口。

c) `layout split’ 显示源代码和汇编代码窗口。

d) `layout regs’ 显示寄存器和源代码窗口,或者寄存器和汇编代码窗口。

e) `layout next` 和 `layout prev’ 切换窗口。

f) ctrl + L 刷新屏幕。

g) `C-x 1′ 单窗口模式。

h) `C-x 2′ 双窗口模式。

i) `C-x a’ 回到传统模式。

7. 字符gdb中,如何在每执行一次next命令后都自动显示backtrace的内容 这个问题实际是如何一次执行多条命令。用自定义命令解决

8. gdb在TUI模式下如何把光标焦点炸转移到command窗口,以便能用上下箭头键能快速翻出历史指令

9. 如何在子函数调用和退出时都暂停运行 watch $ebp

10. 如何获取结构体中特定域的相对偏移量,比如struct stak_struct 中lock_depth的相对偏移量

11. 如何能够交换使用ddd与gdb,也就是说使用ddd调试时,想换回使用纯gdb,同时保证启用gdb后保证“调试上下文”没任何变化

只要.gdbinit 文件没包含 c, next..等等能驱动gdb继续调试的命令就可以。

12. 如何通过函数名确定所在的源文件

13. 由汇编指令地址确定该指令所对应源码的所在行(注:一行c语言一般对应几行汇编指令)

info line *xxxxxxx (xxx是汇编指令地址)

14. 如何快速定位函数中某句C语句对应汇编指令的开始地址。比如以下 [内容太大,准备移到其他位置]

首先,通过函数名查询对应的源文件

然后,利用info line 源文件:目标语句的行数 就能查询到

验证一下

我们通过mkdir参数个数,及testb 指令基本判定我们的猜测没错。也就是说vfs_mkdir函数中dir→i_op→mkdir的实际调用是在0xc017c0fb <vfs_mkdir+179>: call *0×14(%ebx)

15. 下断点的形式

16. 陷入循环语句后,想自动运行到循环语句结束

17. 重复当前的gdb指令

本小节意义:为了方便把调试内容复制出来,而又需要一定的功能,本人经常使用的工具是gdb的tui。所以gdb宏的使用更是成了不可缺少的辅助手 段。比如extendinstr宏,能实时显示调用链的情况,相当于实现了ddd的backtrace分窗口。其他宏的作用就不说了。

参考资料

kgdb官方的gdb宏?http://kgdb.linsyssoft.com/downloads.htm

“Fun with strace and the GDB Debugger”?http://www.ibm.com/developerworks/aix/library/au-unix-strace.html

“GNU Project Debugger: More fun with GDB”?http://www.ibm.com/developerworks/aix/library/au-gdb.html

“14.3.4. Useful Kernel gdb Macros” from “Embedded Linux Primer”?http://book.opensourceproject.org.cn/embedded/embeddedprime/

gdb宏的使用

假设要使用下节的lsmod,该gdb宏能列举内核中的模块。 在内核源码目录下建立一个新文件lsmod,内容见下节。

实例

给出的例子都在2.6.26内核上上测试通过。

链表遍历类

宏名: lsmod(有小bug,饭后再看)

作用: 列举内核模块的名称及对应模块结构体的地址,以及text段的地址[todo,导出.bss,.data地址

效果如下

宏名: psusr,pskern

作用: 列举所有task的结构地址,状态,PID,PPID,comm。

psusr,只列举用户层可见的进程;pskern,列举内核层可见的所有进程。

效果如下

宏名: lssp

作用: 列举超级块地址及其s_id域

效果

功能增强类

宏名: eih, lih, ooi

作用: 克服时钟中断干扰与中断无关的目标代码的调试(X86下适用),解释请看“工程方法”

说明: 使用gdb或ddd时,进入中断后用finish命令的话常常是要么无法返回被中断的原指令处后停住,而是继续运行,要么是会进入到另一个时钟中断中;但是好像在insight下没这个问题。使用这个gdb宏可以解决该问题。

宏名: extendinstr

作用: 扩展指令集。配合gdb自带的tui使用,能代替ddd等界面工具的部分功能。

说明: 指令开头:s→step,si→stepi,n→next,ni→nexti,中间bt→bt,末尾i→info args && info local

效果

宏名: quick

作用: 超级快捷键。gdb的快捷键并没用用尽所有的按键。我们可以利用空余的按键定义自己的命令。方便起见,我只是利用自定义命令简单的实现该该功能,而不是自定义快捷键。可以根据自己偏好来定义。

说明: 这个宏是配合前面的宏ooi和宏extendinstr使用的。这样,如果调试时进入了时钟中断,按a+enter就可以瞬间返回;q+enter–>sibt; z+enter–>finish。

宏名:bttnobp,btt,psusr,pskern,trapinfo,btpid,dmesg

内核文档gdbmacros.txt 的gdb宏的升级版本,还修正了一个bug,已在2.6.26下测试。

如果你运行这个脚本有错误,那说明你的内核版本太低了,请运行内核源码中原文件的宏。

本人这个文件的补丁还在提交的过程中。

能提供non-running进程的backtrace功能,还实现了dmesg。

说明bttnobp没在!CONFIG_frame_POINTER的配置下测试过,但是估计结果很不可靠

因为条件判断太宽大了。

宏名:vmap, lsvmaps, lsmod, lsmodsects, lsallmodsects

说明:没测试,待更新

来源?http://jeanmarc.saffroy.free.fr/kdump2gdb/

注意:某些内容不具备普遍性。比如给出的反汇编代码,在不同的优化等级下是不同的。但是在熟悉了典型的函数调用链反汇编代码,对于有变化的其他形式也就不难理解了。

Intel? 64 and IA-32 Architectures Software Developer’s Manuals

http://www.intel.com/products/processor/manuals/index.htm

参考

“AT&T汇编语言与GCC内嵌汇编简介”?http://blog.chinaunix.net/u2/73528/showart_1110874.html

[杂类文章]

“Linux Assembly and Disassembly an Introduction”?http://www.milw0rm.com/papers/47

GCC-Inline-Assembly-HOWTO?http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html

参考文章 [多如牛毛]

“Guide: Function Calling Conventions”?http://www.delorie.com/djgpp/doc/ug/asm/calling.html

“Intel x86 Function-call Conventions - Assembly View”?http://www.unixwiz.net/techtips/win32-callconv-asm.html

“C Function Call Conventions and the Stack”?http://www.cs.umbc.edu/~chang/cs313.s02/stack.shtml

“The C Calling Convention and the 8086: Using the Stack frame”?http://www.et.byu.edu/groups/ece425web/stable/labs/Stackframe.html

“C Function Calling Convention”?http://adamw-dev.blogspot.com/2007/05/c-function-calling-convention.html

“C函数调用在GNU汇编中的实现”?http://www.unixresources.net/linux/clf/cpu/archive/00/00/59/75/597564.html

“函数调用的几个概念:_stdcall,_cdecl....”?http://blog.chinaunix.net/u2/67530/showart_601750.html

“Calling conventions(调用规则)”?http://www.bobd.cn/itschool/Program/delphi/200612/itschool_12084.html

[扩展,简要说明原理。并用实例解析]

x86终极参考

CHAPTER 6 PROCEDURE CALLS, INTERRUPTS, AND EXCEPTIONS of

IA-32 Intel_ Architecture Software Developer’s Manual Volume 1_ Basic Architecture.pdf?http://download.intel.com/design/processor/manuals/253665.pdf

寄存器的角色与保护

  • 寄存器的角色

1. %esp: 栈指针

指向栈的顶端,也就是指向栈的最后一个正在使用的元素。%esp的值隐式地受到几个机器指令的影响,比如push,pop,call,ret等。

2. %ebp: 基址指针

指向当前栈的基地址,有时也称为“帧指针”。与%esp不同的是,它必须显式地进行操作才能改变值。

3. %eip: 指令指针

保存着下一个被执行机器指令的地址。当CPU执行call指令时,%eip的值自动被保存到栈中。还有,任何一个“jump”跳转指令都会直接地改变%eip

  • 两条规则

1. gcc要求在函数调用的前后,寄存器%ebx,%esi,%edi,%ebp,%esp,%ds, %es,%ss的值保持不变。所以被调用函数如果需要修改这些寄存器的值,被调用函数必须负责对它们进行保护。[后三个??

2. gcc规定在函数调用的前后,寄存器%eax,%edx,%ecx的值可以改变。所以调用函数如果需要防止子函数破坏这三个寄存器的值,调用者必须在函数调用前自己负责保护它们。

我们注意到,是保护,不一定是保存。如果确认没用到某寄存器,那么该寄存器就不需要一定要有一个先保存到栈而后再恢复原值的过程。

这两条规则实际是定义了对系统资源使用的权限和义务。

第一条规则,是银行和借贷者的关系。有人向银行借了几千万,结果赌博全输光了。还钱的期限到了,银行的行长对借贷者说“没事,你回家吧。几千万而 已,我拿我工资给你垫上”。我想这样的事决不会发生,行长一个电话110过去,借贷者一天后就把钱还清了。所以,这里,调用函数是银行行长,子函数是借贷 者。

第二条规则,则是老爸和儿子的关系了。儿子对老爸说“老爸,解我100去买球鞋,我明天还你”。结果,第二天,老爸没钱吃饭了,问儿子“还钱”。儿 子说“昨晚逛街碰到一个美女,请了一顿,把钱化光了”。老爸没法子,总不能把儿子绳以正法吧。怪只能怪自己事前没防这招咯。所以,这里,调用函数是老爸, 子函数是儿子你。

  • 返回值

调用链的形成

  • 应用层实例解析

我们回头看看“寄存器的角色”这一小节,很快就能明白调用链的形成的本质。

调用链包含两方面的内容

1.返回地址的保存与恢复

2.旧栈帧的保存与恢复

因为在普通的调用形式中(call调用),返回地址的保存与恢复是由处理器机制本身保证的,不需人工维护。调用指令call的执行自动将call指令之下 的指令地址压入栈中,被调用函数返回时,ret指令的执行会重新将返回地址从栈弹出传送到pc中。要求下面分析旧栈帧的保存与恢复。

旧栈帧的保存与恢复,无非就是要解决两大问题

1. 建立新栈帧 这一步很简单,栈帧无非有两个头,底端和顶端。%esp指向栈的顶端,而%esp是不需要手工维护的,随着push,pop等指令,它自己就在改变自己。 那么又怎么建立栈帧的底端呢?我们知道,栈底(也就是基址)是由%ebp指定的,在一个栈帧的整个生命周期里,%ebp的值都不变,也就是说,赋个合适的 值给它就完事。怎么赋值就是问题所在了。我们知道,%esp指向栈中最后一个被使用的元素。所以,当我们正在使用(我们认为的)第一个元素时,把%esp 的值赋给%ebp,%ebp不就是指向栈的基址了吗

2. 保护旧栈帧的信息 同样的问题,保护旧栈帧的信息,就是保存旧栈帧指向底端和顶端的指针值,也就是旧%ebp,%esbp的值。当函数调用指令刚执行完,马上就要保护作案现 场了。首先,push %ebp,这句就把旧栈帧的基地址保存在栈的顶端。此时,%esp指向的内存地址中,就放着旧栈帧的基地址的值。但是还不够啊,%esp是个不可靠的东 西,它经常在变化,必须把这个地址放到一个不会隐式变化的寄存器中。于是选择了%ebp。mov %esp %ebp.这样,%ebp指向的内存地址中,就放着旧栈帧的基地址的值。这就解放了%esp,可以用%esp来动态指向新栈帧的顶端了。按照定 义,%ebp所指向的地址是新栈帧的底端,也就是新栈帧的第一个元素,也就是说新栈帧第一个元素的值是旧栈帧基址。

但是注意,%ebp指向的地址再加4bytes的地址上,存放的是被调用函数的返回地址。在执行call指令时,call指令后面的那个指令的地址(也就是被调用函数的返回地址)被自动隐式地放到了栈中。

当子函数返回时,再按照上面文字进行逆操作,就能恢复旧栈帧的信息。

  • 内核层实例解析

栈帧结构与参数传递

  • 栈元素引用的就近原则

为了说明就近原则,我们先看看典型和全面的栈帧是怎样的。函数caller调用子函数callee所形成的栈帧。

1. 从被调用的子函数callee来看,获取caller的传递的实参,以及建立自身本地变量时,因为内存地址都靠近栈帧的基址,所以这两种引用都是利用%ebp加上偏移量的形式。

2. 相反,主函数在调用子函数前,在为子函数准备实参时,因为实参位于栈帧末端,所以对实参的引用都是利用%esp加上偏移量的形式(没画出来)

完整的调用过程

函数caller调用子函数callee,这是应用层的普通函数调用过程。如果是远调用,跨态调用要考虑的东西更多。但这个例子已经充分展示了调用过程的繁复部分。

  • 函数调用前调用者的动作

1.%eax,%edx,%ecx入栈(可选

2.子函数的参数入栈

  • 函数调用 call callee

call机器指令,原子性自动地完成了两种任务.

1.%eip入栈, 保存了callee函数的返回地址

2.callee的函数地址传递到%eip.

所以下一指令就从callee函数的第一指令开始运行。控制权转移给callee

  • 函数调用后被调用者的动作

1.保存caller栈帧基址 push %ebp

2.建立callee栈帧基址 mov %esp,%ebp

3.分配本地变量和临时存储的空间 sub $XXX, %esp

4.本地变量赋值

5.%ebx,%esi,%edi入栈(可选)

  • 调用返回前被调用者的动作

1.%ebx,%esi,%edi还原(出栈,可选)

2.释放本地变量和临时存储的栈空间mov %ebp,%esp

3.还原caller栈帧的基址 pop %ebp

或者2.3.步用一条元语指令完成 leave

4.调用返回 ret

该指令把存放于栈的返回地址取出(出栈),存放到%eip中。下一指令就从call callee指令的下一指令开始运行。控制权返回给caller

  • 调用返回后调用者的动作

1.释放存放callee参数的栈空间 add $XXX, %esp

2.转移%eax的值(子函数的返回值,可选

3.还原%eax,%edx,%ecx(出栈,可选

  • 应用层实例解析

应用层参数的传入: 用户层参数的传递是利用栈来完成的。函数右边的参数先入栈,位于栈的高地址。反之, 函数左边的参数后入栈,位于栈的低地址。

  • 内核层实例解析

内核层参数的传入: 混合使用寄存器和栈来传递参数。当参数个数不多于3个时,参数从左到右依次传递到%eax, %edx, %ecx.当参数个数多于3时,从第4个起的其余参数通过栈传递。同样,函数右边的参数先入栈,位于栈的高地址。反之, 函数左边的参数后入栈,位于栈的低地址。

  • 系统调用实例解析

系统调用的参数传递:[以后再看]

调用链回溯的代码实现

内核中(x86)对调用链的回溯的代码实现在文件dumpstack_32.c文件中。主要函数是dump_trace和print_context_stack.

例1

if ... else if

这个例子有人看来也许是非常非常地简单,但就这个例子,有的人还真给我考”倒”了。他的回话是“还真没见过这样子的代码”。但是,这样的代码在内核中比比 皆是,比如后面附上的函数代码 do_path_lookup。如果对if ... else if 理解有偏差,对内核代码的逻辑理解根本就是差以千里。

这个例子,有人会疑问为什么”j,ok”没打印出来。现在我们分析下它的汇编代码

经过上面的汇编代码分析,可见c代码块

对应的汇编代码是

上面的代码指令根本就没有机会运行。

结论,一个if ... else if ..else..

语句块1,2..N的运行机会是一种互斥的关系。当然它们的“机会优先级”是不一样的。语句块1,2..N只有一个有被运行的机会,如果没有else甚至可能没有一个语句块能被运行。

内核代码实例

例2

短路逻辑算法。

这样的例子在内核代码中也是非常地多,一般用在短的函数或宏中。

这个例子,有人会疑问为什么b的值没有变化,还是为2。现在我们分析下它的汇编代码

分析可见C语句 if (a || ++b)中的++b对应的汇编码是

可是因为a==1,表达式a已经为真++b这个语句,也就是上面的汇编码,根本就没运行。所以变量b的值没有自增,还是保持为2。

结论

内核代码实例

例3

自增自减

自增自减,以及增减的前后问题。这类代码在内核数不胜数。理解稍有偏差,就会产生“边界问题”,或者在条件判断时理解出错。

汇编代码

内核代码实例

例4

函数指针

解释在“穿越交叉索引工具的盲区”→函数指针

其他例子

这部分内容有点偏题,没必要这么钻牛角尖。但是为了说明“调试用的代码和实际运行的代码是不一样”的这个事实以及因为代码优化导致的“非理想状态”的调用链问题(见“内核初窥”),有必要用观察一个实例,以便有个直观的印象。

首先应该知道,有没有指定调试选项-g(–debug),在相同优先级下生成的代码都是一样的。差别只是,指定-g后,多生成了一个调试表。

优化选项

下面文字来自“ARM 系列应用技术完全手册”

使用-Onum选择编译器的优化级别。优化级别分别有

  • -O0: 除一些简单的代码编号外,关闭所有优化,该选项可提供最直接的优化信息。
  • -O1: 关闭严重影响调试效果的优化功能。使用该编译选项,编译器会移除程序中未使用到的内联函数和静态函数。如果于–debug(也就是-g)一起使用,该选项可以在较好的代码密度下,给出最佳调试视图。
  • -O2: 生成充分优化代码。如果与–debug一起使用,调试效果可能不令人满意,因为对目标代码到源代码的映射可能因为代码优化而发生变化。如果不生成调试表,这是默认优化级别。
  • -O3: 最高优化级别。使用该优化级别,使生成的代码在时间和空间上寻求平衡。

例子

说明

1. 部分内容和X86的重复,重复部分请参考X86的内容。

2. 某些内容不具备普遍性。比如给出的反汇编代码,在不同的优化等级下是不同的。但是在熟悉了典型的函数调用链反汇编代码,对于有变化的其他形式也就不难理解了。

ARM7TDMI Technical Reference Manual

ARM920T Technical Reference Manual

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.home/index.html

指令速查?http://www.arm.com/pdfs/QRC0001H_rvct_v2.1_arm.pdf

注意:arm体系过程调用的文字说明部分,都是依据AAPCS标准。

壮观的标准

参考

AAPCS

Procedure Call Standard for the ARM Architecture

http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042b/IHI0042B_aapcs.pdf

终于在“ARM Procedure Call Standard”中找到了答案

下面的标准已过时

APCS

ARM Procedure Call Standard?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0041c/BGBGFIDA.html

Using the ARM Procedure Call Standard?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0040d/Chdbceig.html

APCS 简介http://www.bsdmap.com/UNIX_html/ARM/apcsintro.html#01

TPCS

Thumb Procedure Call Standard?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0041c/BCEEAHAF.html

Using the Thumb Procedure Call Standard?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0040d/Cihdbchi.html

ATPCS

about the ARM-Thumb Procedure Call Standard?http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0056d/Bcffcieh.html

别名的烦恼

arm体系的函数调用标准换了好几个版本,对寄存器的别名也是不一样。不同的调试器,或者它在不同的选项下,对同一个寄存器可能就有多种称呼。又或者你在调试器下看到的名称和书籍上的不一样。所以,又必要知道这些寄存器各自都有哪些别名。

我们运行下命令

我们下载它的源码打开看看

$ sudo apt-get source binutils-arm-linux-gnueabi

完成后,在下载目录下多了几个东东,其中有一个文件夹binutils-2.18.1~cvs20080103,这是debian对官方binutils进行过修改的源码。在里面搜索文件arm-dis.c,该文件中有以下这个数组。

就是不同标准下各个寄存器的不同别名。

[扩展,简要说明原理。并用实例解析]

寄存器的角色与保护

  • 寄存器的角色(AAPCS标准)
寄存器 可选寄存器名 特殊寄存器名 在函数调用中的角色r15 ?PCThe Program Counter.r14 ?LRThe link Register.r13 ?SPThe Stack Pointer.r12 ?IPThe Intra-Procedure-call scratch register.r11v8 ?Variable-register 8.r10v7 ?Variable-register 7.r9 ?v6/SB/TRPlatform register. The meaning of this register is defined by the platform standardr8v5 ?Variable-register 5.r7v4 ?Variable register 4.r6v3 ?Variable register 3.r5v2 ?Variable register 2.r4v1 ?Variable register 1.r3a4 ?Argument / scratch register 4.r2a3 ?Argument / scratch register 3.r1a2 ?Argument / result / scratch register 2.r0a1 ?Argument / result / scratch register 1.

前四个寄存器r0-r3 (a1-a4)用于传递参数给子函数或从函数中返回结果值。他们也可用于在一个函数中保存寄存器的值(但是,一般只用在子函数调用中)。

寄存器r12 (IP) 可在函数以及该函数调用的任何子函数中被链接器用作临时寄存器。它也可以在函数调用中用于保存寄存器的值。

寄存器r9的角色是平台相关的。虚拟系统可能赋予该寄存器任何角色,因此必须说明它的用法。比如,在位置无关数据模型中它可以指定为static base(SB),或者在带有本地线程存储的环境中指定它为thread register(TR)。该寄存器的使用可能要求在所有调用过程前后,它保存的值必须不变。在一个不需要这样特殊寄存器的虚拟平台上,r9可以指定为新 增的callee-saved variable register,v6.

通常,寄存器r4-r8, r10 和 r11 (v1-v5, v7 和 v8)用于保存函数的本地变量。这些寄存器中,只有v1-v4能被整个thumb指令集一致地使用,但是AAPCS并没有规定Thumb代码只能使用这些寄存器。

子函数必须保护寄存器r4-r8, r10, r11 和 SP(还有r9,如果在函数调用过程中r6被指定为v6的话)的值。

在所有的函数调用标准中,寄存器r12-r15都扮演特殊的角色。依据这些角色,它们被标注为IP, SP, LR 和 PC。

寄存器CPSR的属性(省

  • 寄存器保护规则

子函数必须保护寄存器r4-r8, r10, r11 和 SP(还有r9,如果在函数调用过程中r6被指定为v6的话)的值。 子函数调用

  • 子函数调用

ARM 和 Thumb 指令集都有一个函数调用指令元语,BL,它执行branch-with-link 操作。BL的执行效果是把紧跟程序计数器的下一个值-也就是返回地址-传送到链接寄存器(LR),然后把目标地址传送到程序寄存器(PC)中。如果 BL指令是在Thumb状态下执行的,链接寄存器的Bit 0就设置为1;如果是在ARM状态下执行的,则设置为0。执行的结果是,把控制权转给目标地址,并把存放在LR中的返回地址作为附加的参数传递给了被调用 的函数。

当返回地址装载到PC时,控制就返回给跟随BL后面的指令。

子函数调用可以由具有下面效果的任何指令序列完成

例如,在ARM状态中,调用由r4指定了地址的子函数

注意,相同的指令序列在Thumb状态中将不能工作,因为设置LR的指令并没有拷贝Thumb 状态标志位到LR[0]中。

在ARM V5架构中,ARM 和 Thumb指令集都提供了BLX指令,它将调用由一个寄存器指定了地址的子函数,并正确地设置返回地址为程序计数器的下一个值。

条件执行

操作码[31:28] 助记符扩展 解释 用于执行的标志位状态0000 EQ相等/等于0Z置位0001 NE不等Z清00010 CS/HS进位/无符号数高于或等于C置位0011 CC/LO无进位/无符号数小于C清00100 MI负数N置位0101 PL正数或0N清00110 VS溢出V置位0111 VC未溢出V清01000 HI无符号数高于C置位,Z清01001 LS无符号数小于或等于C清0,Z置位1010 GE有符号数大于或等于N等于V1011 LT有符号数小于N不等于V1100 GT有符号数大于Z清0且N等于V1101 LE有符号数小于或等于Z置位且N不等于V1110 AL总是任何状态1111 NV从不(未使用)无

调用链的形成

注意对比ARM和X86在调用链形成的类似和区别之处。

区别,首先在寄存器的名称和角色的差异。

1. X86中寄存器%eip指向的是下一个将要执行的指令。在ARM中也有个类似别名的寄存器ip。但这个寄存器ip的作用并不是指向的是下一个将要执行的指 令。在ARM中,寄存器pc才是起着X86中寄存器%eip的角色,也就是包含下一个将要执行指令的地址。而ARM中的ip寄存器,作用比较自由,类似干 杂工的人,一般用于临时寄存器。[扩展,引用权威手册的话]

2. X86中,返回地址是直接保存在栈中的。但是ARM不一样了,它寄存器比X86多得多,财大气粗,所以,返回地址保存在了专用的寄存器lr(link register)中。但是,不要以为把返回地址放到专用的寄存器中会省事,其实反而多事了。因为,在调用函数刚执行完调用语句之时,lr保存的是子函数 的返回地址,而指令控制权转移到了子函数后,子函数照样可能调用自己的子函数,依次需要使用lr。所以自然也就有了lr的值的保存与恢复的问题,解决方法 还是要靠压栈解决。(参考下面的内容

3. 我们知道,描述栈帧就是描述栈帧的基地址和顶端地址。在X86中,用专用的寄存器%ebp保存栈基址,也就是base pointer;%esp保存栈顶端地址,也就是stack pointer。在ARM中,也有专用的寄存器保存栈顶端地址,就是SP(stack pointer的简称)。但是,在保存栈基址这方面,依据最新的AAPCS标准,ARM就很吝啬了,没有一个保存栈基址的专用寄存器。又不过呢,在 APCS和ATPCS标准中,有fp寄存器用于保存帧指针(frame pointer,也就是X86的base pointer)。在现在的编译器,可以看到,还是依照惯例把fp用于保存帧指针。既然如此,当然也有个入栈保存恢复的问题。

调用链包含两方面的内容,和X86类似

1.返回地址的保存与恢复

由调用函数在执行调用指令时把子函数的返回地址传送进连接寄存器lr中,指令控制权转交给子函数后,再由子函数负责把上层函数的lr(也就是子函数 的返回地址)保存到栈中。然后子函数在返回前的最后时刻,再负责把lr的保存值从栈弹回到lr中,从而恢复了上层函数的lr。这时还没完事,子函数在执行 返回指令时,由返回指令把lr的值传送到寄存器pc(Program Counter),从而导致接下来的指令是从子函数的返回地址开始运行。这样,指令控制权就返回给了调用函数。

我们应当注意到,ARM中调用指令也是多种多样的。有b,bl,bx,bxl。如果调用指令是不带连接的指令,比如b,bx,这时就要人工给lr赋 值。不过为了简便,我不再区分这两类指令,而把实现跳转和连接以及可能的换态这些功能的整个指令序列为“调用指令”,相关区别参考指令手册。在ARM中, 返回指令和调用指令都是同一套的。而X86,调用用call,返回用ret。

2.旧栈帧的保存与恢复

对比X86栈帧的保存与恢复的方式,ARM的更加简单直接。就是直接把上一栈帧的帧指针(frame pointer,也就是栈帧基地址)以及栈顶端指针sp(stack pointer)压入栈中。子函数返回时,在执行返回指令之前的最后关头才从栈弹出fp和sp的值,从而恢复旧栈帧。这个过程真的没有遗漏了吗?我们看 下,上面的步骤保证了调用函数的栈帧不被破坏,但是子函数自己的栈帧却没有建立起来呢。首先是帧指针需要人赋值。这个情形和X86非常相似。子函数在使用 栈帧之前,把上层函数的栈顶端指针sp赋给一个临时寄存器ip,然后在旧fp的值被压栈保存之后,把ip的值减去4,再赋给帧指针寄存器fp,此时,fp 就指向了新栈帧的基址。这是因为,新栈帧基地址刚好位于旧栈帧栈顶之下,地址低了4字节。其次,子函数栈帧的栈顶指针sp也是要考虑的,根据压栈指令的不 同,sp可能不需要人工维护,也可能需要人工维护[有疑问...????]。

我们还注意到,在X86中,子函数的栈帧的底端(也就是%ebp所指的内存位置)存放着上一层栈帧的基址指针(旧%ebp)的值,一层层下去,这样 就形成回溯的链条。那么,在ARM之下,也是靠子函数的栈帧的底端提供回溯的能力的吗?当然不是。实际上子函数的栈帧的基址位置存放的是什么,这无所谓 的。

[疑问?如果旧fp保存在新栈帧中的位置不是固定的,那么调试器是如何做到栈帧回溯的呢

根据AAPCS标准的规定,子函数必须保护寄存器r4-r8, r10, r11 和 SP(还有r9,如果在函数调用过程中r6被指定为v6的话)的值。注意,它用的字眼是“保护”,而不是“保存”。

  • 应用层实例解析
  • 内核层实例解析

栈帧结构与参数传递

[1.栈:栈对齐,栈限制。2.参数传递:variadic函数,nonvariadic函数。3.结果的返回 4.互交代码(ARM-Thumb interworking)]

栈帧示意图

完整的调用过程

函数caller调用子函数callee,这是应用层的普通函数调用过程。如果是远调用,跨态调用要考虑的东西更多。但这个例子已经充分展示了调用过程的繁复部分。

  • 函数调用前调用者的动作
  • 函数调用 call callee
  • 函数调用后被调用者的动作
  • 调用返回前被调用者的动作
  • 调用返回后调用者的动作
  • 应用层实例解析
  • 内核层实例解析

调用链回溯的实现

arm体系对调用链的回溯的代码实现主要在

本节意义: 内核源码的代码量越来越大,不借助源码交叉索引工具根本是无法阅读了。一定要熟练灵活掌握此类工具的使用

1.CodeViz

官网

http://www.csn.ul.ie/~mel/projects/codeviz/

安装使用

CodeViz —— 一款分析C_C++源代码中函数调用关系的调用图生成工具.pdf

http://linux.chinaunix.net/bbs/thread-1031921-1-1.html

用CodeViz产生函数调用图

http://barry-popy.blog.sohu.com/31629163.html

分析函数调用关系图(call graph)的几种方法

http://blog.csdn.net/Solstice/archive/2005/09/24/488865.aspx

用CodeViz绘制函数调用关系图(call graph)

http://blog.csdn.net/Solstice/archive/2005/09/22/486788.aspx

2.ncc

对于源码的阅读工具,一般是选取后面提到的某种源码索引工具,再和find以及grep“高低搭配”一起来使用。

1.命令选项

2.正则表达式

Regular expression HOWTO:?http://www.amk.ca/python/howto/regex/

正则表达式之道:?http://net.pku.edu.cn/~yhf/tao_regexps_zh.html

wine + source insight

优缺点

优点: SI的特点是有图形界面,操作和浏览特别方便快捷。特别是它的“函数调用树”的图形显示功能,以及分窗口自动显示函数,变量等定义的功能。

缺点: 不能解析汇编源文件。

安装wine

在ubuntu/debian下用以下命令就能在线安装wine

安装好后,就能看到wine的快捷菜单被添加到了任务栏的“应用程序”中。

安装SI

wine安装好后,就可以像在windows一样去安装使用SI了。安装完成后,SI的快捷菜单被添加到“应用程序”→“wine”→“programs”→“source insight3”中。以后用快捷菜单就能启动SI

SI的设置

字体,颜色就不说了。现在加入 无名小卒 大侠发现的一个有用设置。

preferences→ display→ trim long path names with ellipses. 去掉该选项的选择。这样就能直接在上下两个分窗口的标题栏上看到一个源文件的全路径。如果不去掉的话,对于长路径它会用...的形式来表示路径的一部分。

SI的使用

可以乱点乱试一下,它能提供很多的功能。其中一些经常要到的功能有 查找符号;函数调用的函数,被调用的函数;以及调用关系的多层展开显示;字符串搜索等。

[待玩]?http://www.gnu.org/software/global/

[待玩]?http://sourcenav.sourceforge.net/

安装

在ubuntu下可以在线安装

运行

参考

cscope的官方教程 “The Vim/Cscope tutorial”

http://cscope.sourceforge.net/cscope_vim_tutorial.html

对应的中文翻译:?http://www.gracecode.com/Archive/Display/316

http://www.lupaworld.com/?uid-151392-action-viewspace-itemid-106656

http://dev.21tx.com/2007/02/21/10252.html

优缺点

优点: 本人感觉在终端下看源码比较舒服。

缺点: 没有一个实时显示函数/变量定义的分窗口。也不能直接显示“调用树”,但有其他小工具可以实现该功能。也许vim高手能解决这些问题。

安装cscope/ctags

ubuntu/debian下用以下命令就能在线安装

命令选项

在终端下可以用 man info –help等形式查看cscope/ctags的手册

在vim下查看手册的方式是

1. 以下是cscope建立索引文件用到的一些选项

2. 在vim下利用:cscope find <关键字> 命令的选项有

使用

建立索引

[可能要修改]

用以下命令先产生一个文件列表,然后让cscope为这个列表中的每个文件都生成索引。在这里,我们只关注.h, .c, .S文件,所以只对他们进行索引。可以根据自己需求进行更改。接着我们用-bq选项利用cscope生成索引。选项意义见上节。同时也生成ctags索 引。

利用vim浏览源码

切换到内核源码的目录上,运行vim,然后在vim下导入索引

然后就可以在vim下调用“:cscope find <关键字>”来查找函数的定义,函数调用的函数以及被调用函数等

“:cscope find <关键字>” 可以缩写为 “:cs f <关键字>”

比如以下命令用来查找sys_read的定义

“cs f”的其他命令选项请看上节

快捷键的使用

kscope是cscope的图形前端工具。在ubuntu下可以在线安装。它的界面上和操作上与source insight都比较类似。但是目前它对cpu的占用很大,不是很好。但是它和cscope相比,有一个很大的优点是:可以图形显示“函数调用树”,甚至 这个功能比SI还强大。

1. 优缺点

优点:本身好像没什么特别的优点。但是有专门提供这种服务的网站,上面有很多不同系统的不同版本源码

缺点:在本机上配置运行的话,配置麻烦。如果是浏览lxr站点的方式,速度比较慢。

2. lxr官方:?http://lxr.linux.no/

特点是可以浏览历史上linux所有版本的源码,可以看到它的演化过程。

3. 其他系统的源码?http://fxr.watson.org/

估计超一流的内核开发人员,可能会经常访问此类站点。因为他需要借鉴其他系统的设计思想。

在源码阅读的功能上

1. SI等适合“面读”,也就是读一个代码段,并且提供更舒适的阅读辅助手段。SI适合分析函数全面的逻辑。

2. gdb适合“线读”,也就是以追踪调用链的方式深入阅读,并且提供了数据分析的调试功能。适合分析特定情况下的函数逻辑表现。

为了能使用调试器,必须理解函数调用链在调试器级别的表现形式。但是,因为存在内嵌函数和代码优化等原因,调试器的表现形式和源码浏览器下的表现形式是不一样的。它们两者的信息显示可能存在“错位”的现象。本节的目的就是为了磨合调试器和交叉索引工具之间的代沟。

为了简化问题的描述,在实际分析前,先将知识点分解介绍一下。

下面我给出一个处于“理想状态”的经典backtrace(backtrace的意思是“回溯”,依照它的作用来说,也就是本人说的调用链)。所谓“理想 状态的”的backtrace是指,可以利用内核源码交叉索引工具,依据gdb给出的这个backtrace,从frame 0开始一级级往后最追溯,能够一直追溯到最前面的frame N,而且追溯的过程中,没有出现多出来的连接frameN和frame(N-1)的“过渡”frame.

注意其中的两个条件:1.能够 2.不多出。但是,在现实的世界里,往往没这么美好。源码浏览工具往往要么“不能”,要么“多出”。造成前者的原因在于源码浏览工具的局限性,造成后者的是内嵌函数以及代码优化。详细情况可看下节的分析。

追溯的方法对于source insight来说就是:打开”relation window”→选中要被追溯的函数→右键→选“view relation”→选“referenced by functions”,这样就能显示出调用了被选函数的函数来。

我们拿下面这个“理想状态”的backtrace分析一下

理想状态下的backtrace各个域的含义是(注意,在非理想状态的backtrace中,这些含义往往对不上号)

我们看下

它说明frame0时,kref_init正要运行。传入的参数是0xdc40abe4。函数kref_init从源文件lib/kref.c第33行开始。 在gdb下调用shell来查看源文件

vi 出来后打命令:set nu可看到

我们再看看frame0这一瞬间是不是“kref_init正要运行”。应该知道,“正要运行”和“正要被调用”是两个不同的概念。前者来说,到了下一个指令,代码的控制权就会交给了被调用的函数;而后者,到了下一个指令,代码的控制权还在调用者手里

可见,kobject_init_internal的调用指令call已经执行完毕,到了frame0时,下一个指令“将要运行”函数kref_init。

再看看

frameN与frame(N-1)之间是调用的关系,前者调用了后者。也就是说,frame1的kobject_init_internal调用 frame0的kref_init,并且kref_init函数返回后,将返回到地址0xc01de8be继续执行。0xc01de8be就在 kobject_init_internal的体内,函数kobject_init_internal中调用kref_init的C语句位于 lib/kobject.c的149行。

查看一下kobject_init_internal的反汇编码

再看看lib/kobject.c,看看最后的那个行数的意义

在验证一下

看看kobject_init的反汇编码

看看看看lib/kobject.c,看看最后的那个行数的意义

通过这两个例子,可见最初的猜想是正确的。

本小节意义: 在利用SI等工具查看函数调用链时,遇到的一个最多的问题是函数指针的调用。所以把该小节内容移到这里来,为下小节的叙述作铺垫。SI等交叉索引工具不能在父函数内部解析出这种调用关系。

我们经常碰到这种情况:如果内核中函数A是通过函数指针调用函数B,那么源码交叉索引工具(如source insight, kscope等)就无法通过函数B的名称回溯到上层函数A。这是因为在函数A内部对函数B的调用并不是通过函数B的名称,而是利用指向函数B代码块的指针 (函数指针)。

要想解决这个问题,方法有两种

1. 利用字符串搜索功能

搜索函数指针的变量名。如果已经知道的是子函数,想找出通过指针调用它的所有上层父函数:利用子函数的函数名进行搜索,就能找到所有相应的函数指针 变量赋值的语句。然后搜索该函数指针变量就能得到所有可能调用该函数的上层父函数。相反,如果是已经知道父函数,想知道该父函数体内的一个函数指针可能会 调用哪些子函数,可以搜索该函数指针变量(一般在该变量名前加个点号“.”),这样可以搜索出所有给该函数指针变量赋值的语句,从而找出所有可能的子函 数。

当然,既然是字符串搜索,搜索结果中会夹带其他没用的信息,这需要进一步的筛选。这个方法能搜索出依赖某函数指针变量的所有调用关系。

2. 利用调试工具

在目标函数处下断点。调试器器会实时拦截该函数的调用,然后用bt命令就能看到整个调用链。

这个方法得到的只是一个特定的具体调用关系。可能还有其他很多的潜在调用路径。

然而,我们研究的目标并不满足于知道调用链。下面我们观察函数究竟是怎样利用函数指针调用子函数的。[待整理]

1. 人观念层次

2. 交叉解析器层次

2. c调用层次

3. 编译器(机器码静态)层次

4. 运行时(机器码动态)层次,也叫调试器层次

很明显,前面所讲的“理想状态”的backtrace就是指在交叉解析器层次下和在调试器层次下的表现相同的调用链。

任务

从一个断点开始,从后向前推导,分析出ramfs注册函数的调用过程。同时,观察调试器的优点和局限性。

ramfs文件系统的注册函数是register_filesystem(&ramfs_fs_type)。为了更快定位,在上层函数init_ramfs_fs下断点。而后在gdb下得到的调用链是

我们注意到

1. 这个backtrace包含的函数只有4个,实际上并非如此。经过分析,它实际上(用C的观点看)调用链如下所示,这是为什么呢

start_kernel→rest_init→kernel_thread→kernel_thread_helper→call %ebx (即call kernel_init)→do_basic_setup→do_initcalls→do_one_initcall→result = fn() (即call init_ramfs_fs)→register_filesystem

2. backtrace推溯到kernel_thread_helper后就再没下文了。又是什么使得调试器变成了瞎子,无法看得再远了呢

欲见其详,且听下回分解

[下面准备材料]

kernel_init对do_basic_setup的调用被优化成内联函数

do_basic_setup对do_initcalls的调用被优化成内联函数

do_initcalls对do_one_initcall的调用被优化成内联函数

有三层的非内联函数都被被优化成内联函数,整个代码被优化的乱七八糟。

如何在汇编码中定位内联(或被优化掉的非内联)函数

[待充实]

调用树的定义

一个复杂的函数调用一定是调用了多个子函数,同时这些子函数又会调用若干“孙”函数,这样依次调用并依次返回到最初的父函数后,就形成了树状的调用关系,我们称之为“调用树”。

调用树的作用

函数调用树是比函数调用链更为复杂的观察对象。如果能够显示调用树,就可以对调用的整个过程有个直观的了解。

调用树的分类

函数调用树有两类

1. 抽象调用树

也叫虚拟调用树。比如在源码中,父函数调用了子函数a, b, c。那么对这三个函数的调用逻辑都考虑进去,这就是“抽象调用”。抽象调用树能全面的描述了父函数的逻辑和代码开发员的意图。但是,在实际的环境中,这三 个函数未必就全部会调用到。把在实际的具体情况下未调用的“潜在”调用关系去掉后,剩下的调用树就称为“具体调用树”。明显,具体调用树不能全面显示代码 开发员的意图,只是放映具体环境下函数的调用关系。

2. 具体调用树

也叫实时调用树。解释见上。

调用树的显示

1. 抽象调用树的显示

借助source insight等工具可以图形显示抽象调用树。

1. 具体调用树的显示

据本人的了解,目前gdb没有一个类似”bt”那样的能显示函数调用树的命令,但是借助gdb宏也许能够实现显示调用树的功能,这有待研究。不过,目前已经有个现成的调试工具可以显示调用树,它就是 systemtap.

效果如下

见于

http://sourceware.org/systemtap/wiki/WSCallGraph?highlight=1)

调用树的拼接

对于一个更刁的函数调用来说,利用工具显示的抽象调用树和具体调用调用树可能是不完整的。比如,对于抽象调用树来说,它的显示工具是source insight。但是如果这个函数对某个子函数或在更下层的函数对下下层的函数调用是通过函数指针来调用的,那么source insight显示的调用树中就会漏掉通过函数指针调用的子函数,以及以子函数为根的子调用树。这是因为函数指针变量的赋值是发生在代码动态运行时的。 source insight无法利用静态的源码就捕捉到未来才出现东西,甚至它也无法在形式上解析出“那里存在一个利用函数指针的调用”。这就要通过阅读源码来找出这 种调用关系。同时,可以利用调试器实时找出具体情况下是通过那个函数指针调用了哪个特定的下层函数。这样就能把漏掉的子调用树拼接到父调用树中。

可见,这些内容又回归到了调用链的内容。具体看前面。

调用图

各函数间的像蜘蛛网一样的调用关系的图形表示就是调用图了,显然它比调用树更复杂。

本节意义:经过上面章节的叙述,利用源码交叉索引工具+调试器已经能解决大部分问题,但是因为调试器和交叉索引工具的各自局限性,依然会存在一些问题。本节尝试如何联合交叉索引工具以及调试器再加上人脑来解决各自的缺点。

[观察积累中,待扩展]

进程切换

中断异常

系统调用

函数指针

该小节内容移到了: 调用链的状态→函数指针调用

查看函数的参数

我们知道,一个函数的计算结果并不都是通过它的返回值返回的,有时会通过函数的参数返回真正感兴趣的数据。看内核源码的时候,如果调用链过长,涉及内容和数据结构过多的话,往往是看到最后都记不住函数的参数哪些是已经“初始化的”。

这也是交叉索引工具无法克服的先天弱点。它能动态索引源码,却无法动态查看数据。此时,可以利用gdb给目标函数下断点,而后可以用命令info args查看参数,另外命令info local可查看本地变量。当然在ddd下查看效果会更好。

内容简单,不展开了。

二叉断点

实例 “什么/proc下无法创建目录?”

给调用指令下断点

如果对目标函数下断点后,受到很多骚扰,那么就转为在上层函数内对目标函数的调用指令处下断点。如果你已经进入了上层函数,对调用指令下断点,是更为精确的断点方法。

绕过时钟中断的干扰

有时我们调试的程序与中断无关的,但是由于时钟中断的异步到来,在调试过程中经常会自动进入时钟中断处理例程中,这严重干扰了我们的工作。用下面的方法可绕过时钟中断的干扰。

使用GDB与QEMU调试内核时的问题分析:?http://www.chinaitlab.com/linux/kernel/356774.html

关于qemu在单步指令时进入时钟中断的问题,上面给出链接给出了比较“深入”地探讨。这个问题涉及虚拟机本身,有人说是虚拟机相对于真机的固有缺 陷,似乎很深奥,我没那个能力也没那个时间研究。但是我们应该知道,如果问题足够的复杂,以至于解决它要花费太高的代价,那么绕过这个问题是个更明智的解 决方法。

解决方法(手工)

1. 内核启动早期

事先下两个断点

自定义返回命令

一旦时钟中断产生,就会拦截在中断处理的通用入口common_interrupt,然后运行返回指令,就会“回到”被时钟中断打断的原指令处

2. 内核启动完毕

事先下两个断点

一旦时钟中断产生,就会拦截在中断处理例程apic_timer_interrupt,然后运行返回指令,就会“回到”被时钟中断打断的原指令处

[主要研究定位bug的技巧,找出是哪条指令引发了panic似乎很容易。但要找出错误产生的源头似乎是门艺术了

经过上面章节的叙述,本小节问题的解决已不成问题了。不再展开叙述。可以参考下面链接。

参考手册

“Using kgdb and the kgdb Internals”?http://www.kernel.org/pub/linux/kernel/people/jwessel/kgdb/index.html

kgdb官网?http://kgdb.linsyssoft.com/

参考书籍(freeebsd

“Debugging Kernel Problems”?http://www.google.cn/search?q=Debugging+Kernel+Problems&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:zh-CN:unofficial&client=firefox-a

“Chapter 10 Kernel Debugging”?http://www.freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/kerneldebug.html

参考书籍(linux)

Chapter 14. Kernel Debugging Techniques of “Embedded Linux Primer: A Practical, Real-World Approach”

http://book.opensourceproject.org.cn/embedded/embeddedprime/

参考文章

“掌握 Linux 调试技术”?http://www.ibm.com/developerworks/cn/linux/sdk/l-debug/index.html

“定位Oops的具体代码行”?http://blog.chinaunix.net/u/12592/showart_1092733.html

“跟踪内核 oops”?http://wiki.zh-kernel.org/doc/oops-tracing.txt

“例解Linux Kernel Debug”?http://blog.chinaunix.net/u/2108/showart_164703.html

“kernel debug的一些小手段”?http://blog.chinaunix.net/u/12592/showart_499502.html

“Kernel Debugging Techniques”?http://www.linuxjournal.com/article/9252

[参考文章]有的已过时,而且深度不够。

网站

http://bugzilla.kernel.org/

http://www.kerneloops.org/

http://www.lkml.org/?搜索bug

这部分的内容侧重于内核原理分析,其中涉及gdb调试器的内容不是很多,但它起的作用很关键,主要用于观察内核数据的生成及变化,在对源码理解有困惑时用 于验证自己的猜想。另外,gdb一个很重要的功能是,拦截通过函数指针调用的函数,从而追溯整个调用链,交叉索引工具无法做到这点。

另外,调试内核时,利用gdb的“list 函数名”命令看到的C代码都是当前处理器当前配置下内核实际运行的函数版本:”disass 函数名”看到的都是处理器实际运行时的机器代码,也就是说define语句和inline函数已经被编译器处理了,而且编译器也完成了优化。所以,gdb 本身就是一种不可替代的源码浏览工具,它能筛选掉出实际运行的函数版本,又能呈现出实际运行的机器码。

gdb远程串口协议

http://sourceware.org/gdb/current/onlinedocs/gdb_34.html#SEC706

http://www.huihoo.org/mirrors/pub/embed/document/debugger/ew_GDB_RSP.pdf

Jason Wessel的linux-2.6-kgdb.git

http://git.kernel.org/?p=linux/kernel/git/jwessel/linux-2.6-kgdb.git;a=summary

gdb调试模式

[分析一个简单的驱动,观察函数调用流程。重点观察驱动与驱动模型,以及和系统内核的交互过程。比如,中断的整个生命周期。

参考

“Debugging kernel modules”?http://lwn.net/Articles/90913/

“Linux 系统内核的调试”?http://www.ibm.com/developerworks/cn/linux/l-kdb/

“Linux 可加载内核模块剖析”?http://www.ibm.com/developerworks/cn/linux/l-lkm/

“使用 KGDB 调试 Linux 内核”?http://blog.chinaunix.net/u/8057/showart_1087126.html

“使用 /proc 文件系统来访问 Linux 内核的内容”?http://www.ibm.com/developerworks/cn/linux/l-proc.html

如何查找出当前系统所安装模块驱动对应的源码,从而对其做些修改等实验

提示

1. lsmod 列出模块名

2. modinfo 模块名, 查看模块信息

3. 模块名,模块信息中的别名,模块的参数说明文字都可结合source insight查找该模块的源码文件;模块信息中的模块路径也可用来定位对应源码的路径以及相关的kconfig文件,从而获取更多相关信息。一般源码文 件的名称就是模块名或在模块名的基础上加上某些后缀,用模块名的方法查找不出时再利用其他信息查找。

4. 如果利用以上方法还找不到源文件,或者一个模块对应着几个源文件,可使用最后的必杀绝招。比如lsmod后得到一个sr_mod。我们用modinfo sr_mod的得到它的已编译文件的路径是 /lib/modules/2.6.24-19-generic/kernel/drivers/scsi/sr_mod.ko ;把它拷贝出来,并用命令objdump -d sr_mod.ko 查看它的机器码,就可以知道它使用了哪些函数,利用这些函数名就可以结合source insight搜索出源码了。

首先,在虚拟系统上装入目标模块foo,然后到/sys/module/foo/sections/下查看目标模块的section偏移地址信息.

实例

然后,到真机的gdb下用add-symbol-file命令装载目标模块的符号信息 格式如下

实例

然后,余下的对模块的调试就类似对内核的调试了。

[从这节开始,侧重于利用kgdb和source insight理解内核原理] [网上好像没这个内容。只看源码的话,因为source insight不能解析汇编源文件,在汇编源码中定位到初始化的源头好像很难,利用调试器很容易做到这点

[待充实]

我们验证一下用户空间的内容(上图的下部分)[未完,待续] 引用于http://linux.chinaunix.net/bbs/viewthread.php?tid=978491

[扩展]

[结合source insight分析一个内核子系统的原理。源码分析工具虽好,但却是个死的东西,不能实时观察数据的生成和变化。如果在内核运行的时候,搭配调试器来分析,这个过程一定很形象和有趣

sysfs

hotplug

参考书籍

UNIX Filesystems Evolution, Design, and Implementation.pdf :

http://www.google.cn/search?q=UNIX+Filesystems+Evolution%2C+Design%2C+and+Implementation&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:zh-CN:unofficial&client=firefox-a

站点

Ext4 (and Ext2/Ext3) Wiki:?http://ext4.wiki.kernel.org/index.php/Main_Page

Ext4 Development project:?http://www.bullopensource.org/ext4/

ext2-devel maillist archive:?http://sourceforge.net/mailarchive/forum.php?forum=ext2-devel

参考文章

“Linux Filesystems in 21 days 45 minutes”?http://us1.samba.org/samba/ftp/cifs-cvs/ols2006-fs-tutorial-smf.pdf

  • 作用: strace能拦截和记录应用程序发起的系统调用和它收到的信号。主要用于观察应用层和内核层的交互。
  • 命令选项: 查看,$strace –help 或$man strace 或 $info strace
  • 实例
  • 作用: ltrace用于监控程序发起的库函数调用以及程序收到的信号。
  • 动态收集Linux内核信息和性能数据
  • 官方??http://sourceware.org/systemtap/
  • 参考文章

http://www.ibm.com/developerworks/cn/linux/l-cn-systemtap3/index.html

http://www.ibm.com/developerworks/cn/linux/l-systemtap/index.html

http://sourceware.org/systemtap/tutorial/

http://sourceware.org/systemtap/wiki

ubuntu下的配置安装:?http://sourceware.org/systemtap/wiki/SystemtapOnUbuntu

  • 作用: 跟踪程序中的内存泄漏和错误
  • 作用: 查找 C 和 C++ 中动态的、与内存分配有关的问题

内核文档 sysrq.txt

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=documentation/sysrq.txt;h=10a0263ebb3f01e832c7827cc75d7fe54b341a6f;hb=f8d56f1771e4867acc461146764b4feeb5245669

linux内核测试指南 相关章节

http://wiki.zh-kernel.org/#%E6%96%87%E7%AB%A0

如何参与 Linux 内核开发

http://wiki.zh-kernel.org/doc/howto

Linux内核代码风格

http://wiki.zh-kernel.org/doc/codingstyle

Linux内核开发邮件客户端资料

http://wiki.zh-kernel.org/doc/email-clients.txt

Linux内核补丁提交注意事项

http://wiki.zh-kernel.org/doc/linux%E5%86%85%E6%A0%B8%E8%A1%A5%E4%B8%81%E6%8F%90%E4%BA%A4%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9

基于git的Gentoo中文文档开发流程

http://www.gentoo-cn.org/doc/zh_cn/git-howto.xml

mutt配置使用

http://hi.baidu.com/springtty/blog/item/e6b25ddbb52f51ddb7fd4805.html

http://www.kongove.cn/blog/?p=149

http://www.kongove.cn/blog/?p=229

http://www.kongove.cn/blog/?p=225

说明:对于初学者,又是发单个补丁的话,本人推荐使用邮件客户端claws。它的优点是有线索成组的功能和草稿上有字数的标尺。本人感觉claws比 Sylpheed要快上几十倍。claws本来是Sylpheed的实验版,后来独立出来了。内核社区中使用的邮件客户端大多数是mutt(并不是专指发 补丁)。发补丁的所用工具也多种多样,有用各种邮件客户端的(mutt,claws,kmail...),有使用git-send-email的,还有使 用quilt的,真是打开眼界。

对于本人,发补丁用的工具目前在内核社区中是独一无二的,因为该工具是我自己写的)凡是用它发出的邮件,在邮件头会有个标志,比如:User- Agent: sniper-patch-carrier/1.06。无论单个还是多个补丁,都用它来发送,它的特点是够用简单又强大。源码在下小节中。

但下面的例子,还是使用claws发补丁的举例。

补丁的任务

过程

有很多此类工具,其中功能最强的是git-send-email.但本人还是自己动手丰衣足食,参照其他工具写了一个。perl学得不久,很没 perl的味道. 这个工具的优点是用perl自带的邮件引擎通过smtp.gmail.com(目前只支持gmail,其他没实验过)发送邮件,而不是通过 sendmail,mutt等第二方工具发送,省去了那些工具麻烦的设置过程。当然,最主要还是因为,自己写的东西可以随时改进,好玩。

使用

把下面的主程序复制到一个文本文件中,并把它命名为:sniperpatchcarrier.pl. 并写好另一个控制文件control。发送补丁时使用下面命令即可

控制文件的内容如下

说明,第一项(比如SMTP等)大小写都可,项目之间(比如To:和邮件地址)有无空格均可。邮件地址的用户名可有可无,没写明用户名时<> 符号可有可无。但为防止意外,还是建议照着下面的模版修改使用。注意,目前只支持gmail。要想支持其他邮箱,简单修改源码即可。

主程序

Git 中文教程

http://www.linuxsir.org/main/doc/git/gittutorcn.htm

git使用小结

http://wangcong.org/blog/?p=307

学习 Git

http://www.zeuux.org/science/learning-git.cn.html

内核git库

http://git.kernel.org/?p=linux/kernel/git

linus-git

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=summary

net

http://git.kernel.org/?p=linux/kernel/git/davem/net-2.6.git;a=summary

net-next

http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=summary

linux-next

http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git;a=summary

免费git库http://repo.or.cz/

综合类

“understanding the linux kernel”

”linux kernel development“

“linux源代码情景分析”

“Embedded.Linux.Primer.A.Practical.Real.World.Approach.”

“The_Linux_Kernel_Primer_A_Top_Down_Approach_For_x86_and_PowerPC_Architectures”

子系统类

文件系统

“UNIX Filesystems Evolution, Design, and Implementation”

“File System Forensic Analysis”

“Windows NT File System Internals”

内存管理

“Understanding The Linux Virtual Memory Manager”

网络系统

“The Linux? Networking Architecture: Design and Implementation of Network Protocols in the Linux Kernel”

“Understanding.Linux.Network.Internals”

The Linux TCP/IP Stack: Networking for Embedded Systems (2.6.0-test10)

网络协议

http://zh.wikipedia.org/wiki/%E7%BD%91%E7%BB%9C%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE

http://www.ietf.org/

通过编号查看?http://www.ietf.org/rfc.html

通过名称查询?http://www.rfc-editor.org/rfcsearch.html

Where and how to get new RFCs

TCP/IP详解中文版

http://220.113.41.171/cgi-bin/parker/search?String=TCP+IP+%E8%AF%A6%E8%A7%A3

TCP/IP详解 所用源码

4.4BSD-Lite.tar.gz

http://www.rcub.bg.ac.yu/~ggajic/pub/4.4BSD/

大侠文章

http://blog.chinaunix.net/u2/64681/article_86575.html

网络编程

Unix Network Programming Vol 1

Unix Network Programming Vol 2

Network_Programming_With_Perl

Linux Socket Programming By Example

网络教材

Computer Networks, Fourth Edition

驱动开发:

“linux device drivers”

“Essential.Linux.Device.Drivers”

源码本身及附带文档

其他操作系统的设计与实现

The Design and Implementation of the 4.4BSD Operating System

The Design and Implementation of the FreeBSD Operating System

Solaris Internals Solaris 10 and OpenSolaris Kernel Architecture

* MM

http://linux-mm.org/

* USB

http://www.linux-usb.org/

http://www.usb.org/home

* MTD

http://www.linux-mtd.infradead.org/

* ARM

http://www.arm.linux.org.uk/

* uclinux

http://www.uclinux.org/

* NET:

http://www.linuxfoundation.org/en/Net

wireless

http://linuxwireless.org/

IPsec

http://www.ipsec-howto.org/

netfilter

http://netfilter.org/

Linux Advanced Routing & Traffic Control

http://lartc.org/

frame Diverter

http://diverter.sourceforge.net/

网络工具源码

iputils

$ apt-get source iputils

net-tools

$ apt-get source net-tools

Iproute2

http://www.linuxfoundation.org/en/Net:Iproute2

* FS:

List of file systems

http://en.wikipedia.org/wiki/List_of_file_systems

ext4

http://sourceforge.net/mailarchive/forum.php?forum=ext2-devel

http://www.bullopensource.org/ext4/

http://ext4.wiki.kernel.org/index.php/Main_Page

btrfs

http://btrfs.wiki.kernel.org/index.php/Project_ideas

coda

http://www.coda.cs.cmu.edu/

nfs

http://wiki.linux-nfs.org/wiki/index.php/Main_Page

yaffs

http://www.yaffs.net/

jffs

http://sourceware.org/jffs2/jffs2-html/

logfs

http://www.logfs.org/logfs/

ubifs

http://www.linux-mtd.infradead.org/doc/ubifs.html

* 其他:

U-Boot

http://www.denx.de/wiki/U-Boot

http://sourceforge.net/projects/u-boot/

udev

http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html

busybox

http://www.busybox.net/

skyeye

http://www.skyeye.org/index.shtml

IBM-Linux 相关专题?http://www.ibm.com/developerworks/cn/linux/?“Debugging Kernel Modules with User Mode Linux”

http://www.linuxjournal.com/article/5749

“Debugging Memory on Linux”?http://www.linuxjournal.com/article/4681

“DDD—Data Display Debugger”?http://www.linuxjournal.com/article/2315

“Linux 系统内核的调试”?http://www.ibm.com/developerworks/cn/linux/l-kdb/

System Dump和Core Dump的区别?http://hi.baidu.com/iruler/blog/item/c203de3522ff398ea61e122c.html

http://www.linuxjournal.com/user/800887/track

http://www.linuxjournal.com/?http://www.ibm.com/developerworks/cn/linux/l-devmapper/index.html

read 系统调用剖析?http://www.ibm.com/developerworks/cn/linux/l-cn-read/index.html

http://blog.chinaunix.net/u/4206/showart_501237.html

http://hi.baidu.com/linux%5Fkernel/blog/category/pci%C9%E8%B1%B8%C7%FD%B6%AF

http://wiki.jk2410.org/wiki/Main_Page

http://www.ibm.com/developerworks/cn/linux/l-cn-clocks/index.html

利用Vmware5.5.1 和 kgdb调试 x86平台的kernel

http://blog.chinaunix.net/u/22617/showart_338509.html

Welcome to Linux From Scratch

http://www.linuxfromscratch.org/

Unreliable Guide To Locking

http://www.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/index.html

How do I printk <type> correctly?

http://lkml.org/lkml/2008/10/23/132

http://www.ibm.com/developerworks/cn/linux/l-linux-networking-stack/

KernelJanitors/Todo

http://kernelnewbies.org/KernelJanitors/Todo

sparse主页

http://www.kernel.org/pub/linux/kernel/people/josh/sparse/

http://linux.bkbits.net:8080/linux-2.6/search/?PAGE=search&EXPR=sparse&SEARCH=ChangeSet+comments

Coccinelle - a framework for Linux Device Driver Evolution

http://www.emn.fr/x-info/coccinelle/

linux论文?http://www.linuxsymposium.org

www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf

www.linuxsymposium.org/2006/linuxsymposium_procv1.pdf

understanding the linux kernel 在线文档

http://www.linux-security.cn/ebooks/ulk3-html/

Data Structures and Algorithms with Object-Oriented Design Patterns in C++/Java/C#/Python/Ruby/Lua/Perl/PHP

http://www.brpreiss.com/books/opus4/

ftp://ftp.akaedu.org/https://www.ngui.cc/1.html

ftp://ftp.freebsd.org/

http://bsd.org/

http://www.micrium.com/

http://v1.moblin.org/index.php

http://moblin.org/

http://www.linuxdriver.cn/

Integrating Flexible Support for Security Policies into the Linux Operating System

http://www.nsa.gov/selinux/papers/slinux/slinux.html

sendpatchset 的地址

http://google.com/codesearch?hl=en&q=show:UIY7Kd7jXdU:OMvU_Vh8FvE:EkVrWPVcX9w&sa=N&ct=rd&cs_p=http://www.speakeasy.net&cs_f=~pj99/sgi/sendpatchset

http://pleac.sourceforge.net/pleac_perl/index.html

http://search.cpan.org/~fayland/Email-Send-SMTP-TLS-0.02/lib/Email/Send/SMTP/TLS.pm#___top

http://www.61dh.com/blog/2008/10/perl_27.html

http://blog.chinaunix.net/u2/77776/showart_1227451.html

剑桥辞典?http://dictionary.cambridge.org/

http://www.merriam-webster.com/

http://dictionary.reference.com/

http://www.thefreedictionary.com/

http://people.freebsd.org/~murray/bsd_flier.html

http://s3c24xx.wiki.zoho.com/

http://bobzhang.wiki.zoho.com/

http://code.google.com/p/root-kit/

免费git库http://repo.or.cz/

本文地址:http://xasic.gawce.com/news/4666.html    阁恬下 http://xasic.gawce.com/ , 查看更多
 
 
更多>同类行业资讯
0相关评论

新闻列表
企业新闻
推荐企业新闻
推荐图文
推荐行业资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2023001713号