[edk2] [RFC v5 3/8] UefiCpuPkg/CpuExceptionHandlerLib/Ia32: Add stack trace support

Paulo Alcantara posted 8 patches 6 years, 11 months ago
[edk2] [RFC v5 3/8] UefiCpuPkg/CpuExceptionHandlerLib/Ia32: Add stack trace support
Posted by Paulo Alcantara 6 years, 11 months ago
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 | 335 +++++++++++++++++++-
 3 files changed, 327 insertions(+), 61 deletions(-)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
index d9abbd772d..66892320c8 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 based on IP(0x%x) ", CurrentEip);
-    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 04f2ab593c..c5d6ea0939 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
@@ -399,20 +399,156 @@ DumpCpuContext (
 }
 
 /**
-  Display CPU information.
+  Dump stack trace.
 
-  @param ExceptionType  Exception type.
-  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+  @param[in]  ExceptionType      Exception type.
+  @param[in]  SystemContext      Pointer to EFI_SYSTEM_CONTEXT.
+  @param[out] UnwoundStacksCount Count of unwound stack frames.
 **/
+STATIC
 VOID
-DumpImageAndCpuContent (
+DumpStacktrace (
+  IN  EFI_EXCEPTION_TYPE   ExceptionType,
+  IN  EFI_SYSTEM_CONTEXT   SystemContext,
+  OUT INTN                 *UnwoundStacksCount
+  )
+{
+  UINT32  Eip;
+  UINT32  Ebp;
+  UINTN   ImageBase;
+  CHAR8   *PdbFileName;
+
+  //
+  // Set current EIP address
+  //
+  if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&
+      ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0)) {
+    //
+    // The EIP in SystemContext could not be used
+    // if it is page fault with I/D set.
+    //
+    Eip = *(UINT32 *)(UINTN)SystemContext.SystemContextIa32->Esp;
+  } else {
+    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]  ExceptionType  Exception type.
+  @param[in]  SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+**/
+STATIC
+VOID
+DumpImageModuleNames (
   IN EFI_EXCEPTION_TYPE   ExceptionType,
   IN EFI_SYSTEM_CONTEXT   SystemContext
   )
 {
-  DumpCpuContext (ExceptionType, SystemContext);
+  EFI_STATUS  Status;
+  UINT32      Eip;
+  UINT32      Ebp;
+  UINTN       ImageBase;
+  VOID        *EntryPoint;
+  CHAR8       *PdbAbsoluteFilePath;
+  CHAR8       *PdbFileName;
+  UINTN       LastImageBase;
+
   //
-  // Dump module image base and module entry point by EIP
+  // Set current EIP address
   //
   if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&
       ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0)) {
@@ -420,8 +556,191 @@ DumpImageAndCpuContent (
     // The EIP in SystemContext could not be used
     // if it is page fault with I/D set.
     //
-    DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp));
+    Eip = *(UINT32 *)(UINTN)SystemContext.SystemContextIa32->Esp;
   } else {
-    DumpModuleImageInfo (SystemContext.SystemContextIa32->Eip);
+    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.
+
+  @param ExceptionType  Exception type.
+  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+DumpImageAndCpuContent (
+  IN EFI_EXCEPTION_TYPE   ExceptionType,
+  IN EFI_SYSTEM_CONTEXT   SystemContext
+  )
+{
+  INTN UnwoundStacksCount;
+
+  //
+  // Dump CPU context
+  //
+  DumpCpuContext (ExceptionType, SystemContext);
+
+  //
+  // Dump stack trace
+  //
+  DumpStacktrace (ExceptionType, SystemContext, &UnwoundStacksCount);
+
+  //
+  // Dump image module names
+  //
+  DumpImageModuleNames (ExceptionType, SystemContext);
+
+  //
+  // Dump stack contents
+  //
+  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