# 41. DEBUG 출력문 내부 구조와 DEBUG 문 제어를 위한 PCD 분석, 그리고 OVMF 부트 로그 가져오기

이번 장에서는 EDKII 코드 베이스에 존재하는 `DEBUG` 매크로와 관련된 정보를 학습한다. 다음은 그 예시이다.

```
DEBUG ((EFI_D_ERROR, "Hello Debug! Check this variable: %d\n", MyVar));
```

일반적인 출력 형식과 유사하지만 다른 기능이 존재한다.

* 로그 레벨을 이용하여 로그 메세지를 분류할 수 있다. PCD를 통한 구성으로 type별 디버그 메세지를 쉽게 켜고 끌 수 있다.
* 서로 다른 UEFI 단계 및 모듈은 서로 다른 `DEBUG` 구현을 가지기 때문에 여러 `DEBUG` 기능 구현이 존재한다.

사전에 정의된 로그 메세지의 범주는 아래와 같다.\
<https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/DebugLib.h>

```
#define DEBUG_INIT      0x00000001  // Initialization
#define DEBUG_WARN      0x00000002  // Warnings
#define DEBUG_LOAD      0x00000004  // Load events
#define DEBUG_FS        0x00000008  // EFI File system
#define DEBUG_POOL      0x00000010  // Alloc & Free (pool)
#define DEBUG_PAGE      0x00000020  // Alloc & Free (page)
#define DEBUG_INFO      0x00000040  // Informational debug messages
#define DEBUG_DISPATCH  0x00000080  // PEI/DXE/SMM Dispatchers
#define DEBUG_VARIABLE  0x00000100  // Variable
#define DEBUG_BM        0x00000400  // Boot Manager
#define DEBUG_BLKIO     0x00001000  // BlkIo Driver
#define DEBUG_NET       0x00004000  // Network Io Driver
#define DEBUG_UNDI      0x00010000  // UNDI Driver
#define DEBUG_LOADFILE  0x00020000  // LoadFile
#define DEBUG_EVENT     0x00080000  // Event messages
#define DEBUG_GCD       0x00100000  // Global Coherency Database changes
#define DEBUG_CACHE     0x00200000  // Memory range cachability changes
#define DEBUG_VERBOSE   0x00400000  // Detailed debug messages that may
                                    // significantly impact boot performance
#define DEBUG_ERROR     0x80000000  // Error
```

하지만 일반적으로 다음 별칭의 값이 사용된다.

```
//
// Aliases of debug message mask bits
//
#define EFI_D_INIT      DEBUG_INIT
#define EFI_D_WARN      DEBUG_WARN
#define EFI_D_LOAD      DEBUG_LOAD
#define EFI_D_FS        DEBUG_FS
#define EFI_D_POOL      DEBUG_POOL
#define EFI_D_PAGE      DEBUG_PAGE
#define EFI_D_INFO      DEBUG_INFO
#define EFI_D_DISPATCH  DEBUG_DISPATCH
#define EFI_D_VARIABLE  DEBUG_VARIABLE
#define EFI_D_BM        DEBUG_BM
#define EFI_D_BLKIO     DEBUG_BLKIO
#define EFI_D_NET       DEBUG_NET
#define EFI_D_UNDI      DEBUG_UNDI
#define EFI_D_LOADFILE  DEBUG_LOADFILE
#define EFI_D_EVENT     DEBUG_EVENT
#define EFI_D_VERBOSE   DEBUG_VERBOSE
#define EFI_D_ERROR     DEBUG_ERROR
```

DEBUG 매크로 자체 또한 `DebugLib`에 정의되어 있다.\
<https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/DebugLib.h>

모든 전처리 과정을 분할하여 살펴보면 일반적으로 다음과 같다.

```
if (DebugPrintEnabled ()) {
  if (DebugPrintLevelEnabled (PrintLevel)) {
    DebugPrint (PrintLevel, ##__VA_ARGS__);
  }
}
```

DEBUG 매크로 인터페이스는 `DebugLib` 헤더에 정의되어 있지만 실제 구현을 위해서는 사용되는 특정 라이브러리의 인터페이스를 살펴봐야 한다[https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.dsc ](https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.dsc)를 살펴보자

* `DebugLib` 은 각 UEFI 단계에서 각기 다른 구현을 가지고 있다.
* `DebugLib`은 `DEBUG_ON_SERAIL_PORT` 정의에 따라 다른 구현이 있다.

```
[LibraryClasses.common.SEC]
!ifdef $(DEBUG_ON_SERIAL_PORT)
  DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
!else
  DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf
!endif
```

```
[LibraryClasses.common.PEI_CORE]
# [LibraryClasses.common.PEIM]
# [LibraryClasses.common.DXE_CORE]
# [LibraryClasses.common.DXE_RUNTIME_DRIVER]
# [LibraryClasses.common.UEFI_DRIVER]
# [LibraryClasses.common.DXE_DRIVER]
# [LibraryClasses.common.UEFI_APPLICATION]
# [LibraryClasses.common.DXE_SMM_DRIVER]
# [LibraryClasses.common.SMM_CORE]
!ifdef $(DEBUG_ON_SERIAL_PORT)
  DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
!else
  DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
!endif
```

기본적으로 `DEBUG_ON_SERIAL_PORT`가 정의되어 있지 않은 경우 `PlatformDebugLibIoPort` 가 기본 라이브러리이다.\
<https://github.com/tianocore/edk2/tree/master/OvmfPkg/Library/PlatformDebugLibIoPort>

```
DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
```

`DEBUG` 매크로는 다음과 같이 번역된다.

```
if (DebugPrintEnabled ()) {
  if (DebugPrintLevelEnabled (PrintLevel)) {
    DebugPrint (PrintLevel, ##__VA_ARGS__);
  }
}
```

아래를 통해`DebugPrintEnabled`,`DebugPrintLevelEnabled` ,`DebugPrint` 정보를 살펴보자. <https://github.com/tianocore/edk2/blob/master/OvmfPkg/Library/PlatformDebugLibIoPort/DebugLib.c>

#### DebugPrintEnabled

`DEBUG` 매크로는 먼저 `DebugPrintEnabled` 결과를 확인한다. 이 함수는 PCD의 `PcdDebugPropertyMask`에 `DEBUG_PROPERTY_DEBUG_PRINT_ENABLED`가 설정되어 있는지 확인한다.

```
BOOLEAN
EFIAPI
DebugPrintEnabled (
  VOID
  )
{
  return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
}
```

#### DebugPrintLevelEnabled

그리고 `DebugPrintLevelEnabled` 함수는 전달된 `ErrorLevel` 이 PCD의 `PcdFixedDebugPrintErrorLevel` 에 있는지 확인한다.

```
BOOLEAN
EFIAPI
DebugPrintLevelEnabled (
  IN  CONST UINTN        ErrorLevel
  )
{
  return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0);
}
```

**DebugPrint**

그런 다음 `DebugPrint` 함수가 실행되며 단순히 제어를 `DebugVPrint`로 전달한다.

```
VOID
EFIAPI
DebugPrint (
  IN  UINTN        ErrorLevel,
  IN  CONST CHAR8  *Format,
  ...
  )
{
  VA_LIST         Marker;

  VA_START (Marker, Format);
  DebugVPrint (ErrorLevel, Format, Marker);
  VA_END (Marker);
}
```

그리고 `DebugVPrint` 는 `DebugPrintMarker`로 제어를 전달한다.

```
VOID
EFIAPI
DebugVPrint (
  IN  UINTN         ErrorLevel,
  IN  CONST CHAR8   *Format,
  IN  VA_LIST       VaListMarker
  )
{
  DebugPrintMarker (ErrorLevel, Format, VaListMarker, NULL);
}
```

`DebugPrintMarker` 는 주요 디버그 기능으로, 전달된 `ErrorLevel` 이 `GetDebugPrintErrorLevel()` 출력에 있는지 확인한다. 최종적으로는 PCD의 `PcdDebugIoPort` 에 의해 정의된 입출력 포트에 디버그 문자열 쓰기를 수행한다.

```
VOID
DebugPrintMarker (
  IN  UINTN         ErrorLevel,
  IN  CONST CHAR8   *Format,
  IN  VA_LIST       VaListMarker,
  IN  BASE_LIST     BaseListMarker
  )
{
  CHAR8    Buffer[MAX_DEBUG_MESSAGE_LENGTH];
  UINTN    Length;

  //
  // If Format is NULL, then ASSERT().
  //
  ASSERT (Format != NULL);

  //
  // Check if the global mask disables this message or the device is inactive
  //
  if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0 ||
      !PlatformDebugLibIoPortFound ()) {
    return;
  }

  //
  // Convert the DEBUG() message to an ASCII String
  //
  if (BaseListMarker == NULL) {
    Length = AsciiVSPrint (Buffer, sizeof (Buffer), Format, VaListMarker);
  } else {
    Length = AsciiBSPrint (Buffer, sizeof (Buffer), Format, BaseListMarker);
  }

  //
  // Send the print string to the debug I/O port
  //
  IoWriteFifo8 (PcdGet16 (PcdDebugIoPort), Length, Buffer);
}
```

`GetDebugPrintErrorLevel()` 는 `DebugPrintErrorLevelLib` 라이브러리에 정의된 함수로 `OvmfPkgX64.dsc` 에서도 그 구현을 확인할 수 있다.

```
[LibraryClasses]
  ...
  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
```

소스를 보면 단순히 다른 PCD를 확인하는 것을 볼 수 있다.\
<https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.c>

```
UINT32
EFIAPI
GetDebugPrintErrorLevel (
  VOID
  )
{
  //
  // Retrieve the current debug print error level mask from PcdDebugPrintErrorLevel.
  //
  return PcdGet32 (PcdDebugPrintErrorLevel);
}
```

### 요약

`DEBUG (( ErrorLevel, String, ... ))` 와 같은 형태의 코드를 정리하자면 다음과 같다.

1. `PcdDebugPropertyMask` 에 `DEBUG_PROPERTY_DEBUG_PRINT_ENABLED`가 있는지 확인한다.
2. 전달된 `ErrorLevel` 이 `PcdFixedDebugPrintErrorLevel` 에 설정되어 있는지 확인한다.
3. 전달된 `ErrorLevel` 이 `PcdDebugPrintErrorLevel` 에 설정되어 있는지 확인한다.
4. 지정된 형식 문자열을 `PcdDebugIoPort` 에 정의된 입출력 포트에 작성한다.

## Check if `PcdDebugPropertyMask` has `DEBUG_PROPERTY_DEBUG_PRINT_ENABLED`

OVMF의 DSC 파일에서는 PCD `PcdDebugPropertyMask` 를 다음과 같이 정의한다.\
[https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.dsc](https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.dsc:)

```
[PcdsFixedAtBuild]
!if $(SOURCE_DEBUG_ENABLE) == TRUE
  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x17
!else
  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F
!endif
```

그리고 이 PCD는 Shell용으로 재정의 된다.

```
[Components]
  ShellPkg/Application/Shell/Shell.inf {
    ...
    <PcdsFixedAtBuild>
    ...
    gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
  }
```

이 PCD에 대한 비트 정의는 다음에서 확인할 수 있다.\
<https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec>

```
## The mask is used to control DebugLib behavior.<BR><BR>
#  BIT0 - Enable Debug Assert.<BR>
#  BIT1 - Enable Debug Print.<BR>
#  BIT2 - Enable Debug Code.<BR>
#  BIT3 - Enable Clear Memory.<BR>
#  BIT4 - Enable BreakPoint as ASSERT.<BR>
#  BIT5 - Enable DeadLoop as ASSERT.<BR>
# @Prompt Debug Property.
# @Expression  0x80000002 | (gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask & 0xC0) == 0
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0|UINT8|0x00000005
```

`SOURCE_DEBUG_ENABLE` 의 설정 값

* TRUE(17h): Debug Assert(1h)/Debug Print(2h)/Debug Code(4h)/BreakPoint(10h) 활성화
* FALSE(2Fh): Debug Assert(1h)/Debug Print(2h)/Debug Code(4h)/Clear Memory(8h)/DeadLoop(20h) 활성화

`DEBUG` 매크로에서 이 `PCD` 를 `DEBUG_PROPERTY_DEBUG_PRINT_ENABLED` 와 비교해보자.\
<https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/DebugLib.h>

```
//
// Declare bits for PcdDebugPropertyMask
//
#define DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED       0x01
#define DEBUG_PROPERTY_DEBUG_PRINT_ENABLED        0x02
#define DEBUG_PROPERTY_DEBUG_CODE_ENABLED         0x04
#define DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED       0x08
#define DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED  0x10
#define DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED    0x20
```

보다시피 해당 검사는 `SOURCE_DEBUG_ENABLE` 와 관계없이 통과된다.

## Checks if passed `ErrorLevel` is set in `PcdFixedDebugPrintErrorLevel`

해당 PCD는 `MdePkg.dsc` 에 정의되었다.\
[https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec](https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec:)

```
[PcdsFixedAtBuild]
  gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel|0xFFFFFFFF|UINT32|0x30001016
```

이 PCD 정보는 OVMF의 DSC 파일에서 재정의 되지 않기 때문에 빌드에 포함되는 값이다. `0xFFFFFFFF` 는 디버그 메세지가 `EFI_D_*` 출력 레벨에 관계없이 이 검사를 통과함을 의미한다.

## Checks if passed `ErrorLevel` is set in `PcdDebugPrintErrorLevel`

해당 PCD는 `MdePkg.dec` 에 정의되었다.\
<https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec>

```
[PcdsFixedAtBuild]
  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000000|UINT32|0x00000006
```

기본적으로 `MdePkg.dec` 및 `MdePkg.dsc` 에서 `0x80000000` 으로 정의된다.\
[https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dsc](https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dsc:)

```
[PcdsFixedAtBuild]
  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000000
```

`0x80000000` 이라는 값은 오류 메시지(`EFI_D_ERROR`) 만 출력함을 의미한다.

빌드하는 OVMF의 DSC 파일에서는 해당 PCD를 재정의하고 있다.

```
[PcdsFixedAtBuild]
  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000004F
```

`0x8000004F` - `EFI_D_ERROR` | `EFI_D_INFO` | `EFI_D_FS` | `EFI_D_LOAD` | `EFI_D_WARN` | `EFI_D_INIT`

만약 DEBUG 가 활성화된다면 위 범주의 메세지가 출력된다.

## Writes formatted String to I/O port defined by `PcdDebugIoPort`

`PcdDebugIoPort` 에 대한 정의는 `OvmfPkg.dec` 에 존재한다.\
<https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkg.dec>

```
[PcdsFixedAtBuild]
  gUefiOvmfPkgTokenSpaceGuid.PcdDebugIoPort|0x402|UINT16|4
```

해당 PCD는 `PlatformDebugLibIoPort` 의 디버그 메세지에 대한 대상 입출력 포트를 제어한다.

##

## DEBUG 테스트

디버그 메세지를 보기 위해서는 디버그 모드에서 OVMF를 다시 컴파일 해야 한다.

먼저 다음과 같이 DEBUG 모드로 빌드를 진행한다.

```
build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=DEBUG --tagname=GCC5
```

결과에 대한 경로는`Build/OvmfX64/DEBUG_GCC5` 이다.

QEMU를 다음과 같은 옵션으로 실행한다.

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

이렇게 하면 OVMF의 모든 DEBUG 로그 메세지가 `debug.log` 파일에 포함되어 생성된다. 해당 파일은 매 실행마다 생성된다.

## 로그파일에서 GUID 치환하기

`debug.log` 파일을 확인해보면 다음과 같은 GUID 값을 확인할 수 있다.

```
$ head debug.log
SecCoreStartupWithStack(0xFFFCC000, 0x820000)
Register PPI Notify: DCD0BE23-9586-40F4-B643-06522CED4EDE
Install PPI: 8C8CE578-8A3D-4F1C-9935-896185C32DD3
Install PPI: 5473C07A-3DCB-4DCA-BD6F-1E9689E7349A
The 0th FV start address is 0x00000820000, size is 0x000E0000, handle is 0x820000
Register PPI Notify: 49EDB1C1-BF21-4761-BB12-EB0031AABB39
Register PPI Notify: EA7CA24B-DED5-4DAD-A389-BF827E8F9B38
Install PPI: B9E0ABFE-5979-4914-977F-6DEE78C278A6
Install PPI: DBE23AA9-A345-4B97-85B6-B226F1617389
DiscoverPeimsAndOrderWithApriori(): Found 0x7 PEI FFS files in the 0th FV
```

edk2 빌드 시스템이 GUID의 이름을 가진 파일을 만들기 때문에 이를 이용하면 GUID 값에 대응하는 텍스트로 대체시켜 가독성을 높일 수 있다.

```
$ head Build/OvmfX64/DEBUG_GCC5/FV/Guid.xref
8c1a6b71-0c4b-4497-aaad-07404edf142c PCDLesson
1BA0062E-C779-4582-8566-336AE8F78F09 ResetVector
df1ccef6-f301-4a63-9661-fc6030dcc880 SecMain
52C05B14-0B98-496c-BC3B-04B50211D680 PeiCore
9B3ADA4F-AE56-4c24-8DEA-F03B7558AE50 PcdPeim
A3610442-E69F-4DF3-82CA-2360C4031A23 ReportStatusCodeRouterPei
9D225237-FA01-464C-A949-BAABC02D31D0 StatusCodeHandlerPei
86D70125-BAA3-4296-A62F-602BEBBB9081 DxeIpl
222c386d-5abc-4fb4-b124-fbb82488acf4 PlatformPei
89E549B0-7CFE-449d-9BA3-10D8B2312D71 S3Resume2Pei
```

다음과 같은 파이썬 코드를 작성하자.

```
from shutil import copyfile

GUIDS_FILE_PATH = "Build/OvmfX64/DEBUG_GCC5/FV/Guid.xref"
EXTRA_GUIDS_FILE_PATH = "Guid_extra.xref"
LOG_IN_FILE_PATH = "debug.log"
LOG_OUT_FILE_PATH = "debug_parsed.log"

guids = {}

with open(GUIDS_FILE_PATH) as p:
    for line in p:
        l = line.split(" ")
        if len(l)==2:
            guids[l[0].upper()] = l[1][:-1]

if EXTRA_GUIDS_FILE_PATH:
    with open(EXTRA_GUIDS_FILE_PATH) as p:
        for line in p:
            l = line.split(" ")
            if len(l)==2:
                guids[l[0].upper()] = l[1][:-1]

copyfile(LOG_IN_FILE_PATH, LOG_OUT_FILE_PATH)

f = open(LOG_OUT_FILE_PATH, 'r')
filedata = f.read()
f.close()

for key,val in guids.items():
    filedata = filedata.replace(key, val)

f = open(LOG_OUT_FILE_PATH, 'w')
f.write(filedata)
f.close()
```

결과물은 `debug_parsed.log` 에 저장되며 추가적인GUID 값이 존재하는 경우 `EXTRA_GUIDS_FILE_PATH` 경로에 지정하여 추가할 수 있다.

```
$ python replace_guids.py
$ head debug_parsed.log
SecCoreStartupWithStack(0xFFFCC000, 0x820000)
Register PPI Notify: gEfiPeiSecurity2PpiGuid
Install PPI: gEfiFirmwareFileSystem2Guid
Install PPI: gEfiFirmwareFileSystem3Guid
The 0th FV start address is 0x00000820000, size is 0x000E0000, handle is 0x820000
Register PPI Notify: gEfiPeiFirmwareVolumeInfoPpiGuid
Register PPI Notify: gEfiPeiFirmwareVolumeInfo2PpiGuid
Install PPI: gEfiPeiLoadFilePpiGuid
Install PPI: gEfiTemporaryRamSupportPpiGuid
DiscoverPeimsAndOrderWithApriori(): Found 0x7 PEI FFS files in the 0th FV
```

추가적으로 해당 스크립트를 범용적으로 이용하기 위해서 아래와 같이 작성해볼 수 있다.

```
from argparse import ArgumentParser

parser = ArgumentParser(description="Convert GUIDs to text identifiers in UEFI firmware boot log")
parser.add_argument('-g', '--guids', help="Guid.xref file location", required=True)
parser.add_argument('-e', '--guids_extra', help="additional Guid.xref file location")
parser.add_argument('-i', '--log_input', help="input log file location", required=True)
parser.add_argument('-o', '--log_output', help="output log file location (by default input file is changed in place)")
args = parser.parse_args()

GUIDS_FILE_PATH = args.guids
EXTRA_GUIDS_FILE_PATH = args.guids_extra

LOG_IN_FILE_PATH = args.log_input
if args.log_output:
    LOG_OUT_FILE_PATH = args.log_output
else:
    LOG_OUT_FILE_PATH = args.log_input

...

if LOG_IN_FILE_PATH != LOG_OUT_FILE_PATH:
    copyfile(LOG_IN_FILE_PATH, LOG_OUT_FILE_PATH)

...
```

```
$ python replace_guids.py -g Build/OvmfX64/DEBUG_GCC5/FV/Guid.xref -e Guid_extra.xref -i debug.log -o debug_parsed.log
$ python replace_guids.py --help
usage: replace_guids.py [-h] -g GUIDS [-e GUIDS_EXTRA] -i LOG_INPUT [-o LOG_OUTPUT]

Convert GUIDs to text identifiers in UEFI firmware boot log

optional arguments:
  -h, --help            show this help message and exit
  -g GUIDS, --guids GUIDS
                        Guid.xref file location
  -e GUIDS_EXTRA, --guids_extra GUIDS_EXTRA
                        additional Guid.xref file location
  -i LOG_INPUT, --log_input LOG_INPUT
                        input log file location
  -o LOG_OUTPUT, --log_output LOG_OUTPUT
                        output log file location (by default input file is changed in place)
```

## DEBUG 메세지 출력길이 제한

DEBUg 문으로 출력할 수 있는 최대 문자열의 길이가 제한되어 있다.\
[https://github.com/tianocore/edk2/blob/master/OvmfPkg/Library/PlatformDebugLibIoPort/DebugLib.c](https://github.com/tianocore/edk2/blob/master/OvmfPkg/Library/PlatformDebugLibIoPort/DebugLib.c:)

```
#define MAX_DEBUG_MESSAGE_LENGTH  0x100
```

정의에 따라 0x100보다 긴 출력이 발생할 수 있으므로 해당 값을 변경하여 빌드함으로써 그 제한을 늘릴 수 있다.

```
build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=DEBUG --tagname=GCC5
```

\\
