Linux驱动调试之修改系统时钟中断定位系统僵死问题
目录
1 将驱动程序改错
2 调试
1 将驱动程序改错
我们在点灯的函数里面增加一个死循环,
编译完之后,加载,测试,发现系统卡死。
2 调试
我们的系统不管在做什么事情,系统时钟中断是永远都在进行的,
在内核中搜索Timer Tick,
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)
{write_seqlock(&xtime_lock);timer_tick();write_sequnlock(&xtime_lock);return IRQ_HANDLED;
}
我们在里面增加打印,
/** IRQ handler for the timer*/
static irqreturn_t
s3c2410_timer_interrupt(int irq, void *dev_id)
{//如果10秒钟之内都是同一个进程再运行,就打印static pid_t pre_pid;static int cnt = 0;if(pre_pid == current->pid){cnt++;}else{cnt = 0;pre_pid = current->pid;}if(cnt == 10*HZ){cnt = 0;printf("s3c2410_timer_interrupt: pid = %d, task name = %s\n", currrent->pid,current->comm);}write_seqlock(&xtime_lock);timer_tick();write_sequnlock(&xtime_lock);return IRQ_HANDLED;
}
这样我们就可以知道在哪个进程里面导致系统卡死,然后重新编译内核,然后重启系统使用新内核启动,然后加载我们的驱动程序,并测试,系统卡死
从这里可以知道是哪个进程卡死了,但是我们还想知道是卡死在这个进程的哪里,我们知道在执行中断函数之前,有个保存现场的操作,那么我们可以把寄存器的值打印出来,把PC打印出来
当发生中断时,会跳到0xFFFF0018这里,然后去asm_do_IRQ保存现场,
在内核中搜asm_do_IRQ
asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{struct pt_regs *old_regs;struct irq_desc *desc = irq_desc + irq;unsigned short pending, other_ints;old_regs = set_irq_regs(regs);/** Some hardware gives randomly wrong interrupts. Rather* than crashing, do something sensible.*/if (irq >= NR_IRQS)desc = &bad_irq_desc;irq_enter();generic_handle_irq(irq);/* If we're the only interrupt running (ignoring IRQ15 which is forsyscalls), lower our priority to IRQ14 so that softirqs run atthat level. If there's another, lower-level interrupt, irq_exitwill defer softirqs to that. */CSYNC();pending = bfin_read_IPEND() & ~0x8000;other_ints = pending & (pending - 1);if (other_ints == 0)lower_to_irq14();irq_exit();set_irq_regs(old_regs);
}
我们的现场就保存在pt_regs里面,
/** This struct defines the way the registers are saved on system* calls.** We don't save all floating point register because the kernel* is compiled to use only a very small subset, so the other are* untouched.** THIS STRUCTURE MUST BE A MULTIPLE 16-BYTE IN SIZE* (because the memory stack pointer MUST ALWAYS be aligned this way)**/
struct pt_regs {/* The following registers are saved by SAVE_MIN: */unsigned long b6; /* scratch */unsigned long b7; /* scratch */unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */unsigned long ar_ssd; /* reserved for future use (scratch) */unsigned long r8; /* scratch (return value register 0) */unsigned long r9; /* scratch (return value register 1) */unsigned long r10; /* scratch (return value register 2) */unsigned long r11; /* scratch (return value register 3) */unsigned long cr_ipsr; /* interrupted task's psr */unsigned long cr_iip; /* interrupted task's instruction pointer *//** interrupted task's function state; if bit 63 is cleared, it* contains syscall's ar.pfs.pfm:*/unsigned long cr_ifs;unsigned long ar_unat; /* interrupted task's NaT register (preserved) */unsigned long ar_pfs; /* prev function state */unsigned long ar_rsc; /* RSE configuration *//* The following two are valid only if cr_ipsr.cpl > 0 || ti->flags & _TIF_MCA_INIT */unsigned long ar_rnat; /* RSE NaT */unsigned long ar_bspstore; /* RSE bspstore */unsigned long pr; /* 64 predicate registers (1 bit each) */unsigned long b0; /* return pointer (bp) */unsigned long loadrs; /* size of dirty partition << 16 */unsigned long r1; /* the gp pointer */unsigned long r12; /* interrupted task's memory stack pointer */unsigned long r13; /* thread pointer */unsigned long ar_fpsr; /* floating point status (preserved) */unsigned long r15; /* scratch *//* The remaining registers are NOT saved for system calls. */unsigned long r14; /* scratch */unsigned long r2; /* scratch */unsigned long r3; /* scratch *//* The following registers are saved by SAVE_REST: */unsigned long r16; /* scratch */unsigned long r17; /* scratch */unsigned long r18; /* scratch */unsigned long r19; /* scratch */unsigned long r20; /* scratch */unsigned long r21; /* scratch */unsigned long r22; /* scratch */unsigned long r23; /* scratch */unsigned long r24; /* scratch */unsigned long r25; /* scratch */unsigned long r26; /* scratch */unsigned long r27; /* scratch */unsigned long r28; /* scratch */unsigned long r29; /* scratch */unsigned long r30; /* scratch */unsigned long r31; /* scratch */unsigned long ar_ccv; /* compare/exchange value (scratch) *//** Floating point registers that the kernel considers scratch:*/struct ia64_fpreg f6; /* scratch */struct ia64_fpreg f7; /* scratch */struct ia64_fpreg f8; /* scratch */struct ia64_fpreg f9; /* scratch */struct ia64_fpreg f10; /* scratch */struct ia64_fpreg f11; /* scratch */
};
那么我们可以把想要的寄存器打印出来,
然后重新编译内核,启动,然后ismod加载驱动程序,运行测试程序,
./firstdrvtest on
asm_do_IRQ => s3c2410_timer_interrupt : pid = 752, task name = firstdrvtest
pc = bf000084
asm_do_IRQ => s3c2410_timer_interrupt : pid = 752, task name = firstdrvtest
pc = bf000084 // 对于中断, pc-4才是发生中断瞬间的地址
然后就可以根据PC确定出错位置,先看一下加载的驱动的函数地址范围
cat /proc/kallsyms > kallsyms.txt
然后可以在里面搜索bf000084,搜索不到就搜bf0000,然后可以
那么就是first_drv模块,然后反汇编这个模块,找到84的位置
3c: e1a0c00d mov ip, sp40: e92dd800 stmdb sp!, {fp, ip, lr, pc}44: e24cb004 sub fp, ip, #4 ; 0x448: e24dd004 sub sp, sp, #4 ; 0x44c: e3cd3d7f bic r3, sp, #8128 ; 0x1fc050: e3c3303f bic r3, r3, #63 ; 0x3f54: e5933008 ldr r3, [r3, #8]58: e0910002 adds r0, r1, r25c: 30d00003 sbcccs r0, r0, r360: 33a03000 movcc r3, #0 ; 0x064: e3530000 cmp r3, #0 ; 0x068: e24b0010 sub r0, fp, #16 ; 0x106c: 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 ; 0x07c: 11a01002 movne r1, r280: 1bfffffe blne 80 <first_drv_write+0x44> // 卡死的地方84: ea00001f b 108 <init_module+0x80>
虽然出错的位置打印出来PC是84,但是我们之前知道,中断处理完之后返回的位置是PC-4,所以出错的位置在80.
80: 1bfffffe blne 80 <first_drv_write+0x44> // 卡死的地方
这就是那个死循环,永远跳到80.
Linux驱动调试之修改系统时钟中断定位系统僵死问题相关推荐
- Linux驱动调试中的Debugfs的使用简介
Linux驱动调试中的Debugfs的使用简介 (2012-03-31 14:14) 在调试linux驱动的时候,可以用debugfs来调试,debugfs类似字符设备驱动一样,甚至更简单,不需要主设 ...
- Linux驱动调试中的Debugfs的使用简介 CONFIG_DEBUG_FS 的功能与配置
Linux驱动调试中的Debugfs的使用简介 (2012-03-31 14:14) 在调试linux驱动的时候,可以用debugfs来调试,debugfs类似字符设备驱动一样,甚至更简单,不需要主设 ...
- linux使用date命令修改系统日期,使用date命令设置CentOS Linux修改系统日期和时间...
您可以使用date命令来修改CentOS Linux的时间 修改日期: 将时间设置为2014年6月20日的命令如下: #date -s 2014年6月20日 修改时间: 将系统时间设置为14:20:0 ...
- linux驱动调试--oops信息
在移植dm9000 时被一个错误困扰了很久,当时手里只有printk调试手段,觉得自己应该升级下了,先学习了根据oops信息来调试. 先构造一个错误,insmod后抛出如下信息 我们着重看这几句 PC ...
- linux驱动调试--段错误之oops信息分析
原文地址 http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29401328&id=4923447 发生段错误原因就是访问 ...
- linux 下Qt 如何修改系统时间
Qt 提供日期时间的类有 QDate QTime 和QDateTime,这三个类. 一.获取系统时间 可以通过三个静态函数来获取 1.QDate::currentDate() 来获取当前系统的日期 2 ...
- Linux驱动段错误,linux驱动调试--段错误之oops信息分析
下面根据Oops信息来分析一下段错误 first_drv.c 点击(此处)折叠或打开 #include #include #include #include #include #include #in ...
- linux驱动调试技巧:灌寄存器---------以mma7660为例
本文可以使用linux的cat echo命令直接设置mma7660的寄存器的值 部分driver代码如下: static DEVICE_ATTR(mma7660_regs, S_IRUGO | S_I ...
- linux驱动调试--段错误之栈信息分析
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29401328&id=4923529 接着上一篇来分析一下Oop ...
最新文章
- 09CSS元素显示模式
- http://wenku.baidu.com/view/26afdb8371fe910ef12df8ccRevit采用DWG和FBX两种格式导入3D max方法的总结...
- 可能是GitHub上最好用的文字语法校验工具
- 菜鸟自学数据结构系列——(一)如何写出能够在VC下运行的单链表生成程序
- 基础知识收藏(ASP.NET的OnClientClick与OnClick事件)-2013.07.10
- android 官方教程中文版
- 深入互联网广告中的出价模式(上)— 基础出价模式
- FastReport使用方法(C/S版)
- RIP RETE时间获得PHREAKY
- CentOS7升级内核kernel5.0
- 2021暨南大学计算机技术上岸经验贴
- mini139聊天软件
- 实现asp程序调用摄像头并控制摄像头进行拍照
- [re入门]音乐文件加密破解
- CSDN博客去除上传的图片水印
- Kindle 可旋转桌面时钟
- file.exists()方法,明明存在,
- Android异步加载图像(含线程池,缓存方法)
- 摩尔定律,梅特卡夫定律和科斯定律
- 长高不仅靠遗传,让孩子再次长高的秘诀都在这