首页 > 系统服务 > 详细

linux内核调试技术之修改内核定时器来定位系统僵死问题(未完)

时间:2016-12-30 23:28:25      阅读:637      评论:0      收藏:0      [点我收藏+]

1.简介(未完)

  在内核调试中,会经常出现内核僵死的问题,也就是发生死循环,内核不能产生调度。导致内核失去响应。这种情况下我们可以采用修改系统内核中的系统时钟的中断来定位发生僵死的进程和函数名称。因为内核系统系统时钟采用的是硬件中断的形式存在,所以,软件发生僵死的时候,系统时钟照样会发生中断。

  1.1、我们在命令行输入:# cat /proc/interrupts 
# cat /proc/interrupts 
           CPU0
 30:       8316         s3c  S3C2410 Timer Tick -----> 系统时钟
 33:          0         s3c  s3c-mci
 34:          0         s3c  I2SSDI
 35:          0         s3c  I2SSDO
 37:         12         s3c  s3c-mci
 42:          0         s3c  ohci_hcd:usb1
 43:          0         s3c  s3c2440-i2c
 51:       1047     s3c-ext  eth0
 60:          0     s3c-ext  s3c-mci
 70:         16   s3c-uart0  s3c2440-uart
 71:         26   s3c-uart0  s3c2440-uart
 79:          8     s3c-adc  s3c2410_action
 80:       1732     s3c-adc  s3c2410_action
 83:          0           -  s3c2410-wdt
Err:          0
# 
   30:       8316         s3c  S3C2410 Timer Tick 这个就是系统时钟,中断号为30
 1.2、在内核代码中
搜索"
S3C2410 Timer Tick"字样。
  在
Time.c (arch\arm\plat-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
 */
static irqreturn_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\n",current->pid,current->comm);
        }
    }
#endif
    
    write_seqlock(&xtime_lock);
    timer_tick();
    write_sequnlock(&xtime_lock);
    return IRQ_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, lr
1:    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语言的函数

  

  函数原型:

asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
    static pid_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函数里面加入如下信息:
    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\n",current->pid,current->comm);
            printk("pc = %08x\n",regs->ARM_pc);//打印pc值
        }
    }

  修改后改函数为:

  
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\n",current->pid,current->comm);
            printk("pc = %08x\n",regs->ARM_pc);//打印pc值
        }
    }
#endif

    static pid_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);

    
}

 

 测试:
# insmod first_drv.ko 
# ./firstdrvtest on
s3c2410_timer_interrupt : pid = 771, task_name = firstdrvtest
pc = bf000084

  查看反汇编

0000003c <first_drv_write>:
  3c:    e1a0c00d     mov    ip, sp
  40:    e92dd800     stmdb    sp!, {fp, ip, lr, pc}
  44:    e24cb004     sub    fp, ip, #4    ; 0x4
  48:    e24dd004     sub    sp, sp, #4    ; 0x4
  4c:    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, r3
  60:    33a03000     movcc    r3, #0    ; 0x0
  64:    e3530000     cmp    r3, #0    ; 0x0
  68:    e24b0010     sub    r0, fp, #16    ; 0x10
  6c:    1a00001c     bne    e4 <init_module+0x5c>
  70:    ebfffffe     bl    70 <first_drv_write+0x34>
  74:    ea00001f     b    f8 <init_module+0x70>
  78:    e3520000     cmp    r2, #0    ; 0x0
  7c:    11a01002     movne    r1, r2
  80:    1bfffffe     blne    80 <first_drv_write+0x44> #错误在这,死循环!!!!
  84:   ea00001f      b 108 <init_module+0x80>

 



linux内核调试技术之修改内核定时器来定位系统僵死问题(未完)

原文:http://www.cnblogs.com/veryStrong/p/6236577.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!