This patch adds stack trace support during a X64 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/X64/ArchExceptionHandler.c | 376 +++++++++++++++++++-
1 file changed, 374 insertions(+), 2 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
index 1dcf4277de..19bfaa329a 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
@@ -14,6 +14,11 @@
#include "CpuExceptionCommon.h"
+//
+// Unknown PDB file name
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mUnknownPdbFileName = "????";
+
/**
Return address map of exception handler template so that C code can generate
exception tables.
@@ -398,6 +403,357 @@ DumpCpuContext (
);
}
+/**
+ Get absolute path and file name of PDB file in PE/COFF image.
+
+ @param[in] ImageBase Base address of PE/COFF image.
+ @param[out] PdbAbsoluteFilePath Absolute path of PDB file.
+ @param[out] PdbFileName File name of PDB file.
+**/
+STATIC
+VOID
+GetPdbFileName (
+ IN UINTN ImageBase,
+ OUT CHAR8 **PdbAbsoluteFilePath,
+ OUT CHAR8 **PdbFileName
+ )
+{
+ VOID *PdbPointer;
+ CHAR8 *Str;
+
+ //
+ // Get PDB file name from PE/COFF image
+ //
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)ImageBase);
+ if (PdbPointer == NULL) {
+ //
+ // No PDB file name found. Set it to an unknown file name.
+ //
+ *PdbFileName = (CHAR8 *)mUnknownPdbFileName;
+ if (PdbAbsoluteFilePath != NULL) {
+ *PdbAbsoluteFilePath = NULL;
+ }
+ } else {
+ //
+ // Get file name portion out of PDB file in PE/COFF image
+ //
+ Str = (CHAR8 *)((UINTN)PdbPointer +
+ AsciiStrLen ((CHAR8 *)PdbPointer) - sizeof *Str);
+ for (; *Str != '/' && *Str != '\\'; Str--) {
+ ;
+ }
+
+ //
+ // Set PDB file name (also skip trailing path separator: '/' or '\\')
+ //
+ *PdbFileName = Str + 1;
+
+ if (PdbAbsoluteFilePath != NULL) {
+ //
+ // Set absolute file path of PDB file
+ //
+ *PdbAbsoluteFilePath = PdbPointer;
+ }
+ }
+}
+
+/**
+ Dump stack contents.
+
+ @param[in] CurrentRsp Current stack pointer address.
+ @param[in] UnwoundStacksCount Count of unwound stack frames.
+**/
+STATIC
+VOID
+DumpStackContents (
+ IN UINT64 CurrentRsp,
+ IN INTN UnwoundStacksCount
+ )
+{
+ //
+ // Check for proper stack pointer alignment
+ //
+ if (((UINTN)CurrentRsp & (CPU_STACK_ALIGNMENT - 1)) != 0) {
+ InternalPrintMessage ("!!!! Unaligned stack pointer. !!!!\n");
+ return;
+ }
+
+ //
+ // Dump out stack contents
+ //
+ InternalPrintMessage ("\nStack dump:\n");
+ while (UnwoundStacksCount-- > 0) {
+ InternalPrintMessage (
+ "0x%016lx: %016lx %016lx\n",
+ CurrentRsp,
+ *(UINT64 *)CurrentRsp,
+ *(UINT64 *)((UINTN)CurrentRsp + 8)
+ );
+
+ //
+ // Point to next stack
+ //
+ CurrentRsp += CPU_STACK_ALIGNMENT;
+ }
+}
+
+/**
+ 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;
+ UINT64 Rip;
+ UINTN ImageBase;
+ VOID *EntryPoint;
+ CHAR8 *PdbAbsoluteFilePath;
+ CHAR8 *PdbFileName;
+ UINT64 Rbp;
+ UINTN LastImageBase;
+
+ //
+ // Set current RIP address
+ //
+ Rip = SystemContext.SystemContextX64->Rip;
+
+ //
+ // Set current frame pointer address
+ //
+ Rbp = SystemContext.SystemContextX64->Rbp;
+
+ //
+ // Check for proper frame pointer alignment
+ //
+ if (((UINTN)Rbp & (CPU_STACK_ALIGNMENT - 1)) != 0) {
+ InternalPrintMessage ("!!!! Unaligned frame pointer. !!!!\n");
+ return;
+ }
+
+ //
+ // Get initial PE/COFF image base address from current RIP
+ //
+ ImageBase = PeCoffSearchImageBase (Rip);
+ 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%016lx, EntryPoint=0x%016lx):\n",
+ PdbFileName,
+ ImageBase,
+ (UINTN)EntryPoint
+ );
+ InternalPrintMessage ("%a\n", PdbAbsoluteFilePath);
+ }
+
+ //
+ // Walk through call stack and find next module names
+ //
+ for (;;) {
+ //
+ // Set RIP with return address from current stack frame
+ //
+ Rip = *(UINT64 *)((UINTN)Rbp + 8);
+
+ //
+ // If RIP is zero, then stop unwinding the stack
+ //
+ if (Rip == 0) {
+ break;
+ }
+
+ //
+ // Search for the respective PE/COFF image based on RIP
+ //
+ ImageBase = PeCoffSearchImageBase (Rip);
+ if (ImageBase == 0) {
+ //
+ // Stop stack trace
+ //
+ break;
+ }
+
+ //
+ // If RIP 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%016lx, EntryPoint=0x%016lx):\n",
+ PdbFileName,
+ ImageBase,
+ (UINTN)EntryPoint
+ );
+ InternalPrintMessage ("%a\n", PdbAbsoluteFilePath);
+ }
+
+ //
+ // Save last PE/COFF image base address
+ //
+ LastImageBase = ImageBase;
+ }
+
+ //
+ // Unwind the stack
+ //
+ Rbp = *(UINT64 *)(UINTN)Rbp;
+ }
+}
+
+/**
+ 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
+ )
+{
+ UINT64 Rip;
+ UINT64 Rbp;
+ UINTN ImageBase;
+ CHAR8 *PdbFileName;
+
+ //
+ // Set current RIP address
+ //
+ Rip = SystemContext.SystemContextX64->Rip;
+
+ //
+ // Set current frame pointer address
+ //
+ Rbp = SystemContext.SystemContextX64->Rbp;
+
+ //
+ // Get initial PE/COFF image base address from current RIP
+ //
+ ImageBase = PeCoffSearchImageBase (Rip);
+ 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:
+ //
+ // # <RIP> @ <ImageBase>+<RelOffset> (RBP) in [<ModuleName> | ????]
+ //
+ InternalPrintMessage (
+ "%d 0x%016lx @ 0x%016lx+0x%x (0x%016lx) in %a\n",
+ *UnwoundStacksCount - 1,
+ Rip,
+ ImageBase,
+ Rip - ImageBase - 1,
+ Rbp,
+ PdbFileName
+ );
+
+ //
+ // Set RIP with return address from current stack frame
+ //
+ Rip = *(UINT64 *)((UINTN)Rbp + 8);
+
+ //
+ // If RIP is zero, then stop unwinding the stack
+ //
+ if (Rip == 0) {
+ break;
+ }
+
+ //
+ // Search for the respective PE/COFF image based on RIP
+ //
+ ImageBase = PeCoffSearchImageBase (Rip);
+ if (ImageBase == 0) {
+ //
+ // Stop stack trace
+ //
+ break;
+ }
+
+ //
+ // Get PDB file name
+ //
+ GetPdbFileName (ImageBase, NULL, &PdbFileName);
+
+ //
+ // Unwind the stack
+ //
+ Rbp = *(UINT64 *)(UINTN)Rbp;
+
+ //
+ // Increment count of unwound stacks
+ //
+ (*UnwoundStacksCount)++;
+ }
+}
+
/**
Display CPU information.
@@ -410,9 +766,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 RIP
+ // Dump stack contents
//
- DumpModuleImageInfo (SystemContext.SystemContextX64->Rip);
+ DumpStackContents (SystemContext.SystemContextX64->Rsp, UnwoundStacksCount);
}
--
2.14.3
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Paulo,
I did not receive your #0 patch. So, I reply #1 here.
Your serial of patches should work for IA32/X64 GCC and IA32 MSFT. I suggest you could push this serial of patches as soon as pass UefiCpuPkg owner/reviewers’ review and validation,
And then I could send my x64 MSFT support later.
Thanks!
Jeff
________________________________
From: edk2-devel <edk2-devel-bounces@lists.01.org> on behalf of Paulo Alcantara <paulo@paulo.ac>
Sent: Friday, December 29, 2017 12:39:34 PM
To: edk2-devel@lists.01.org
Cc: Laszlo Ersek; Eric Dong
Subject: [edk2] [RFC v4 1/6] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support
This patch adds stack trace support during a X64 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/X64/ArchExceptionHandler.c | 376 +++++++++++++++++++-
1 file changed, 374 insertions(+), 2 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
index 1dcf4277de..19bfaa329a 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
@@ -14,6 +14,11 @@
#include "CpuExceptionCommon.h"
+//
+// Unknown PDB file name
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mUnknownPdbFileName = "????";
+
/**
Return address map of exception handler template so that C code can generate
exception tables.
@@ -398,6 +403,357 @@ DumpCpuContext (
);
}
+/**
+ Get absolute path and file name of PDB file in PE/COFF image.
+
+ @param[in] ImageBase Base address of PE/COFF image.
+ @param[out] PdbAbsoluteFilePath Absolute path of PDB file.
+ @param[out] PdbFileName File name of PDB file.
+**/
+STATIC
+VOID
+GetPdbFileName (
+ IN UINTN ImageBase,
+ OUT CHAR8 **PdbAbsoluteFilePath,
+ OUT CHAR8 **PdbFileName
+ )
+{
+ VOID *PdbPointer;
+ CHAR8 *Str;
+
+ //
+ // Get PDB file name from PE/COFF image
+ //
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)ImageBase);
+ if (PdbPointer == NULL) {
+ //
+ // No PDB file name found. Set it to an unknown file name.
+ //
+ *PdbFileName = (CHAR8 *)mUnknownPdbFileName;
+ if (PdbAbsoluteFilePath != NULL) {
+ *PdbAbsoluteFilePath = NULL;
+ }
+ } else {
+ //
+ // Get file name portion out of PDB file in PE/COFF image
+ //
+ Str = (CHAR8 *)((UINTN)PdbPointer +
+ AsciiStrLen ((CHAR8 *)PdbPointer) - sizeof *Str);
+ for (; *Str != '/' && *Str != '\\'; Str--) {
+ ;
+ }
+
+ //
+ // Set PDB file name (also skip trailing path separator: '/' or '\\')
+ //
+ *PdbFileName = Str + 1;
+
+ if (PdbAbsoluteFilePath != NULL) {
+ //
+ // Set absolute file path of PDB file
+ //
+ *PdbAbsoluteFilePath = PdbPointer;
+ }
+ }
+}
+
+/**
+ Dump stack contents.
+
+ @param[in] CurrentRsp Current stack pointer address.
+ @param[in] UnwoundStacksCount Count of unwound stack frames.
+**/
+STATIC
+VOID
+DumpStackContents (
+ IN UINT64 CurrentRsp,
+ IN INTN UnwoundStacksCount
+ )
+{
+ //
+ // Check for proper stack pointer alignment
+ //
+ if (((UINTN)CurrentRsp & (CPU_STACK_ALIGNMENT - 1)) != 0) {
+ InternalPrintMessage ("!!!! Unaligned stack pointer. !!!!\n");
+ return;
+ }
+
+ //
+ // Dump out stack contents
+ //
+ InternalPrintMessage ("\nStack dump:\n");
+ while (UnwoundStacksCount-- > 0) {
+ InternalPrintMessage (
+ "0x%016lx: %016lx %016lx\n",
+ CurrentRsp,
+ *(UINT64 *)CurrentRsp,
+ *(UINT64 *)((UINTN)CurrentRsp + 8)
+ );
+
+ //
+ // Point to next stack
+ //
+ CurrentRsp += CPU_STACK_ALIGNMENT;
+ }
+}
+
+/**
+ 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;
+ UINT64 Rip;
+ UINTN ImageBase;
+ VOID *EntryPoint;
+ CHAR8 *PdbAbsoluteFilePath;
+ CHAR8 *PdbFileName;
+ UINT64 Rbp;
+ UINTN LastImageBase;
+
+ //
+ // Set current RIP address
+ //
+ Rip = SystemContext.SystemContextX64->Rip;
+
+ //
+ // Set current frame pointer address
+ //
+ Rbp = SystemContext.SystemContextX64->Rbp;
+
+ //
+ // Check for proper frame pointer alignment
+ //
+ if (((UINTN)Rbp & (CPU_STACK_ALIGNMENT - 1)) != 0) {
+ InternalPrintMessage ("!!!! Unaligned frame pointer. !!!!\n");
+ return;
+ }
+
+ //
+ // Get initial PE/COFF image base address from current RIP
+ //
+ ImageBase = PeCoffSearchImageBase (Rip);
+ 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%016lx, EntryPoint=0x%016lx):\n",
+ PdbFileName,
+ ImageBase,
+ (UINTN)EntryPoint
+ );
+ InternalPrintMessage ("%a\n", PdbAbsoluteFilePath);
+ }
+
+ //
+ // Walk through call stack and find next module names
+ //
+ for (;;) {
+ //
+ // Set RIP with return address from current stack frame
+ //
+ Rip = *(UINT64 *)((UINTN)Rbp + 8);
+
+ //
+ // If RIP is zero, then stop unwinding the stack
+ //
+ if (Rip == 0) {
+ break;
+ }
+
+ //
+ // Search for the respective PE/COFF image based on RIP
+ //
+ ImageBase = PeCoffSearchImageBase (Rip);
+ if (ImageBase == 0) {
+ //
+ // Stop stack trace
+ //
+ break;
+ }
+
+ //
+ // If RIP 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%016lx, EntryPoint=0x%016lx):\n",
+ PdbFileName,
+ ImageBase,
+ (UINTN)EntryPoint
+ );
+ InternalPrintMessage ("%a\n", PdbAbsoluteFilePath);
+ }
+
+ //
+ // Save last PE/COFF image base address
+ //
+ LastImageBase = ImageBase;
+ }
+
+ //
+ // Unwind the stack
+ //
+ Rbp = *(UINT64 *)(UINTN)Rbp;
+ }
+}
+
+/**
+ 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
+ )
+{
+ UINT64 Rip;
+ UINT64 Rbp;
+ UINTN ImageBase;
+ CHAR8 *PdbFileName;
+
+ //
+ // Set current RIP address
+ //
+ Rip = SystemContext.SystemContextX64->Rip;
+
+ //
+ // Set current frame pointer address
+ //
+ Rbp = SystemContext.SystemContextX64->Rbp;
+
+ //
+ // Get initial PE/COFF image base address from current RIP
+ //
+ ImageBase = PeCoffSearchImageBase (Rip);
+ 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:
+ //
+ // # <RIP> @ <ImageBase>+<RelOffset> (RBP) in [<ModuleName> | ????]
+ //
+ InternalPrintMessage (
+ "%d 0x%016lx @ 0x%016lx+0x%x (0x%016lx) in %a\n",
+ *UnwoundStacksCount - 1,
+ Rip,
+ ImageBase,
+ Rip - ImageBase - 1,
+ Rbp,
+ PdbFileName
+ );
+
+ //
+ // Set RIP with return address from current stack frame
+ //
+ Rip = *(UINT64 *)((UINTN)Rbp + 8);
+
+ //
+ // If RIP is zero, then stop unwinding the stack
+ //
+ if (Rip == 0) {
+ break;
+ }
+
+ //
+ // Search for the respective PE/COFF image based on RIP
+ //
+ ImageBase = PeCoffSearchImageBase (Rip);
+ if (ImageBase == 0) {
+ //
+ // Stop stack trace
+ //
+ break;
+ }
+
+ //
+ // Get PDB file name
+ //
+ GetPdbFileName (ImageBase, NULL, &PdbFileName);
+
+ //
+ // Unwind the stack
+ //
+ Rbp = *(UINT64 *)(UINTN)Rbp;
+
+ //
+ // Increment count of unwound stacks
+ //
+ (*UnwoundStacksCount)++;
+ }
+}
+
/**
Display CPU information.
@@ -410,9 +766,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 RIP
+ // Dump stack contents
//
- DumpModuleImageInfo (SystemContext.SystemContextX64->Rip);
+ DumpStackContents (SystemContext.SystemContextX64->Rsp, UnwoundStacksCount);
}
--
2.14.3
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Hi Jeff, On 1/3/2018 6:53 AM, Fan Jeff wrote: > Paulo, > > I did not receive your #0 patch. So, I reply #1 here. > > Your serial of patches should work for IA32/X64 GCC and IA32 MSFT. I > suggest you could push this serial of patches as soon as pass UefiCpuPkg > owner/reviewers’ review and validation, OK - That would be really appreciable if you could test it with IA32 MSFT toolchain and see if the stacktrace is printed out correctly when passing the '/Oy-' compile option. > > And then I could send my x64 MSFT support later. Cool. Thanks Paulo > ------------------------------------------------------------------------ > *From:* edk2-devel <edk2-devel-bounces@lists.01.org> on behalf of Paulo > Alcantara <paulo@paulo.ac> > *Sent:* Friday, December 29, 2017 12:39:34 PM > *To:* edk2-devel@lists.01.org > *Cc:* Laszlo Ersek; Eric Dong > *Subject:* [edk2] [RFC v4 1/6] UefiCpuPkg/CpuExceptionHandlerLib/X64: > Add stack trace support > This patch adds stack trace support during a X64 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/X64/ArchExceptionHandler.c | > 376 +++++++++++++++++++- > 1 file changed, 374 insertions(+), 2 deletions(-) > > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c > index 1dcf4277de..19bfaa329a 100644 > --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c > +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c > @@ -14,6 +14,11 @@ > > #include "CpuExceptionCommon.h" > > +// > +// Unknown PDB file name > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mUnknownPdbFileName = "????"; > + > /** > Return address map of exception handler template so that C code can > generate > exception tables. > @@ -398,6 +403,357 @@ DumpCpuContext ( > ); > } > > +/** > + Get absolute path and file name of PDB file in PE/COFF image. > + > + @param[in] ImageBase Base address of PE/COFF image. > + @param[out] PdbAbsoluteFilePath Absolute path of PDB file. > + @param[out] PdbFileName File name of PDB file. > +**/ > +STATIC > +VOID > +GetPdbFileName ( > + IN UINTN ImageBase, > + OUT CHAR8 **PdbAbsoluteFilePath, > + OUT CHAR8 **PdbFileName > + ) > +{ > + VOID *PdbPointer; > + CHAR8 *Str; > + > + // > + // Get PDB file name from PE/COFF image > + // > + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)ImageBase); > + if (PdbPointer == NULL) { > + // > + // No PDB file name found. Set it to an unknown file name. > + // > + *PdbFileName = (CHAR8 *)mUnknownPdbFileName; > + if (PdbAbsoluteFilePath != NULL) { > + *PdbAbsoluteFilePath = NULL; > + } > + } else { > + // > + // Get file name portion out of PDB file in PE/COFF image > + // > + Str = (CHAR8 *)((UINTN)PdbPointer + > + AsciiStrLen ((CHAR8 *)PdbPointer) - sizeof *Str); > + for (; *Str != '/' && *Str != '\\'; Str--) { > + ; > + } > + > + // > + // Set PDB file name (also skip trailing path separator: '/' or '\\') > + // > + *PdbFileName = Str + 1; > + > + if (PdbAbsoluteFilePath != NULL) { > + // > + // Set absolute file path of PDB file > + // > + *PdbAbsoluteFilePath = PdbPointer; > + } > + } > +} > + > +/** > + Dump stack contents. > + > + @param[in] CurrentRsp Current stack pointer address. > + @param[in] UnwoundStacksCount Count of unwound stack frames. > +**/ > +STATIC > +VOID > +DumpStackContents ( > + IN UINT64 CurrentRsp, > + IN INTN UnwoundStacksCount > + ) > +{ > + // > + // Check for proper stack pointer alignment > + // > + if (((UINTN)CurrentRsp & (CPU_STACK_ALIGNMENT - 1)) != 0) { > + InternalPrintMessage ("!!!! Unaligned stack pointer. !!!!\n"); > + return; > + } > + > + // > + // Dump out stack contents > + // > + InternalPrintMessage ("\nStack dump:\n"); > + while (UnwoundStacksCount-- > 0) { > + InternalPrintMessage ( > + "0x%016lx: %016lx %016lx\n", > + CurrentRsp, > + *(UINT64 *)CurrentRsp, > + *(UINT64 *)((UINTN)CurrentRsp + 8) > + ); > + > + // > + // Point to next stack > + // > + CurrentRsp += CPU_STACK_ALIGNMENT; > + } > +} > + > +/** > + 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; > + UINT64 Rip; > + UINTN ImageBase; > + VOID *EntryPoint; > + CHAR8 *PdbAbsoluteFilePath; > + CHAR8 *PdbFileName; > + UINT64 Rbp; > + UINTN LastImageBase; > + > + // > + // Set current RIP address > + // > + Rip = SystemContext.SystemContextX64->Rip; > + > + // > + // Set current frame pointer address > + // > + Rbp = SystemContext.SystemContextX64->Rbp; > + > + // > + // Check for proper frame pointer alignment > + // > + if (((UINTN)Rbp & (CPU_STACK_ALIGNMENT - 1)) != 0) { > + InternalPrintMessage ("!!!! Unaligned frame pointer. !!!!\n"); > + return; > + } > + > + // > + // Get initial PE/COFF image base address from current RIP > + // > + ImageBase = PeCoffSearchImageBase (Rip); > + 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%016lx, EntryPoint=0x%016lx):\n", > + PdbFileName, > + ImageBase, > + (UINTN)EntryPoint > + ); > + InternalPrintMessage ("%a\n", PdbAbsoluteFilePath); > + } > + > + // > + // Walk through call stack and find next module names > + // > + for (;;) { > + // > + // Set RIP with return address from current stack frame > + // > + Rip = *(UINT64 *)((UINTN)Rbp + 8); > + > + // > + // If RIP is zero, then stop unwinding the stack > + // > + if (Rip == 0) { > + break; > + } > + > + // > + // Search for the respective PE/COFF image based on RIP > + // > + ImageBase = PeCoffSearchImageBase (Rip); > + if (ImageBase == 0) { > + // > + // Stop stack trace > + // > + break; > + } > + > + // > + // If RIP 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%016lx, EntryPoint=0x%016lx):\n", > + PdbFileName, > + ImageBase, > + (UINTN)EntryPoint > + ); > + InternalPrintMessage ("%a\n", PdbAbsoluteFilePath); > + } > + > + // > + // Save last PE/COFF image base address > + // > + LastImageBase = ImageBase; > + } > + > + // > + // Unwind the stack > + // > + Rbp = *(UINT64 *)(UINTN)Rbp; > + } > +} > + > +/** > + 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 > + ) > +{ > + UINT64 Rip; > + UINT64 Rbp; > + UINTN ImageBase; > + CHAR8 *PdbFileName; > + > + // > + // Set current RIP address > + // > + Rip = SystemContext.SystemContextX64->Rip; > + > + // > + // Set current frame pointer address > + // > + Rbp = SystemContext.SystemContextX64->Rbp; > + > + // > + // Get initial PE/COFF image base address from current RIP > + // > + ImageBase = PeCoffSearchImageBase (Rip); > + 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: > + // > + // # <RIP> @ <ImageBase>+<RelOffset> (RBP) in [<ModuleName> | ????] > + // > + InternalPrintMessage ( > + "%d 0x%016lx @ 0x%016lx+0x%x (0x%016lx) in %a\n", > + *UnwoundStacksCount - 1, > + Rip, > + ImageBase, > + Rip - ImageBase - 1, > + Rbp, > + PdbFileName > + ); > + > + // > + // Set RIP with return address from current stack frame > + // > + Rip = *(UINT64 *)((UINTN)Rbp + 8); > + > + // > + // If RIP is zero, then stop unwinding the stack > + // > + if (Rip == 0) { > + break; > + } > + > + // > + // Search for the respective PE/COFF image based on RIP > + // > + ImageBase = PeCoffSearchImageBase (Rip); > + if (ImageBase == 0) { > + // > + // Stop stack trace > + // > + break; > + } > + > + // > + // Get PDB file name > + // > + GetPdbFileName (ImageBase, NULL, &PdbFileName); > + > + // > + // Unwind the stack > + // > + Rbp = *(UINT64 *)(UINTN)Rbp; > + > + // > + // Increment count of unwound stacks > + // > + (*UnwoundStacksCount)++; > + } > +} > + > /** > Display CPU information. > > @@ -410,9 +766,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 RIP > + // Dump stack contents > // > - DumpModuleImageInfo (SystemContext.SystemContextX64->Rip); > + DumpStackContents (SystemContext.SystemContextX64->Rsp, > UnwoundStacksCount); > } > -- > 2.14.3 > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2024 Red Hat, Inc.