作为Linux内核关键的调试技术,可以修改内核定时器来定位系统僵死问题

 1.简介

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

 作为Linux内核关键的调试技术,可以修改内核定时器来定位系统僵死问题_设计制作_可编程逻辑

1.1、我们在命令行输入:# cat /proc/in     te   rrupts

# cat /proc/interrupts     CPU   0 30: 8316 s3c S3C2410     Ti   mer Tick -----> 系统时钟 33: 0 s3c s3c-mci 34: 0 s3c I2S     SDI   35: 0 s3c I2SSDO 37: 12 s3c s3c-mci 42: 0 s3c ohci_hcd:     usb   1 43: 0 s3c s3c2440-     i2c   51: 1047 s3c-ext eth0 60: 0 s3c-ext s3c-mci 70: 16 s3c-     uart   0 s3c2440-uart 71: 26 s3c-uart0 s3c2440-uart 79: 8 s3c-     adc   s3c2410_ac  TI on 80: 1732 s3c-adc s3c2410_ac  TI on 83: 0 - s3c2410-wdtErr: 0#

30: 8316 s3c S3C2410  TI mer  TI ck 这个就是系统时钟,中断号为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_ts3c2410_timer_interrupt(int irq, void *dev_id){#if 1 static     pi   d_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 fi     rs   t_drv.ko # ./firstdrvtest ons3c2410_timer_interrupt : pid = 770, task_name = firstdrvtests3c2410_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){ 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函数里面加修改后改函数为:(红色为添加的程序)

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); }

4、测试:

# insmod first_drv.ko # ./firstdrvtest ons3c2410_timer_interrupt : pid = 771, task_name = firstdrvtestpc = bf000084

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

#cat /proc/kallsyms > /kallsyms.txt

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

....................................00000000 a 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]00000000 a 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 g     pfc   on [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_f     rom   _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, 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 0x5c> 70: ebfffffe bl 70 0x34> 74: ea00001f b f8 0x70> 78: e3520000 cmp r2, #0 ; 0x0 7c: 11a01002 movne r1, r2 80: 1bfffffe blne 80 #错误在这,死循环!!!! 84:  ea00001f b 108

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




51
161
0
10

相关资讯

  1. 1、听说“速激”系列也要开启宇宙了?“郭达森”片场照揭秘冰山一角2464
  2. 2、关晓彤缺课太多留级成王俊凯同学?知情人辟谣否认留级132
  3. 3、《白日》强硬背后:电影局、中影、华夏齐护航160
  4. 4、赵本山推自传剧《不是钱的事》颠覆出演成亮点681
  5. 5、华谊兄弟压力大了?沈腾新片获吴京盛赞:票房至少60亿3973
  6. 6、双女主剧vs双男主剧,谁的武力值更强?3258
  7. 7、《误入浮华》张雨绮剧照发布,形象与人设不符,剧情有点狗血3224
  8. 8、马伊琍10年前长发写真曝光,笑容甜美超迷人,这才是最真实的她819
  9. 9、她两度与张家辉合作,张家辉喘不过气,网友:影帝也有怕的时候?1848
  10. 10、他们是相差7岁姐弟恋,高龄拼生一儿一女,如今合影像同龄夫妻3382
全部评论(0)
我也有话说
0
收藏
点赞
顶部