$ gdb
(gdb) add-symbol-file Build/UefiLessonsPkg/RELEASE_GCC5/X64/ShowBootVariables.debug 0x65FD240 -s .data 0x6601F80
add symbol table from file "Build/UefiLessonsPkg/RELEASE_GCC5/X64/ShowBootVariables.debug" at
.text_addr = 0x65fd240
.data_addr = 0x6601f80
(y or n) y
Reading symbols from Build/UefiLessonsPkg/RELEASE_GCC5/X64/ShowBootVariables.debug...
(gdb) b UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c:63
Breakpoint 1 at 0x664c50f: file /home/kostr/tiano/edk2/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c, line 68.
(gdb) target remote :1234
Remote debugging using :1234
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x000000000716e151 in ?? ()
(gdb) c
Continuing.
FS0:\> ShowBootVariables.efi
Breakpoint 1, ShellAppMain (Argc=1, Argv=0x6609b98)
at /home/minishell/src/edk2-ws/edk2/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c:69
69 Status = GetNvramVariable(L"BootCurrent", &gEfiGlobalVariableGuid, (VOID**)&BootCurrent, &OptionSize);
(gdb) tui enable
$ gdb -ex 'source efi.py'
(gdb) efi -64 ShowBootVariables
Turning pagination off
Using pre-defined driver list: ['ShowBootVariables']
The target architecture is assumed to be i386:x86-64:intel
With architecture X64
Looking for addresses in debug.log
EFI file Build/UefiLessonsPkg/RELEASE_GCC5/X64/ShowBootVariables.efi
Base address 0x000065FD000
.text address 0x0000000000000240
.data address 0x0000000000004f80
add symbol table from file "Build/UefiLessonsPkg/RELEASE_GCC5/X64/ShowBootVariables.debug" at
.text_addr = 0x65fd240
.data_addr = 0x6601f80
Restoring pagination
#!/bin/bash
##
# Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com>
#
# SPDX-License-Identifier: MIT
##
##### Controllable parameters #####
QEMU_SHARED_FOLDER=~/UEFI_disk
PACKAGE=UefiLessonsPkg
###################################
function show_help {
echo "Description:"
echo " run_gdb.sh is a script that helps to debug UEFI shell applications and drivers"
echo ""
echo "Usage: run_gdb.sh -m <module> [-1|-f|-p <package>|-q <dir>]"
echo " -1 This is a first run of this configuration"
echo " (in this case before main gdb launch there would be another QEMU start that will create 'debug.log' file)"
echo " -f Load all debug symbols"
echo " (this will load all OVMF debug symbols - with this you could step inside OVMF functions)"
echo " -m <module> UEFI module to debug"
echo " -p <package> UEFI package to debug"
echo " (by default it is equal to PACKAGE variable in the head of the script)"
echo " -q <dir> QEMU shared directory"
echo " (by default it is equal to QEMU_SHARED_FOLDER variable in the head of the script)"
echo ""
echo "Examples:"
echo " run_gdb.sh -1 -m MyApp - create 'debug.log' file with the necessary address information for the 'MyApp'"
echo " and debug it with gdb"
echo " run_gdb.sh -1 -m MyApp -f - create 'debug.log' file with the necessary address information for the 'MyApp'"
echo " and debug it with gdb (all debug symbols are included, i.e. you can step into OVMF functions)"
echo " run_gdb.sh -m MyApp - debug 'MyApp' with gdb ('debug.log' was created in the last run, no need to remake it again)"
}
# A POSIX variable
OPTIND=1 # Reset in case getopts has been used previously in the shell.
while getopts "h?1fm:q:p:" opt; do
case "$opt" in
h|\?)
show_help
exit 0
;;
1) FIRST_RUN=1
;;
f) FULL=1
;;
m) TARGET=$OPTARG
;;
q) QEMU_SHARED_FOLDER=$OPTARG
;;
p) PACKAGE=$OPTARG
;;
esac
done
shift $((OPTIND-1))
[ "${1:-}" = "--" ] && shift
if [[ ! -z "${FULL}" ]]; then
DRIVERS=''
else
DRIVERS=${TARGET}
fi
if [[ -z $TARGET ]]; then
echo "Error! Module is not provided."
echo ""
show_help
exit 1
fi
function test_file {
FILE_NAME=$1
if [[ ! -f ${FILE_NAME} ]]; then
echo "Error! There is no file ${FILE_NAME}"
exit 1;
fi
}
TARGET_INF="${PACKAGE}/${TARGET}/${TARGET}.inf"
TARGET_C="${PACKAGE}/${TARGET}/${TARGET}.c"
OVMF="Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd"
test_file "${TARGET_INF}"
test_file "${TARGET_C}"
test_file "${OVMF}"
ENTRY_POINT_NAME=$(grep ENTRY_POINT ${TARGET_INF} | cut -f 2 -d "=")
if [ ${ENTRY_POINT_NAME} == "ShellCEntryLib" ]; then
ENTRY_POINT_NAME="ShellAppMain"
fi
ENTRY_POINT_LINE=$(grep -n ${ENTRY_POINT_NAME} ${TARGET_C} | cut -f 1 -d ":")
MODULE_TYPE=$(grep MODULE_TYPE ${TARGET_INF} | cut -f 2 -d "=")
if [ ${MODULE_TYPE} == "UEFI_DRIVER" ]; then
LAUNCH_COMMAND="load fs0:${TARGET}.efi"
else
LAUNCH_COMMAND="fs0:${TARGET}.efi"
fi
if [[ ! -z "${FIRST_RUN}" || ! -f debug.log ]]; then
touch debug.log
# If it is a first run, we need to create 'debug.log' file for addresses
TARGET_EFI="Build/${PACKAGE}/RELEASE_GCC5/X64/${TARGET}.efi"
test_file "${TARGET_EFI}"
cp ${TARGET_EFI} ${QEMU_SHARED_FOLDER}
tmux new-session \; \
send-keys "tail -f debug.log" Enter \; \
split-window -v \; \
send-keys "qemu-system-x86_64 \
-drive if=pflash,format=raw,readonly,file=${OVMF} \
-drive format=raw,file=fat:rw:${QEMU_SHARED_FOLDER} \
-net none \
-nographic \
-global isa-debugcon.iobase=0x402 \
-debugcon file:debug.log \
-s" C-m Enter \; \
send-keys C-m Enter \; \
send-keys "${LAUNCH_COMMAND}" Enter \;
fi
test_file "${QEMU_SHARED_FOLDER}/${TARGET}.efi"
touch debug_temp.log
tmux new-session \; \
send-keys "gdb -ex 'source efi.py' -tui" Enter \; \
split-window -h \; \
send-keys "tail -f debug_temp.log" Enter \; \
split-window -v \; \
send-keys "qemu-system-x86_64 \
-drive if=pflash,format=raw,readonly,file=${OVMF} \
-drive format=raw,file=fat:rw:${QEMU_SHARED_FOLDER} \
-net none \
-nographic \
-global isa-debugcon.iobase=0x402 \
-debugcon file:debug_temp.log \
-s" C-m Enter \; \
select-pane -t 0 \; \
send-keys "efi -64 ${DRIVERS}" Enter \; \
send-keys "b ${TARGET_C}:${ENTRY_POINT_LINE}" Enter \; \
send-keys Enter \; \
send-keys "target remote :1234" Enter \; \
send-keys "c" Enter \; \
select-pane -t 2 \; \
send-keys C-m Enter \; \
send-keys "${LAUNCH_COMMAND}" Enter \; wnd
$ ./run_gdb.sh -h
Description:
run_gdb.sh is a script that helps to debug UEFI shell applications and drivers
Usage: run_gdb.sh -m <module> [-1|-f|-p <package>|-q <dir>]
-1 This is a first run of this configuration
(in this case before main gdb launch there would be another QEMU start that will create 'debug.log' file)
-f Load all debug symbols
(this will load all OVMF debug symbols - with this you could step inside OVMF functions)
-m <module> UEFI module to debug
-p <package> UEFI package to debug
(by default it is equal to PACKAGE variable in the head of the script)
-q <dir> QEMU shared directory
(by default it is equal to QEMU_SHARED_FOLDER variable in the head of the script)
Examples:
run_gdb.sh -1 -m MyApp - create 'debug.log' file with the necessary address information for the 'MyApp'
and debug it with gdb
run_gdb.sh -1 -m MyApp -f - create 'debug.log' file with the necessary address information for the 'MyApp'
and debug it with gdb (all debug symbols are included, i.e. you can step into OVMF functions)
run_gdb.sh -m MyApp - debug 'MyApp' with gdb ('debug.log' was created in the last run, no need to remake it again)
#!/bin/bash
##
# Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com>
#
# SPDX-License-Identifier: MIT
##
##### Controllable parameters #####
QEMU_SHARED_FOLDER=~/UEFI_disk
###################################
function show_help {
echo "Description:"
echo " run_gdb_ovmf.sh is a script that helps to debug OVMF"
echo ""
echo "Usage: run_gdb_ovmf.sh [-1] [-q <dir>]"
echo " -1 This is a first run of this configuration"
echo " (in this case before main gdb launch there would be another QEMU start that will create 'debug.log' file)"
echo " -q <dir> QEMU shared directory"
echo " (by default it is equal to QEMU_SHARED_FOLDER variable in the head of the script)"
echo ""
echo "Examples:"
echo " run_gdb_ovmf.sh -1 - create 'debug.log' file with the necessary address information"
echo " and debug OVMF it with gdb"
echo " run_gdb_ovmf.sh - debug OVMF with gdb ('debug.log' was created in the last run, no need to remake it again)"
}
# A POSIX variable
OPTIND=1 # Reset in case getopts has been used previously in the shell.
while getopts "h?1q:" opt; do
case "$opt" in
h|\?)
show_help
exit 0
;;
1) FIRST_RUN=1
;;
q) QEMU_SHARED_FOLDER=$OPTARG
;;
esac
done
shift $((OPTIND-1))
[ "${1:-}" = "--" ] && shift
function test_file {
FILE_NAME=$1
if [[ ! -f ${FILE_NAME} ]]; then
echo "Error! There is no file ${FILE_NAME}"
exit 1;
fi
}
OVMF="Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd"
test_file "${OVMF}"
if [[ ! -z "${FIRST_RUN}" || ! -f debug.log ]]; then
touch debug.log
# If it is a first run, we need to create 'debug.log' file for addresses
tmux new-session \; \
send-keys "tail -f debug.log" Enter \; \
split-window -v \; \
send-keys "qemu-system-x86_64 \
-drive if=pflash,format=raw,readonly,file=${OVMF} \
-drive format=raw,file=fat:rw:${QEMU_SHARED_FOLDER} \
-net none \
-nographic \
-global isa-debugcon.iobase=0x402 \
-debugcon file:debug.log \
-s" C-m Enter \;
fi
touch debug_temp.log
tmux new-session \; \
send-keys "gdb -ex 'source efi.py' -tui" Enter \; \
split-window -h \; \
send-keys "tail -f debug_temp.log" Enter \; \
split-window -v \; \
send-keys "qemu-system-x86_64 \
-drive if=pflash,format=raw,readonly,file=${OVMF} \
-drive format=raw,file=fat:rw:${QEMU_SHARED_FOLDER} \
-net none \
-nographic \
-global isa-debugcon.iobase=0x402 \
-debugcon file:debug_temp.log \
-s -S" C-m Enter \; \
select-pane -t 0 \; \
send-keys "efi -64" Enter \; \
send-keys "target remote :1234" Enter \;
$ ./run_gdb_ovmf.sh -h
Description:
run_gdb_ovmf.sh is a script that helps to debug OVMF
Usage: run_gdb_ovmf.sh [-1] [-q <dir>]
-1 This is a first run of this configuration
(in this case before main gdb launch there would be another QEMU start that will create 'debug.log' file)
-q <dir> QEMU shared directory
(by default it is equal to QEMU_SHARED_FOLDER variable in the head of the script)
Examples:
run_gdb_ovmf.sh -1 - create 'debug.log' file with the necessary address information
and debug OVMF it with gdb
run_gdb_ovmf.sh - debug OVMF with gdb ('debug.log' was created in the last run, no need to remake it again)
(gdb) p ConvertDevicePathToText(DevicePath, 0, 1)
$1 = (CHAR16 *) 0x6d04518
(gdb) x /sh 0x6d04518
0x6d04518: u"PciRoot(0x0)/Pci(0x2,0x0)"
(gdb) x /sh ConvertDevicePathToText(DevicePath, 0, 1)
0x6d02098: u"PciRoot(0x0)/Pci(0x2,0x0)"