UEFI开发探索39 – Ubuntu 16.04下用gdb建立UEFI调试环境

(请保留-> 作者: 罗冰)

准确地说,应该是在Ubuntu 16.04下,使用Qemu模拟UEFI启动环境,同时配合Intel UDK Debugger tool和gdb建立的X64调试环境。

使用的是Qemu和OvmfPkg,类似于之前使用windbg在Windows下搭建调试环境,这次换为在Linux下搭建了。正是上一篇博客留下的题目。

1 参考资料

如何在Linux下搭建调试环境,网上的资料不多,特别是如何让gdb挂上UEFI启动环境,我摸索了几天。

可供参考的资料有《UDK_Debugger_Tool_User_Manual_V1.11.pdf》,在网站https://firmware.intel.com/develop/intel-uefi-tools-and-utilities/intel-uefi-development-kit-debugger-tool上下载,其中第六章开始介绍如何在Linux下搭建调试环境。

以及开源项目Slim Bootloader: https://slimbootloader.github.io/index.html。它在调试的时候使用了UDK Debugger Tool,搭建调试环境的方法可用来类比。

UEFI开发探索39 – Ubuntu 16.04下用gdb建立UEFI调试环境_第1张图片

图1 Slim Bootloader’s LOGO

这个开源项目还处于早期阶段,甚至都没到1.0。既然它主要偏向于x86(intel推出的项目),是不是能够考虑用于机器人的x86开发板?它的编译架构和EDKII很类似,可以找时间研究研究。

其他的资料就来源于Google和Bing了(Baidu上找需要的资料很费劲),主要解决的问题包括:Qemu的镜像盘创建、gdb编译、镜像文件的格式化和数据拷贝等等。

编译OvmfPkg

可以对照本系列博客第28篇-使用windbg建立调试环境,很多步骤比较类似。

需要说明的是,我在Ubuntu 16.04下所建立的开发环境,是直接git EDKII的最新文件。在编译OvmfPkg的时候需要openssl,使用哪个版本的openssl颇费了一番周折。

UDK2018下使用的openssl-1.1.0g,拷贝到对应文件夹后,编译时提示缺少aria.c文件。下载了各种版本进行实验,最后发现openssl-1.1.1c.tar.gz是可以编译OvmfPkg的。

UEFI开发探索39 – Ubuntu 16.04下用gdb建立UEFI调试环境_第2张图片

图2 所使用文件

 

图2为我搭建环境所使用的文件,像这种因为版本导致的问题,实在够弱智的,在帮助文件中应该指明才对。

Linux下主要是用来调试64位程序的,所以编译64位的OVMF.fd就可以了,贴出编译命令:

$ . edksetup.sh
$ build -a X64 -p OvmfPkg/OvmfPkg.dsc -b NOOPT -D SOURCE_DEBUG_ENABLE

编译出来的文件OVMF.fd在/home/robin/src/edk2/Build/OvmfX64/NOOPT_GCC5/FV下,将其拷贝到自己需要的文件夹下即可。

搭建环境概述

参照UDK Debugger Tool的用户手册,6.1节给出了搭建Linux调试环境的主要步骤:

1) 编译固件镜像并且烧录到TARGET中(举例说来,就是编译需要调试的efi程序,并且放入调试目标中,比如Qemu启动的UEFI运行环境);
2) 在主机上(HOST)上重编译GDB;
3) 在主机上(HOST)安装Intel UDK Debugger Tool; 4) 连接主机(HOST)与目标机(TARGET)。

UEFI开发探索39 – Ubuntu 16.04下用gdb建立UEFI调试环境_第3张图片

图3 Linux平台上的调试组件

第1步不用说了,按照平常编译efi程序的步骤进行即可。

第2步有点奇怪,我到现在也有点糊涂。参照用户手册,重编译gdb的目的是使gdb包含解析Expat XML的分析库。而我机器上的gdb中,查看一下配置:

UEFI开发探索39 – Ubuntu 16.04下用gdb建立UEFI调试环境_第4张图片

图4 我机器上的gdb配置

从中可以看到,已经有了—with-expat了。不过,从最终的结果来看,调试的时候没有进入源代码级别,是不是和这个还是有关系,我没有弄清楚。

姑且把重编译gdb的步骤记录一下,防止以后需要:

1) 安装expat(也可以按照用户手册的说明,下载源码编译)

$ sudo apt-get install libexpat-dev
$ sudo apt-get install expat

2) 编译安装gdb

$ wget “http://ftp.gnu.org/gnu/gdb/gdb-7.11.1.tar.gz
$ tar -xvzf gdb-7.11.1.tar.gz
$ cd gdb-7.11.1
$ sudo ./configure –with-expat
$ sudo make
$ sudo make install

补充一下,我的make install没有成功,没找到问题所在。待以后有需要的时候再仔细钻研,目前还是继续探索之旅吧。

安装UDK Debugger Tool

下载的UDK_Debugger_Tool_v1_5_1_Linux.zip,解压后其安装文件是一个bin文件,采用了JDK的方式进行打包。

安装步骤如下:

$ sudo chmod +x UDK_Debugger_Tool_v1_5_1.bin
$ sudo ./ UDK_Debugger_Tool_v1_5_1.bin

之后将会启动界面,继续进行安装。前几个步骤选择缺省设置即可,在配置调试端口时,如下进行配置:

UEFI开发探索39 – Ubuntu 16.04下用gdb建立UEFI调试环境_第5张图片

图5 设置pipe:/tmp/serial

最终的配置为:

UEFI开发探索39 – Ubuntu 16.04下用gdb建立UEFI调试环境_第6张图片

图6 最终配置参数

点击”Install”按钮,继续安装直到完成。

建立调试用镜像硬盘

在之前用Windbg搭建Window下调试环境时,我使用了img文件作为Qemu的硬盘。而调试用的efi执行文件,是通过WinImage拷贝到img文件中的。

在Linux下,这个工作可以通过命令dd和mount完成,非常简单。

先准备好需要调试的程序。我使用上一博客的例子Luo3.c,在需要调试的位置添加代码CpuBreakpoint(),像这样:


gST->ConOut->OutputString(gST->ConOut,L”please input key(ESC to exit):\n\r”);
CpuBreakpoint();
while(scanCode!=0x17)  //ESC
{…}

将示例程序编译为X64的,Target设置为Debug。

接下来创建调试用的Qemu镜像硬盘。我把之前编译好的OVMF.fd放在了文件夹ovmf-qemu下,类似地,把创建的硬盘镜像文件也放在此处。

$ dd if=/dev/zero of=~/ovmf-qemu/hda.img bs=1 count=60M
$ mkfs.vfat had.img
$ sudo mkdir /mnt/image
$ sudo mount -o loop ~/ovmf-qemu/had.img /mnt/image
$ sudo cp ~/src/edk2/Build/Shell/DEBUG_GCC5/X64/Luo3.efi /mnt/image/
$ sudo umount /mnt/image

上述的命令依次为:创建镜像、格式化镜像为FAT32、建立文件夹、镜像挂载、拷贝调试efi文件、镜像卸载。

嗯,从拷贝效率上来说,和WinImage差不多。如果写个批处理,速度会更快些。

开始调试

至此,调试的材料基本都准备好了。

哦,Qemu还没有安装,使用apt-get安装即可,在Ubuntu下没有之前Windows的限制(只能用0.13版),直接安装即可:

$ sudo apt-get install qemu

1) 建立pipe

$ mkfifo /tmp/serial.in
$ mkfifo /tmp/serial.out

2) 启动Terminal,运行udk-gdb-server

$ sudo /opt/intel/udkdebugger/bin/udk-gdb-server

3) 再开一个Terminal,启动qemu和uefi运行环境

$ cd ~/ovmf-qemu
$ sudo qemu-system-x86_64 -bios OVMF.fd -hdd hda.img -serial pipe:/tmp/serial

执行之后,将启动模拟环境。而运行udk-gdb-server的Terminal,也将连接上它,如图:

UEFI开发探索39 – Ubuntu 16.04下用gdb建立UEFI调试环境_第7张图片

图7 启动模拟环境,并与udk-gdb-server连接

4) 再开一个Terminal,启动gdb和udb调试

$ gdb
(gdb) source /opt/intel/udkdebugger/script/udk_gdb_script
(udb) target remote robin-virtual-machine:1234
(udb) c

注意,在udb中设定的调试目标,是使用图7中所标识的。

5) 继续运行UEFI模拟环境,执行Luo3.efi,将中断到之前设定的CpuBreakpoint()处,此时可用开始使用udb进行调试了。

UEFI开发探索39 – Ubuntu 16.04下用gdb建立UEFI调试环境_第8张图片

图8 开始调试示例代码

小尾巴

磕磕碰碰地建立起了调试环境,但 从上面的调试来看,只能进行汇编级别的调试,没有达到源代码级调试的效果。我怀疑和gdb没有重新编译有关系。

不过,我在linux下搭建编译和调试环境,已经花了太多时间了。而且从效果看,并不一定比在Windows编程更快,毕竟我还是更熟悉微软的编译器。

这条小尾巴已经没有时间解决了,等到在Linux开发更熟悉的时候再来解决。后面还有十几篇的计划,还是回到Windows上来开发吧。

调试工具可参考网站:

http://unicon.org/utr/utr10.html#_Toc232119627
https://sourceware.org/gdb/current/onlinedocs/gdb.html#Break-Commands
http://www.gdbtutorial.com/tutorial/how-install-gdb

你可能感兴趣的:(UEFI开发)