目录
1 将驱动程序改错
2 调试
1 将驱动程序改错
我们在点灯的函数里面增加一个死循环,
![](https://img8.php1.cn/3cdc5/18d35/c5a/848961bfd5e2df8a.png)
编译完之后,加载,测试,发现系统卡死。
2 调试
我们的系统不管在做什么事情,系统时钟中断是永远都在进行的,
![](https://img8.php1.cn/3cdc5/18d35/c5a/afed219da9c3b2ec.png)
在内核中搜索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;
}
这样我们就可以知道在哪个进程里面导致系统卡死,然后重新编译内核,然后重启系统使用新内核启动,然后加载我们的驱动程序,并测试,系统卡死
![](https://img8.php1.cn/3cdc5/18d35/c5a/4bc6f7428608885e.png)
从这里可以知道是哪个进程卡死了,但是我们还想知道是卡死在这个进程的哪里,我们知道在执行中断函数之前,有个保存现场的操作,那么我们可以把寄存器的值打印出来,把PC打印出来![](https://img8.php1.cn/3cdc5/18d35/c5a/e5d61398fe77e977.png)
当发生中断时,会跳到0xFFFF0018这里,然后去asm_do_IRQ保存现场,
![](https://img8.php1.cn/3cdc5/18d35/c5a/49dea9cc586aebcc.png)
在内核中搜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&#39;s psr */unsigned long cr_iip; /* interrupted task&#39;s instruction pointer *//** interrupted task&#39;s function state; if bit 63 is cleared, it* contains syscall&#39;s ar.pfs.pfm:*/unsigned long cr_ifs;unsigned long ar_unat; /* interrupted task&#39;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&#39;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 */
};
那么我们可以把想要的寄存器打印出来&#xff0c;![](https://img8.php1.cn/3cdc5/18d35/c5a/75b49a88901402ca.png)
然后重新编译内核&#xff0c;启动&#xff0c;然后ismod加载驱动程序&#xff0c;运行测试程序&#xff0c;
./firstdrvtest on
asm_do_IRQ &#61;> s3c2410_timer_interrupt : pid &#61; 752, task name &#61; firstdrvtest
pc &#61; bf000084
asm_do_IRQ &#61;> s3c2410_timer_interrupt : pid &#61; 752, task name &#61; firstdrvtest
pc &#61; bf000084 // 对于中断, pc-4才是发生中断瞬间的地址
然后就可以根据PC确定出错位置&#xff0c;先看一下加载的驱动的函数地址范围
cat /proc/kallsyms > kallsyms.txt
然后可以在里面搜索bf000084&#xff0c;搜索不到就搜bf0000&#xff0c;然后可以![](https://img8.php1.cn/3cdc5/18d35/c5a/ebc103b566ec0e64.png)
那么就是first_drv模块&#xff0c;然后反汇编这个模块&#xff0c;找到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 70: ebfffffe bl 70 74: ea00001f b f8 78: e3520000 cmp r2, #0 ; 0x07c: 11a01002 movne r1, r280: 1bfffffe blne 80 // 卡死的地方84: ea00001f b 108
虽然出错的位置打印出来PC是84&#xff0c;但是我们之前知道&#xff0c;中断处理完之后返回的位置是PC-4,所以出错的位置在80.
80: 1bfffffe blne 80 // 卡死的地方
这就是那个死循环&#xff0c;永远跳到80.