Board logo

标题: 内核调试的方法(3) [打印本页]

作者: yuyang911220    时间: 2017-5-15 11:16     标题: 内核调试的方法(3)

sp : c3e69e88  ip : c3e69e98  fp : c3e69e94
r10: 00000000  r9 : c3e68000  r8 : c0490620
r7 : 00000000  r6 : 00000000  r5 : c3e320a0  r4 : c06a8300
r3 : bf000000  r2 : 56000050  r1 : bf000964  r0 : 00000000
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  Segment user
Control: c000717f  Table: 33e78000  DAC: 00000015
Process firstdrvtest (pid: 752, stack limit = 0xc3e68258)

可以仅根据栈信息,来确定函数的调用关系。栈就是一块内存
分析如下 :
Stack: (0xc3e69e88 to 0xc3e6a000)
9e80:                   c3e69ebc c3e69e98 c008c888 bf000010 00000000 c0490620
fp         ip   返回地址=lr   pc
栈信息开始部分的4个数据 是first_drv_open 的 栈                chrdev_open is sp
first_drv_open执行完之后,返回地址lr=c008c888,再在 vmlinux.dis 中找到 调用者的函数。
4个数据后面的数据,就是它的调用者的函数的栈空间中的数据。
9ea0: c3e320a0 c008c73c c0465e20 c3e36cb4 c3e69ee4 c3e69ec0 c0088e48 c008c74c
                                                            lr=c0088e48      
                                                                                 
9ec0: c0490620 c3e69f04 00000003 ffffff9c c002b044 c06e0000 c3e69efc c3e69ee8
      __dentry_open 的栈

9ee0: c0088f64 c0088d58 00000000 00000002 c3e69f68 c3e69f00 c0088fb8 c0088f40
      lr=c0088f64       nameidata_to_filp的栈               lr=c0088fb8
      
9f00: c3e69f04 c3e36cb4 c0465e20 00000000 00000000 c3e79000 00000101 00000001
      do_filp_open的栈

9f20: 00000000 c3e68000 c04c1468 c04c1460 ffffffe8 c06e0000 c3e69f68 c3e69f48
9f40: c008916c c009ec70 00000003 00000000 c0490620 00000002 be94eee0 c3e69f94
9f60: c3e69f6c c00892f4 c0088f88 00008520 be94eed4 0000860c 00008670 00000005
               lr=c00892f4       do_sys_open的栈

9f80: c002b044 4013365c c3e69fa4 c3e69f98 c00893a8 c00892b0 00000000 c3e69fa8
                                          lr=c00893a8       sys_open的栈

9fa0: c002aea0 c0089394 be94eed4 0000860c 00008720 00000002 be94eee0 00000001
      lc=002aea0        ret_fast_syscall的栈
                        
9fc0: be94eed4 0000860c 00008670 00000002 00008520 00000000 4013365c be94eea8
9fe0: 00000000 be94ee84 0000266c 400c98e0 60000010 00008720 00000000 00000000
ret_fast_syscall()函数是被谁调用的,我们这里还不需要详细了解,只要知道是应用程序是通过swi中断来加入内核的。
注意 : 上面的信息,从下往上,从大地址到小地址方向。是从栈底开始,往栈顶方向打印栈中的值。也是函数调用的方向。
三. 修改内核来定位系统僵死问题
1,\kernel-2.6.13\arch\arm\kernel\irq.c  //修改这个内核文件
修改这个文件的原因 : 只要系统还在运行,即使某个驱动程序卡死了,系统时钟中断是绝对不会停歇的。
                 所以,可以在系统中断代码中加入一些调试代码,来帮助我们找到bug。
/*
* do_IRQ handles all hardware IRQ's.  Decoded IRQs should not
* come via this function.  Instead, they should provide their
* own 'handler'
*/
asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct irqdesc *desc = irq_desc + irq;

static pid_t pre_pid;
static int count = 0;

/*
* Some hardware gives randomly wrong interrupts.  Rather
* than crashing, do something sensible.
*/
if (irq >= NR_IRQS)
desc = &bad_irq_desc;
if(irq == 30) /*系统时钟中断*/
{
/*如果10秒之内,都是同一个进程在运行,就打印卡死信息。*/

/*静态局部变量:
只有在这个函数中能访问,但是生命周期是和全局变量差不多的,函数退出之后变量还在,
而且只在第一次进入的时候做初始化,以后会跳过初始化语句,保留原来的值*/
if(pre_pid == current->pid) /*当前进程 等于 之前记录下来的进程号*/
{
count++;
}
else /*当前进程 不等于 之前记录下来的进程号*/
{
count = 0;
pre_pid = current->pid; /*把新的当前进程记录下来。*/
}
if(count == 10*HZ) /*累计达到10秒的时候*/
{
count = 0;
/*明确是在哪个进程导致卡死的,明确PC值*/
printk("asm_do_IRQ==>s3c2410_timer_interrupt : pid=[%d], task_name=[%s], PC=[0x%08x]\n", current->pid, current->comm, regs->ARM_pc);
}
}

irq_enter();
spin_lock(&irq_controller_lock);
desc->handle(irq, desc, regs);

/*
* Now re-run any pending interrupts.
*/
if (!list_empty(&irq_pending))
do_pending_irqs(regs);

irq_finish(irq);

spin_unlock(&irq_controller_lock);
irq_exit();
}

重新编译内核 make clean;make
重新启动这个新的内核


2, 在这个驱动文件中加入死循环,来模拟系统僵死问题 \nfs_2.6.13\wxc\driver\chardriver\led\leddriver2.c
static int leddriver2_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
//printk("DEVICE:mydriver2_ioctl Called!\n");
printk("DEVICE:cmd=[%d], arg=[%ld]\n", cmd, arg);
while(1);  //故意加的
if(cmd == 0) //所有的灯全亮2s
{
....
}
return 0;
}

启动待测试的驱动程序
# insmod leddriver2.ko
[kernel/sys.c][notifier_call_chain][175]
[kernel/sys.c][notifier_call_chain][187]
DEVICE:leddriver2_init
DEVICE:register leddriver2 OK! Major = [253]
# mknod /dev/leddriver2 c 253 0
[root@EmbedSky ko]# ls -lrt /dev/led*
crw-r--r--    1 root     root     253,   0 Jan  1 00:03 /dev/leddriver2

启动应用程序
# ./leddrivertest2 0 3
APPpen fd=[3]
APP:led_no=[0] time=[3]
DEVICE:cmd=[0], arg=[3]  //会发现驱动程序卡死在这里了,无论怎么也退出不了,下面打印出来了很多关键信息。
asm_do_IRQ==>s3c2410_timer_interrupt : pid=[806], task_name=[leddrivertest2], PC=[0xbf000044]
asm_do_IRQ==>s3c2410_timer_interrupt : pid=[806], task_name=[leddrivertest2], PC=[0xbf000044]
PC=0xbf000044




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0