This patch adds stack trace support during a IA32 CPU exception. It will dump out back trace, stack contents as well as image module names that were part of the call stack.
Contributed-under: TianoCore Contribution Agreement 1.1 Cc: Eric Dong <eric.d...@intel.com> Cc: Laszlo Ersek <ler...@redhat.com> Signed-off-by: Paulo Alcantara <pa...@paulo.ac> --- UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c | 42 --- UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h | 11 - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c | 310 +++++++++++++++++++- 3 files changed, 308 insertions(+), 55 deletions(-) diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c index f62ab8c48c..867c5c01d6 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c @@ -109,48 +109,6 @@ InternalPrintMessage ( SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer)); } -/** - Find and display image base address and return image base and its entry point. - - @param CurrentEip Current instruction pointer. - -**/ -VOID -DumpModuleImageInfo ( - IN UINTN CurrentEip - ) -{ - EFI_STATUS Status; - UINTN Pe32Data; - VOID *PdbPointer; - VOID *EntryPoint; - - Pe32Data = PeCoffSearchImageBase (CurrentEip); - if (Pe32Data == 0) { - InternalPrintMessage ("!!!! Can't find image information. !!!!\n"); - } else { - // - // Find Image Base entry point - // - Status = PeCoffLoaderGetEntryPoint ((VOID *) Pe32Data, &EntryPoint); - if (EFI_ERROR (Status)) { - EntryPoint = NULL; - } - InternalPrintMessage ("!!!! Find image "); - PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data); - if (PdbPointer != NULL) { - InternalPrintMessage ("%a", PdbPointer); - } else { - InternalPrintMessage ("(No PDB) " ); - } - InternalPrintMessage ( - " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n", - (VOID *) Pe32Data, - EntryPoint - ); - } -} - /** Read and save reserved vector information diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h index 64c7094513..ec46c2d9d3 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h @@ -130,17 +130,6 @@ InternalPrintMessage ( ... ); -/** - Find and display image base address and return image base and its entry point. - - @param CurrentEip Current instruction pointer. - -**/ -VOID -DumpModuleImageInfo ( - IN UINTN CurrentEip - ); - /** Display CPU information. diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c index 6ac8549839..25e02fbbc1 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c @@ -398,6 +398,296 @@ DumpCpuContext ( ); } +/** + Dump stack trace. + + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. + @param[out] UnwoundStacksCount Count of unwound stack frames. +**/ +STATIC +VOID +DumpStackTrace ( + IN EFI_SYSTEM_CONTEXT SystemContext, + OUT INTN *UnwoundStacksCount + ) +{ + UINT32 Eip; + UINT32 Ebp; + UINTN ImageBase; + CHAR8 *PdbFileName; + + // + // Set current EIP address + // + Eip = SystemContext.SystemContextIa32->Eip; + + // + // Set current frame pointer address + // + Ebp = SystemContext.SystemContextIa32->Ebp; + + // + // Check for proper frame pointer alignment + // + if (((UINTN)Ebp & (CPU_STACK_ALIGNMENT - 1)) != 0) { + InternalPrintMessage ("!!!! Unaligned frame pointer. !!!!\n"); + return; + } + + // + // Get initial PE/COFF image base address from current EIP + // + ImageBase = PeCoffSearchImageBase (Eip); + if (ImageBase == 0) { + InternalPrintMessage ("!!!! Could not find backtrace information. !!!!"); + return; + } + + // + // Get PDB file name from initial PE/COFF image + // + GetPdbFileName (ImageBase, NULL, &PdbFileName); + + // + // Initialize count of unwound stacks + // + *UnwoundStacksCount = 1; + + // + // Print out back trace + // + InternalPrintMessage ("\nCall trace:\n"); + + for (;;) { + // + // Print stack frame in the following format: + // + // # <EIP> @ <ImageBase>+<RelOffset> (EBP) in [<ModuleName> | ????] + // + InternalPrintMessage ( + "%d 0x%08x @ 0x%08x+0x%x (0x%08x) in %a\n", + *UnwoundStacksCount - 1, + Eip, + ImageBase, + Eip - ImageBase - 1, + Ebp, + PdbFileName + ); + + // + // Set EIP with return address from current stack frame + // + Eip = *(UINT32 *)((UINTN)Ebp + 4); + + // + // If EIP is zero, then stop unwinding the stack + // + if (Eip == 0) { + break; + } + + // + // Search for the respective PE/COFF image based on EIP + // + ImageBase = PeCoffSearchImageBase (Eip); + if (ImageBase == 0) { + // + // Stop stack trace + // + break; + } + + // + // Get PDB file name + // + GetPdbFileName (ImageBase, NULL, &PdbFileName); + + // + // Unwind the stack + // + Ebp = *(UINT32 *)(UINTN)Ebp; + + // + // Increment count of unwound stacks + // + (*UnwoundStacksCount)++; + } +} + +/** + Dump all image module names from call stack. + + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. +**/ +STATIC +VOID +DumpImageModuleNames ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + EFI_STATUS Status; + UINT32 Eip; + UINT32 Ebp; + UINTN ImageBase; + VOID *EntryPoint; + CHAR8 *PdbAbsoluteFilePath; + CHAR8 *PdbFileName; + UINTN LastImageBase; + + // + // Set current EIP address + // + Eip = SystemContext.SystemContextIa32->Eip; + + // + // Set current frame pointer address + // + Ebp = SystemContext.SystemContextIa32->Ebp; + + // + // Get initial PE/COFF image base address from current EIP + // + ImageBase = PeCoffSearchImageBase (Eip); + if (ImageBase == 0) { + InternalPrintMessage ("!!!! Could not find image module names. !!!!"); + return; + } + + // + // Set last PE/COFF image base address + // + LastImageBase = ImageBase; + + // + // Get initial PE/COFF image's entry point + // + Status = PeCoffLoaderGetEntryPoint ((VOID *)ImageBase, &EntryPoint); + if (EFI_ERROR (Status)) { + EntryPoint = NULL; + } + + // + // Get file name and absolute path of initial PDB file + // + GetPdbFileName (ImageBase, &PdbAbsoluteFilePath, &PdbFileName); + + // + // Print out initial image module name (if any) + // + if (PdbAbsoluteFilePath != NULL) { + InternalPrintMessage ( + "\n%a (ImageBase=0x%08x, EntryPoint=0x%08x):\n", + PdbFileName, + ImageBase, + (UINTN)EntryPoint + ); + InternalPrintMessage ("%a\n", PdbAbsoluteFilePath); + } + + // + // Walk through call stack and find next module names + // + for (;;) { + // + // Set EIP with return address from current stack frame + // + Eip = *(UINT32 *)((UINTN)Ebp + 4); + + // + // Search for the respective PE/COFF image based on Eip + // + ImageBase = PeCoffSearchImageBase (Eip); + if (ImageBase == 0) { + // + // Stop stack trace + // + break; + } + + // + // If EIP points to another PE/COFF image, then find its respective PDB file + // name. + // + if (LastImageBase != ImageBase) { + // + // Get PE/COFF image's entry point + // + Status = PeCoffLoaderGetEntryPoint ((VOID *)ImageBase, &EntryPoint); + if (EFI_ERROR (Status)) { + EntryPoint = NULL; + } + + // + // Get file name and absolute path of PDB file + // + GetPdbFileName (ImageBase, &PdbAbsoluteFilePath, &PdbFileName); + + // + // Print out image module name (if any) + // + if (PdbAbsoluteFilePath != NULL) { + InternalPrintMessage ( + "%a (ImageBase=0x%08x, EntryPoint=0x%08x):\n", + PdbFileName, + ImageBase, + (UINTN)EntryPoint + ); + InternalPrintMessage ("%a\n", PdbAbsoluteFilePath); + } + + // + // Save last PE/COFF image base address + // + LastImageBase = ImageBase; + } + + // + // Unwind the stack + // + Ebp = *(UINT32 *)(UINTN)Ebp; + } +} + +/** + Dump stack contents. + + @param[in] CurrentEsp Current stack pointer address. + @param[in] UnwoundStacksCount Count of unwound stack frames. +**/ +STATIC +VOID +DumpStackContents ( + IN UINT32 CurrentEsp, + IN INTN UnwoundStacksCount + ) +{ + // + // Check for proper stack alignment + // + if (((UINTN)CurrentEsp & (CPU_STACK_ALIGNMENT - 1)) != 0) { + InternalPrintMessage ("!!!! Unaligned stack pointer. !!!!\n"); + return; + } + + // + // Dump out stack contents + // + InternalPrintMessage ("\nStack dump:\n"); + while (UnwoundStacksCount-- > 0) { + InternalPrintMessage ( + "0x%08x: %08x %08x\n", + CurrentEsp, + *(UINT32 *)CurrentEsp, + *(UINT32 *)((UINTN)CurrentEsp + 4) + ); + + // + // Point to next stack + // + CurrentEsp += CPU_STACK_ALIGNMENT; + } +} + /** Display CPU information. @@ -410,9 +700,25 @@ DumpImageAndCpuContent ( IN EFI_SYSTEM_CONTEXT SystemContext ) { + INTN UnwoundStacksCount; + + // + // Dump CPU context + // DumpCpuContext (ExceptionType, SystemContext); + + // + // Dump stack trace + // + DumpStackTrace (SystemContext, &UnwoundStacksCount); + + // + // Dump image module names + // + DumpImageModuleNames (SystemContext); + // - // Dump module image base and module entry point by EIP + // Dump stack contents // - DumpModuleImageInfo (SystemContext.SystemContextIa32->Eip); + DumpStackContents (SystemContext.SystemContextIa32->Esp, UnwoundStacksCount); } -- 2.14.3 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel