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.dong@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paulo Alcantara <paulo@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
© 2016 - 2024 Red Hat, Inc.