热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux驱动调试之修改系统时钟中断定位系统僵死问题

目录1将驱动程序改错2调试1将驱动程序改错我们在点灯的函数里面增加一个死循环,编译完之后,加载,测试,发现系统卡死。2

目录

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&#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;

 然后重新编译内核&#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;然后可以

 那么就是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.


推荐阅读
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 配置IPv4静态路由实现企业网内不同网段用户互访
    本文介绍了通过配置IPv4静态路由实现企业网内不同网段用户互访的方法。首先需要配置接口的链路层协议参数和IP地址,使相邻节点网络层可达。然后按照静态路由组网图的操作步骤,配置静态路由。这样任意两台主机之间都能够互通。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
author-avatar
温柔的诱惑2012_431
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有