历史上的今天
返回首页

历史上的今天

今天是:2024年11月28日(星期四)

正在发生

2018年11月28日 | 技术文章—Linux编程时遇到Oops提示该如何排查?

2018-11-28

各位工程师在Linux下开发程序时,有没有遇到由于系统中存在某些小故障而跳出了“Oops”提示的情况,此时你是如何排查故障?一行行的查看代码吗?其实不用那么复杂,本文将为你介绍一种高效的Linux编程的故障排除方法。

 

在分析Oops之前,我们先来看以下这么一个例子,使用GPIO的中断做掉电检测,参考《嵌入式Linux开发教程下册》的驱动框架,设计如下程序框图:

 

                                              image.png?imageView2/2/w/550


这个框架设计之初的理想流程为:应用启动->程序初始化->应用open设备->等待中断事件,但实际项目开发时,往往发生许许多多不可预测的事情。如小王正在调Qt应用,发现老王的进程老在打印,那就不让老王的进程开机自启动,调了两三天后,不定时地提示个Oops提示,小王按照“以前代码不出现,新加的出现,那么起因绝对在新代码内”的惯性思维,认为是新加的Qt导致的,然后小王就不断测试,不断查找bug中.......这样就过去了十年。

 

但原因其实是小王没有open设备,即驱动层没有初始化定时器队列,那么中断处理函数中50ms触发的队列就为一个空值,空指针时Linux内核当然“哎呦”一下提醒你了,而不定时地提示其实就是因为电源不定时地松动,gpio检测到掉电了所以触发了中断。

 

实际上,这样的案例十分常见,原本想A->B->C,实际使用是A->D->C,又或者驱动中有某个变量忘记初始化等等,这时分析Oops就可以十分快速地解决问题。那接下来我们就用Linux中标准驱动去触发一个Oops,对的你没看错,Linux内核标准源码也存在这样的异常,而且我们也可以去修复这样的问题。

 

使用我司的EasyARM-iMX283开发板,内核源码为光盘内的Linux-2.6.35.3.tar.bz2,编译方法请参考光盘资料,我们需要把lcd的背光驱动修改为ko模式。

 

image.png?imageView2/2/w/550

 

烧录完新内核,加载新编译出来的drivers/video/backlight/mxs_bl.ko文件就会提示以下Oops信息:

 

image.png?imageView2/2/w/550

 

乍看之下,这段信息跟乱码差不多,但只要你一层层地分析,你就会发现,这些信息已经告诉了我们错误的原因。接下来就开始我们的Oops分析之旅。

 

1、主要错误信息

 

image.png?imageView2/2/w/550

 

用于提示错误的类型,这里表示使用空指针。

 

2、操作入口

 

image.png?imageView2/2/w/550

 

用于提示错误的操作,这里表示加载mxs_bl模块时出错,对应于加载操作insmod mxs_bl.ko。

 

3、PC指针

 

image.png?imageView2/2/w/550

 

用于提示出错时的PC指针位置,PC指针即当前程序运行点的地址,这里提示表示错误函数为regulator_set_current_limit,偏移地址为0xc。

 

4、LR指针

 

image.png?imageView2/2/w/550

 

用于提示出错时的LR指针位置,LR指针即调用子函数的上一个函数名以及入口偏移量,这里表示上一个函数为set_bl_intensity,偏移地址为0xd8。即set_bl_intensity调用regulator_set_current_limit时出错。

 

5、寄存器值

 

image.png?imageView2/2/w/550

 

用于记录出错时各个寄存器的值,对于汇编比较熟悉的同志们可以研究一下这段信息。

 

6、出错进程信息

 

image.png?imageView2/2/w/550

 

用于提示出错的进程id号与进程名称。出错进程为insmod, PID号2261,对于多任务系统中,可能存在多个PID调用同一个接口的情况。

 

7、出错时的堆栈信息

 

image.png?imageView2/2/w/550

 

用于提示出错时堆栈内保存的寄存器信息,当程序由于中断发生或子程序调用时,会执行压栈操作,即将运行环境保存到堆栈内,保证退出中断或跳出子程序后,运行环境不发生改变。

 

而此处的堆栈信息即记录了程序运行时的环境信息。从中我们可以找到许多LR地址,从而分析出函数调用关系,与下一段的信息有类似作用。

 

8、函数执行的回溯关系

 

image.png?imageView2/2/w/550

 

用于表示函数的调用关系,通过这段信息我们可以知道,函数的整个执行流程,知道它的函数调用关系,最后整理出来的函数执行流程如下:

 

image.png?imageView2/2/w/550

 

从中我们看到了熟悉的init函数、probe函数、以及清楚probe函数下执行的操作过程是到哪一步出错的。现在我们知道了代码的执行流程,出错的PC指针的位置,但还是看不到代码,出错指针处我们只看到了一串数字,那么接下来我们就操作一下,把pc指针的数据变为有意义的代码。

 

第一步,分辨出错误代码在什么位置

 

这次实验涉及的二进制文件有内核的烧录固件以及驱动的ko文件,所以第一步分析就需要确定出错代码是在内核固件里还是ko文件里。

 

首先得到内核代码的范围,用以下命令将内核反汇编。

 

image.png?imageView2/2/w/550

 

查看这个文件的格式如是:

 

image.png?imageView2/2/w/550

 

第一列行数,第二列运行地址,第三列二进制码,第四列汇编代码,既然第二列为运行地址,即等同于程序运行到这行时,pc指针的值等于这个数值。这样只要翻看这个文件的头部以及尾部,就能知道内核代码的PC指针范围为:c0008000~c0562338。

 

根据前面第5步寄存器值,出错时PC指针为c02f1878,即在内核源码范围内。

 

第二步,分析出错函数的出错语句

 

那么根据3步PC指针,得到regulator_set_current_limit的汇编代码,如下:

 

image.png?imageView2/2/w/550

 

函数入口地址为c02f186c

 

在第3步PC指针指出偏移地址为“PC is at regulator_set_current_limit+0xc”。

 

         PC = 0xc02f1878 = 0xc02f186c + 0xc,符合汇编代码地址。

 

第三步,找到出错函数的C语言代码

 

这步可以说是最困难的,因为内核代码层次多,同名函数也可能存在许多份,可能几份编译进内核(static声明的局部函数),也可能没编译进内核,如何从众多的代码中分析出具体哪段呢。

 

本人就使用了一些小手段,首先给每个同名函数的入口加段乱码,让编译器筛选出编译进内核的文件(因为乱码,所以编译会报错),然后给剩下的函数加打印语句,通常经过第一步之后,可选的目标就两三个,通过打印进一步确认代码即可。

 

以下为筛选出来的C语言代码。

 

image.png?imageView2/2/w/550

 

看到这好像是定位了函数,但对于不熟悉汇编的人来说,C与汇编还是没有关联起来,好像进入了死胡同,但先别气馁,从上面的汇编代码中我们知道,函数名即为函数的首地址,那么调用子函数即需要让CPU知道子函数名,那么汇编如何调用子函数呢?使用bl指令, bl+子函数名。既然汇编有这么一个特性,那么我们看汇编代码。

 

上面582734行为“bl  c0493104

 

image.png?imageView2/2/w/550

 

那么结果显而易见,不可能定义个变量都报错吧,所以唯一可能错误的语句就是struct regulator_dev *rdev = regulator->rdev,同理,这句的前半部也只是定义一个rdev的变量,再结合内核给出来的提示——空指针,所以错误就是regulator->rdev是一个空指针。

 

最终的问题就归结于,为什么regulatar->rdev为空指针。这部分的查阅代码以及推理需要更深层次地挖掘,工作量也非本文能说清的,故作者在这里就大胆地推测与上面的A->B->C模型类似。所以我们就需要在这个资源存在的时刻,调用它之前给它赋值。

 

这时侯,我们就需要拿出第8步函数执行的回溯关系图,既然知道这个图中最后的函数的输入参数regulator的rdev为空,那么我们就关心regulator结构体以及它的意义。从结构体的意义我们才能知道如何给它赋值。

 

image.png?imageView2/2/w/550

 

在相关的代码文件中搜索关键字”regulator”或”regulator =”(建议搜这个,因为这种才是赋值语句)得到如下代码。

 

image.png?imageView2/2/w/550

 

分析这个函数可知,regulator实际是pdata的一个成员,他需要data来初始化,那么接下来的事情就简单了,在回溯关系中找一个位置把data的数据塞入pdata中,刚好这段函数就是初始化的regulator的,那就直接拿去用吧。

 

把这段添加到probe函数内的这个位置,实现了在mxsbl_probe和mxsbl_do_probe之间赋值此变量。

 

image.png?imageView2/2/w/550


这样重新编译后即可正常加载ko文件。

 

 

 

 


推荐阅读

史海拾趣

General Dynamics SATCOM Technologies公司的发展小趣事

对于集成电路控制方式的恒水压自动控制电路,网友可能会提出多个问题,以下是一些常见问题及其回答:

1. 恒水压自动控制电路的基本工作原理是什么?

回答
恒水压自动控制电路主要利用集成电路(如单片机、微处理器等)对水压进行实时监测与控制。其基本工作原理是通过压力传感器采集水系统中的水压信号,将模拟信号转换为数字信号后送入微处理器进行处理。微处理器根据预设的水压值与实际水压值进行比较,通过控制水泵电机或其他执行机构的启停或转速来调节水流量,从而实现水压的恒定控制。

2. 如何实现精确的水压控制?

回答
实现精确的水压控制需要依赖于高精度的压力传感器和先进的控制算法。首先,选择具有高精度和良好稳定性的压力传感器是关键。其次,在控制算法上,常采用PID(比例-积分-微分)控制算法,通过不断调整比例、积分和微分系数来优化控制效果,使系统能够快速响应水压变化并保持稳定。此外,还可以引入模糊控制、神经网络控制等先进算法,以进一步提高控制系统的智能化水平和控制精度。

3. 恒水压自动控制电路中的集成电路如何选择?

回答
在选择集成电路时,需要考虑多个因素,包括控制精度、处理能力、成本、功耗以及是否易于编程等。对于恒水压自动控制电路来说,单片机或ARM等微处理器是常见的选择。这些微处理器具有较高的集成度和较强的数据处理能力,能够满足实时控制和复杂算法的需求。同时,还需要考虑其外部接口和扩展性,以便与压力传感器、电机驱动器等其他元件进行连接和通信。

4. 如何解决电路中的噪声和干扰问题?

回答
在恒水压自动控制电路中,噪声和干扰可能会影响压力传感器的测量精度和控制系统的稳定性。为了解决这些问题,可以采取以下措施:

  • 在电路设计阶段,采用合理的布局和布线方式,减少信号线之间的串扰和耦合。
  • 使用屏蔽线和滤波器来抑制高频噪声和电磁干扰。
  • 对模拟信号进行滤波处理,提高信号的信噪比。
  • 在软件层面,采用数字滤波算法进一步滤除噪声干扰。

5. 如何实现远程监控和故障诊断?

回答
为了实现恒水压自动控制电路的远程监控和故障诊断,可以将控制系统与物联网技术相结合。通过在控制系统中集成无线通信模块(如Wi-Fi、蓝牙、NB-IoT等),将实时水压数据、运行状态等信息传输到云端服务器或远程监控中心。同时,可以通过手机APP、网页等客户端远程查看和控制系统状态,及时发现并处理故障问题。此外,还可以利用大数据分析技术对历史数据进行挖掘和分析,为系统的优化和维护提供数据支持。

以上是对集成电路控制方式的恒水压自动控制电路可能遇到的问题及其回答的总结。希望这些信息能够对网友有所帮助。

北京人民电器厂公司的发展小趣事

为了加强技术研发和创新能力,北京人民电器建立了北京市级技术研究中心,并吸引了教授级高工、博士后、博士、硕士等多层次的专业技术人才。这些人才为公司的新产品研发、技术创新提供了强大的智力支持,使得北京人民电器在激烈的市场竞争中始终保持领先地位。

Gravitech公司的发展小趣事

北京人民电器厂有限公司,作为北方地区最大的低压电器制造企业,于1995年成功研发出全球首台高分断微型直流断路器。这一创新成果不仅填补了国内空白,更在国际上展现了中国在低压电器领域的研发实力。该断路器的诞生,标志着北京人民电器在直流断路器技术领域迈出了坚实的一步,为后续的产品研发和市场拓展奠定了坚实的基础。

Hi-Light Electronic Co Ltd公司的发展小趣事

为了加强技术研发和创新能力,北京人民电器建立了北京市级技术研究中心,并吸引了教授级高工、博士后、博士、硕士等多层次的专业技术人才。这些人才为公司的新产品研发、技术创新提供了强大的智力支持,使得北京人民电器在激烈的市场竞争中始终保持领先地位。

ABI Electronics公司的发展小趣事

随着业务的不断发展和产品的不断升级,ABI Electronics公司的品牌影响力也逐渐提升。其产品在市场上获得了良好的口碑和声誉,成为了电子行业内的知名品牌。同时,ABI还积极参与行业内的交流和合作,为行业的发展做出了积极的贡献,进一步提升了其在行业内的地位和影响力。

这五个故事展示了ABI Electronics公司在电子行业里的发展历程,从电路板测试技术的突破,到集成电路测试技术的创新,再到全球市场布局和合作伙伴关系的建立,以及研发实力的持续增强和品牌影响力的提升,都体现了ABI Electronics公司不断进取、不断创新的精神。

Alutronic Kuhlkorper Gmbh & Co Kg公司的发展小趣事

随着业务的不断发展和产品的不断升级,ABI Electronics公司的品牌影响力也逐渐提升。其产品在市场上获得了良好的口碑和声誉,成为了电子行业内的知名品牌。同时,ABI还积极参与行业内的交流和合作,为行业的发展做出了积极的贡献,进一步提升了其在行业内的地位和影响力。

这五个故事展示了ABI Electronics公司在电子行业里的发展历程,从电路板测试技术的突破,到集成电路测试技术的创新,再到全球市场布局和合作伙伴关系的建立,以及研发实力的持续增强和品牌影响力的提升,都体现了ABI Electronics公司不断进取、不断创新的精神。

问答坊 | AI 解惑

射频和微波开关测试系统基础

无线通信产业的巨大成长意味着对于无线设备的元器件和组件的测试迎来了大爆发,包括对组成通信系统的各种RF  IC 和微波单片集成电路的测试。这些测试通常需要很高的频率,普遍都在GHz范围。本文讨论了射频和微波开关测试系统中的关键问题 ...…

查看全部问答>

求好心人帮忙pudn下个2410上的U盘代码

http://www.pudn.com/downloads100/sourcecode/embed/detail410820.html 哪位有帐号的好心人下来 发到我邮箱:carrot_shi@yahoo.com.cn 先谢过!!…

查看全部问答>

s3c2440 800x600 如何提速控件显示速度

本人初学wince,请教大虾们一个问题。 本人使用的是S3c2440,wince5.0,800x600的LCD。 因为屏幕过大,wince的显示看起来已经较慢。 因为客户的要求,开发软件需要保持与pc机版本的界面一致。导致程序中需要在一个界面上绘制上百个控件,可以看 ...…

查看全部问答>

手机内存卡原文件夹都变成了后缀ink格式,在手机里打不开,只有在电脑上才能打开是什么原因

手机内存卡原文件夹都变成了后缀ink格式,在手机里打不开,只有在电脑上才能打开是什么原因…

查看全部问答>

PCB布线1(差分线)

布差分线时,两条线的长度要尽量的一样长、两条线的间距要尽可能的近,两条线要保持平行,越早平行越好。那么,如何走平行线呢?有两种方法:两条线走在同一走线层,两条线走在上下相邻的两层。不过,一般是走在同一走线层。 下面是有用的资料: ...…

查看全部问答>

can拨特率计算?

我算的怎么和例子上的不一样啊?例子上的100KBPS/S:设置如下(用的外部晶振(是8M的吗?),SYSCLK是HSE,CAN时钟应该是4M吧!  CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;  CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;  ...…

查看全部问答>

"Cannot load flash programming Algorithm"错误,怎么整!!!

我的板子是9b92 用的是ulink2 +keil 4.10    程序编译没有问题,ulink也没有问题,就是下载的时候失败,这个是相关的设置页面,大家帮忙看一下,相当的着急上火啊!   [ 本帖最后由 bonnypro 于 2011-5-16 12:27 编辑 ]…

查看全部问答>

请问如何提取接收到的字字符数据

Z-stack文件夹里的SerialApp这个例程中,接收节点发过来的信息并转给串口是UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events )函数里的下面语句:      case AF_INCOMING_MSG_CMD:    & ...…

查看全部问答>

A7103芯片做的rf模块看上去还不错,为什么没有卖的?

A7103芯片做的rf模块看上去还不错,为什么没有卖的?…

查看全部问答>