快速查找内核源代码脚本

              学习Linux驱动时,经常要和内核API打交道。可能讲解Linux驱动的书籍会说明某某函数包含在某某头文件里,但是当要刻意去查找调用某个函数应该包含哪个文件时,却怎么也找不找。再者,如果想要查看某个函数的源代码,却不知从哪找起,不知道在哪个.c文件里。而Linux驱动书上也不一定能找到答案。进入内核源码文件夹,grep一下,噼里啪啦地在终端里打印一大堆信息,还得去粗取精,也挺麻烦的。到在线阅读Linux源代码之类的网站去查找,也不一定方便。ctags工具也不一定能准确锁定到要查找的函数的位置。

       据此,写了个shell脚本,以实现快速查找内核函数、内核数据结构、宏定义等。


       不过,要借助ctags工具生成tags文件。所以,首先得先安装ctags工具。

       在命令行上输入如下命令:

$ sudo apt-get install ctags

然后进入内核源代码目录下,如

$ cd /home/john/Kernel/linux-2.6.35.7

然后,输入如下命令:

$ ctags -R .

经过一段时间的等待后,tags文件生成完毕。

然后保存如下脚本为ksearch.sh。


#! /bin/sh


KERNEL="/home/john/Kernel/linux-2.6.35.7"
INCLUDE="$KERNEL/include"
INCLUDE_LINUX="$INCLUDE/linux"
TAGS="$KERNEL/tags"

TARGET=$1
TYPE=$2

FLAG=0

if [ "$TYPE" = "s" -o "$TYPE" = "struct" ]
then
	EXP="struct $TARGET {"
	FLAG=1

elif [ "$TYPE" = "m" -o  "$TYPE" = "macro" ]
then
	EXP="^\<$TARGET\>"
	FLAG=2

elif [ "$TYPE" = "f" -o  "$TYPE" = "func" ]
then
	EXP="\<$TARGET\>([[:alpha:]]"
	FLAG=3

elif [ "$TYPE" = "t" -o  "$TYPE" = "typedef" ]
then
	EXP="\<$TARGET\>;"
	FILE_PATH=`grep -nrs "$EXP" $INCLUDE_LINUX | awk -F"\n" '{print $1}'`

	if [ -z "$FILE_PATH" ]; then
		FILE_PATH=`grep -nrs "$EXP" $INCLUDE | awk -F"\n" '{print $1}'`
	fi

	if [ -z "$FILE_PATH" ]; then
		exit 1
	fi

	FILE_PATH=`echo $FILE_PATH | awk -F":" '{print $1 " +" $2}'`
	vi $FILE_PATH
	echo ">>Include:"
	echo "$FILE_PATH"

	exit 1

else
	echo "Usage: $PROGRAM <target> <type>"
	echo ">>type: s|struct; m|macro; f|func; t|typedef"
	exit 1
fi

echo "+-----------------------------------------------------------------------+"

# 分析tags文件,以获得欲查找内容所在的文件路径
RECORD=`grep -nrs "$EXP" $TAGS | awk -F"\n" '{print $1}'`
FILE=`echo $RECORD | awk -F" " '{print $2}'`
#echo "RECORD: $RECORD"
#echo "FILE: $FILE"

# 拼接成绝对路径
FILE_PATH=$KERNEL/$FILE
echo ">>FILE_PATH: "
echo "$FILE_PATH"

# 此时已经锁定到了具体文件
# 构造正则表达式并模式匹配,锁定到具体行
if [ $FLAG -eq 1 ]	#TYPE=struct
then
	EXP="^struct $TARGET {"
	LINE=`grep -nsr "$EXP" $FILE_PATH | awk -F":" '{print $1}'`

elif [ $FLAG -eq 2 ]	#TYPE=macro
then
	EXP="^#[[:space:]]*define \<$TARGET\>"
	LINE=`grep -nsr "$EXP" $FILE_PATH | awk -F":" '{print $1}'`

elif [ $FLAG -eq 3 ]	#TYPE=func
then
	# 获得函数原型
	PROTOTYPE=`echo $RECORD | awk -F"^" '{print $2}' | awk -F"$" '{print $1}'`
	echo "+---------------------------------------------------------+"
	echo ">>Function Prototype:"
	echo "$PROTOTYPE"

	EXP="[[:alpha:]]+[[:space:]]+\**\<$TARGET\>\([[:alpha:]]"
	LINE=`grep -E -nsr "$EXP" $FILE_PATH | awk -F":" '{print $1}'`

	# 解决形如
	# extern inline long
	# copy_to_user(void __user *to, const void *from, long n)
	# 将返回类型和函数名分行的函数声明
	if [ -z "$LINE" ]; then
		TMP="^\<$TARGET\>\([[:alpha:]]"
		LINE=`grep -E -nsr "$TMP" $FILE_PATH | awk -F":" '{print $1}'`
	fi

fi

LINE=`echo $LINE | awk -F" " '{print $1}'`
#echo ">>LINE: $LINE"

vi $FILE_PATH +$LINE

# 函数所在的头文件的绝对路径
if [ $FLAG -eq 3 ]	# TYPE=func;
then
	echo "+---------------------------------------------------------+"

	echo ">>Include:"

	HEAD_EXP=$EXP		

	# 在KERNEL/include/linux目录下查找
	HEADER=`grep -E -nrs "$HEAD_EXP" $INCLUDE_LINUX`

	# 在KERNEL/include/linux目录下未找到
	# 则在KERNEL/include目录下查找
	if [ -z "$HEADER" ]; then
		HEADER=`grep -E -nrs "$HEAD_EXP" $INCLUDE`
	fi

	#echo "$HEADER"
	HEADER=`echo "$HEADER" | awk -F"\n" '{printf $1}'`
	HEADER=`echo "$HEADER" | awk -F":" '{print $1 " +" $2}'`
	echo "$HEADER"
fi

echo "+-----------------------------------------------------------------------+"


需要给这个脚本一个可执行权限,命令如下:

$ chmod +x ksearch.sh

不过,有一点要注意,脚本开头的KERNEL要改为你自己的内核所在的文件夹的绝对路径。


现在来看看此脚本如何使用。

如果要查找内核数据结构,比如sk_buff结构体,在命令行上输入:

$ ./ksearch.sh sk_buff s

或者 $ ./ksearch.sh sk_buff struct

按回车,vi编辑器立马就会打开sk_buff所在的文件,并把光标定在sk_buff所在行。

而退出vi编辑器后,发现命令行打印了一些信息,这就是sk_buff所在文件的绝对路径。

如果要查找宏定义,比如MKDEV,在命令行上输入:

$ ./ksearch.sh MKDEV m

或者 $ ./ksearch.sh MKDEV macro

按回车,vi编辑器立马就会打开MKDEV所在的文件,并把光标定在MKDEV所在行。

而退出vi编辑器后,发现命令行也打印了一些信息,其实就是MKDEV所在文件的绝对路径。

如果查找的是typedef类型定义,如irqreturn_t,在命令行输入:

$ ./ksearch.sh irqreturn_t t

或者 $ ./ksearch.sh irqreturn_t typedef

按回车,vi编辑器会打开irqreturn_t所在的文件,并把光标定在irqreturn_t所在行。

退出vi编辑器后,命令行上打印的是包含irqreturn_t的头文件的绝对路径。

如果查找的是函数,如函数i2c_add_adapter(),在命令行输入:

$ ./ksearch.sh i2c_add_adapter f

或者 $ ./ksearch.sh i2c_add_adapter func

也能达到预期的效果,退出vi后,可以看到终端上输出有函数所在文件的绝对路径、函数原型、包含函数的头文件的绝对路径。如图所示:


图中424表示函数i2c_add_adapter在i2c.h的424行,如果想查看头文件,只需输入vi,然后粘帖424所在的整行,即

$ vi /home/john/Kernel/linux-2.6.35.7/include/linux/i2c.h +424

就可以打开vi,并且光标定位在函数i2c_add_adapter所在行处。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值