From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=34.238.86.106; helo=mail.paulo.ac; envelope-from=paulo@paulo.ac; receiver=edk2-devel@lists.01.org Received: from mail.paulo.ac (mail.paulo.ac [34.238.86.106]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id D33F1222DDBE3 for ; Sun, 14 Jan 2018 16:18:42 -0800 (PST) Received: from localhost (localhost [127.0.0.1]) by mail.paulo.ac (Postfix) with ESMTP id DAA06C08891; Mon, 15 Jan 2018 00:23:55 +0000 (UTC) X-Virus-Scanned: amavisd-new at paulo.ac X-Spam-Flag: NO X-Spam-Score: -1.099 X-Spam-Level: X-Spam-Status: No, score=-1.099 tagged_above=-999 required=6.31 tests=[ALL_TRUSTED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, URIBL_BLOCKED=0.001] autolearn=ham autolearn_force=no Authentication-Results: mail.paulo.ac (amavisd-new); dkim=pass (1024-bit key) header.d=paulo.ac Received: from mail.paulo.ac ([127.0.0.1]) by localhost (mail.paulo.ac [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ieG1rWPY3v13; Mon, 15 Jan 2018 00:23:53 +0000 (UTC) Received: from thor.domain.name (177.204.15.215.dynamic.adsl.gvt.net.br [177.204.15.215]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.paulo.ac (Postfix) with ESMTPSA id 784FBC78F41; Mon, 15 Jan 2018 00:23:51 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.paulo.ac 784FBC78F41 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=paulo.ac; s=default; t=1515975833; bh=f8i6sucGEbRNKBrN2JadLYIswJyF3Ck4LqzRlG/IgUU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:In-Reply-To: References:From; b=GWqocJR6JDct3k2kEca1qlhYaLaM1P+HhdZ2MUlpz/4/8+nt84a5bvKimOezVHAba 4X8Bhb6dhLIdACjhvxkb6yYdK6kVsHxH3zq7p39Xf9P3ZT8RjE2Wf4csU/uJKtLqLo CHHAC+URVY8Rw+X/HLM0tOqsfzfAfiM+fiNDN1tg= From: Paulo Alcantara To: edk2-devel@lists.01.org Cc: Paulo Alcantara , Eric Dong , Laszlo Ersek Date: Sun, 14 Jan 2018 22:23:29 -0200 Message-Id: <076e74849f88219927d8c53dde61ff66477df094.1515974582.git.paulo@paulo.ac> X-Mailer: git-send-email 2.14.3 In-Reply-To: References: In-Reply-To: References: Subject: [RFC v5 1/8] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Jan 2018 00:18:44 -0000 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 | 401 +++++++++++++++++++- 1 file changed, 393 insertions(+), 8 deletions(-) diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c index 56180f4c17..4db9f6465e 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. @@ -399,20 +404,281 @@ DumpCpuContext ( } /** - Display CPU information. + Get absolute path and file name of PDB file in PE/COFF image. - @param ExceptionType Exception type. - @param SystemContext Pointer to EFI_SYSTEM_CONTEXT. + @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 -DumpImageAndCpuContent ( +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] 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; + UINT64 Rip; + UINTN ImageBase; + VOID *EntryPoint; + CHAR8 *PdbAbsoluteFilePath; + CHAR8 *PdbFileName; + UINT64 Rbp; + UINTN LastImageBase; + + // + // Set current RIP address + // + if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) && + ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0)) { + // + // The RIP in SystemContext could not be used + // if it is page fault with I/D set. + // + Rip = *(UINT64 *)(UINTN)SystemContext.SystemContextX64->Rsp; + } else { + 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] ExceptionType Exception type. + @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT. + @param[out] UnwoundStacksCount Count of unwound stack frames. +**/ +STATIC +VOID +DumpStacktrace ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN EFI_SYSTEM_CONTEXT SystemContext, + OUT INTN *UnwoundStacksCount + ) +{ + UINT64 Rip; + UINT64 Rbp; + UINTN ImageBase; + CHAR8 *PdbFileName; + // - // Dump module image base and module entry point by RIP + // Set current RIP address // if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) && ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0)) { @@ -420,8 +686,127 @@ DumpImageAndCpuContent ( // The RIP in SystemContext could not be used // if it is page fault with I/D set. // - DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp)); + Rip = *(UINT64 *)(UINTN)SystemContext.SystemContextX64->Rsp; } else { - DumpModuleImageInfo (SystemContext.SystemContextX64->Rip); + 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: + // + // # @ + (RBP) in [ | ????] + // + 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. + + @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.SystemContextX64->Rsp, UnwoundStacksCount); +} -- 2.14.3