mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
178 lines
6.6 KiB
Markdown
178 lines
6.6 KiB
Markdown
UEFI Debugging with GDB
|
|
=======================
|
|
|
|
These scripts provide support for easier UEFI code debugging on virtual machines like VMware Fusion
|
|
or QEMU. The code is based on [Andrei Warkentin](https://github.com/andreiw)'s
|
|
[DebugPkg](https://github.com/andreiw/andreiw-wip/tree/master/uefi/DebugPkg) with improvements
|
|
in macOS support, pretty printing, and bug fixing.
|
|
|
|
The general approach is as follows:
|
|
|
|
1. Build GdbSyms binary with EDK II type info in DWARF
|
|
1. Locate `EFI_SYSTEM_TABLE` in memory by its magic
|
|
1. Locate `EFI_DEBUG_IMAGE_INFO_TABLE` by its GUID
|
|
1. Map relocated images within GDB
|
|
1. Provide handy functions and pretty printers
|
|
|
|
#### Preparing Source Code
|
|
|
|
By default EDK II optimises produced binaries, so to build a "real" debug binary one should target
|
|
`NOOPT`. Do be aware that it strongly affects resulting binary size:
|
|
|
|
```
|
|
build -a X64 -t XCODE5 -b NOOPT -p OpenCorePkg/OpenCorePkg.dsc # for macOS
|
|
build -a X64 -t CLANGPDB -b NOOPT -p OpenCorePkg/OpenCorePkg.dsc # for other systems
|
|
```
|
|
|
|
`GdbSyms.dll` is built as a part of OpenCorePkg, yet prebuilt binaries are also available:
|
|
|
|
- `GdbSyms/Bin/X64_XCODE5/GdbSyms.dll` is built with XCODE5
|
|
|
|
To wait for debugger connection on startup `WaitForKeyPress` functions from `OcMiscLib.h` can be
|
|
utilised. Do be aware that this function additionally calls `DebugBreak` function, which may
|
|
be broken at during GDB init.
|
|
|
|
#### VMware Configuration
|
|
|
|
VMware Fusion contains a dedicated debugStub, which can be enabled by adding the following
|
|
lines to .vmx file. Afterwards vmware-vmx will listen on TCP ports 8832 and 8864 (on the host)
|
|
for 32-bit and 64-bit gdb connections respectively, similarly to QEMU:
|
|
```
|
|
debugStub.listen.guest32 = "TRUE"
|
|
debugStub.listen.guest64 = "TRUE"
|
|
```
|
|
|
|
In case the debugging session is remote the following lines should be appended:
|
|
```
|
|
debugStub.listen.guest32.remote = "TRUE"
|
|
debugStub.listen.guest64.remote = "TRUE"
|
|
```
|
|
|
|
To halt the virtual machine upon executing the first instruction the following line code be added.
|
|
Note, that it does not seem to work on VMware Fusion 11 and results in freezes:
|
|
```
|
|
monitor.debugOnStartGuest32 = "TRUE"
|
|
```
|
|
|
|
To force hardware breakpoints (instead of software INT 3 breakpoints) add the following line:
|
|
```
|
|
debugStub.hideBreakpoints = "TRUE"
|
|
```
|
|
|
|
To stall during POST for 3 seconds add the following line. Pressing any key will boot into firmware
|
|
settings:
|
|
```
|
|
bios.bootDelay = "3000"
|
|
```
|
|
|
|
#### QEMU configuration
|
|
|
|
In addition to VMware it is also possible to use [QEMU](https://www.qemu.org). QEMU debugging
|
|
on macOS host is generally rather limited and slow, but it is enough for generic troubleshooting
|
|
when no macOS guest booting is required.
|
|
|
|
1. Build OVMF firmware in NOOPT mode to be able to debug it:
|
|
|
|
```
|
|
git submodule init
|
|
git submodule update # to clone OpenSSL
|
|
build -a X64 -t XCODE5 -b NOOPT -p OvmfPkg/OvmfPkgX64.dsc # for macOS
|
|
build -a X64 -t CLANGPDB -b NOOPT -p OvmfPkg/OvmfPkgX64.dsc # for other systems
|
|
```
|
|
|
|
To build OVMF with SMM support add `-D SMM_REQUIRE=1`. To build OVMF with serial debugging
|
|
add `-D DEBUG_ON_SERIAL_PORT=1`.
|
|
|
|
2. Prepare launch directory with OpenCore as usual. For example, make a directory named
|
|
`QemuRun` and `cd` to it. You should have a similar directory structure:
|
|
|
|
```
|
|
.
|
|
└── ESP
|
|
└── EFI
|
|
├── BOOT
|
|
│ └── BOOTx64.efi
|
|
└── OC
|
|
├── OpenCore.efi
|
|
└── config.plist
|
|
```
|
|
|
|
3. Run QEMU (`OVMF_BUILD` should point to OVMF build directory, e.g.
|
|
`$HOME/UefiWorkspace/Build/OvmfX64/NOOPT_XCODE5/FV`):
|
|
|
|
```
|
|
qemu-system-x86_64 -L . -bios "$OVMF_BUILD/OVMF.fd" -hda fat:rw:ESP \
|
|
-machine q35 -m 2048 -cpu Penryn -smp 4,cores=2 -usb -device usb-mouse -gdb tcp::8864
|
|
```
|
|
|
|
To run QEMU with SMM support use the following command:
|
|
```
|
|
qemu-system-x86_64 -L . -global driver=cfi.pflash01,property=secure,value=on \
|
|
-drive if=pflash,format=raw,unit=0,file="$OVMF_BUILD"/OVMF_CODE.fd,readonly=on \
|
|
-drive if=pflash,format=raw,unit=1,file="$OVMF_BUILD"/OVMF_VARS.fd -hda fat:rw:ESP \
|
|
-global ICH9-LPC.disable_s3=1 -machine q35,smm=on,accel=tcg -m 2048 -cpu Penryn \
|
|
-smp 4,cores=2 -usb -device usb-mouse -gdb tcp::8864
|
|
```
|
|
|
|
You may additionally pass `-S` flag to QEMU to stop at first instruction
|
|
and wait for GDB connection. To use serial debugging add `-serial stdio`.
|
|
|
|
#### Debugger Configuration
|
|
|
|
For simplicitly `efidebug.tool` performs all the necessary GDB or LLDB scripting.
|
|
Note, that you need to run `reload-uefi` after any new binary loads.
|
|
|
|
Check `efidebug.tool` header for environment variables to configure your setup.
|
|
For example, you can use `EFI_DEBUGGER` variable to force LLDB (`LLDB`) or GDB (`GDB`).
|
|
|
|
#### GDB Configuration
|
|
|
|
It is a good idea to use GDB Multiarch in case different debugging architectures are planned to be
|
|
used. This can be done in several ways:
|
|
|
|
- https://www.gnu.org/software/gdb/ — from source
|
|
- https://macports.org/ — via MacPorts (`sudo port install gdb +multiarch`)
|
|
- Your preferred method here
|
|
|
|
Once GDB is installed you can use `efidebug.tool` for debugging. In case you do not
|
|
want to use `efidebug.tool`, the following set of commands can be used as a reference:
|
|
|
|
```
|
|
$ ggdb /opt/UDK/Build/OpenCorePkg/NOOPT_XCODE5/X64/OpenCorePkg/Debug/GdbSyms/GdbSyms/DEBUG/GdbSyms.dll.dSYM/Contents/Resources/DWARF/GdbSyms.dll
|
|
|
|
target remote localhost:8864
|
|
source /opt/UDK/OpenCorePkg/Debug/Scripts/gdb_uefi.py
|
|
set pagination off
|
|
reload-uefi
|
|
b DebugBreak
|
|
```
|
|
|
|
#### CLANGDWARF
|
|
|
|
CLANGDWARF toolchain is an LLVM-based toolchain that directly generates
|
|
PE/COFF images with DWARF debug information via LLD linker. LLVM 9.0 or
|
|
newer with working dead code stripping in LLD is required for this to work
|
|
([LLD patches](https://bugs.llvm.org/show_bug.cgi?id=45273)).
|
|
|
|
*Installation*: After applying `ClangDwarf.patch` hack onto EDK II `CLANGPDB`
|
|
toolchain will behave as if it was `CLANGDWARF`.
|
|
|
|
For debugging support it may be necessary to set `EFI_SYMBOL_PATH`
|
|
environment variable to `:`-separated list of paths with `.debug` files,
|
|
for example:
|
|
|
|
```
|
|
export EFI_SYMBOL_PATH="$WORKSPACE/Build/OvmfX64/NOOPT_CLANGPDB/X64:$WORKSPACE/Build/OpenCorePkg/NOOPT_CLANGPDB/X64"
|
|
```
|
|
|
|
The reason for this requirement is fragile `--add-gnudebug-link` option
|
|
[implementation in llvm-objcopy](https://bugs.llvm.org/show_bug.cgi?id=45277).
|
|
It strips path from the debug file preserving only filename and also does not
|
|
update DataDirectory debug entry.
|
|
|
|
#### References
|
|
|
|
1. https://communities.vmware.com/thread/390128
|
|
1. https://wiki.osdev.org/VMware
|
|
1. https://github.com/andreiw/andreiw-wip/tree/master/uefi/DebugPkg
|