|
|
https://retrage.github.io/2019/12/05/debugging-ovmf-en.html
Building EDK2
Build EDK2 using gcc as usual.
$ git clone git@github.com:tianocore/edk2.git
$ cd edk2
$ git submodule update --init --recursive
$ source edksetup.sh
$ make -C BaseTools
$ build -p OvmfPkg/OvmfPkgX64.dsc -b DEBUG -a X64 -t GCC5
To make debugging easy, create a Makefile as follow. Note that we have to connect debugcon at 0x402 to dump debug information (debug.log) from OVMF[4].
#!/usr/bin/env make
SHELL=/bin/bash
LOG=debug.log
OVMFBASE=edk2/Build/OvmfX64/DEBUG_GCC5/
OVMFCODE=$(OVMFBASE)/FV/OVMF_CODE.fd
OVMFVARS=$(OVMFBASE)/FV/OVMF_VARS.fd
QEMU=qemu-system-x86_64
QEMUFLAGS=-drive format=raw,file=fat:rw:image \
-drive if=pflash,format=raw,readonly,file=$(OVMFCODE) \
-drive if=pflash,format=raw,file=$(OVMFVARS) \
-debugcon file:$(LOG) -global isa-debugcon.iobase=0x402 \
-serial stdio \
-nographic \
-nodefaults
run:
$(QEMU) $(QEMUFLAGS)
debug:
$(QEMU) $(QEMUFLAGS) -s -S
.PHONY: run debug
Before debugging, run the firmware to get debug.log. It may be better to provide startup.nsh script.
$ make run
Now, we have debug.log. It includes the addresses of loaded UEFI images like this:
Loading PEIM at 0x00007EA8000 EntryPoint=0x00007EAB0BC DxeCore.efi
Next, extract text section (.text) RVA from *.efi PE binaries. This can be done by readelf if it is ELF, but the images are PE format. Here we use retrage/peinfo[3].
$ git clone git@github.com:retrage/peinfo.git
$ cd peinfo
$ make
peinfo extracts section information from a binary. This time we want to know VirtualAddress in RVA.
Name: .text
VirtualSize: 0x000204c0
VirtualAddress: 0x00000240
SizeOfRawData: 0x000204c0
PointerToRawData: 0x00000240
PointerToRelocations: 0x00000000
PointerToLinenumbers: 0x00000000
NumberOfRelocations: 0x0000
NumberOfLinenumbers: 0x0000
Characteristics: 0x60000020
Run following bash script with debug.log and peinfo. This outputs a snippet of GDB script that adds symbol information (add-symbol-file). It calculates the address of UEFI image text section from base address and VirtualAddress.
#!/bin/bash
LOG="debug.log"
BUILD="edk2/Build/OvmfX64/DEBUG_GCC5/X64"
PEINFO="peinfo/peinfo"
cat ${LOG} | grep Loading | grep -i efi | while read LINE; do
BASE="`echo ${LINE} | cut -d " " -f4`"
NAME="`echo ${LINE} | cut -d " " -f6 | tr -d "[:cntrl:]"`"
ADDR="`${PEINFO} ${BUILD}/${NAME} \
| grep -A 5 text | grep VirtualAddress | cut -d " " -f2`"
TEXT="`python -c "print(hex(${BASE} + ${ADDR}))"`"
SYMS="`echo ${NAME} | sed -e "s/\.efi/\.debug/g"`"
echo "add-symbol-file ${BUILD}/${SYMS} ${TEXT}"
done
$ bash gen_symbol_offsets.sh > gdbscript
cat gdb
The generated GDB script is like this:
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/PcdPeim.debug 0x82c380
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/ReportStatusCodeRouterPei.debug 0x831080
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/StatusCodeHandlerPei.debug 0x833100
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/PlatformPei.debug 0x835100
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/PeiCore.debug 0x7ee8240
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/DxeIpl.debug 0x7ee3240
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/S3Resume2Pei.debug 0x7edf240
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/CpuMpPei.debug 0x7ed6240
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/DxeCore.debug 0x7ea8240
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/DevicePathDxe.debug 0x7b8f240
Now we are ready.
$ less debug.log
...
The 0th FV start address is 0x0000082000
...
Loading PEIM at 0x0000082BFC0
Entry Point = 0x0000082F40A PcdPeim.efi
...
$ make debug
Let’s place a breakpoint at BootServices->HandleProtocol().
(gdb) source gdbscript
.
.
.
add symbol table from file "/home/koenigr/Memtest/git/edk2/Build/OvmfX64/DEBUG_GCC5/X64/UsbBusDxe.debug" at
.text_addr = 0x6c85240
add symbol table from file "/home/koenigr/Memtest/git/edk2/Build/OvmfX64/DEBUG_GCC5/X64/UsbKbDxe.debug" at
.text_addr = 0x6cb3240
add symbol table from file "/home/koenigr/Memtest/git/edk2/Build/OvmfX64/DEBUG_GCC5/X64/UsbMassStorageDxe.debug" at
.text_addr = 0x6c6d240
add symbol table from file "/home/koenigr/Memtest/git/edk2/Build/OvmfX64/DEBUG_GCC5/X64/QemuVideoDxe.debug" at
.text_addr = 0x6c66240
add symbol table from file "/home/koenigr/Memtest/git/edk2/Build/OvmfX64/DEBUG_GCC5/X64/VirtioGpuDxe.debug" at
.text_addr = 0x6c60240
add symbol table from file "/home/koenigr/Memtest/git/edk2/Build/OvmfX64/DEBUG_GCC5/X64/Shell.debug" at
.text_addr = 0x64f5240
(gdb) info functions CoreHandleProtocol
All functions matching regular expression "CoreHandleProtocol":
File /.../edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c:
EFI_STATUS CoreHandleProtocol(EFI_HANDLE, EFI_GUID *, void **);
(gdb) info address CoreHandleProtocol
Symbol "CoreHandleProtocol" is a function at address 0x7ea4aa9.
(gdb) b CoreHandleProtocol
(gdb) info symbol 0x82F40A
_ModuleEntryPoint in section .text of /home/koenigr/Memtest/git/edk2/Build/OvmfX64/DEBUG_GCC5/X64/PcdPeim.debug
(gdb) b *0x82F40A
Breakpoint 2 at 0x82f40a: file /home/koenigr/Memtest/git/edk2/MdePkg/Library/PeimEntryPoint/PeimEntryPoint.c, line 33.
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x000000000000fff0 in ?? ()
(gdb) c
The debugger stops, and we can do source code level debug.
!!!!!!!!!!!!!!!!!!!!!!!!!!! DOES NOT WORK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
┌──/home/akira/src/ovmf-debug/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c──────┐
│933 CoreHandleProtocol ( │
│934 IN EFI_HANDLE UserHandle, │
│935 IN EFI_GUID *Protocol, │
│936 OUT VOID **Interface │
│937 ) │
B+>│938 { │
│939 return CoreOpenProtocol ( │
│940 UserHandle, │
│941 Protocol, │
│942 Interface, │
│943 gDxeCoreImageHandle, │
│944 NULL, │
│945 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL │
└───────────────────────────────────────────────────────────────────────────┘
remote Thread 1 In: CoreHandleProtocol L938 PC: 0x7eb6ad4
(gdb)
|