Re: [edk2] [RFC 1/1] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support

2017-11-14 Thread Brian J. Johnson

On 11/14/2017 09:30 AM, Paulo Alcantara wrote:

Hi Andrew,

On 14/11/2017 12:01, Andrew Fish wrote:
C> Paulo,


Cool feature. How does this code deal with VC++ that code does not 
store the frame pointer and requires symbols to unwind.


I haven't tested in with MSVC, so I'd hope to get some help from Intel's 
guys to help supporting and testing it :-)


Regarding the symbols, I performed some tests by writing a userspace 
PE/COFF application [1] and tried to:


(a) handle the RUNTIME_FUNCTION entries in exception table (.pdata 
section) to find the function starting address and then its respective 
symbol name in COFF symbol table.


(b) Walk through UNWIND_INFO entries in .xdata section to figure out 
which CPU register a function used as a frame pointer or if it didn't 
use any at

all.

The problem I had with (a) was that the COFF symbol table is not mapped 
directory into the image's address space -- that is, the 
"PointerToSymbolTable" in File Header *should* be 0 as per PE/COFF 
format specific when handling an executable file rather a object file. 
Additionally, if it's non-zero, it contains a file offset rather than a 
RVA address, so impossible to parse it at runtime.


In (b), I realized that the CodeView format data in debug directory 
should be kept in a separate file (PDB file?) and they aren't mapped 
into image's address space as well.


I don't have so much experience with PE/COFF format, so please correct 
me if I'm mistaken.




You are correct that unfortunately, Microsoft's compilers don't put 
symbolic information in the executable file, they put it in a separate 
PDB file.  And the PDB file format is not documented (although the Wine 
project has reverse engineered parts of it) and changes with different 
compiler versions.  I've struggled with it before, and concluded that 
the only feasible way to parse it is to use the APIs Microsoft provides 
for that purpose, such as dbghelp.dll.  That doesn't work inside a BIOS, 
of course.


It is possible to define a simple, compiler-agnostic symbol table format 
and write a build-time tool to extract symbol data from the PDB files, 
convert it, and insert it into each module.  GenFw is a handy place to 
generate symbol data, since it's reformatting the images already.  I 
actually have code which does this  I'd have to get permission from 
my company's Open Source Review Board to release it, though.  That would 
take time.


Brian


IMHO, there should be exist a function like AsmGetFrameAddress() and/or 
AsmGetStackAddress() which would get implemented for both GCC and MSVC 
toolchains.


Thank you very much for your comments!

Also on the page fault you can print the fault address since it is in 
CR2.


Good point! We should also do that.

It should be possible to post process the text file and make a 
symbolicated backtrace.


Yes.

Thanks!
Paulo



Thanks,

Andrew Fish


On Nov 14, 2017, at 4:47 AM, Paulo Alcantara  wrote:

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 
Cc: Laszlo Ersek 
Signed-off-by: Paulo Alcantara 
---
UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c 
| 344 +++-

1 file changed, 342 insertions(+), 2 deletions(-)

diff --git 
a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c 


index 65f0cff680..7048247be3 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.
@@ -243,6 +248,325 @@ DumpCpuContext (
}

/**
+  Dump stack contents.
+
+  @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 = 

Re: [edk2] [RFC 1/1] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support

2017-11-14 Thread Paulo Alcantara

Hi Andrew,

On 14/11/2017 12:01, Andrew Fish wrote:
C> Paulo,


Cool feature. How does this code deal with VC++ that code does not store the 
frame pointer and requires symbols to unwind.


I haven't tested in with MSVC, so I'd hope to get some help from Intel's 
guys to help supporting and testing it :-)


Regarding the symbols, I performed some tests by writing a userspace 
PE/COFF application [1] and tried to:


(a) handle the RUNTIME_FUNCTION entries in exception table (.pdata 
section) to find the function starting address and then its respective 
symbol name in COFF symbol table.


(b) Walk through UNWIND_INFO entries in .xdata section to figure out 
which CPU register a function used as a frame pointer or if it didn't 
use any at

all.

The problem I had with (a) was that the COFF symbol table is not mapped 
directory into the image's address space -- that is, the 
"PointerToSymbolTable" in File Header *should* be 0 as per PE/COFF 
format specific when handling an executable file rather a object file. 
Additionally, if it's non-zero, it contains a file offset rather than a 
RVA address, so impossible to parse it at runtime.


In (b), I realized that the CodeView format data in debug directory 
should be kept in a separate file (PDB file?) and they aren't mapped 
into image's address space as well.


I don't have so much experience with PE/COFF format, so please correct 
me if I'm mistaken.


IMHO, there should be exist a function like AsmGetFrameAddress() and/or 
AsmGetStackAddress() which would get implemented for both GCC and MSVC 
toolchains.


Thank you very much for your comments!


Also on the page fault you can print the fault address since it is in CR2.


Good point! We should also do that.


It should be possible to post process the text file and make a symbolicated 
backtrace.


Yes.

Thanks!
Paulo



Thanks,

Andrew Fish


On Nov 14, 2017, at 4:47 AM, Paulo Alcantara  wrote:

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 
Cc: Laszlo Ersek 
Signed-off-by: Paulo Alcantara 
---
UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 
+++-
1 file changed, 342 insertions(+), 2 deletions(-)

diff --git 
a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c 
b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
index 65f0cff680..7048247be3 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.
@@ -243,6 +248,325 @@ DumpCpuContext (
}

/**
+  Dump stack contents.
+
+  @param[in]  ImageBaseBase 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  UINTNImageBase,
+  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]  UnwondStacksCount  Count of unwond stack frames.
+**/
+STATIC
+VOID
+DumpStackContents (
+  IN UINT64  CurrentRsp,
+  IN INTNUnwondStacksCount
+  )
+{
+  if (UnwondStacksCount == 0) {
+return;
+  }
+
+  //
+  // Dump out stack contents
+  //
+  InternalPrintMessage ("\nStack dump:\n");
+  while (UnwondStacksCount-- > 0) {
+InternalPrintMessage (
+  "0x%016lx: %016lx %016lx\n",
+  CurrentRsp,
+  *(UINT64 *)CurrentRsp,
+  *(UINT64 

Re: [edk2] [RFC 1/1] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support

2017-11-14 Thread Andrew Fish

> On Nov 14, 2017, at 6:26 AM, Fan Jeff <vanjeff_...@hotmail.com> wrote:
> 
> Andrew,
>  
> We could use he EIP offset in Paul’s trace message and work with the 
> generated map file under debug directory for debug trace.

It would also be possible to use gdb. 

Given
0 0x7E510F7F @ 0x7E509000+0x7F7E (0x7F762CB0) in 
PartitionDxe.dll

If you load PartitionDxe.dll into gdb you can then do "l *0x7F7E" to dump the 
source. 

I'm mapping lldb behavior to gdb, but it should be close. 

Thanks,

Andrew Fish

>  
> Jeff
>  
> 发件人: Andrew Fish <mailto:af...@apple.com>
> 发送时间: 2017年11月14日 22:01
> 收件人: Paulo Alcantara <mailto:pca...@zytor.com>
> 抄送: edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org>; Laszlo Ersek 
> <mailto:ler...@redhat.com>; Eric Dong <mailto:eric.d...@intel.com>
> 主题: Re: [edk2] [RFC 1/1] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack 
> trace support
>  
> Paulo,
> 
> Cool feature. How does this code deal with VC++ that code does not store the 
> frame pointer and requires symbols to unwind. 
> 
> Also on the page fault you can print the fault address since it is in CR2. 
> 
> It should be possible to post process the text file and make a symbolicated 
> backtrace. 
> 
> Thanks,
> 
> Andrew Fish
> 
> > On Nov 14, 2017, at 4:47 AM, Paulo Alcantara <pca...@zytor.com> wrote:
> > 
> > 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.d...@intel.com>
> > Cc: Laszlo Ersek <ler...@redhat.com>
> > Signed-off-by: Paulo Alcantara <pca...@zytor.com>
> > ---
> > UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 
> > +++-
> > 1 file changed, 342 insertions(+), 2 deletions(-)
> > 
> > diff --git 
> > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c 
> > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
> > index 65f0cff680..7048247be3 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.
> > @@ -243,6 +248,325 @@ DumpCpuContext (
> > }
> > 
> > /**
> > +  Dump stack contents.
> > +
> > +  @param[in]  ImageBaseBase 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  UINTNImageBase,
> > +  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.
> > +
> > +  

Re: [edk2] [RFC 1/1] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support

2017-11-14 Thread Andrew Fish
Paulo,

Cool feature. How does this code deal with VC++ that code does not store the 
frame pointer and requires symbols to unwind. 

Also on the page fault you can print the fault address since it is in CR2. 

It should be possible to post process the text file and make a symbolicated 
backtrace. 

Thanks,

Andrew Fish

> On Nov 14, 2017, at 4:47 AM, Paulo Alcantara  wrote:
> 
> 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 
> Cc: Laszlo Ersek 
> Signed-off-by: Paulo Alcantara 
> ---
> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 
> +++-
> 1 file changed, 342 insertions(+), 2 deletions(-)
> 
> diff --git 
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c 
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
> index 65f0cff680..7048247be3 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.
> @@ -243,6 +248,325 @@ DumpCpuContext (
> }
> 
> /**
> +  Dump stack contents.
> +
> +  @param[in]  ImageBaseBase 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  UINTNImageBase,
> +  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]  UnwondStacksCount  Count of unwond stack frames.
> +**/
> +STATIC
> +VOID
> +DumpStackContents (
> +  IN UINT64  CurrentRsp,
> +  IN INTNUnwondStacksCount
> +  )
> +{
> +  if (UnwondStacksCount == 0) {
> +return;
> +  }
> +
> +  //
> +  // Dump out stack contents
> +  //
> +  InternalPrintMessage ("\nStack dump:\n");
> +  while (UnwondStacksCount-- > 0) {
> +InternalPrintMessage (
> +  "0x%016lx: %016lx %016lx\n",
> +  CurrentRsp,
> +  *(UINT64 *)CurrentRsp,
> +  *(UINT64 *)((UINTN)CurrentRsp + 8)
> +  );
> +
> +//
> +// As per Microsoft x64 ABI, the stack pointer must be aligned on a 16 
> byte
> +// boundary.
> +//
> +CurrentRsp = CurrentRsp + 16;
> +  }
> +}
> +
> +/**
> +  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;
> +
> +  //
> +  // 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 image module names. ");
> +return;
> +  }
> +
> +  //
> +  // Get initial PE/COFF image's entry point
> +  //
> +  Status = PeCoffLoaderGetEntryPoint ((VOID *)ImageBase, );
> +  if (EFI_ERROR (Status)) {
> +EntryPoint = NULL;
> +  }
> +
> +  //
> 

[edk2] [RFC 1/1] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support

2017-11-14 Thread Paulo Alcantara
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 
Cc: Laszlo Ersek 
Signed-off-by: Paulo Alcantara 
---
 UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 
+++-
 1 file changed, 342 insertions(+), 2 deletions(-)

diff --git 
a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c 
b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
index 65f0cff680..7048247be3 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.
@@ -243,6 +248,325 @@ DumpCpuContext (
 }
 
 /**
+  Dump stack contents.
+
+  @param[in]  ImageBaseBase 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  UINTNImageBase,
+  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]  UnwondStacksCount  Count of unwond stack frames.
+**/
+STATIC
+VOID
+DumpStackContents (
+  IN UINT64  CurrentRsp,
+  IN INTNUnwondStacksCount
+  )
+{
+  if (UnwondStacksCount == 0) {
+return;
+  }
+
+  //
+  // Dump out stack contents
+  //
+  InternalPrintMessage ("\nStack dump:\n");
+  while (UnwondStacksCount-- > 0) {
+InternalPrintMessage (
+  "0x%016lx: %016lx %016lx\n",
+  CurrentRsp,
+  *(UINT64 *)CurrentRsp,
+  *(UINT64 *)((UINTN)CurrentRsp + 8)
+  );
+
+//
+// As per Microsoft x64 ABI, the stack pointer must be aligned on a 16 byte
+// boundary.
+//
+CurrentRsp = CurrentRsp + 16;
+  }
+}
+
+/**
+  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;
+
+  //
+  // 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 image module names. ");
+return;
+  }
+
+  //
+  // Get initial PE/COFF image's entry point
+  //
+  Status = PeCoffLoaderGetEntryPoint ((VOID *)ImageBase, );
+  if (EFI_ERROR (Status)) {
+EntryPoint = NULL;
+  }
+
+  //
+  // Get file name and absolute path of initial PDB file
+  //
+  GetPdbFileName (ImageBase, , );
+
+  //
+  // 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);
+
+//
+// Check if RIP is within another PE/COFF image base address
+//
+if (Rip < ImageBase) {