百姓大小事,一呼百应!

百姓网 | 百姓知道

硬件

你碰到过的最难调试的 Bug 是什么样的?

在 Quora 上有一个和 Bug 相关的热门问答帖:《What’s the hardest bug you’ve debugged? | 你调试过的最难 Bug 是?我大中国的程序员攻城师们遇到最难调试的bug是什么呢?欢迎吐槽!

2 个回答

  • 林铠鹏 | 2017-07-30 09:24:50

    实在忍不住了,第一次答题。

    08年的时候,我所在的公司调试三星的一款新的arm9 CPU,型号是S3C2416,是S3C2450的简配版。开发板刚入手的时候还是热乎的,因为三星的这个芯片刚刚出来,国内的代理商一共就几块开发板。各公司评估开发板都是分时使用的,只能预约几天。开发板入手的时候,三星那面连BSP都没有准备好,没有test code,没有u-boot,没有linux-kernel,甚至连Spec都是错误百出。还好我公司虽然小,研发能力在本地区还算不差,没有的东西可以自己移植。
    公司急着要出新品,在没有完全验证处理器的情况下,已经layout好了PCB,并且去打样了(当时竞争确实比较激烈,400M主频处理器而且这么低的价格绝对非常有诱惑力,所以公司决定冒这个险了)。在没黑没白的工作两周后,硬件和软件做的都差不多稳定了。这时候经理说,功能上问题不大了,我们必须调整睡眠的力量(我们的产品作为产品卖点已经非常低的功耗)。然而这却是噩梦的开始……
    公司的指标是待机时休眠电流500uA~800uA(电源电压4V)之间。以前所有的产品都在这个范围之内,三星方面的技术支持也明确表示,他们的解决方案达到这个指标。
    在我们调试过程中发现,整个系统休眠时的功耗在1800uA左右,一直降不下来。我们重新核对了所有的IO和外围电路的所有连接,以及IO口的电平配制,都没有问题。这时,我们决定测试每一个单元的功耗,用电流表分别串联进每一个外围电路,每个单元都很正常,就是系统总体偏大1000uA。
    我们连flash和ram的待机电流都测过了,仍然正常。好了,通过排除法已经确定了就是CPU的功耗过大。但是在开发板上调试休眠的时候,CPU功耗却是正常的。
    我们怀疑是开发板上CPU批号和我们自己拿到的CPU样品的批号之间有区别导致的,因为三星那面也在同步修正CPU的BUG,所以我们“大胆地”把开发板上的CPU用风枪吹下来,换到我们的PCB上,把我们的CPU贴到了开发板上进行交叉验证。结果是开发板仍然功耗正常,我们自己的板子上功耗偏大,还是大了1000uA。
    CPU周边的核心电路设计出现了问题!这是我们一致的判断!但是问题出在哪里,我们反复核对开发板的原理图和我们自己板子的原理图,简直就是一模一样!因为整个核心电路这部分就是从开发板上抄过来的,实在没有什么可比对的。我们转而又去怀疑PCB的问题了。
    我是做系统移植和软件的,纯电气的问题我就无能为力了。闲着没事,我就反复检查我在linux中对系统休眠的IO引脚配置。然后挂着电流表做反复测试。电流表也对的起我,每次都是那个数。在一次系统待机的时候,我实在忍无可忍,一把抓起了板子。突然之间,电流表的读数飞快下降,降到了300uA!我松开手电流表的读数就又爬回来了。我把我这个惊奇的发现告诉了同事——一个硬件工程师。同事说可能是哪儿摸短路了,让我试试还能不能唤醒系统。我给了一个外部中断,系统神奇的正常唤醒了!
    “难道这就是问题?”,我想重现一下。但是再次在待机的时候抓起电路板的时候,读数并没有显著发生变化。“可能是手法不好”,我这么想着,用手在板子上继续抚摸着。果然!当我的手指按到PCB中的某一个位置时,电流又降了下来!反复试了几次,都是这样,就是在我手指按压的这一片,只要是用手指按着,电流就正常!
    这回同事开始重视了,打开PCB图,拿着电路图和万用表,查查我摸的到底是那块电路。硬件工程师觉得不可思议,因为我摸的部分并没有连接任何的电路——焊盘是空的。他于是用万用表的表笔去检查是不是PCB制版的问题,测一下这些空焊盘到底哪一个有电压。但是万用表中没有读数,这块都没有电。但是当万用表的表笔落在一处空焊盘的时候,电流表的读数又降下来了!
    这可是重大发现,我们对照了一下电路图。这处空焊盘是CPU中USB-Host模块的D+信号。由于我们的产品不需要USB的主机功能,所以这一块儿没有做任何处理。多亏了画原理图和PCB的同事,多留了一手,把USB Host的引脚都在PCB上做了个引出。谁也没想到是这个引脚出现了问题,辛亏这个信号引出来了,要是没有引出来,一辈子也查不出问题。我们给D+信号加了一个下拉电阻后,系统的功耗瞬间正常了。
    事后分析,三星自己开发板上有USB-Host的功能,所以USB-Host的外围电路也是完备的,所以功耗不会有问题。但是我们自己的产品上不使用USB-Host功能,没有相关外围电路,所以出了问题。这是因为在CPU休眠的时候,D+信号内部被悬空了!一句话,是三星CPU自己的BUG。我们修改了我们的PCB,增加了一个下拉电阻,同时将问题反馈给了三星。
    一个月后,当我们的产品量产时,三星也及时的解决了这个问题。那个下拉电阻也不需要再贴上去了。

    最后用手指头找到了CPU的BUG,不知道这算不算是最难调的。
    反正这么多年了,这个经历留给我的印象是最深的。

    本问答由林铠鹏提供

  • 林铠鹏 | 2017-07-30 08:45:03

    2017年1月17更新

    好像最近这个帖子又被翻出来了,又陆续有一些朋友点赞或者留下评论,谢谢大家!有一些大家共同关心的问题,我在这里做一些统一的回复,谢谢!

    1. 那哥们后来怎么样了?

    没怎么样,混的不错。去Intel继续祸害大众了,哈哈

    2. 同行啊,请问答主目前哪里高就

    现在混互联网。搞了家小公司。不写BIOS很多很多很多年了

    3. 300万行代码如何编译成不足8m的rom?

    这个问题问得很好。首先300万行的规模是整个项目的规模,里面包含有几乎所有硬件的platform code,事实上在每个特定的主板上,是要做一些裁剪的,把一些这个主板没有用到的硬件代码去掉;其次这300万行里面还包含所有的工具代码,makefile,配置文件等等等等,尤其是工具类的代码,除去编译以及连接工具,大概有几十个自行开发的工具要参与构建过程,整个BIOS的构建过程首先就是先构建这些工具,然后再用这些工具去处理配置文件,创建总的makefile,在一步步的逐渐的去创建各个模块的makefile,最后再根据最上一级的模块配置文件来逐步的构建每一个组件。当这些组件都生成了,再根据预先配置好的FLASH的存储结构,按照相关的规范来打包成ROM文件,压缩格式是略微调整过的LZMA,按照FFS规范来进行存储

    我那个时候(2005年 - 2010年),编译工具用的是VS2003 + MASM;后来听说他们升级到了VS2010,貌似也可以用GCC了,好像也可以用Intel C Compiler


    2015年8月23更新

    评论里有几位朋友对于我提到的BIOS有上百万行源代码表示不可能,甚至有一位朋友提到BIOS就是个boot loader,要那么多代码干什么?我想我有必要在这里做一些简单的说明。

    在说明之前,我首先要申明一下由于我2010年就已经离开BIOS行业了,并且之后的日子我并没有持续的去跟踪最新的技术趋势,所以我对于目前的最新情况并不了解,事实上这个行业的知识刷新速度看起来非常快。所以我这里说的其实还是基于我当年的知识构成。

    首先,目前的BIOS都是基于UEFI的新一代BIOS。这类系统本身就具备十分强大的功能。完全可以视作一个小型的操作系统,有自己的shell,自己的drivers,自己的app,甚至自己的图形环境。这样的系统的代码量自然不会小。

    其次是因为x86系统的历史包袱非常非常严重,而bios作为最核心的系统固件承担了太多的历史兼容性的责任。举个例子,就是对于usb键盘的支持,大家可能会简单的认为,支持一个usb键盘那不是太简单的事情么?的确是这样,但是个人电脑有一个非常非常重要的原则就是兼容性。具体到键盘上,如果你现在找一个古董级的PS/2接口的键盘,然后把它接到现代的主板上,假如你的主板已经没有PS/2接口了,那么买一个转换头,然后再接上去你会发现这个古董级的硬件仍然可以使用。是的!对于我们用户而言,这是完全符合逻辑的一件事情。但是对于bios开发者而言,这就是一个很要命的问题了。原因很简单,我们暂时穿越到几十年前,那个年代的电脑主板上都有一个叫做8042的芯片,用来控制诸如键盘这样的外设,那个时代的开发者通过读写60H以及64H端口来访问键盘,然后那个时代的汇编BIOS则提供了INT 9H中断来为应用程序提供键盘服务,在几十年前那个时代,这一切是很美好的。那个时代的操作系统DOS就是这样来访问键盘的。现在让我们回到更加美好的现代,由于历史兼容性原则,所以现在的每一台计算机还必须可以安装DOS,还必须让DOS或者运行在DOS之上的应用程序可以无差别的运行在现代的计算机之上 - 可是,大家是否知道,现代的计算机压根没有8042这块芯片!更要命的是,后来人们发明了一个叫做USB的新玩意儿,基于这个新玩意儿的键盘根本不会接到60/64端口上,而且这个新接口的键盘采用的编码与过去PS/2接口的编码完全不一样!那么如果不做任何处理的情况下,那些过去年代的软件压根不会认识新的键盘,所谓的历史兼容性根本无从谈起!所以我们伟大的bios这个时候就扮演了救世主的角色了,bios会做很多处理,以现在的角度看,现代bios模拟了一个PS/2键盘:现代bios一边读取来自USB键盘的信息,一边将其转换成那些古老软件能够识别的键盘编码,然后再中断系统,写入内部的60/64端口的缓冲区。大家也许会发现,所有的现代bios里会有一个设置项,一般叫做legacy USB Support,默认值就是Enable,打开这个选项你才可以在DOS下使用usb键盘。当然,具体的实现过程异常复杂,涉及x86处理器最神秘的SMM模式,我们就不展开讲了,这已经远远超出本文的初衷。所以一句话,bios的代码非常复杂,还要包含大量的历史兼容性代码,除了我们上面谈及的键盘问题,还包括比如INT 10H的屏幕服务,据说直到Windows 7的安装程序,还有一小部分使用INT 10H来写屏。那么我们的bios就必须包含这些可能有些用户一辈子也用不上的服务。代码量刷刷的就上去了。

    --------------------------

    每次想起这个bug,虽然很多很多年了,我仍然满脸都是泪水啊!

    当年做x86 BIOS,客户是长城电脑。有一回我们的新版本发布给他们后进行系统重启测试,就是安装好操作系统后反复不停的重启机器,看看重启几百上千次后情况如何。原因是客户买了电脑每天用,至少得保障人家用个俩三年没事吧。

    结果我们的新版本重启到一百多次的时候挂了,现象就是开机黑屏,没有任何输出,就和当年的CIH病毒发作一模一样,经验判断系统压根还没有boot OS就跑飞了,我们自己测试也是这样,而且一旦出现问题就只能重新刷BIOS

    这个bug非常难调,因为当时我们的版本将近300万行源代码,大概2%的汇编与98%的C,几千个源文件,光是用来参与build过程的工具就有十几个。而且这些工具都是自己写的,构建项目的时候先编译这些工具,再去用这些工具加编译器来生成最后的ROM文件

    并且更加恼人的是,我们当时没有source level的debug tool,甚至连汇编级别的单步调试工具也没有,压根没法对代码做step into/over,更没法加个断点。。。当时可以用来调试BIOS的工具有两个,一个是Intel自己内部用的ITP,这个是人家公司自己的,一般不给外面人用,当时我们公司与I公司的关系尚处蜜月期,给了我们两个,但是当时被Chipset team霸占着做porting用;另一个工具就是American Arium(这家鸟公司不知道现在还活着不),这个东西说白了就是商品化的ITP,因为目标客户少,所以价格巨贵巨贵!一套系统价格几万美金,而且每一代CPU都要换一个插座上的适配器,这个适配器又是一万美金好像,还不太稳定,用着用着就挂了。。。我们公司当时有俩,但是因为没有买新一代处理器的适配器,于是只能吃灰了

    于是我们唯一的调试手段就是serial debug,就是系统启动的时候会通过port 80把一些重要信息打出来,然后我们根据这些信息判断执行到哪里了,系统的情况如何。这类似原始的printf打印。如果要看一个变量的值或者验证一下我们的判断,就得重新写代码,在需要的地方加入调试语句,然后花上半个小时rebuild bios,再重新烧录,再上电运行看看打出来的到底是啥。如果有疑问,或者发现这里没有问题,又或者有了新的思路,重复上述过程。记忆中整整一个礼拜,我们都在不停的看debug info,反复烧录bios 哭啊!简直不是人过的日子!

    最后发现系统可以成功的跑过PEI,到了DXE阶段的某个环节,突然就像心脏骤停一样,跑飞了!去看疑似跑飞的DXE Driver,是个很普通的平台硬件初始化程序,没什么疑点,压根没有头绪。那段时间,几乎每时每刻都在想着这个bug,实在是茶饭不思,根本没心情做任何事!

    就这样差不多过了俩礼拜,经过了无数次的重启与烧录bios,以及猜测,验证,被否定,再猜测,再验证,再否定。。。。。的过程后,我们终于发现了问题的原因:

    大家可能还记得电脑主板上有个CMOS,传统上用来存bios设置,但是现代的系统已经逐渐弃用这个东西。我们现在的bios芯片都是可擦写的,也就是用程序可编程。bios大小是8MB,里面会规划好,哪里是code,哪里放设置等等,然后代码里有专门写flash的函数,让大家可以保存一些东西,比如你想用硬盘还是光驱启动等等。同时系统每次启动也都会自己写一点没什么鸟用的信息进来。

    问题就出在这个写flash的函数上,我们后来发现,这哥们算错了存储区域的地址,导致写很多次后终于越界,误写到了人家代码区,把人家好端端的代码给写的乱七八糟,就如同当年CIH破坏系统的方法一模一样,照这样哪个机器能点亮才怪呢!又因为每次系统写的信息不一样,比如启动时间就不太一样,所以越界需要的次数不是恒定,更加重了我们排错的难度,泪啊!

    第一次写这么长的回答,还是手机打的,累!

    本问答由林铠鹏提供

* 本站部分内容来源自网络,仅作分享之用,侵删。