linux内核定时器异常,linux内核调试技术之修改内核定时器来定位系统僵死问题...

# cat /proc/interrupts

CPU030: 8316 s3c S3C2410 Timer Tick -----> 系统时钟33: 0 s3c s3c-mci34: 0s3c I2SSDI35: 0s3c I2SSDO37: 12 s3c s3c-mci42: 0s3c ohci_hcd:usb143: 0 s3c s3c2440-i2c51: 1047 s3c-ext eth060: 0 s3c-ext s3c-mci70: 16 s3c-uart0 s3c2440-uart71: 26 s3c-uart0 s3c2440-uart79: 8 s3c-adc s3c2410_action80: 1732 s3c-adc s3c2410_action83: 0 - s3c2410-wdt

Err:0#

30: 8316 s3c S3C2410 Timer Tick 这个就是系统时钟,中断号为30

1.2、在内核代码中搜索"S3C2410 Timer Tick"字样。

在Time.c (archarmplat-s3c24xx)文件中有如下代码。

static struct irqaction s3c2410_timer_irq ={

.name= "S3C2410 Timer Tick",

.flags= IRQF_DISABLED | IRQF_TIMER |IRQF_IRQPOLL,

.handler=s3c2410_timer_interrupt,

};/** IRQ handler for the timer*/

staticirqreturn_t

s3c2410_timer_interrupt(int irq, void *dev_id)

{#if 1

static pid_t pre_pid;

static int cnt=0;

//时钟中断的中断号是30

if(irq==30)

{

if(pre_pid==current->pid)

{

cnt++;

}

else

{

cnt=0;

pre_pid=current->pid;

}

//如果本进程十秒钟还没有离开的话,就会打印下面的语句

if(cnt==10*HZ)

{

cnt=0;

printk("s3c2410_timer_interrupt : pid = %d, task_name = %s

",current->pid,current->comm);

}

}#endifwrite_seqlock(&xtime_lock);

timer_tick();

write_sequnlock(&xtime_lock);returnIRQ_HANDLED;

}

①、每个进程都有一个结构task_struct用来存储进程的一些状态信息。current是一个宏,表示当前进程的信息,也就是一个task_struct结构体,所以current->pid为当前进程的pid号,current->comm表示当前进程的name。

②、HZ也是一个宏定于,表示1s需要多少次中断。10*HZ表示就就是10s需要多少次中断!

2、测试

编译内核:#make uImage

加载一个带有while(1);的驱动程序,系统发送僵死,系统会打印如下信息:

# insmod first_drv.ko

# ./firstdrvtest on

s3c2410_timer_interrupt : pid= 770, task_name =firstdrvtest

s3c2410_timer_interrupt : pid= 770, task_name = firstdrvtest

根据上述信息可知,发送僵死的进程号为:770,发送僵死的进程名称为:firstdrvtest

3、继续完善,增加PC值,更加详细的定位僵死的地方

我们知道,当中断发送的时候,在汇编中会调用asm_do_irq函数,

.macro irq_handler

get_irqnr_preamble r5, lr1: get_irqnr_and_base r0, r6, r5, lr

movne r1, sp

@

@ routine called with r0= irq number, r1 = struct pt_regs *@

adrne lr, 1b

bne asm_do_IRQ #调用C语言的函数

asm_do_IRQ 函数原型:

asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)

{ staticpid_t pre_pid;static int cnt=0;struct pt_regs *old_regs =set_irq_regs(regs);struct irq_desc *desc = irq_desc +irq;/** Some hardware gives randomly wrong interrupts. Rather

* than crashing, do something sensible.*/

if (irq >=NR_IRQS)

desc= &bad_irq_desc;

irq_enter();

desc_handle_irq(irq, desc);/*AT91 specific workaround*/irq_finish(irq);

irq_exit();

set_irq_regs(old_regs);

}

asm_do_IRQ这个函数,在这个函数里面我们发现了一个结构体:struct pt_regs,这个结构体就用来保存发生中断时的现场,其中PC值就是:ARM_pc

我们将上面在:s3c2410_timer_interrupt里面加入的信息都删除,并在:asm_do_IRQ函数里面加修改后改函数为:(红色为添加的程序)

asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)

{#if 1

static pid_t pre_pid;

static int cnt=0;

//时钟中断的中断号是30

if(irq==30)

{

if(pre_pid==current->pid)

{

cnt++;

}

else

{

cnt=0;

pre_pid=current->pid;

}

if(cnt==10*HZ)

{

cnt=0;

printk("s3c2410_timer_interrupt : pid = %d, task_name = %s

",current->pid,current->comm);

printk("pc = %08x

",regs->ARM_pc);//打印pc值

}

}#endif

staticpid_t pre_pid;static int cnt=0;struct pt_regs *old_regs =set_irq_regs(regs);struct irq_desc *desc = irq_desc +irq;/** Some hardware gives randomly wrong interrupts. Rather

* than crashing, do something sensible.*/

if (irq >=NR_IRQS)

desc= &bad_irq_desc;

irq_enter();

desc_handle_irq(irq, desc);/*AT91 specific workaround*/irq_finish(irq);

irq_exit();

set_irq_regs(old_regs);

}

4、测试:

# insmod first_drv.ko

# ./firstdrvtest on

s3c2410_timer_interrupt : pid= 771, task_name = firstdrvtest

pc = bf000084

4.1、查看内核中内核函数、加载的函数的地址

#cat /proc/kallsyms > /kallsyms.txt

找到pc地址为bf000084附近的函数:

....................................00000000a first_drv.c [first_drv]

bf000088 t first_drv_init [first_drv]

bf000140 t first_drv_exit [first_drv]

c48761cc?__mod_license87 [first_drv]

bf000940 b $d [first_drv]

bf000740 d first_drv_fops [first_drv]

bf000740 d $d [first_drv]

bf00003c t first_drv_write [first_drv]  #大概就在这个函数里面,可以确定僵死的地方在

bf000000 t first_drv_open  [first_drv]

bf000000 t $a [first_drv]

bf000038 t $d [first_drv]

bf00003c t $a [first_drv]

bf000114 t $d [first_drv]

bf00094c b firstdrv_class [first_drv]

bf000950 b firstdrv_class_dev [first_drv]

bf000140 t $a [first_drv]

bf000184 t $d [first_drv]00000000a first_drv.mod.c [first_drv]

c48761d8?__module_depends [first_drv]

bf0008ac d $d [first_drv]

c4876204?__mod_vermagic5 [first_drv]

c01bd44c u class_device_create [first_drv]

c008ca94 u register_chrdev [first_drv]

c01bd668 u class_device_unregister [first_drv]

bf000948 b major [first_drv]

bf000944 b gpfcon [first_drv]

c0031ad0 u __iounmap [first_drv]

c01bc968 u class_create [first_drv]

bf0007c0 d __this_module [first_drv]

bf000088 t init_module [first_drv]

c008c9dc u unregister_chrdev [first_drv]

bf000140 t cleanup_module [first_drv]

c01bc9dc u class_destroy [first_drv]

bf000940 b gpfdat [first_drv]

c0031a6c u __arm_ioremap [first_drv]

c0172f80 u __copy_from_user [first_drv]

c01752e0 u __memzero [first_drv]

4.2、查看反汇编

#arm-linux-objdump -D first_drv.ko > first_drv.dis

在kallsyms.txt中可以知道,first_drv_write的入口地址为 bf00003c

打开first_drv.dis,如何查找真正僵死的位置?

(1)首先从反汇编文件中找到位置为00000000的函数:00000000 :

(2)在kallsyms.txt中,first_drv_open 实际位置是:bf000000

(3)根据上面的信息,可知知道,在反汇编中,发送僵死的位置为00000084 - 4  处

(4)查找00000084处代码在函数:first_drv_write中

0000003c :

3c: e1a0c00d mov ip, sp40: e92dd800 stmdb sp!, {fp, ip, lr, pc}44: e24cb004 sub fp, ip, #4 ; 0x4

48: e24dd004 sub sp, sp, #4 ; 0x44c: e3cd3d7f bic r3, sp, #8128 ; 0x1fc0

50: e3c3303f bic r3, r3, #63 ; 0x3f

54: e5933008 ldr r3, [r3, #8]58: e0910002 adds r0, r1, r2

5c: 30d00003 sbcccs r0, r0, r360: 33a03000 movcc r3, #0 ; 0x0

64: e3530000 cmp r3, #0 ; 0x0

68: e24b0010 sub r0, fp, #16 ; 0x106c: 1a00001c bne e4

70: ebfffffe bl 70

74: ea00001f b f8

78: e3520000 cmp r2, #0 ; 0x07c: 11a01002 movne r1, r280: 1bfffffe blne 80 #错误在这,死循环!!!!

84:  ea00001f b108

注意:在arm中,中断保存的PC是当前指令加4,所以真正僵死的位置是:bf00000080,也就是:80

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值