From: Paulo Alcantara <pcacjr@zytor.com>
To: Andrew Fish <afish@apple.com>
Cc: edk2-devel@lists.01.org, Laszlo Ersek <lersek@redhat.com>,
Eric Dong <eric.dong@intel.com>
Subject: Re: [RFC 1/1] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support
Date: Tue, 14 Nov 2017 13:30:10 -0200 [thread overview]
Message-ID: <60b6223a-f88a-5e56-e49a-31f2b1d94278@zytor.com> (raw)
In-Reply-To: <EDC25FBA-7050-48B0-9BDB-D7A27F2F1E5A@apple.com>
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 <pcacjr@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.dong@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Signed-off-by: Paulo Alcantara <pcacjr@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] 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] UnwondStacksCount Count of unwond stack frames.
>> +**/
>> +STATIC
>> +VOID
>> +DumpStackContents (
>> + IN UINT64 CurrentRsp,
>> + IN INTN UnwondStacksCount
>> + )
>> +{
>> + 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, &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);
>> +
>> + //
>> + // Check if RIP is within another PE/COFF image base address
>> + //
>> + if (Rip < ImageBase) {
>> + //
>> + // Search for the respective PE/COFF image based on RIP
>> + //
>> + ImageBase = PeCoffSearchImageBase (Rip);
>> + if (ImageBase == 0) {
>> + //
>> + // Stop stack trace
>> + //
>> + break;
>> + }
>> +
>> + //
>> + // 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);
>> + }
>> + }
>> +
>> + //
>> + // Unwind the stack
>> + //
>> + Rbp = *(UINT64 *)(UINTN)Rbp;
>> + }
>> +}
>> +
>> +/**
>> + Dump stack trace.
>> +
>> + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
>> + @param[out] UnwondStacksCount Count of unwond stack frames.
>> +**/
>> +STATIC
>> +VOID
>> +DumpStackTrace (
>> + IN EFI_SYSTEM_CONTEXT SystemContext,
>> + OUT INTN *UnwondStacksCount
>> + )
>> +{
>> + UINT64 Rip;
>> + UINT64 Rbp;
>> + UINTN ImageBase;
>> + CHAR8 *PdbFileName;
>> +
>> + //
>> + // Initialize count of unwond stacks
>> + //
>> + *UnwondStacksCount = 0;
>> +
>> + //
>> + // 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);
>> +
>> + //
>> + // Print out back trace
>> + //
>> + InternalPrintMessage ("\nBack 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",
>> + *UnwondStacksCount,
>> + Rip,
>> + ImageBase,
>> + Rip - ImageBase - 1,
>> + Rbp,
>> + PdbFileName
>> + );
>> +
>> + //
>> + // 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) {
>> + //
>> + // 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 unwond stacks
>> + //
>> + (*UnwondStacksCount)++;
>> + }
>> +}
>> +
>> +/**
>> Display CPU information.
>>
>> @param ExceptionType Exception type.
>> @@ -254,9 +578,25 @@ DumpImageAndCpuContent (
>> IN EFI_SYSTEM_CONTEXT SystemContext
>> )
>> {
>> + INTN UnwondStacksCount;
>> +
>> + //
>> + // Dump CPU context
>> + //
>> DumpCpuContext (ExceptionType, SystemContext);
>> +
>> + //
>> + // Dump stack trace
>> + //
>> + DumpStackTrace (SystemContext, &UnwondStacksCount);
>> +
>> + //
>> + // 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, UnwondStacksCount);
>> }
>> --
>> 2.11.0
>>
>> _______________________________________________
>> edk2-devel mailing list
>> edk2-devel@lists.01.org
>> https://lists.01.org/mailman/listinfo/edk2-devel
>
next prev parent reply other threads:[~2017-11-14 15:28 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 [this message]
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 ` [RFC v5 3/8] UefiCpuPkg/CpuExceptionHandlerLib/Ia32: Add stack trace support Paulo Alcantara
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=60b6223a-f88a-5e56-e49a-31f2b1d94278@zytor.com \
--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