请保留-> 【原文: https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】
这篇博客使用的是Windbg+UDK Debugger Tool调试代码,在Windows10下操作,具体搭建方法可以查看以前的博客。
在最近的开发中,因为碰到不少问题,对UEFI的调试方法更为深入了。在第39篇博客中留下的问题(7 小尾巴),也有了解答,后续看什么时候再把解答补上。
虽然在日常开发中,很少直接用到固件,但在学习中,需要跟踪UEFI每个阶段的工作,直接使用OvmfPkg编译后的Firmware,对其进行调试是个不错的方法。
图1为UEFI运行的7个阶段:
我使用的工具是windbg+intel UDK Debugger Tool,当然,在Linux下使用gdb+UDK debugger Tool也是可以的,有空时也把Linux下调试过程记录下来。
针对几个阶段的调试过程,介绍如下。
1 添加调试支持
所添加的调试库(DebugAgentLib),用来支持源码级别的调试。DSC文件中需要修改的内容如下:
Libraries
[LibraryClasess] General
PeCoffExtraActionLib
[LibraryClasses.IA32] PEI
DebugAgentLib
[LibraryClasses.X64] DXE
DebugAgentLib
[LibraryClasses.X64.DXE_SMM_DRIVER] SMM
DebugAgentLib
源码级调试,其SourceLevelDebugPkg Lib对应Module的INF文件为:
PeCoffExtraActionLibDebug.inf
SecPeiDebugAgentLib.inf
DxeDebugAgentLib.inf
SmmDebugAgentLib.in
FDF文件中,需要添加TerminalDxe.inf,示例如下:
[FV.FVMAIN]
. . .
# DXE Phase modules
. . .
Comment out module for
TerminalDxe.inf
#INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
在OvmfPkg中,上述调试支持已经添加了。注意查看其DSC文件,以编译宏开关SOURCE_DEBUG_ENABLE包含了相应的调试库支持。比如:
!ifdef $(SOURCE_DEBUG_ENABLE)
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf
!else
PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
!endif
当然,也并不是所有应用环境都能调试,以下限制需要注意:
- 不要去调试调试器本身;
- 不支持MSR(Model Specific Register)读写访问;
- 不支持多处理器;
- 不支持纯粹的32位平台;
- 不是所有Windbg命令都支持;
- 在Module没有加载前,无法对其设置断点;
- 部分代码无法被调试,比如早期的SEC、早期SMM;
编译OvmfPkg的方法,在之前的博客中已经讨论过了,比如针对x64,其编译命令为:
build -a X64 -p OvmfPkg\OvmfPkgX64.dsc -b NOOPT -D SOURCE_DEBUG_ENABLE
2 SEC阶段调试
其实最好是从Reset Vector开始调试,可是我没找到在实模式下ffff:fff0下断点的方法。如果有哪位朋友知道如何下断,望不吝告知(在评论中写就可以了,多谢^^)。
目前我采用的办法是,从最开始处,通过汇编指令一直跟踪下去。曾经尝试过在PEI阶段读取到了SECMAIN模块的符号,然后对SECMAIN下的函数下断,比如bp SECMAIN!IsS3Resume,没有成功。直接对执行地址下断,也没有成功。
找个机会问问人吧。
SEC阶段可以去查看CAR(Cache As RAM)的实现,如何进入保护模式的过程等,这个过程比较枯燥,有兴趣的话可以跟踪试试。
3 PEI阶段调试
在启动调试的时候,可以执行如下命令:
bp PEICORE!PeiCore
执行命令‘g’之后,程序会断在$MyWorkspace\mdemodulepkg\core\pei\peimain\peimain.c中的PeiCore()函数上,之后就可以跟踪PEI阶段的代码了。
如果想直接看Pei Module的分配过程,可以在如下函数上下断:
bp PEICORE!PeiDispatcher
函数位于$MyWorkspace \mdemodulepkg\core\pei\dispatcher\dispatcher.c下。
4 DXE阶段调试
调试DXE阶段的驱动加载过程,可以在下面的函数上下断点:
bp DXECORE!CoreStartImage
函数位于$MyWorkspace \mdemodulepkg\core\dxe\image\image.c下。
在执行到此处时,使用lm命令,查看得到的模块信息如下:
0: kd> lm
start end module name
00000000`00820120 00000000`0083a260 PEICORE (private pdb symbols)
00000000`0083a400 00000000`00843940 PCDPEIM (private pdb symbols) 00000000`008439a0 00000000`008486e0 REPORTSTATUSCODEROUTERPEI (private pdb symbols)
00000000`008487a0 00000000`0084df60 STATUSCODEHANDLERPEI (private pdb symbols)
00000000`0084e020 00000000`0085f060 PLATFORMPEI (private pdb symbols)
00000000`07b88000 00000000`07b9ae60 DEVICEPATHDXE (private pdb symbols)
00000000`07ed3000 00000000`07f2ed60 DXECORE (private pdb symbols)
00000000`07f38000 00000000`07f49180 CPUMPPEI (private pdb symbols)
00000000`07f4a000 00000000`07f53f60 S3RESUME2PEI (private pdb symbols)
00000000`07f54000 00000000`07f5fd80 DXEIPL (private pdb symbols)
00000000`07f60000 00000000`07f7a140 PEICORE_7f60000 (private pdb symbols)
00000000`fffcc094 00000000`fffe2f54 SECMAIN (private pdb symbols)
可以使用x命令,查看各模块的符号,以及哪些函数可以调试。
5 BDS阶段调试
下断点:
bp DXECORE!DxeMain
函数位于$MyWorkspace \mdemodulepkg\core\dxe\dxemain\dxemain.c。函数中的这几句,是进入BDS的入口:
gBds->Entry (gBds);
// BDS should never return
ASSERT (FALSE)
使用windbg过程中的一些常用命令:
.reboot //重启目标机器
x //显示模块符号,包括函数、变量等
lm //列出所有加载模块
bp //下断点
ba //在物理地址上下断点,示例ba e1 0x820000
g //执行,直到断点被命中
3,276 total views, 1 views today