public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Paulo Alcantara <paulo@paulo.ac>
To: edk2-devel@lists.01.org
Cc: Paulo Alcantara <paulo@paulo.ac>, Eric Dong <eric.dong@intel.com>,
	Laszlo Ersek <lersek@redhat.com>
Subject: [RFC v5 3/8] UefiCpuPkg/CpuExceptionHandlerLib/Ia32: Add stack trace support
Date: Sun, 14 Jan 2018 22:23:31 -0200	[thread overview]
Message-ID: <457cabcc8075d638e5a27eb7794736cde02a6bdf.1515974582.git.paulo@paulo.ac> (raw)
In-Reply-To: <cover.1515974582.git.paulo@paulo.ac>
In-Reply-To: <cover.1515974582.git.paulo@paulo.ac>

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



  parent reply	other threads:[~2018-01-15  0:18 UTC|newest]

Thread overview: 82+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-14 12:47 [RFC 0/1] Stack trace support in X64 exception handling Paulo Alcantara
2017-11-14 12:47 ` [RFC 1/1] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support Paulo Alcantara
2017-11-14 14:01   ` Andrew Fish
2017-11-14 14:26     ` 答复: " Fan Jeff
2017-11-14 14:38       ` Andrew Fish
2017-11-14 15:30     ` Paulo Alcantara
2017-11-14 16:51       ` Brian J. Johnson
2017-12-29  3:48   ` [RFC v4 0/6] Stack trace support in X64 exception handling Paulo Alcantara
2017-12-29  4:39     ` [RFC v4 1/6] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support Paulo Alcantara
2018-01-03  8:53       ` 答复: " Fan Jeff
2018-01-03 14:51         ` Paulo Alcantara
2017-12-29  4:39     ` [RFC v4 2/6] UefiCpuPkg/CpuExceptionHandlerLib: Export GetPdbFileName() Paulo Alcantara
2017-12-29  4:39     ` [RFC v4 3/6] UefiCpuPkg/CpuExceptionHandlerLib/Ia32: Add stack trace support Paulo Alcantara
2017-12-29  4:39     ` [RFC v4 4/6] UefiCpuPkg/CpuExceptionHandlerLib: Add helper to valid memory addresses Paulo Alcantara
2018-01-03  8:42       ` 答复: " Fan Jeff
2018-01-03 14:45         ` Paulo Alcantara
2018-01-03 16:59       ` Brian J. Johnson
2018-01-04 13:03         ` Paulo Alcantara
2018-01-04  1:36       ` Yao, Jiewen
2018-01-04  1:58         ` Yao, Jiewen
2018-01-04 13:29           ` Paulo Alcantara
2018-01-04 14:35             ` Yao, Jiewen
2018-01-04 15:15               ` Paulo Alcantara
2018-01-04 13:18         ` Paulo Alcantara
2017-12-29  4:39     ` [RFC v4 5/6] UefiCpuPkg/CpuExceptionHandlerLib: Ensure valid frame/stack pointers Paulo Alcantara
2018-01-03  8:45       ` 答复: " Fan Jeff
2018-01-03 14:48         ` Paulo Alcantara
2018-01-04  1:07       ` Yao, Jiewen
2017-12-29  4:39     ` [RFC v4 6/6] UefiCpuPkg/CpuExceptionHandlerLib: Correctly print IP addresses Paulo Alcantara
2018-01-03  8:46       ` 答复: " Fan Jeff
2018-01-04  0:59     ` [RFC v4 0/6] Stack trace support in X64 exception handling Yao, Jiewen
2018-01-04 13:36       ` Paulo Alcantara
2018-01-15  0:23     ` [RFC v5 0/8] " Paulo Alcantara
2018-01-15  0:23       ` [RFC v5 1/8] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support Paulo Alcantara
2018-01-15  0:23       ` [RFC v5 2/8] UefiCpuPkg/CpuExceptionHandlerLib: Export GetPdbFileName() Paulo Alcantara
2018-01-15  0:23       ` Paulo Alcantara [this message]
2018-01-15  0:23       ` [RFC v5 4/8] UefiCpuPkg/CpuExceptionHandlerLib: Add helper to validate memory addresses Paulo Alcantara
2018-01-15  0:23       ` [RFC v5 5/8] UefiCpuPkg/CpuExceptionHandlerLib: Ensure valid frame/stack pointers Paulo Alcantara
2018-01-15  0:23       ` [RFC v5 6/8] UefiCpuPkg/CpuExceptionHandlerLib: Correctly print IP addresses Paulo Alcantara
2018-01-15  0:23       ` [RFC v5 7/8] UefiCpuPkg/CpuExceptionHandlerLib: Validate memory address ranges Paulo Alcantara
2018-01-15  0:23       ` [RFC v5 8/8] UefiCpuPkg/CpuExceptionHandlerLib: Add early check in DumpStackContents Paulo Alcantara
2018-01-17 12:57       ` [RFC v5 0/8] Stack trace support in X64 exception handling Yao, Jiewen
2018-01-17 22:48         ` Yao, Jiewen
2018-01-19  0:09           ` Paulo Alcantara
2018-01-19  0:02         ` Paulo Alcantara
2018-01-19  0:15           ` Paulo Alcantara
2018-01-29 13:38         ` Paulo Alcantara
2018-01-31  5:56           ` Yao, Jiewen
2018-01-31 19:05             ` Paulo Alcantara
2017-11-14 13:21 ` [RFC 0/1] " Paulo Alcantara
2017-11-14 14:03   ` 答复: " Fan Jeff
2017-11-14 14:12     ` 答复: " Fan Jeff
2017-11-14 15:37     ` Paulo Alcantara
2017-11-14 16:33       ` Brian J. Johnson
2017-11-14 17:23         ` Andrew Fish
2017-11-14 17:41           ` Brian J. Johnson
2017-11-14 17:56             ` Paulo Alcantara
2017-11-15 13:21       ` 答复: 答复: " Fan Jeff
2017-11-15 14:41         ` Paulo Alcantara
2017-11-15 14:52           ` 答复: " Fan Jeff
2017-11-16  1:18 ` [RFC v2 0/3] " Paulo Alcantara
2017-11-16  1:18   ` [RFC v2 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support Paulo Alcantara
2017-11-16  1:57     ` Yao, Jiewen
2017-11-16 22:13       ` Paulo Alcantara
2017-11-17  3:43         ` Yao, Jiewen
2017-11-20 14:51           ` Paulo Alcantara
2017-11-16 15:43     ` Brian J. Johnson
2017-11-16 22:19       ` Paulo Alcantara
2017-11-16  1:18   ` [RFC v2 2/3] UefiCpuPkg/CpuExceptionHandlerLib: Export GetPdbFileName() Paulo Alcantara
2017-11-16  1:18   ` [RFC v2 3/3] UefiCpuPkg/CpuExceptionHandlerLib/Ia32: Add stack trace support Paulo Alcantara
2017-11-16  1:46   ` [RFC v2 0/3] Stack trace support in X64 exception handling Paulo Alcantara
2017-11-16  5:01     ` Andrew Fish
2017-11-16 22:02       ` Paulo Alcantara
2017-11-16 21:56   ` [RFC v3 " Paulo Alcantara
2017-11-16 21:56     ` [RFC v3 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support Paulo Alcantara
2017-11-17  7:24       ` 答复: " Fan Jeff
2017-11-20 14:59         ` Paulo Alcantara
2017-11-23 14:27           ` 答复: " Fan Jeff
2017-11-23 18:34             ` Andrew Fish
2017-11-23 19:49               ` Fan Jeff
2017-11-16 21:56     ` [RFC v3 2/3] UefiCpuPkg/CpuExceptionHandlerLib: Export GetPdbFileName() Paulo Alcantara
2017-11-16 21:56     ` [RFC v3 3/3] UefiCpuPkg/CpuExceptionHandlerLib/Ia32: Add stack trace support Paulo Alcantara

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=457cabcc8075d638e5a27eb7794736cde02a6bdf.1515974582.git.paulo@paulo.ac \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox