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

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

(gdb) tui enable

efi.py

앞선 과정들을 효율적으로 수행하기 위해서 Artem Nefedov 의 efi.py 스크립트를 사용한다.

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

$ 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

#!/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만 입력해도 대상 애플리케이션이 실행된다.

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

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

모든 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

#!/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를 실행하지 않는다는 차이점이 존재한다.

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

Last updated