本文共 13897 字,大约阅读时间需要 46 分钟。
Ø
1 、掌握printk 的使用、设置及实现原理,理解分级别进行打印log 信息的实现方法
2 、掌握如何分析oops 的方法
3 、掌握strace 工具的移植和使用方法
Ø
1 、请回顾栈的工作原理,尤其是栈帧的作用
2 、请对照printk 的源代码来进行printk 相关实验,并在实验中进一步理解源代码
Ø
一. Printk 实验 。
1 、在内核中编写自己的printk 代码,可利用上次系统调用实验中已有的代码,也可利用之前驱动实验中的模块。
2 、在根文件系统中增加/proc 目录,用来挂载proc 文件系统
3 、重新烧录uImage (如果有所改动的话)和根文件系统,进入控制台之后,输入命令挂载proc 文件系统:mount – t proc none /proc 。
如果挂载成功, /proc 目录应该可以看到文件,比如下面的结果:
# ls proc
1
100
101
102
103
2
3
4
5
6
60
65
71
737
4 、检查并修改printk 的log 级别,比如下面的命令:
# cat /proc/sys/kernel/printk 7
修改之后,默认的printk 打印(级别为4 )不会显示到串口终端,但仍可以通过“ cat /proc/kmsg ”看到打印结果。
5 、通过代码和 /proc/sys/kernel/printk 分别修改log 级别,并对应printk 的源代码来分析结果。
二.C 语言可变参数实验
1 、在内核代码kernel/printk.c 中的printk 函数用到了C 语言中的可变参数的用法。请参考下面的代码来学习如何使用可变参数。以下代码可直接在x86 环境测试:
#include <stdio.h>
typedef char *va_list;
#define
#define
#define _bnd(X, bnd)
#define va_arg(ap, T)
#define va_end(ap)
#define va_start(ap, A)
int max ( int num, ... )
{
}
int main ( int argc, char* argv[] )
{
}
2 、自己动手 分析上面代码可变参数的用法及实现方式。提示:va_start ( ap, num ) 是为了取得可变参数在栈中的位置,该宏展开执行后,ap 将指向第一个可变参数。可利用GDB 和汇编代码协助分析。
3 、ARM 架构中通常使用寄存器而不是栈来传递参数,那么,上述可变参数的方式能够用于ARM 架构中吗?请想办法找到证据 来支持你的猜测。
三. Oops 实验 。
1 、在上次系统调用实验的代码中,人为的制造产生oops 的条件,比如下面的改动:
asmlinkage long sys_mytest()
{
printk("pid: %d:\tThis is my call.\n",current->pid);
*(int *)0 = 0;
}
2 、从串口终端得到所产生的oops 消息,并进行初步分析
3 、在内核代码中,利用arm-linux-objdump 得到kernel/sys.o 的汇编代码,对照汇编代码进行分析
4 、arm-linux-addr2line 工具可用来寻找代码地址所对应的c 代码(),可尝试:
arm-linux-addr2line – e sys.o 0xnnnn( 你出错的代码地址)
(1) 在kernel/sys.c 文件里
#arm-linux-gcc – c sys.o sys.c( 生成汇编文件)
#vim sys.o
寻找:sys_mytest
找到地址是:000000b0
而通过下面Oops 信息知道:PC is at sys_mytest+0x28/0x34
则0xnnnn( 代码出错的地址)=000000b0+0x28=0xd8
(2) # arm-linux-addr2line – e sys.o 0xd8
结果输出是137 行
则查出出错的地方在sys.c 中的137 行。
5 、下面是我实验中遇到的oops ,请尝试做一些初步分析:
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c3eb0000
[00000000] *pgd=33ddd031, *pte=00000000, *ppte=00000000
Internal error: Oops: 817 [#1]
Modules linked in:
CPU: 0
PC is at sys_mytest+0x28/0x34 (表示在sys_mytest+0x28 至sys_mytest+0x34 之间,以4 个字节为一个单位)
LR is at 0xc031781c
pc : [<c00561ec>]
sp : c3ec3f98
r10: 00008528
r7 : 00000161
r3 : 80000013
Flags: nZCv
Control: 0000717f
Process syscall_test (pid: 777, stack limit = 0xc3ec2260)
Stack: (0xc3ec3f98 to 0xc3ec4000)
3f80:
3fa0: c002c9e0 c00561d4 00000000 beeced1c 00000161 beecef14 beecef1c 0000000a
3fc0: 0000000a 00000000 beeced1c 00000001 beecef14 000081c4 00008528 beeced18
3fe0: beeced08 beececfc 000081e8 0000f8e0 60000010 00000161 7bf2fafd eff7fbbd
Backtrace:
[<c00561c4>] (sys_mytest+0x0/0x34) from [<c002c9e0>] (ret_fast_syscall+0x0/0x2c)
Code: e59f0010 e59310d8 ebffcf47 e3a00000 (e5800000)
---[ end trace e5388d99d2481600 ]---
四. Strace 实验 。
1 、从www.sourceforge.net 上下载strace 的源代码
2 、配置并编译strace :
./configure --host=arm-linux
make
3 .将strace 工具加入到你的根文件系统中,并测试使用它