From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.24; helo=mga09.intel.com; envelope-from=jiewen.yao@intel.com; receiver=edk2-devel@lists.01.org Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) (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 14038202E5E62 for ; Wed, 15 Nov 2017 17:52:59 -0800 (PST) Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 15 Nov 2017 17:57:08 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.44,402,1505804400"; d="scan'208";a="176741660" Received: from fmsmsx103.amr.corp.intel.com ([10.18.124.201]) by fmsmga006.fm.intel.com with ESMTP; 15 Nov 2017 17:57:08 -0800 Received: from fmsmsx116.amr.corp.intel.com (10.18.116.20) by FMSMSX103.amr.corp.intel.com (10.18.124.201) with Microsoft SMTP Server (TLS) id 14.3.319.2; Wed, 15 Nov 2017 17:57:08 -0800 Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by fmsmsx116.amr.corp.intel.com (10.18.116.20) with Microsoft SMTP Server (TLS) id 14.3.319.2; Wed, 15 Nov 2017 17:57:07 -0800 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.175]) by SHSMSX151.ccr.corp.intel.com ([169.254.3.218]) with mapi id 14.03.0319.002; Thu, 16 Nov 2017 09:57:07 +0800 From: "Yao, Jiewen" To: Paulo Alcantara , "edk2-devel@lists.01.org" CC: Laszlo Ersek , "Dong, Eric" Thread-Topic: [edk2] [RFC v2 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support Thread-Index: AQHTXnkhjviIJpWzXUmXsIl6yh6ASaMWO1uQ Date: Thu, 16 Nov 2017 01:57:06 +0000 Message-ID: <74D8A39837DF1E4DA445A8C0B3885C503AA1E9D1@shsmsx102.ccr.corp.intel.com> References: <11840074660da43fd43fac88cff851f1ccc31143.1510778784.git.pcacjr@zytor.com> In-Reply-To: <11840074660da43fd43fac88cff851f1ccc31143.1510778784.git.pcacjr@zytor.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiOTNiMjUwNWYtYjFjYi00NWU3LTk5ZjMtODQ2YmMyMDg4NzE3IiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX0lDIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjIuNS4xOCIsIlRydXN0ZWRMYWJlbEhhc2giOiJRdUcwczFkXC9rS3A2dzgrSDBOWWhlQXh6ajdtTE1zTXJ1WVhMc0daT2d5eXk1UEF0bVNOanpwS3ZSMzNPbVV0YiJ9 x-ctpclassification: CTP_IC dlp-product: dlpe-windows dlp-version: 11.0.0.116 dlp-reaction: no-action x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [RFC v2 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 16 Nov 2017 01:53:00 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi Paulo Thanks to bring this cool feature. I have same feeling as Jeff Fan. It is great! I have some questions, hope you can clarify. 1) Would you please let us know which tool change is validated? Such as MSV= C, or GCC? 2) Would you please let us know which phase is validated? Such as PEI PreMe= mory, PEI PostMemory, DXE, SMM? 3) Would you please let us know if there is any special condition validated= ? Such as code is in an interrupt handler, SMM initialization code, thunk c= ode during mode switch, etc. I ask this because I have seen lots of discussion on sanity check, to avoid= double exception. 4) We supported some security feature to create a hole in normal memory map= , such as PageGuard, StackGuard, SMM communication protection, etc. Accessing those memory directly will cause #PF immediately. Would you please let us know how we detect that case, to avoid RIP or RSP f= ail to the non-present page? 5) May I know why we check RIP < ImageBase? Is that legal or illegal if RIP= > ImageBase+ImageSize, but RIP in another PE/COFF image? > + // > + // Check if RIP is within another PE/COFF image base address > + // > + if (Rip < ImageBase) { > + // > + // Search for the respective PE/COFF image based on RIP > + // Thank you Yao Jiewen > -----Original Message----- > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Pa= ulo > Alcantara > Sent: Thursday, November 16, 2017 9:18 AM > To: edk2-devel@lists.01.org > Cc: Laszlo Ersek ; Dong, Eric > Subject: [edk2] [RFC v2 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add s= tack > trace support >=20 > This patch adds stack trace support during a X64 CPU exception. >=20 > It will dump out back trace, stack contents as well as image module > names that were part of the call stack. >=20 > Contributed-under: TianoCore Contribution Agreement 1.1 > Cc: Eric Dong > Cc: Laszlo Ersek > Signed-off-by: Paulo Alcantara > --- > UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 3= 69 > +++++++++++++++++++- > 1 file changed, 367 insertions(+), 2 deletions(-) >=20 > diff --git > a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c > b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c > index 65f0cff680..11cd7c9e1c 100644 > --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.= c > +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.= c > @@ -14,6 +14,11 @@ >=20 > #include "CpuExceptionCommon.h" >=20 > +// > +// Unknown PDB file name > +// > +GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 > *mUnknownPdbFileName =3D "????"; > + > /** > Return address map of exception handler template so that C code can > generate > exception tables. > @@ -242,6 +247,350 @@ DumpCpuContext ( > ); > } >=20 > +/** > + 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 =3D PeCoffLoaderGetPdbPointer ((VOID *)ImageBase); > + if (PdbPointer =3D=3D NULL) { > + // > + // No PDB file name found. Set it to an unknown file name. > + // > + *PdbFileName =3D (CHAR8 *)mUnknownPdbFileName; > + if (PdbAbsoluteFilePath !=3D NULL) { > + *PdbAbsoluteFilePath =3D NULL; > + } > + } else { > + // > + // Get file name portion out of PDB file in PE/COFF image > + // > + Str =3D (CHAR8 *)((UINTN)PdbPointer + > + AsciiStrLen ((CHAR8 *)PdbPointer) - sizeof *Str); > + for (; *Str !=3D '/' && *Str !=3D '\\'; Str--) { > + ; > + } > + > + // > + // Set PDB file name (also skip trailing path separator: '/' or '\\'= ) > + // > + *PdbFileName =3D Str + 1; > + > + if (PdbAbsoluteFilePath !=3D NULL) { > + // > + // Set absolute file path of PDB file > + // > + *PdbAbsoluteFilePath =3D 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 > + ) > +{ > + // > + // Check for proper stack pointer alignment > + // > + if (((UINTN)CurrentRsp & (CPU_STACK_ALIGNMENT - 1)) !=3D 0) { > + InternalPrintMessage ("!!!! Unaligned stack pointer. !!!!\n"); > + 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) > + ); > + > + // > + // Point to next stack > + // > + CurrentRsp +=3D 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; > + > + // > + // Set current RIP address > + // > + Rip =3D SystemContext.SystemContextX64->Rip; > + > + // > + // Set current frame pointer address > + // > + Rbp =3D SystemContext.SystemContextX64->Rbp; > + > + // > + // Check for proper frame pointer alignment > + // > + if (((UINTN)Rbp & (CPU_STACK_ALIGNMENT - 1)) !=3D 0) { > + InternalPrintMessage ("!!!! Unaligned frame pointer. !!!!\n"); > + return; > + } > + > + // > + // Get initial PE/COFF image base address from current RIP > + // > + ImageBase =3D PeCoffSearchImageBase (Rip); > + if (ImageBase =3D=3D 0) { > + InternalPrintMessage ("!!!! Could not find image module names. !!!!"= ); > + return; > + } > + > + // > + // Get initial PE/COFF image's entry point > + // > + Status =3D PeCoffLoaderGetEntryPoint ((VOID *)ImageBase, &EntryPoint); > + if (EFI_ERROR (Status)) { > + EntryPoint =3D 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 !=3D NULL) { > + InternalPrintMessage ( > + "\n%a (ImageBase=3D0x%016lx, EntryPoint=3D0x%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 =3D *(UINT64 *)((UINTN)Rbp + 8); > + > + // > + // If RIP is zero, then stop unwinding the stack > + // > + if (Rip =3D=3D 0) { > + break; > + } > + > + // > + // 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 =3D PeCoffSearchImageBase (Rip); > + if (ImageBase =3D=3D 0) { > + // > + // Stop stack trace > + // > + break; > + } > + > + // > + // Get PE/COFF image's entry point > + // > + Status =3D PeCoffLoaderGetEntryPoint ((VOID *)ImageBase, &EntryPoi= nt); > + if (EFI_ERROR (Status)) { > + EntryPoint =3D NULL; > + } > + > + // > + // Get file name and absolute path of PDB file > + // > + GetPdbFileName (ImageBase, &PdbAbsoluteFilePath, &PdbFileName); > + > + // > + // Print out image module name (if any) > + // > + if (PdbAbsoluteFilePath !=3D NULL) { > + InternalPrintMessage ( > + "%a (ImageBase=3D0x%016lx, EntryPoint=3D0x%016lx):\n", > + PdbFileName, > + ImageBase, > + (UINTN)EntryPoint > + ); > + InternalPrintMessage ("%a\n", PdbAbsoluteFilePath); > + } > + } > + > + // > + // Unwind the stack > + // > + Rbp =3D *(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; > + > + // > + // Set current RIP address > + // > + Rip =3D SystemContext.SystemContextX64->Rip; > + > + // > + // Set current frame pointer address > + // > + Rbp =3D SystemContext.SystemContextX64->Rbp; > + > + // > + // Get initial PE/COFF image base address from current RIP > + // > + ImageBase =3D PeCoffSearchImageBase (Rip); > + if (ImageBase =3D=3D 0) { > + InternalPrintMessage ("!!!! Could not find backtrace information. !!= !!"); > + return; > + } > + > + // > + // Get PDB file name from initial PE/COFF image > + // > + GetPdbFileName (ImageBase, NULL, &PdbFileName); > + > + // > + // Initialize count of unwond stacks > + // > + *UnwondStacksCount =3D 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", > + *UnwondStacksCount - 1, > + Rip, > + ImageBase, > + Rip - ImageBase - 1, > + Rbp, > + PdbFileName > + ); > + > + // > + // Set RIP with return address from current stack frame > + // > + Rip =3D *(UINT64 *)((UINTN)Rbp + 8); > + > + // > + // If RIP is zero, then stop unwinding the stack > + // > + if (Rip =3D=3D 0) { > + break; > + } > + > + // > + // 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 =3D PeCoffSearchImageBase (Rip); > + if (ImageBase =3D=3D 0) { > + // > + // Stop stack trace > + // > + break; > + } > + > + // > + // Get PDB file name > + // > + GetPdbFileName (ImageBase, NULL, &PdbFileName); > + } > + > + // > + // Unwind the stack > + // > + Rbp =3D *(UINT64 *)(UINTN)Rbp; > + > + // > + // Increment count of unwond stacks > + // > + (*UnwondStacksCount)++; > + } > +} > + > /** > Display CPU information. >=20 > @@ -254,9 +603,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.14.3 >=20 > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel