首页 > 其他分享 >记录一次optionRom卡死问题排查(图片不可见)

记录一次optionRom卡死问题排查(图片不可见)

时间:2022-08-28 14:44:59浏览次数:64  
标签:bios 代码 打印 问题 排查 卡死 BIOS optionRom

1. 概述

        xx项目中,UEFI的cli工具,可以实现与optionRom程序的通信。其中的一项功能是将事件日志dump出来。在dump日志的过程中,发现存在卡死的现象。添加多处打印进行问题的分析,发现卡死在了字符串打印的接口中。反复进行日志的打印,大概3小时左右可以复现问题

2. 问题排查

        在压力测试中存在卡死的问题,率先想到的就是存在内存越界或者陷入了某个死循环。当然了,经验问题有时候也会给人错误的指引。UEFI是单线程的程序,为了定位问题,只能根据第一次出现问题时候的日志,大致了解出现问题的代码位置,再添加打印进行问题的追踪。

2.1. 代码执行流程

        排查界面卡死的问题,率先将该指令的执行流程进行梳理,cli /c0 show termlog的执行流程如下所示:

 

        以上的流程图,大致绘制整个termlog show的执行流程,因为项目问题,不做细致的描述。其中的4、5、6步骤都进行了内存的申请于释放。

2.2. 出现问题的代码位置

        最开始出现问题的打印显示如下:

 

        只能在将内容进行dump的时候,出现了卡住,在使用sol获取的打印日志中看不到具体卡住的位置。为了确定问题出现的位置,将整个执行流程的代码中添加打印,进行问题的复现。

       在第二次问题复现时候,发现了程序卡住的位置:

 

      卡住的位置对应上文的394行。

2.3. 问题根因的定位

2.3.1. 问题分析

        看到函数卡在了gBS->output中,以为问题已经定位完成,仅仅需要看一下gBS->output中哪里出现的问题即可,但是很不幸,在开源的edk2中,并没有找到gBS->output赋值的位置,即使找到对个别全局变量赋值的位置,添加的打印也不会生效。

        经过一段时间的学习,可以确认这样的一个流程。Edk2是bios于UEFI公共的代码,edk2看作是看远的bios。OptionRom看作是bios代码的一个插件,但是这个插件中调用的一些底层接口,是在编译生成bios时候就固定好的,不是编译到optionRom程序中的。

        想到这里,突然恍然大悟,既然追到问题是卡在bios中,那应该看一下出现问题时候bios的打印。在bios的advance界面,按住ctrl+F11,可以显示隐藏开关。

        在放开bios打印的情况下,进行问题的复现,发现卡住的位置依旧是gBS->output中,查看出现问题的打印如下:

 

        有了这种打印信息,我们知道问题出现在bios里面。但是触发的原因是在BIOS中还是在optionRom的代码中,这个问题还不清楚,于是从两个方面进行问题的定位。从optionRom的代码出发,找可能出发问题的原因;从BIOS方向出发,找到出现问题的代码;

2.3.2.  optionRom中引起问题的代码

        在排查optionRom代码中问题的时候,最开始怀疑的是,存在代码的越界。于是在但凡用到malloc和free的接口处都加上了打印,以及防御机制。这里涉及了两个定位问题的技巧:

2.3.2.1. 使用宏定义替代原本的free函数

 

        使用新的宏代替原本的函数,多传入两个函数和行号的参数,这样可以在不改变其他代码的前提下,实现打印行号的功能。

        类似的方式也可以用到指令上,例如将shell下面的一个指令改名,自己手写一个sh文件代替这个指令程序,实现添加打印的效果。

2.3.2.2.  malloc和free函数封装头尾

        标准的malloc和free函数时候,是在堆空间上申请一段内存。在申请指定内存的前提下,还会多申请一段内存,作为malloc内存的header头结构体和tail结构体。头尾结构体中,根据系统不一样,存放的呢容也是不同的。以UEFI的代码为例,进行malloc申请于释放函数的位置是:

 

       头和尾指针中的内容,如下所示:

 

       为了模拟edk2中的数据结构,在optionRom程序中,字节封装一个malloc和free接口:

 

       有了这种函数的申请方式,一旦出现数据的越界,就能在optionRom的函数中显示,不会走到BIOS的代码中。

       当然做到这里,发现程序卡死的时候,不会走到optionRom程序的malloc和free函数中。说明导致卡死的原因不是越界。

2.3.2.3. 代码深度review

        我们在已经知道代码是卡死在标准输出函数的基础上,进行代码的review,看一下问题可能出现在哪里。在流程图的第4步,需要将从片内获取的二进制log信息,进行转换。这一步需要先读取16byte的数据,一次转成类似0x3e的形式。在判断是否将这个16Byte的数据,转换成为ASSIC的形式进行输出。这里存在一个问题,那就是ASSIC码的0-31和127号数据,是不可以输出显示的,属于控制字符。详细信息参考:

        https://www.sojson.com/ascii.html

        从卡住的位置,也可以看到,出现问题时候,总是有不可显示的字符存在:

 

       考虑到这点,我们尝试将不可显示的字符屏蔽掉。结果出任意料,问题不在发生。

2.3.3. bios中问题的定位

       仅仅从sol的打印信息中,是看不出来问题的。于是我们拉来了BIOS的同事,进行问题的协助定位。BISO同事进行问题定位的第一步,是查看BMC的日志,具体如下:

 

       根据复现问题的时候节点,可以在BMC中找到ASSERT的日志,存在紧急级别的日志,确实可以证明出现了ASSERT的问题。但是仅仅从BMC的日志中,不足以完全定位问题,于是用到了DCI工具,进行堆栈的显示。

       在intel G30机器上进行问题的复现。有如下的定位:

 

       可以看到最终的函数卡在了字符串高度和偏移的函数中(BIOS中),这个是由于我们输入了包含不可显示ASSIC码的原因。

3. 问题总结

        该问题花费了大量的时间进行定位,最终确定是BIOS中的标准输出函数会在打印不可显示ASSIC码字符时候,寻找字符偏移和位置错误,出现了卡住。由于代码在BISO中,UEFI组内看不到,问题不再继续追。总结一下该问题排查的收获。

(1)      排查问题,先梳理流程再层层划分

(2)      使用宏替换以及malloc添加头尾的方式,可以确认是否存在数据的越界

(3)      开启BIOS打印以及使用DCI工具,可以查看BIOS的堆栈信息

(4)      BMC的log日志可以进行问题的初步分析

(5)      optionRom中使用的大量开源库函数,在BIOS中编译

        当然在本次的bug追查中,UEFI组内也使用了gdb工具进行问题的分析,UEFI下gdb的使用,可以在以后进行总结

标签:bios,代码,打印,问题,排查,卡死,BIOS,optionRom
From: https://www.cnblogs.com/free-1122/p/16632731.html

相关文章

  • SearchContextMissingException: No search context found for id [xx] 问题排查
    背景需要将存放在ES系统中的IMEI信息,将全量的数据分批拉取结果集到另外的系统,处理流程大抵就是先调用ES的查询方法,Scroll查询每批次10000条数据,得到数据集合后,在转换成自......
  • 【Java】使用Druid连接池的监控面板排查慢SQL
     默认在后台服务的地址:http://localhost:8078/druid/login.html账号信息放在配置文件中获取:server:port:8078spring:datasource:druid:......
  • 【HDFS】一次Namenode的RPC延迟故障排查引发的深入思考
    一次Namenode的RPC延迟故障排查引发的深入思考前言正文问题排查初步定位临时恢复定位可疑进程问题分析问题脚本分析问题原因分析代码分析测试代码prometheus_clien......
  • Linux网络问题排查
     网络排查一般是有一定的思路和顺序的,其实排查的思路就是根据具体的问题逐段排除故障可能发生的地方,最终确定问题。所以首先要问一问,网络问题是什么,是不通,还是......
  • 一个奇葩的线上问题,导致我排查了一天
    昨天线上又出了个问题,花了一天的时间才找到原因,说起来原因其实特别的坑爹啊。事情是这样的,最近我们上线了一个刷新用户token的功能,也就是APP里经常有的,只要你经常操作......
  • SMB登录事件排查经验分享
    1.概述1.1案例先来看两张图:  看到这两张图的第一印象应该是这是一个成功的登陆,其类型为3,代表网络登陆,4624表示成功登陆,可能大部分人都是如此认为。那么实际上呢?这里面......
  • firewalld启动失败问题排查
    今天需要在防火墙上添加端口策略发现起不来了#systemctlrestartfirewalld报错如下Authorizationnotavailable.Checkifpolkitserviceisrunningorseedeb......
  • linux开机卡死-end tarce dcec58a1576e8cea
    故障表述:因为机房空调其中一台不制冷,机房内温度过高,关闭部分非正式环境的服务器以减少散热。修好空调后,观察半天,没有问题。重新打开前面关闭的linux服务器,发生以下错误:见......
  • 服务器负载暴增排查
    top状态查看      系统平均负载高,但cpu,内存,磁盘io都正常      系统平均负载   1.平均负载是指单位时间内,系统处于可运行状态和不可中断状态......
  • mysql执行语句卡死后杀线程
    1.查询正在运行的线程SHOWPROCESSLIST;#或select*frominformation_schema.PROCESSLIST;2.批量生成杀线程的命令selectconcat("kill",ID,";")ascommand......