> For the complete documentation index, see [llms.txt](https://bob-mcd-team.gitbook.io/uefi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bob-mcd-team.gitbook.io/uefi/uefi-development/debug/42.gdb-ovmf-debug.md).

# 42. GDB를 이용한 Driver/Application 및 OVMF Debug

GDB를 사용하여 디버깅을 수행하기 위해서는 올바른 오프셋에 디버그 심볼을 로그해야 한다.

* 메모리 상의 애플리케이션 오프셋
* 애플리케이션 내부의 오프셋

이번 과정에서는 이전에 개발한 `ShowBootVariable.efi` 애플리케이션을 디버깅한다.

## 메모리 상의 애플리케이션 오프셋 구하기

QEMU에서 OVMF를 실행한다.

```
qemu-system-x86_64 \
  -drive if=pflash,format=raw,readonly,file=Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd \
  -drive format=raw,file=fat:rw:~/UEFI_disk \
  -net none \
  -nographic \
  -global isa-debugcon.iobase=0x402 \
  -debugcon file:debug.log
```

또 다른 터미널을 이용하여 아래 명령어를 실행한다.

```
tail -f debug.log
```

이를 통해 런타임 로그를 추적할 수 있다.

부팅 이후 `ShowBootVariables.efi` 애플리케이션을 실행하고 아래와 같은 메세지를 `debug.log` 에서 확인한다.

```
Loading driver at 0x00006649000 EntryPoint=0x0000664C80F ShowBootVariables.efi
InstallProtocolInterface: BC62157E-3E33-4FEC-9920-2D3B36D750DF 666B898
ProtectUefiImageCommon - 0x666B4C0
  - 0x0000000006649000 - 0x0000000000005540
InstallProtocolInterface: 752F3136-4E16-4FDC-A22A-E5F46812F4CA 7EA36C8
```

다음 문장에서 제작한 이미지가 로드된 주소를 확인한다. `0x6649000`

```
Loading driver at 0x00006649000 EntryPoint=0x0000664C80F ShowBootVariables.efi
```

## Application section의 offset 구하기

`objdump` 명령어를 이용하여 `.efi` 파일에 포함된 섹션을 확인한다.

```
$ objdump -h Build/UefiLessonsPkg/RELEASE_GCC5/X64/ShowBootVariables.efi


Build/UefiLessonsPkg/RELEASE_GCC5/X64/ShowBootVariables.efi:     file format pei-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00004d40  0000000000000240  0000000000000240  00000240  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000580  0000000000004f80  0000000000004f80  00004f80  2**4
                  CONTENTS, ALLOC, LOAD, DATA
  2 .reloc        00000080  0000000000005500  0000000000005500  00005500  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

```

또한 `.debug` 파일에 존재하는 섹션도 확인한다.

```
$ objdump -h Build/UefiLessonsPkg/RELEASE_GCC5/X64/ShowBootVariables.debug

Build/UefiLessonsPkg/RELEASE_GCC5/X64/ShowBootVariables.debug:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00004d15  0000000000000240  0000000000000240  000000c0  2**6
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         000004a1  0000000000004f80  0000000000004f80  00004e00  2**6
                  CONTENTS, ALLOC, LOAD, RELOC, DATA
  2 .eh_frame     00000000  0000000000005440  0000000000005440  000052c0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .rela         00000510  0000000000005440  0000000000005440  000052c0  2**3
                  CONTENTS, READONLY
  4 .build-id     00000024  0000000000005950  0000000000005950  000057d0  2**2
                  CONTENTS, READONLY
  5 .debug_info   00026067  0000000000000000  0000000000000000  000057f4  2**0
                  CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
  6 .debug_abbrev 00003553  0000000000000000  0000000000000000  0002b85b  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
  7 .debug_loc    00009fde  0000000000000000  0000000000000000  0002edae  2**0
                  CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
  8 .debug_aranges 00000570  0000000000000000  0000000000000000  00038d8c  2**0
                  CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
  9 .debug_ranges 000013f0  0000000000000000  0000000000000000  000392fc  2**0
                  CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
 10 .debug_line   00008163  0000000000000000  0000000000000000  0003a6ec  2**0
                  CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
 11 .debug_str    000065d7  0000000000000000  0000000000000000  0004284f  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 12 .debug_frame  000015a8  0000000000000000  0000000000000000  00048e28  2**3
                  CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
```

두 정보의 차이는 `.debug` 정보의 유무이다.

`objdump` 결과를 통해서 필요한 섹션의 오프셋을 확인할 수 있다. (환경에 따라 그 결과가 다를 수도 있다.)

* `.text` -> `0x240`
* `.data` -> `0x4f40`

## GDB에 디버그 심볼적용

QEMU 실행 시 `-s` 옵션을 포함하여 원격 디버깅을 활성화 한다. 해당 옵션은 `tcp::1234` 의 축어이며 QEMU는 해당 포트에서 GDB 연결을 수신할 수 있다.

```
qemu-system-x86_64 \
  -drive if=pflash,format=raw,readonly,file=Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd \
  -drive format=raw,file=fat:rw:~/UEFI_disk \
  -net none \
  -nographic \
  -s
```

심볼 적용을 위해 사전에 확인한 애플리케이션 이미지 주소에 구한 `.text` 와 `.data` 의 오프셋 값 연산한다.

```
0x6649000 +  0x240 = 0x6649240
0x6649000 + 0x4f40 = 0x664df40
```

GDB를 실행하고 다음과 같이 심볼을 적용한다.

```
$ 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...
```

애플리케이션의 Entry Point에 break point을 적용하기 위해서 `ShellAppMain` 함수를 검색한다.

```
$ grep -n ShellAppMain UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
63:INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
```

이후 진입점에 break point를 설정한다.

```
(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 ?? ()
```

연결 이후 QEMU는 중단되며 재실행을 위해서는 GDB에서 `c` 명령어를 입력하면 된다.

```
(gdb) c
Continuing.
```

설정한 break point를 trigger 하기 위해 애플리케이션을 실행한다.

```
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);
```

<figure><img src="/files/lqsC1NV8yDK3pArIJXs1" alt=""><figcaption></figcaption></figure>

GDB에 편의를 위한 TUI 기능이 존재한다.

```
(gdb) tui enable
```

<figure><img src="/files/yWpgfBnZ85ZYIOZCVL0N" alt=""><figcaption></figcaption></figure>

## efi.py

앞선 과정들을 효율적으로 수행하기 위해서 Artem Nefedov 의 [efi.py](https://github.com/Kostr/UEFI-Lessons/blob/master/Lessons/Lesson_42/efi.py) 스크립트를 사용한다.

해당 스크립트를 통해 디버그 심볼을 로드하는데 큰 도움을 받을 수 있다.\
<https://github.com/artem-nefedov/uefi-gdb/blob/master/efi.py>

```bash
$ gdb -ex 'source efi.py'
```

gdb 내부에서 추가된 `efi` 명령어를 이용해 디버그 심볼을 로드한다.

```
(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

```

위 과정은 스크립트가 `ShowBootVariables` 문자열에 대해 `debug.log` 파일에서 검색하고 주소 정보를 가져온 다음 필요한 심볼을 구해 gdb에 로드한다.

디버깅을 시도해보면 앞선 과정과 동일한 결과를 얻을 수 있다.

## run\_gdb.sh

`efi.py` 도 훌륭한 스크립트이지만 아직 수행할 작업이 많다.

* 적절한 인자로 QEMU를 실행하고 부팅 이후 애플리케이션을 실행해야 하며, 애플리케이션을 다시 컴파일 할 경우 이 과정을 매번 수행해야 한다.
* `efi.py` 를 GDB에 로드한 뒤 실행하여 `efi` 명령을 실행해야 한다.
* break point 지정을 위해 함수 Entry Point를 검색해야 한다.
* QEMU 환경을 디버깅하기 위해 별도의 터미널이 요구된다.
* GDB를 QEMU에 연결하고 애플리케이션을 실행해야 한다.

따라서 디버깅과 동시에 OVMF 로그를 볼 수 있으며 위 과정을 자동화할 수 있는 스크립트를 작성하자.\
<https://github.com/Kostr/UEFI-Lessons/blob/master/scripts/run_gdb.sh>

```bash
#!/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
```

위 코드는 `tmux` 세션을 이용하여 필요한 키를 자동적으로 전달할 수 있다.

```
$ ./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)
```

처음 디버깅하는 경우 `debug.log` 를 생성해야 한다.

```
./run_gdb.sh -1 -m ShowBootVariables
```

이후 QEMU 환경에서 `enter`만 입력해도 대상 애플리케이션이 실행된다.

<figure><img src="/files/ukPfPzfrWkFo2IoKWgkB" alt=""><figcaption></figcaption></figure>

이후 다른 터미널을 통해 tmux 세션을 닫거나 tmux 환경에서 `ctrl+b` 입력하고 `:kill-session` 을 입력하여 tmux 세션을 닫는다.

<figure><img src="/files/hr0FucSvnOulIIyzrZgF" alt=""><figcaption></figcaption></figure>

다시 로드된 QEMU 환경과 디버그 심볼이 추가된 GDB 환경을 확인할 수 있다. QEMU 환경에서 `enter` 를 입력하면 대상 애플리케이션 Entry Point에break point가 발생한다.

<figure><img src="/files/nlgZKUJH7P5B82JeD47I" alt=""><figcaption></figcaption></figure>

## 모든 symbols 로드하기

만약 애플리케이션 또는 드라이버 외부에서 정의된 함수 (예: gRT->GetVariable)를 단계별로 실행하려면 모든 심볼을 GDB에 로드해야 한다.

이 때 `-f` 인자를 통해 `run_gdb.sh` 를 실행하면 된다.

```
./run_gdb.sh -1 -m ShowBootVariables -f
```

함수들의 심볼이 존재하므로 원하는 지점에 break point를 설정할 수 있다.

## OVMF 자체 Debug

OVMF 자체를 디버깅할 경우에 시작 시 QEMU를 중지해야 한다. 이 작업을 위해 `-S` 옵션을 사용할 수 있다.

```
qemu-system-x86_64 \
  -drive if=pflash,format=raw,readonly,file=Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd \
  -drive format=raw,file=fat:rw:~/UEFI_disk \
  -net none \
  -nographic \
  -s \
  -S
```

이후 GDB을 실행하고 이전과 같이 `debug.log` 파일을 통해 필요 symbols를 로드해야 한다.

아래는 해당 작업을 자동화하기 위한 `run_gdb_ovmf.sh` 스크립트이다.\
<https://github.com/Kostr/UEFI-Lessons/blob/master/scripts/run_gdb_ovmf.sh>

```bash
#!/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)
```

`run_gdb.sh` 와 별반 다르지 않지만 break point을 설정하거나 OVMF를 실행하지 않는다는 차이점이 존재한다.

<figure><img src="/files/WVFY7HXqfLa92gnGQZ1j" alt=""><figcaption></figcaption></figure>

## GDB cheatsheet

아래는 GDB 환경에서 사용할 수 있는 명령어 일부의 정보이다.

* `s` - step
* `n` - next
* `fin` - step out
* `i loc` - info about local variables
* `i arg` - info about function arguments
* `p <var>` - print value of `<var>`
* `b <number>` - set breakpoint at line `<number>` in the current file
* `b <file>:<number>` - set breakpoint at line `<number>` in the `<file>` file
* `b <func>` - break on function `<func>`
* `i b` - info breakpoints
* `d <number>` - delete breakpoint `<number>`
* `c` - continue
* `q` - quit GDB
* `Ctrl+p` - previous GDB command in history
* `Ctrl+n` - next GDB command in history
* `Ctrl+x` and `o` - change active window in tui mode

16 진수로 값을 출력하고 싶을 경우에는 `p/x` 를 사용한다.

CHAR16 문자열을 출력할 경우 `x /sh` 명령어를 이용할 수 있다. 다음은 장치 경로를 출력하는 예제이다.

```
(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)"
```

만약 출력 데이터의 길이가 길어 완전히 출력하지 못할 경우 다음 명령어를 통해 출력 길이 제한을 해제할 수 있다.

```
(gdb) set print elements 0
```

## TMUX cheatsheet

* `Ctrl+b` and `up/down/left/right` - switch between panes
* `Ctrl+b` and `:kill-session` - close all panes
* `Ctrl+b` and `Ctrl+up/down/left/right` - change pane size


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bob-mcd-team.gitbook.io/uefi/uefi-development/debug/42.gdb-ovmf-debug.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
