memtest86plus/build32/debug_memtest.sh
Regina König bcf8171593 Script to debug memtest86plus (efi-version) with GDB in QEMU (#177)
* Add HOW_TO_DEBUG_WITH_GDB file
* Add debug_memtest.sh
* Add debug target to Makefile
* Add binaries and generated files for debugging to gitignore
* Add DEBUG code for memset and memcpy
* Add debug additions to Makefile in build32
* Add debug_memtest.sh to build32

[Lionel Debroux: post-merge fixups: removed a couple whitespace changes and a backup file; undone Github squash merge authorship damage.]
2023-07-30 22:09:25 +02:00

227 lines
6.7 KiB
Bash
Executable File

#! /bin/bash
###############################################################################
#
# Description : `debug_memtest.sh` is a script that allows memtest86plus
# developers to set up a debugging environment with GDB in QEMU. It calls
# the `make debug` target of a modified Makefile to create an additional
# debug-symbol file called `memtest.debug`. The symbols of this file are
# loaded with an offset (in accordance with the loading location of the
# efi-image) into GDB to match the exact addresses of the symbols in memory.
#
# For more detailed information, please read 'HOW_TO_DEBUG_WITH_GDB'
#
# Author : Regina König
# Year : 2022
# Email : koenig_regina@arcor.de
#
##############################################################################
Help() {
echo "Syntax: $0 [-h|-c|-t <terminal><execution_command>]"
echo "options:"
echo " -h Print this help"
echo " -c Delete all debugging related files"
echo " -t Define an alternative terminal"
echo " You can define your own terminal inclusive its execution command via:"
echo " ./debug_script.sh -t \"<terminal> <execution_command> \""
echo " See following examples:"
echo " ./debug_script.sh -t \"x-terminal-emulator -e \""
echo " ./debug_script.sh -t \"gnome-terminal -- \""
echo " ./debug_script.sh -t \"xterm -e \""
}
Clear() {
echo "Deleting files..."
rm -rf hda-contents
rm -f debug.log
rm -f gdbscript
rm -f QemuKill
make clean
rm -f OVMF32_VARS.fd
rm -f OVMF32_CODE.fd
rm -f memtest_shared_debug.lds
}
while getopts ":hct:" option; do
case $option in
h) # display Help
Help
exit;;
c) # clear directory
Clear
exit;;
t) # define own terminal
TERMINAL="$OPTARG"
if ! $TERMINAL ls; then
echo "Your entered command is not valid. Please check it again"
echo "Or type \"./debug_memtest.sh -h\" for help"
exit 1
fi
exit;;
\?) # invalid option
echo "Error: Invalid option"
echo "Type $0 -h for more information"
exit;;
esac
done
Check() {
# Check if QEMU and OVMF are installed
if ! command -v qemu-system-i386 > /dev/null 2>&1; then
echo "Qemu not installed"
exit 1
fi
# Check for presence of OVMF32_VARS.fd and OVMF32_CODE.fd
if [ ! -f OVMF32_CODE.fd ] && [ ! -f /usr/share/OVMF/OVMF32_CODE.fd ]; then
echo "Package ovmf-ia32 not installed. Type 'sudo apt install ovmf-ia32' and create some symlinks."
echo "Or copy your own versions of OVMF32_VARS.fd and OVMF32_CODE.fd into this directory"
exit 1
fi
# Check if gdb is installed
if ! command -v gdb > /dev/null 2>&1; then
echo "GDB not installed"
exit 1
fi
# Check for various terminals. Do not define TERMINAL if already defined by commandline
if [ -z $TERMINAL ]; then
if command -v x-terminal-emulator &> /dev/null; then
echo "x-terminal-emulator found"
TERMINAL="x-terminal-emulator -e "
elif command -v gnome-terminal &> /dev/null; then
echo "gnome-terminal found"
TERMINAL="gnome-terminal -- "
elif command -v xterm &> /dev/null; then
echo "xterm found"
TERMINAL="xterm -e "
else
echo "No terminal recognized. Please install x-terminal-emulator or gnome-terminal or xterm."
echo "Or define your own terminal alternatively."
echo "Type ./debug_memtest.sh -h for more information"
exit 1
fi
fi
}
Make() {
make debug DEBUG=1
ret_val=$?
if [[ $ret_val -ne 0 ]] ; then
echo "Make failed with return value: $ret_val"
exit 1
fi
}
# Retrieve addresses from code (not used in this version)
# Get_Offsets() {
# IMAGEBASE=$(grep -P '#define\tIMAGE_BASE' header.S | cut -f3)
# BASEOFCODE=$(grep -P '#define\tBASE_OF_CODE' header.S | cut -f3)
# TODO: get RELOCADDR and DATA
# }
Init() {
QEMU="qemu-system-i386"
QEMU_FLAGS+=" -hda fat:rw:hda-contents -net none"
QEMU_FLAGS+=" -drive if=pflash,format=raw,readonly=on,file=OVMF32_CODE.fd"
QEMU_FLAGS+=" -drive if=pflash,format=raw,file=OVMF32_VARS.fd"
# Define offsets for loading of symbol-table
IMAGEBASE=0x200000
BASEOFCODE=0x1000
DATA=0x23000
RELOCADDR=0x400000
printf -v OFFSET "0x%X" $(($IMAGEBASE + $BASEOFCODE))
printf -v DATAOFFSET "0x%X" $(($IMAGEBASE + $BASEOFCODE + $DATA))
printf -v RELOCDATA "0x%X" $(($RELOCADDR + $DATA))
GDB_FILE="gdbscript"
# Check if gdbscript exists. If not, create one.
if [ ! -f $GDB_FILE ]
then
echo "Creating gdbscript.."
echo "set pagination off" > $GDB_FILE
if [ -z "$OFFSET" ] || [ -z "$RELOCADDR" ]; then
echo "OFFSET or RELOCADDR is not set."
exit 1
fi
echo "add-symbol-file memtest.debug $OFFSET -s .data $DATAOFFSET" >> $GDB_FILE
echo "add-symbol-file memtest.debug $RELOCADDR -s .data $RELOCDATA" >> $GDB_FILE
echo "b main" >> $GDB_FILE
echo "commands" >> $GDB_FILE
echo "layout src" >> $GDB_FILE
echo "delete 1" >> $GDB_FILE
echo "end" >> $GDB_FILE
echo "b run_at" >> $GDB_FILE
echo "shell sleep 0.5" >> $GDB_FILE
echo "target remote localhost:1234" >> $GDB_FILE
echo "info b" >> $GDB_FILE
echo "c" >> $GDB_FILE
fi
if [ ! -f ldscripts/memtest_shared.lds ]; then
echo "'memtest_shared.lds' does not exist."
exit 1
fi
sed '/DISCARD/d' ldscripts/memtest_shared.lds > memtest_shared_debug.lds
if [ ! -f memtest_shared_debug.lds ]; then
echo "Creation of 'memtest_shared_debug.lds' failed."
exit 1
fi
}
Prepare_Directory() {
# Create dir hda-contents and a boot directory
mkdir -p hda-contents/EFI/boot
if [ ! -d hda-contents ]; then
echo "Creation of directory hda-contents failed."
exit 1
fi
# Copy memtest.efi to hda-contents
cp memtest.efi hda-contents/
cp memtest.efi hda-contents/EFI/boot/BOOT_IA32.efi
# Copy OVMF* files from /usr/share
if [ ! -f OVMF32_VARS.fd ] || [ ! -f OVMF32_CODE.fd ]; then
cp /usr/share/OVMF/OVMF32_CODE.fd .
cp /usr/share/OVMF/OVMF32_VARS.fd .
fi
}
# Global checks
Check
# Initialize
Init
# Build
Make
# Create needed directories and move efi binary to appropriate location
Prepare_Directory
# Run QEMU and launch second terminal,
# wait for connection via gdb
$TERMINAL gdb -x $GDB_FILE &
$QEMU $QEMU_FLAGS -s -S