UEFI DebugLib 介绍

1.我们调试中常用Debug 打印信息,这些会输出到BIOS串口日志中

EFI_STATUSEFIAPIHelloWorld2(IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable){EFI_STATUS      Status;Status=EFI_SUCCESS;gST->ConOut->OutputString(gST->ConOut,L"ConOut:Hellow World \n\r");Print(L"Print:Hellow World\n");DEBUG ((DEBUG_ERROR, "Debug:Hellow World\n"));return Status;}

UEFI shell下运行效果:我们发现这几种输出都打印到了Shell界面而不是串口中

通常在shell 界面显示打印信息会使用到Print() gST->ConOut->OutputString,Debug 是打印在串口日志中

Debug 对于调试至关重要,那么我们需要深入了解DebugLib 和Debug()实现

 /**Macro that calls DebugPrint().If MDEPKG_NDEBUG is not defined and the DEBUG_PROPERTY_DEBUG_PRINT_ENABLEDbit of PcdDebugProperyMask is set, then this macro passes Expression toDebugPrint().@param  Expression  Expression containing an error level, a format string,and a variable argument list based on the format string.**/#if !defined (MDEPKG_NDEBUG)#define DEBUG(Expression)        \do {                           \if (DebugPrintEnabled ()) {  \_DEBUG (Expression);       \}                            \} while (FALSE)#else#define DEBUG(Expression)#endif

有多个Lib 对DebugPrintEnabled 做了定义,因此可以使用不同的Lib 让Debug()产生不同的效果,这点也适用于其他函数

对于不同的架构实现方式可能不同,但是可以用同样的模块代码,通过替换Lib去替换实现函数

EDK常用的Debuglib

DebugLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf

DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf

DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf

其中MDEPKG_NDEBUGDebugPrintEnabled()时调试信息开关和等级的控制方法

包括PcdDebugPropertyMask   DEBUG_PROPERTY_DEBUG_PRINT_ENABLED

BOOLEAN

EFIAPI

DebugPrintEnabled (

  VOID

  )

{

  return (BOOLEAN)((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);

}

PcdDebugPropertyMask   定义

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

  #  BIT6 - Enable Debug Assert as BreakPoint only.<BR>

  # @Prompt Debug Property.

  # @Expression  0x80000002 | (gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask & 0xC0) == 0

  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0|UINT8|0x00000005

//

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

#define DEBUG_PROPERTY_ASSERT_ONLY_BREAKPOINT     0x40

第二个相关的Pcd : PcdFixedDebugPrintErrorLevel 打印信息等级常用的就是EFI_D_ERROR   EFI_D_WARN    EFI_D_INFO

  ## This flag is used to control build time optimization based on debug print level.

  #  Its default value is 0xFFFFFFFF to expose all debug print level.

  #  BIT0  - Initialization message.<BR>

  #  BIT1  - Warning message.<BR>

  #  BIT2  - Load Event message.<BR>

  #  BIT3  - File System message.<BR>

  #  BIT4  - Allocate or Free Pool message.<BR>

  #  BIT5  - Allocate or Free Page message.<BR>

  #  BIT6  - Information message.<BR>

  #  BIT7  - Dispatcher message.<BR>

  #  BIT8  - Variable message.<BR>

  #  BIT10 - Boot Manager message.<BR>

  #  BIT12 - BlockIo Driver message.<BR>

  #  BIT14 - Network Driver message.<BR>

  #  BIT16 - UNDI Driver message.<BR>

  #  BIT17 - LoadFile message.<BR>

  #  BIT19 - Event message.<BR>

  #  BIT20 - Global Coherency Database changes message.<BR>

  #  BIT21 - Memory range cachability changes message.<BR>

  #  BIT22 - Detailed debug message.<BR>

  #  BIT31 - Error message.<BR>

  # @Prompt Fixed Debug Message Print Level.

  gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel|0xFFFFFFFF|UINT32|0x30001016

//

// Declare bits for PcdDebugPrintErrorLevel and the ErrorLevel parameter of DebugPrint()

//

#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_MANAGEABILITY  0x00800000  // Detailed debug and payload message of manageability

                                         // related modules, such Redfish, IPMI, MCTP and etc.

#define DEBUG_ERROR  0x80000000          // Error

 

 MdeModulePkg/Application/HelloWorld/HelloWorld.inf {

    <PcdsFixedAtBuild>

      gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel | 0xffffffff

      gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xff

    <LibraryClasses>

    #DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf

    #DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf

    DebugLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf

  }

  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0  就不会打印Debug 信息

 

      gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xff  进行打印

 _DEBUG (Expression);  #define _DEBUG(Expression)  _DEBUG_PRINT Expression#define _DEBUG_PRINT(PrintLevel, ...)              \do {                                             \if (DebugPrintLevelEnabled (PrintLevel)) {     \DebugPrint (PrintLevel, ##__VA_ARGS__);      \}                                              \} while (FALSE)BOOLEANEFIAPIDebugPrintLevelEnabled (IN  CONST UINTN  ErrorLevel){return (BOOLEAN)((ErrorLevel & PcdGet32 (PcdFixedDebugPrintErrorLevel)) != 0);}**/VOIDEFIAPIDebugPrint (IN  UINTN        ErrorLevel,IN  CONST CHAR8  *Format,...){VA_LIST  Marker;VA_START (Marker, Format);DebugVPrint (ErrorLevel, Format, Marker);VA_END (Marker);}VOIDEFIAPIDebugVPrint (IN  UINTN        ErrorLevel,IN  CONST CHAR8  *Format,IN  VA_LIST      VaListMarker){DebugPrintMarker (ErrorLevel, Format, VaListMarker, NULL);}1.BaseDebugLibSerialPort Debuglib 使用的是SerialPortWrite 打印信息DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.infMdePkg\Library\BaseDebugLibSerialPort\DebugLib.cVOIDDebugPrintMarker (IN  UINTN        ErrorLevel,IN  CONST CHAR8  *Format,IN  VA_LIST      VaListMarker,IN  BASE_LIST    BaseListMarker){CHAR8  Buffer[MAX_DEBUG_MESSAGE_LENGTH];//// If Format is NULL, then ASSERT().//ASSERT (Format != NULL);//// Check driver debug mask value and global mask//if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {return;}if (AsciiStrStr (Format, "\n") != NULL) {UINTN           ModuleNameLength;ModuleNameLength = AsciiStrLen (gEfiCallerBaseName) + 2;*Buffer = '[';AsciiStrnCpyS (Buffer + 1,ModuleNameLength -1,gEfiCallerBaseName,ModuleNameLength - 2);*(Buffer + ModuleNameLength - 1) = ']';*(Buffer + ModuleNameLength)     = 0;//// Send the print string to a Serial Port//SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));}//// Convert the DEBUG() message to an ASCII String//if (BaseListMarker == NULL) {AsciiVSPrint (Buffer, sizeof (Buffer), Format, VaListMarker);} else {AsciiBSPrint (Buffer, sizeof (Buffer), Format, BaseListMarker);}//// Send the print string to a Serial Port//SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));}2.  PeiDxeDebugLibReportStatusCode是更通用的Debug 实现了从PEI DXE 等都有实现DebugLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.infMdeModulePkg\Library\PeiDxeDebugLibReportStatusCode\DebugLib.c**/VOIDDebugPrintMarker (IN  UINTN        ErrorLevel,IN  CONST CHAR8  *Format,IN  VA_LIST      VaListMarker,IN  BASE_LIST    BaseListMarker){UINT64          Buffer[(EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)) + 1];EFI_DEBUG_INFO  *DebugInfo;UINTN           TotalSize;BASE_LIST       BaseListMarkerPointer;CHAR8           *FormatString;BOOLEAN         Long;//// If Format is NULL, then ASSERT().//ASSERT (Format != NULL);//// Check driver Debug Level value and global debug level//if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {return;}//// Compute the total size of the record.// Note that the passing-in format string and variable parameters will be constructed to// the following layout:////                Buffer->|------------------------|//                        |         Padding        | 4 bytes//             DebugInfo->|------------------------|//                        |      EFI_DEBUG_INFO    | sizeof(EFI_DEBUG_INFO)// BaseListMarkerPointer->|------------------------|//                        |           ...          |//                        |   variable arguments   | 12 * sizeof (UINT64)//                        |           ...          |//                        |------------------------|//                        |       Format String    |//                        |------------------------|<- (UINT8 *)Buffer + sizeof(Buffer)//TotalSize = 4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64) + AsciiStrSize (Format);//// If the TotalSize is larger than the maximum record size, then truncate it.//if (TotalSize > sizeof (Buffer)) {TotalSize = sizeof (Buffer);}//// Fill in EFI_DEBUG_INFO//// Here we skip the first 4 bytes of Buffer, because we must ensure BaseListMarkerPointer is// 64-bit aligned, otherwise retrieving 64-bit parameter from BaseListMarkerPointer will cause// exception on IPF. Buffer starts at 64-bit aligned address, so skipping 4 types (sizeof(EFI_DEBUG_INFO))// just makes address of BaseListMarkerPointer, which follows DebugInfo, 64-bit aligned.//DebugInfo             = (EFI_DEBUG_INFO *)(Buffer) + 1;DebugInfo->ErrorLevel = (UINT32)ErrorLevel;BaseListMarkerPointer = (BASE_LIST)(DebugInfo + 1);FormatString          = (CHAR8 *)((UINT64 *)(DebugInfo + 1) + 12);//// Copy the Format string into the record. It will be truncated if it's too long.//AsciiStrnCpyS (FormatString,sizeof (Buffer) - (4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64)),Format,sizeof (Buffer) - (4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64)) - 1);//// The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments// of format in DEBUG string, which is followed by the DEBUG format string.// Here we will process the variable arguments and pack them in this area.////// Use the actual format string.//Format = FormatString;for ( ; *Format != '\0'; Format++) {//// Only format with prefix % is processed.//if (*Format != '%') {continue;}Long = FALSE;//// Parse Flags and Width//for (Format++; TRUE; Format++) {if ((*Format == '.') || (*Format == '-') || (*Format == '+') || (*Format == ' ')) {//// These characters in format field are omitted.//continue;}if ((*Format >= '0') && (*Format <= '9')) {//// These characters in format field are omitted.//continue;}if ((*Format == 'L') || (*Format == 'l')) {//// 'L" or "l" in format field means the number being printed is a UINT64//Long = TRUE;continue;}if (*Format == '*') {//// '*' in format field means the precision of the field is specified by// a UINTN argument in the argument list.//if (BaseListMarker == NULL) {BASE_ARG (BaseListMarkerPointer, UINTN) = VA_ARG (VaListMarker, UINTN);} else {BASE_ARG (BaseListMarkerPointer, UINTN) = BASE_ARG (BaseListMarker, UINTN);}continue;}if (*Format == '\0') {//// Make no output if Format string terminates unexpectedly when// looking up for flag, width, precision and type.//Format--;}//// When valid argument type detected or format string terminates unexpectedly,// the inner loop is done.//break;}//// Pack variable arguments into the storage area following EFI_DEBUG_INFO.//if ((*Format == 'p') && (sizeof (VOID *) > 4)) {Long = TRUE;}if ((*Format == 'p') || (*Format == 'X') || (*Format == 'x') || (*Format == 'd') || (*Format == 'u')) {if (Long) {if (BaseListMarker == NULL) {BASE_ARG (BaseListMarkerPointer, INT64) = VA_ARG (VaListMarker, INT64);} else {BASE_ARG (BaseListMarkerPointer, INT64) = BASE_ARG (BaseListMarker, INT64);}} else {if (BaseListMarker == NULL) {BASE_ARG (BaseListMarkerPointer, int) = VA_ARG (VaListMarker, int);} else {BASE_ARG (BaseListMarkerPointer, int) = BASE_ARG (BaseListMarker, int);}}} else if ((*Format == 's') || (*Format == 'S') || (*Format == 'a') || (*Format == 'g') || (*Format == 't')) {if (BaseListMarker == NULL) {BASE_ARG (BaseListMarkerPointer, VOID *) = VA_ARG (VaListMarker, VOID *);} else {BASE_ARG (BaseListMarkerPointer, VOID *) = BASE_ARG (BaseListMarker, VOID *);}} else if (*Format == 'c') {if (BaseListMarker == NULL) {BASE_ARG (BaseListMarkerPointer, UINTN) = VA_ARG (VaListMarker, UINTN);} else {BASE_ARG (BaseListMarkerPointer, UINTN) = BASE_ARG (BaseListMarker, UINTN);}} else if (*Format == 'r') {if (BaseListMarker == NULL) {BASE_ARG (BaseListMarkerPointer, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS);} else {BASE_ARG (BaseListMarkerPointer, RETURN_STATUS) = BASE_ARG (BaseListMarker, RETURN_STATUS);}}//// If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then ASSERT()// This indicates that the DEBUG() macro is passing in more argument than can be handled by// the EFI_DEBUG_INFO record//ASSERT ((CHAR8 *)BaseListMarkerPointer <= FormatString);//// If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then return//if ((CHAR8 *)BaseListMarkerPointer > FormatString) {return;}}//// Send the DebugInfo record//REPORT_STATUS_CODE_EX (EFI_DEBUG_CODE,(EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED),0,NULL,&gEfiStatusCodeDataTypeDebugGuid,DebugInfo,TotalSize);}**/#define REPORT_STATUS_CODE_EX(Type, Value, Instance, CallerId, ExtendedDataGuid, ExtendedData, ExtendedDataSize)  \(ReportProgressCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE)             ?  \ReportStatusCodeEx(Type,Value,Instance,CallerId,ExtendedDataGuid,ExtendedData,ExtendedDataSize)        :  \(ReportErrorCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE)                   ?  \ReportStatusCodeEx(Type,Value,Instance,CallerId,ExtendedDataGuid,ExtendedData,ExtendedDataSize)        :  \(ReportDebugCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)                   ?  \ReportStatusCodeEx(Type,Value,Instance,CallerId,ExtendedDataGuid,ExtendedData,ExtendedDataSize)        :  \EFI_UNSUPPORTED#endif

最后调用的是ReportStatusCodeEx,该函数在PEI,DXE Runtime SMM Driver中都有实现

ReportStatusCodeEx

PEI实现举例:最终调用的是PeiService 的ppi

**/EFI_STATUSEFIAPIReportStatusCodeEx (IN EFI_STATUS_CODE_TYPE   Type,IN EFI_STATUS_CODE_VALUE  Value,IN UINT32                 Instance,IN CONST EFI_GUID         *CallerId          OPTIONAL,IN CONST EFI_GUID         *ExtendedDataGuid  OPTIONAL,IN CONST VOID             *ExtendedData      OPTIONAL,IN UINTN                  ExtendedDataSize){EFI_STATUS_CODE_DATA  *StatusCodeData;UINT64                Buffer[(MAX_EXTENDED_DATA_SIZE / sizeof (UINT64)) + 1];//// If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().//ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));//// If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().//ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));if (ExtendedDataSize > (MAX_EXTENDED_DATA_SIZE - sizeof (EFI_STATUS_CODE_DATA))) {//// The local variable Buffer not large enough to hold the extended data associated// with the status code being reported.//DEBUG ((DEBUG_ERROR, "Status code extended data is too large to be reported!\n"));return EFI_OUT_OF_RESOURCES;}StatusCodeData             = (EFI_STATUS_CODE_DATA  *)Buffer;StatusCodeData->HeaderSize = (UINT16)sizeof (EFI_STATUS_CODE_DATA);StatusCodeData->Size       = (UINT16)ExtendedDataSize;if (ExtendedDataGuid == NULL) {ExtendedDataGuid = &gEfiStatusCodeSpecificDataGuid;}CopyGuid (&StatusCodeData->Type, ExtendedDataGuid);if (ExtendedData != NULL) {CopyMem (StatusCodeData + 1, ExtendedData, ExtendedDataSize);}if (CallerId == NULL) {CallerId = &gEfiCallerIdGuid;}return InternalReportStatusCode (Type, Value, Instance, CallerId, StatusCodeData);}////// Pei service instance///EFI_PEI_SERVICES  gPs = {{PEI_SERVICES_SIGNATURE,PEI_SERVICES_REVISION,sizeof (EFI_PEI_SERVICES),0,0},PeiInstallPpi,PeiReInstallPpi,PeiLocatePpi,PeiNotifyPpi,PeiGetBootMode,PeiSetBootMode,PeiGetHobList,PeiCreateHob,PeiFfsFindNextVolume,PeiFfsFindNextFile,PeiFfsFindSectionData,PeiInstallPeiMemory,PeiAllocatePages,PeiAllocatePool,(EFI_PEI_COPY_MEM)CopyMem,(EFI_PEI_SET_MEM)SetMem,PeiReportStatusCode,PeiResetSystem,&gPeiDefaultCpuIoPpi,&gPeiDefaultPciCfg2Ppi,PeiFfsFindFileByName,PeiFfsGetFileInfo,PeiFfsGetVolumeInfo,PeiRegisterForShadow,PeiFfsFindSectionData3,PeiFfsGetFileInfo2,PeiResetSystem2,PeiFreePages,};

 

UEFI中 PeiService 中包含的函数

  //

  // Status Code

  //

  EFI_PEI_REPORT_STATUS_CODE        ReportStatusCode;

 PeiServices->PeiReportStatusCode

 //// Locate StatusCode Ppi.//Status = PeiServicesLocatePpi (&gEfiPeiStatusCodePpiGuid,0,NULL,(VOID **)&StatusCodePpi);EFI_STATUSInternalReportStatusCode (IN EFI_STATUS_CODE_TYPE   Type,IN EFI_STATUS_CODE_VALUE  Value,IN UINT32                 Instance,IN CONST EFI_GUID         *CallerId OPTIONAL,IN EFI_STATUS_CODE_DATA   *Data     OPTIONAL){CONST EFI_PEI_SERVICES  **PeiServices;EFI_STATUS              Status;if ((ReportProgressCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE)) ||(ReportErrorCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE)) ||(ReportDebugCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE))){GUID_WITH_MODULENAME    GuidWithName;EFI_GUID                *CallerGuid;CallerGuid = (EFI_GUID *)CallerId;if (CallerGuid != NULL) {CopyGuid (&GuidWithName.Guid, CallerId);GuidWithName.Signature  = REPORT_STATUS_GUID_MODULE_SIGNATURE;GuidWithName.ModuleName = gEfiCallerBaseName;CallerGuid = &GuidWithName.Guid;}PeiServices = GetPeiServicesTablePointer ();Status      = (*PeiServices)->ReportStatusCode (PeiServices,Type,Value,Instance,(EFI_GUID *)CallerGuid,Data);if (Status == EFI_NOT_AVAILABLE_YET) {Status = OemHookStatusCodeInitialize ();if (!EFI_ERROR (Status)) {return OemHookStatusCodeReport (Type, Value, Instance, (EFI_GUID *)CallerGuid, Data);}}return Status;}return EFI_UNSUPPORTED;}

3.UefiDebugLibConOut.inf 这个Lib就是开始我们提到的将debug信息打印到Shell 使用的Lib

#DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf

MdePkg\Library\UefiDebugLibConOut\DebugLib.c

同样关注不同Lib中的 DebugPrintMarker 实现 了解各DebugLib的区别

#define MAX_DEBUG_MESSAGE_LENGTH  0x100  定义了最大的Buffer size

VOIDDebugPrintMarker (IN  UINTN        ErrorLevel,IN  CONST CHAR8  *Format,IN  VA_LIST      VaListMarker,IN  BASE_LIST    BaseListMarker){CHAR16  Buffer[MAX_DEBUG_MESSAGE_LENGTH];if (!mPostEBS) {//// If Format is NULL, then ASSERT().//ASSERT (Format != NULL);//// Check driver debug mask value and global mask//if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {return;}//// Convert the DEBUG() message to a Unicode String//if (BaseListMarker == NULL) {UnicodeVSPrintAsciiFormat (Buffer, sizeof (Buffer), Format, VaListMarker);} else {UnicodeBSPrintAsciiFormat (Buffer, sizeof (Buffer), Format, BaseListMarker);}//// Send the print string to the Console Output device//if ((mDebugST != NULL) && (mDebugST->ConOut != NULL)) {mDebugST->ConOut->OutputString (mDebugST->ConOut, Buffer);}}}

可以看到最后调用的就是 mDebugST->ConOut->OutputString (mDebugST->ConOut, Buffer);

 

最后EFI Shell下常用的Print 最后调用的都是gRT->ConOut->OutputString ()


*

*/UINTNEFIAPIPrint (IN CONST CHAR16  *Format,...){VA_LIST  Marker;UINTN    Return;VA_START (Marker, Format);Return = InternalPrint (Format, gST->ConOut, Marker);VA_END (Marker);return Return;}UINTNInternalPrint (IN  CONST CHAR16                     *Format,IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *Console,IN  VA_LIST                          Marker){EFI_STATUS  Status;UINTN       Return;CHAR16      *Buffer;UINTN       BufferSize;ASSERT (Format != NULL);ASSERT (((UINTN)Format & BIT0) == 0);ASSERT (Console != NULL);BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);Buffer = (CHAR16 *)AllocatePool (BufferSize);ASSERT (Buffer != NULL);Return = UnicodeVSPrint (Buffer, BufferSize, Format, Marker);if ((Console != NULL) && (Return > 0)) {//// To be extra safe make sure Console has been initialized//Status = Console->OutputString (Console, Buffer);if (EFI_ERROR (Status)) {Return = 0;}}FreePool (Buffer);return Return;}

  1. 除了常用的Debug() 我们还可以使用其他调试手段

 1ASSERT()

 2CpuBreakpoint ();

  3CpuDeadLoop ();

   4CpuPause ();

 

ASSERT是一种在程序中用于检查特定条件是否为真的方法。当条件为假时,断言会触发错误处理机制,通常会导致程序中

止或输出错误信息。

HelloWorld2(IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable){EFI_STATUS      Status;Status=EFI_SUCCESS;UINT8 index=0;ASSERT(index == 1);gST->ConOut->OutputString(gST->ConOut,L"ConOut:Hellow World \n\r");Print(L"Print:Hellow World\n");DEBUG ((DEBUG_ERROR, "Debug:Hellow World\n"));return Status;}

 

当运行到Assert 就会出现Assert 信息 会打印所在的函数 行数 和 报错条件不满足原因

**/#if !defined (MDEPKG_NDEBUG)#define ASSERT(Expression)        \do {                            \if (DebugAssertEnabled ()) {  \if (!(Expression)) {        \_ASSERT (Expression);     \ANALYZER_UNREACHABLE ();  \}                           \}                             \} while (FALSE)#else#define ASSERT(Expression)#endif

执行 CpuDeadLoop (); 后会出现Hang机现象 原因是出现循环

现在Shell应该在CpuDeadLoop()处循环等待。

**/VOIDEFIAPICpuDeadLoop (VOID){volatile UINTN  Index;for (Index = 0; Index == 0;) {CpuPause ();}}

CpuPause (); 其实是等待 Nop 命令

CpuPausenopnopnopnopnopret

CpuBreakpoint () 是设置断点  后续可以进行单步操作

VOIDEFIAPICpuBreakpoint (VOID){__asm__ __volatile__ ("int $3");}__asm{int 3;}

x86 系列处理器从其第一代产品英特尔 8086 开始就提供了一条专门用来支持调试的指令,即 INT 3。简单地说,这条指令

的目的就是使 CPU 中断(break)到调试器,以供调试者对执行现场进行各种分析。

当我们调试程序时,可以在可能有问题的地方插入一条 INT 3 指令,使 CPU 执行到这一点时停下来。这便是软件调试中经

常用到的断点(breakpoint)功能,因此 INT 3 指令又被称为断点指令。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/875531.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【vluhub】zabbix漏洞

介绍&#xff1a; zabbix是对服务器资源状态例如、内存空间、CPU、程序运行状态进行检测、设置预警值、短信设置等功能等一款开源工具。配置不当存在未授权,SQL注入漏洞 弱口令 nameadmin&passwordzabbix nameguest&password POST /index.php HTTP/1.1 Host: 192.1…

Flex布局中元素主轴上平均分布 多余的向左对齐

content&#xff1a;父元素 content-item: 子元素 主轴上子元素平均分布 .content {display: flex;flex-wrap: wrap;justify-content: space-between;.service-item {display: flex;flex-direction: column;justify-content: center;align-items: center;width: 80px;height:…

【C++】19.红黑树模拟实现 set 和 map

我们想要实现STL中的set和map&#xff0c;那么第一步就需要看一下库函数是如何实现的&#xff1a; 通过查看源代码我们发现两个容器都包含了stl_tree.h&#xff0c;因此我们猜测此头文件实现的是红黑树。 但是set和map很显然不是使用同一棵树实现的&#xff0c;那么STL库是怎么…

vue3 Axios封装使用

先安装axios&#xff1a; npm install axios 第一步&#xff1a;项目src下创建一个名为request的文件夹&#xff08;看一下示例图&#xff09;&#xff1a; 然后在request下创建两个api.ts和index.ts的文件 api.ts里的内容&#xff1a;&#xff08;url写你自己的接口&#xff…

Vscode——如何快速搜索项目工程中的某个文件的位置

第一步&#xff1a;按 shift ctrl p 第二步&#xff1a;然后把 > 删除 第三步&#xff1a;输入文件名称即可

飞书群聊机器人自定义机器人接入,并实现艾特@群成员功能

飞书群聊机器人还是比钉钉的要麻烦一点&#xff0c;钉钉的直接通过手机号就可以艾特群里面的人&#xff0c;但是飞书的要想艾特群里面的人&#xff0c;需要使用用户的 Open ID 或 User ID。这两个ID怎么获取呢&#xff1f;还需要在飞书的开放平台上创建一个应用&#xff0c;然后…

《Java初阶数据结构》----6.<优先级队列之PriorityQueue底层:堆>

前言 大家好&#xff0c;我目前在学习java。之前也学了一段时间&#xff0c;但是没有发布博客。时间过的真的很快。我会利用好这个暑假&#xff0c;来复习之前学过的内容&#xff0c;并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区…

使用FileZilla Cilent快速让手机与电脑进行文件互传(无需生态)

目录 前言使用 FileZilla笔者的话 前言 当设备多的时候文件的传输就成了一种问题。 就比如说我想将手机上的文件传到电脑里面&#xff0c;因为我使用的电脑跟我的手机不是一个生态的&#xff0c;它们唯一的联系或许就是连接到了统一 WIFI 下&#xff0c;也就是说它们在同一个…

【React】全面解析:从基础知识到高级应用,掌握现代Web开发利器

文章目录 一、React 的基础知识1. 什么是 React&#xff1f;2. React 的基本概念3. 基本示例 二、React 的进阶概念1. 状态&#xff08;State&#xff09;和属性&#xff08;Props&#xff09;2. 生命周期方法&#xff08;Lifecycle Methods&#xff09;3. 钩子&#xff08;Hoo…

计算存储背景与发展

随着云计算、企业级应用以及物联网领域的飞速发展&#xff0c;当前的数据处理需求正以前所未有的规模增长&#xff0c;以满足存储行业不断变化的需求。这种增长导致网络带宽压力增大&#xff0c;并对主机计算资源&#xff08;如内存和CPU&#xff09;造成极大负担&#xff0c;进…

TikTok养号的网络环境及相关代理IP知识

TikTok作为一个流行的短视频分享平台&#xff0c;其用户量非常庞大&#xff0c;很多商家和个人都会使用TikTok来进行引流和推广。由于TikTok的规则和政策限制了每个用户每天发布视频的数量&#xff0c;因此许多用户会使用多个账号来发布更多的视频以提高曝光率。 然而&#xff…

Oracle中LISTAGG 函数的介绍以及使用详情

LISTAGG 函数介绍 listagg 函数是 Oracle 11.2 推出的新特性。 其主要功能类似于 wmsys.wm_concat 函数&#xff0c; 即将数据分组后&#xff0c; 把指定列的数据再通过指定符号合并。 LISTAGG 使用 listagg 函数有两个参数&#xff1a; 1、 要合并的列名 2、…

一种多策略改进鹅智能优化算法IGOOSE(2024年新出优化算法) 种群初始化精英反向策略+非线性下降因子+黄金正弦变异策略

一种多策略改进鹅智能优化算法IGOOSE&#xff08;2024年新出优化算法&#xff09; 种群初始化精英反向策略非线性下降因子黄金正弦变异策略 文章目录 前言一种多策略改进鹅智能优化算法IGOOSE&#xff08;2024年新出优化算法&#xff09; 种群初始化精英反向策略非线性下降因子…

游泳耳机品牌哪个牌子好?四大高热度游泳耳机综合分析

近年来&#xff0c;游泳耳机的受欢迎程度呈指数级增长&#xff0c;市场热度不断攀升。但作为一名长期关注运动科技的专业人士&#xff0c;我必须提醒大家&#xff0c;在享受水下音乐的同时&#xff0c;也要注意选择专业可靠的产品。市面上许多所谓的“游泳耳机”其实缺乏必要的…

【C++】:红黑树深度剖析 --- 手撕红黑树!

目录 前言一&#xff0c;红黑树的概念二&#xff0c;红黑树的性质三&#xff0c;红黑树节点的定义四&#xff0c;红黑树的插入操作4.1 第一步4.2 第二步4.3 插入操作的完整代码 五&#xff0c;红黑树的验证六&#xff0c;实现红黑树的完整代码五&#xff0c;红黑树与AVL树的比较…

python实现盲反卷积算法

python实现盲反卷积算法 盲反卷积算法算法原理算法实现Python实现详细解释优缺点应用领域盲反卷积算法 盲反卷积算法是一种图像复原技术,用于在没有先验知识或仅有有限信息的情况下,估计模糊图像的原始清晰图像和点扩散函数(PSF)。盲反卷积在摄影、医学成像、天文学等领域…

前端数据可视化适配方案汇总

前端数据可视化适配方案汇总 1、前言2、方案一&#xff1a;vw vh2.1 实现效果2.2 实现思路2.3 实现代码2.3.1 css 方案2.3.1.1 sass2.3.1.2 less 2.3.2 js方案2.3.3 图表字体、间距、位移等尺寸自适应 3、scale3.1 实现效果3.2 实现思路3.3 实现代码 4、rem方案4.1 实现思路4.2…

2024暑假友谊赛 2

Problem - 1150B - Codeforces 小C是重度强迫症晚期患者&#xff0c;如果某些图形无法按照他的想法排列&#xff0c;那么他就会迎来他的末日。某天小C来到了心心念念的女神家里&#xff08;绝对不可能是女装大佬&#xff0c;绝对不可能&#xff09;&#xff0c;他发现地砖有两…

【漏洞复现】E-Cology OA——WorkflowServiceXml——SQL注入

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 E-Cology OA协同商务系统是一款面向中大型组织的数字化办公产品…

Mysql数据库第四次作业

mysql> create table student(sno int primary key auto_increment,sname varchar(30) not null unique,Ssex varchar(2) check (Ssex男 or Ssex女) not null,Sage int not null,Sdept varchar(10) default计算机 not null); mysql> create table Course(Con int primar…