当然,我对很多计算机课程的认识,原来都是基本停留在书本上面。不管是计算机网络、编译原理还是人机界面,书本上的知识点虽然大概也知道些,但是你要说理解得有多透彻却说不上来。等到自己真正阅读了lwip、lua和ftk的相关代码,你才会大呼一声,原来是这么回事,好像也不是很复杂。所以,对于计算机的知识,要想把自己的认识提高一个层次的话,最好的方法就是实践。
在国内,喜欢研究linux的人很多,但是大多数朋友对linux kenel的理解只是停留在书本上面、视频上面以及ppt上面。真正自己动手做实验、把每一行代码都弄懂弄明白的朋友却不是那么多。其实,和以前相比,现在的linux版本更多、也更稳定,资源也特别丰富。就我个人认为,linux系统是学习计算机最好的系统。因为在这么一个系统上面,没有人帮你,很多的困惑都需要自己去解决,只有去克服一个一个难点,你才能感受到自己确实实在进步。这种进步不是停留在学会了某种配置、安装了某种软件、熟悉了某种环境,而在于你对系统本身的认识更高了,看问题的角度发生改变了。
在书店里面,介绍linux基本软件开发的书特别多,但是却有很少的书介绍如何在linux进行kernel的学习、编译、调试,哪些调试工具比较合适等等。他们做的就是直接把答案告诉你,至于为什么这样设计,交代的内容却很少。一方面这方面的需求比较少,另外一方面这些知识点有点难度,不易被大家接受。实际上,这里大家存在一个误区,现在的linux kernel开发其实不是那么难,你所需要的其实就是一个pc、一根网线,这样你就获得了学习的全部资源。下面内容主要是介绍给大家如何学习linux kernel,特别是如何在实践中学习。
(1)选择一个合适linux发行版本,我自身选用的版本是CentOS 6,使用非常方便
(2)从www.kernel.org下载kernel代码,学习如何编译linux 内核,其实步骤也不复杂
a)解压linux内核版本
b)cd linux目录
c)cp /boot/config-2.6.32-220.el6.i686 .config
d) make menuconfig
e)保存,直接exit退出
f)make bzImage
g) make modules
h) make modules_install
i) make install
(3) 重启电脑,开机选用新的linux 内核。开始编写hello.c文件,生成模块,利用模块与linux内核函数进行互动,用dmesg -c查看打印
#include <linux/module.h> #include <linux/init.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("feixiaoxing"); MODULE_DESCRIPTION("This is just a hello module!\n"); static int __init hello_init(void) { printk(KERN_EMERG "hello, init\n"); dump_stack(); return 0; } static void __exit hello_exit(void) { printk(KERN_EMERG "hello, exit\n"); } module_init(hello_init); module_exit(hello_exit);
(4)安装elfutils-devel,systemtap安装包,用stap -v *.stp开始分析内核。你要做的就是插入调试点,编写脚本文件,自由分析内核的代码内容,
a)基础打印
probe begin{ printf("hello begin!\n") } probe end{ printf("hello end!\n") }
global number probe begin { number = 0 } probe timer.ms(5000) { number ++ printf ("%d\n", number) } probe end { number = 0 }
global syscalls function print_top () { cnt = 0 log ("SYSCALL\t\t\tCOUNT") foreach ([name] in syscalls-) { printf("%-20s %5d\n",name, syscalls[name]) if (cnt++ == 20) break } printf("--------------------------------------\n") delete syscalls } probe kernel.function("sys_*") { syscalls[probefunc()]++ } # print top syscalls every 5 seconds probe timer.ms(5000) { print_top () }
d)统计schedule函数被调用的次数
global count probe kernel.function("schedule") { count ++ } probe begin{ count = 0 } probe end{ printf("count = %d\n", count); }
e)打印回调堆栈
global count probe kernel.function("schedule").return { if(!count) print_backtrace() count ++ } probe begin{ count = 0 } probe end{ }
f)记录一次进程切换
global count probe begin { count = 0 } probe kernel.function("__switch_to") { if(!count) { printf("from [%s] to [%s]\n", task_execname($prev_p), task_execname($next_p)) } exit() } probe end { }
更多关于systemtap的范例,可以参考《systemtap language reference》这本手册。