UEFI开发探索28 – 用Windbg建立UEFI调试环境

(请保留->发布地址: http://yiiyee.cn/blog/author/luobing/ )

最近的翻译计划和博客计划严重滞后。一方面是因为有两个案子在推进,业余时间也被占用;另外一方面,在尝试用windbg搭建调试环境的时候,遇到了一些阻碍。

大部分情况下,我都是使用win10的虚拟机,配合UDK2018开发的。对照文档,第一次尝试就失败了。

文档中建议的环境是Win 7/Win8 64位,UDK2010。搭建win7的虚拟机,安装Vs2008+UDK2010,再试,不行。

我怀疑虚拟机是不是会有影响,幸好公司到处都是Mini PC。下班后找了台实际机器搭建,还是不行。

在工作间隙和下班后,只要有时间,我就苦苦寻找可能性。各类操作系统,各类UDK,各版本Qemu和各版本windbg,组合起来起码也有20几种。

在我搭建这些环境的次数多到想吐,准备转到Linux下时,今天早上,竟然成功了!

冷静下来思考,发现自己有80%以上的工作,都是无用功。不过正如7个炊饼的故事一样,这些无用功才引导我尝试成功。收拾起心情,把这几天的无用功整理一下。

1 经验教训

我参考的文档主要来自UDK Debugger Tool的说明书,以及网上有位同行分享的博客。网址分别为:

https://firmware.intel.com/develop/intel-uefi-tools-and-utilities/intel-uefi-development-kit-debugger-tool
https://www.cnblogs.com/zhongts/p/5789686.html

另外,Ovmf的编译,在EDK的github上也能找到,网址就不再贴出了。

intel提供的调试工具版本为1.5,安装之前必须装好windbg。文档中使用的是WinDbg6.11.0001.404,我简单尝试了其他版本的windbg,之后就回到了文档建议的版本。

UDK2018是可以的,不一定非得UDK2010去编译。我的理解,只要SourceLevelDebugPkg的版本号高于0.85,就可以配合UDK Debugger tool v1.5工作。其版本号可以再dsc文件中查看,我的UDK2018中所用的版本号是0.95,工作得很好。

到了坑人的地方了:Qemu必须用0.13的版本!

我起码试了不下10个版本的Qemu,在上面的博客中,作者提醒过他用的是特定版本0.13,我并没有当回事。UDK Debugger Tool的文档中并没有特别提示此事,EDKII的文档中也没有相关内容。就是这个疏忽,让我折腾了整整一周!

开始搭建吧,我在实际机器上和虚拟机上都试过,都可以工作。用来示例的是虚拟机环境,主要软件配置为:Win10+VS2015+UDK2018,intel UDK Debugger Tool v1.5+Qemu 0.13.0,WinDbg6.11.0001.404,以及用来导入efi文件到img镜像的WinImage 8.0。

2 调试工具和Qemu安装

Windbg的安装比较简单,注意不要修改其安装的缺省路径,Intel UDK Debugger Tool(名字好长,就简称为Debugger吧,不会搞混就行了)会自动寻找它。 Debugger安装的时候,注意这个步骤,我们准备使用命名管道作为通信道路:

图1 安装UDK Debugger Tool

Debugger将搭建windbg与Qemu(实际应该是Ovmf)之间的通道,实现源码级的UEFI App/Driver调试。

Qemu的安装比较简单。不过,Qemu官网上,我没有找到0.13版本的软件。找起来确实麻烦,我把qemu和windbg放到百度云里了。

Qemu安装后,记得在系统Path中添加其目录。

图2 设定Qemu目录

3 编译OvmfPkg

我们需要一个Qemu支持的BIOS image,OvmfPkg就是为了实现这个目的而存在的。之前写的App,为了在TianoCore的模拟环境中运行,一般都是编译为32位的。因此,所需要的Ovmf镜像应该是32位的。根据需要,OvmfPkg 可以编译为32位或者64位。

32位的编译命令:
build -a IA32 -p OvmfPkg\OvmfPkgIa32.dsc -b NOOPT -D SOURCE_DEBUG_ENABLE
64位的编译命令:
build -a X64 -p OvmfPkg\OvmfPkgX64.dsc -b NOOPT -D SOURCE_DEBUG_ENABLE

编译出来的文件在\MyWorkspace\Build\OvmfIa32\NOOPT_VS2015x86\FV和\MyWorkspace\Build\OvmfX64\NOOPT_VS2015x86\FV下。

UDK2018集成得已经比较好了,需要注意的地方不多。主要是需要打开SOURCE_DEBUG_ENABLE的宏开关,使得镜像文件支持源码级调试。Debugger的文档中对此有很详细的说明,就不一一讨论了。

另外,在前面的博客《搭建环境3》中没有提到ASL工具的建立。编译的时候出错了,根据github上UDK2018搭建说明,找到asl的网址,下载软件并拷贝到相应目录,添加到Path中就可以了。

4 调试

1) 启动” Start WinDbg with Intel UDK Debugger Tool”,Debugger和windbg将会启动,如图:

图3 启动调试器

2) 把所需要的OVMF.fd文件以及其他镜像文件拷贝到同一个目录下(非必要,可以命令行指定各个文件,我主要是为了操作方便)。如图:

图4 准备调试需要的文件

其中,OVMF.fd是从32位编译的OvmfPkg中拷贝而来。

dos.img是我很久以前,为了开发Foxdisk而做的一个镜像文件,当时是为了在bochs中启动Dos而做的。Qemu本身也提供创建img的功能,可以按照帮助文档做一个。dos.img中是一个格式化为Fat32的硬盘,并且安装了DOS7.1。

lbdebug.img是一个软盘镜像,非常古老的东西了。里面也是个Dos启动盘,这次我们不需要使用它。

qemu-x86_64.bat是我从Qemnu 0.13的目录中拷贝过来的,并且根据自己的需要做了一些修改。注意看最后一行,指定了BIOS镜像,硬盘镜像以及串口的命名管道。

3) 一切就绪后,双击qemu-x86_64.bat,windbg很快就挂载上了:

图5 windbg第一次断点

输入’g’,windbg继续运行,同时会加载很多符号。

进入UEFI Shell中,FS0:为第一个硬盘,也是就我们之前指定的dos.img文件。

4) 调试UEFI app。

把之前显示PCX的例子拿来编译,注意指定TARGET = DEBUG。 将编译好的执行文件Luo2.efi拷贝至dos.img中。我是使用winimage来拷贝的:

图6 准备需要调试的执行文件

安装步骤3中的顺序,启动调试,进入UEFI Shell。执行Luo2.efi之前,Ctrl+Break中断执行,在windbg的命令行中下断点:bu Luo2!ShellAppMain,按’g’继续执行。

在UEFI shell中执行Luo2.efi,程序会被中断到指定位置,源码也会被调出:

图7 源代码级调试app

从图中可以看出,断点命中了。

开始调试的时候,我习惯性地给Luo2!UefiMain下断,始终命中不了。最后才发现是自己手误了,清除了这些断点后,才中断到我期望的地方。

5 一些小技巧

在尝试搭建调试环境时,文档翻来覆去地看,问题一个个解决。在这个过程中学会了一些小技巧,值得记录下来。

第一是Intel UDK debugger Tool的配置文件。在其开始菜单的软件目录下,有个”Change Configurations”的选项,打开后可以编辑SoftDebugger.ini,修改软件的配置文件。把这段加入:

[Debug]
Debug=1

这将启动对SourceLevelDebugPkg的版本检查。在调试UDK2010的时候,弹出图8的对话框,我才确定自己找对了方向。这是很好的调试信息,不知道为什么要隐藏起来。

图8 版本不对应的提示

第二是对命名管道的检查。最开始时,怎么都不成功。我看什么都有问题,也怀疑命名管道是不是创建成功,需要一个工具来检测。

我本想自己写个命名管道的枚举工具,但是似乎记得微软的Sysinternals工具集中提供了类似的工具。问了张佩,他告诉了我名字(感谢^_^):pipelist。我们调试的命名管道qemu_pipe_dbg是由qemu创建的,截图如下:

图9 pipelist

工具可以在微软的网站上下载:https://docs.microsoft.com/en-us/sysinternals/

6 细节未解

在安装调试环境的过程中,我下载了很多工具。比如在安装win7+vs2008+UDK2010的过程中,找不到Vs2008的完整版,只好用express版。发现编译工具中竟然少了ml.exe! 只好拷贝了之前环境中的软件过来,编译通过了。

类似这样的细节,实际上需要一个个去抠。大部分都是不需要深究的问题,解决了也就解决了,我记录在自己的有道云笔记上。不过有些问题还是值得研究一下。

我想象中需要深究的几个问题:

1) 只能支持Qemu0.13,到底是怎么回事?是因为Qemu后面的版本修改了什么,导致windbg无法挂上吗,还是Intel UDK Debugger Tool本身的原因?
2) 这种调试方式,似乎不能支持所有windbg的命令,虽然对我而言已经足够了,哪些命令不能支持,什么原因 ?
3) Intel UDK Debugger Tool的原理是什么,怎么通过命名管道让windbg跑起来的?windbg对此支持的机制是什么?
4) SourceLevelDebugPkg是如何运作的?之前串口读的问题没有解决,我觉得应该是使用Event,至于如何使用,从这个Pkg中估计能找到很多例子。

当然,还有其他很多各类问题,在后续的开发中慢慢学习吧。另外,也要找个时间,把Linux下的调试环境搭建起来。从intel网站上的时间来看,intel UDK debugger Tool的windows版更新时间为2015年,Linux版为2017年。看来Linux下的更新一些,也许BUG会少点。

这是之后的事情了,下篇开始,回到主干道上来,继续格UEFI APP和Option ROM。

百度云链接:https://pan.baidu.com/s/1gccSosw8_UAGTI5gZPnLCA
提取码:dx23
文件在 X5 调试所需工具 下
工具不解释了,都是博客中所用过的工具。WinImage没有放入,因为是收费软件,可以到网上去下载。

8,136 total views, 5 views today

《UEFI开发探索28 – 用Windbg建立UEFI调试环境》有11个想法

  1. HI 博主,

    感谢你的分享, 按照你的步骤我可以加断点 debug UEFI APP. 这边还有个问题 如果我想debug driver(比如PCI driver)要怎么搞呢。 我在Qemu里面输入pci cmd 只能看见很少的pci 设备, 因为根据相应的ID安装相应的驱动, 但是这个ID 在Qemu里面都找不到。

    Thanks

    1. 我调试过pci option rom,也是一种pci driver,是可以加载的。是不是你的代码没有符合规范? 猜测的,找一个空driver先试着load,看看是否加载了。

      1. 我插了一个PCI设备,在开机UEFI启动 shell里 我输入pci 是可以看到该设备的(没有装驱动)。 然后我我去load drv 就可以根据ID给该设备安装驱动了。 但是如果用Qemu 我就找不到那个PCI设备。 我在想是不是Qemu完全就是虚拟的, 并不能mapping电脑上所有的PCI设备。 所以如果是PCI driver的debug 需要双机调试(Host/Remote), 这种Qemu更适合APP 不太适合driver是么?

        然后如果是双机调试 有没有比较详细的文档呢, 刚接触UEFI 很多不懂,也走了很多弯路。 然后在网上搜索了Debug相关的资料, 大多都是讲Qemu 这种方式, 但是对driver来说好像不是太适用。

        然后如果方便的话 可以加个Q么?

        1. 在uefi的培训文档中,有关于使用windbg/dbg双机调试的。看intel的文档中,就是这个使用windbg调试uefi的说明,应该是可以双机调试的,我也没去试。调试driver,我使用打印的方法基本上就足够了,目前遇到的问题也没有需要到双机调试这个地步的。

          后面看是否有机会尝试一下,到时再和大家讨论。

          另外,intel提供了DCI的接口,可以进行芯片级的调试,有兴趣可以自己研究下。

    1. 可以的哦。直接用双机调试更好,intel提供了trainning的文档,可以去看看:https://github.com/tianocore-training/Tianocore_Training_Contents/wiki

发表评论

电子邮件地址不会被公开。