UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 +++++++++++++++++++- 1 file changed, 342 insertions(+), 2 deletions(-)
Hi, This series adds stack trace support during a X64 CPU exception. Informations like back trace, stack contents and image module names (that were part of the call stack) will be dumped out. We already have such support in ARM/AArch64 (IIRC) exception handling (thanks to Ard), and then I thought we'd also deserve it in X64 and IA-32 platforms. What do you think guys? BTW, I've tested this only with OVMF (X64 only), using: - gcc-6.3.0, GCC5, NOOPT Any other tests would be really appreciable. Thanks! Paulo Repo: https://github.com/pcacjr/edk2.git Branch: stacktrace_x64 Cc: Rick Bramley <richard.bramley@hp.com> Cc: Andrew Fish <afish@apple.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> --- Paulo Alcantara (1): UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 +++++++++++++++++++- 1 file changed, 342 insertions(+), 2 deletions(-) -- 2.11.0 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi, On 14/11/2017 10:47, Paulo Alcantara wrote: > Hi, > > This series adds stack trace support during a X64 CPU exception. > > Informations like back trace, stack contents and image module names > (that were part of the call stack) will be dumped out. > > We already have such support in ARM/AArch64 (IIRC) exception handling > (thanks to Ard), and then I thought we'd also deserve it in X64 and > IA-32 platforms. > > What do you think guys? > > BTW, I've tested this only with OVMF (X64 only), using: > - gcc-6.3.0, GCC5, NOOPT > > Any other tests would be really appreciable. I've attached a file to show you how the trace would look like. Thanks! Paulo > > Thanks! > Paulo > > Repo: https://github.com/pcacjr/edk2.git > Branch: stacktrace_x64 > > Cc: Rick Bramley <richard.bramley@hp.com> > Cc: Andrew Fish <afish@apple.com> > Cc: Eric Dong <eric.dong@intel.com> > Cc: Laszlo Ersek <lersek@redhat.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> > --- > > Paulo Alcantara (1): > UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support > > UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 +++++++++++++++++++- > 1 file changed, 342 insertions(+), 2 deletions(-) > !!!! X64 Exception Type - 0E(#PF - Page-Fault) CPU Apic ID - 00000000 !!!! ExceptionData - 0000000000000002 I:0 R:0 U:0 W:1 P:0 PK:0 S:0 RIP - 000000007E510F7F, CS - 0000000000000038, RFLAGS - 0000000000010202 RAX - 0000000000000000, RCX - 000000007EA01318, RDX - 000000007F6EE018 RBX - 0000000000810248, RSP - 000000007F762C70, RBP - 000000007F762CB0 RSI - 0000000000000007, RDI - 000000007EA01418 R8 - 000000007E513A88, R9 - 000000007EA01798, R10 - 0000000000000036 R11 - 00000000000000D7, R12 - 0000000000000000, R13 - 0000000000000000 R14 - 0000000000000000, R15 - 0000000000000000 DS - 0000000000000030, ES - 0000000000000030, FS - 0000000000000030 GS - 0000000000000030, SS - 0000000000000030 CR0 - 0000000080010033, CR2 - 0000000000000000, CR3 - 000000007F701000 CR4 - 0000000000000668, CR8 - 0000000000000000 DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000 DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400 GDTR - 000000007F6EEA98 0000000000000047, LDTR - 0000000000000000 IDTR - 000000007EEF2018 0000000000000FFF, TR - 0000000000000000 FXSAVE_STATE - 000000007F7628D0 Back trace: 0 0x000000007E510F7F @ 0x000000007E509000+0x7F7E (0x000000007F762CB0) in PartitionDxe.dll 1 0x000000007E51135D @ 0x000000007E509000+0x835C (0x000000007F762CE0) in PartitionDxe.dll 2 0x000000007E50C116 @ 0x000000007E509000+0x3115 (0x000000007F762D20) in PartitionDxe.dll 3 0x000000007F776972 @ 0x000000007E509000+0x126D971 (0x000000007F762DB0) in PartitionDxe.dll 4 0x000000007F78EE08 @ 0x000000007E509000+0x1285E07 (0x000000007F762E30) in PartitionDxe.dll 5 0x000000007F791343 @ 0x000000007E509000+0x1288342 (0x000000007F762F60) in PartitionDxe.dll 6 0x000000007F791AC7 @ 0x000000007E509000+0x1288AC6 (0x000000007F762F90) in PartitionDxe.dll 7 0x000000007F767DDB @ 0x000000007E509000+0x125EDDA (0x000000007F762FC0) in PartitionDxe.dll 8 0x000000007F7DF75F @ 0x000000007E509000+0x12D675E (0x000000007B7DC840) in PartitionDxe.dll 9 0x000000007F7E5546 @ 0x000000007E509000+0x12DC545 (0x000000007B7DC8C0) in PartitionDxe.dll 10 0x000000007F7E4312 @ 0x000000007E509000+0x12DB311 (0x000000007B7DCA30) in PartitionDxe.dll 11 0x000000007F7F0DB9 @ 0x000000007E509000+0x12E7DB8 (0x000000007B7DCF80) in PartitionDxe.dll 12 0x00000000008286E9 @ 0x0000000000820140+0x85A8 (0x000000007B7DD4D0) in PeiCore.dll 13 0x000000000083092F @ 0x0000000000820140+0x107EE (0x0000000000817600) in PeiCore.dll 14 0x0000000000831574 @ 0x0000000000820140+0x11433 (0x00000000008176D0) in PeiCore.dll 15 0x0000000000828D9B @ 0x0000000000820140+0x8C5A (0x0000000000817C20) in PeiCore.dll 16 0x000000000083238A @ 0x0000000000820140+0x12249 (0x0000000000817C50) in PeiCore.dll 17 0x0000000000824312 @ 0x0000000000820140+0x41D1 (0x0000000000817C80) in PeiCore.dll 18 0x00000000FFFD4291 @ 0x0000000000820140+0xFF7B4150 (0x0000000000817CE0) in PeiCore.dll 19 0x00000000FFFCF578 @ 0x0000000000820140+0xFF7AF437 (0x0000000000817D10) in PeiCore.dll 20 0x00000000FFFD422C @ 0x0000000000820140+0xFF7B40EB (0x0000000000817FD0) in PeiCore.dll 21 0x00000000FFFD4489 @ 0x0000000000820140+0xFF7B4348 (0x00000000FFFCC000) in PeiCore.dll PartitionDxe.dll (ImageBase=0x000000007E509000, EntryPoint=0x000000007E50C01F): /home/pcacjr/src/edk2.git/Build/OvmfX64/NOOPT_GCC5/X64/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe/DEBUG/PartitionDxe.dll PeiCore.dll (ImageBase=0x0000000000820140, EntryPoint=0x00000000008242EC): /home/pcacjr/src/edk2.git/Build/OvmfX64/NOOPT_GCC5/X64/MdeModulePkg/Core/Pei/PeiMain/DEBUG/PeiCore.dll Stack dump: 0x000000007F762C70: 000000007E5137E0 0000000000000000 0x000000007F762C80: 000000007E513A88 0000000000000100 0x000000007F762C90: 000000007F762CB0 0000000000000000 0x000000007F762CA0: 000000007F762CE0 0000000000000000 0x000000007F762CB0: 000000007F762CE0 000000007E51135D 0x000000007F762CC0: 000000007EA01318 000000007F6EE018 0x000000007F762CD0: 000000077F776852 0000000000000000 0x000000007F762CE0: 000000007F762D20 000000007E50C116 0x000000007F762CF0: 000000007EA01318 000000007F6EE018 0x000000007F762D00: 0000000000000000 0000000000000000 0x000000007F762D10: 0000000000000000 0000000000000000 0x000000007F762D20: 000000007F762DB0 000000007F776972 0x000000007F762D30: 000000007EA01318 000000007F6EE018 0x000000007F762D40: 0000000000000000 0000000000000004 0x000000007F762D50: 000000007F79A1A8 000000007F79AF90 0x000000007F762D60: 000000007F762DB0 0000000000000000 0x000000007F762D70: 000000007F79A180 00000000000000C8 0x000000007F762D80: 0000000000000000 000000007EA01418 0x000000007F762D90: 000000007EA01318 0000000000000000 0x000000007F762DA0: 000000007F79A1A8 000000007F79AF90 0x000000007F762DB0: 000000007F762E30 000000007F78EE08 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Paul, I like this feature very much. Actually, I did some POC one year ago but I did finalize it. In my POC, I could use EBP to tack the stack frame on IAS32 arch. But for x64, I tried to use �Ckeepexceptiontable flag to explain stack frame from the debug section of image. I may workson MSFT toolchain, but it did now work well for GCC toolchain. I think Eric could help to verify MSFT for your patch. If it works well, that’s will be great! Say again, I like this feature!!!:-) Thanks! Jeff 发件人: Paulo Alcantara<mailto:pcacjr@zytor.com> 发送时间: 2017年11月14日 21:23 收件人: edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org> 抄送: Rick Bramley<mailto:richard.bramley@hp.com>; Laszlo Ersek<mailto:lersek@redhat.com>; Andrew Fish<mailto:afish@apple.com>; Eric Dong<mailto:eric.dong@intel.com> 主题: Re: [edk2] [RFC 0/1] Stack trace support in X64 exception handling Hi, On 14/11/2017 10:47, Paulo Alcantara wrote: > Hi, > > This series adds stack trace support during a X64 CPU exception. > > Informations like back trace, stack contents and image module names > (that were part of the call stack) will be dumped out. > > We already have such support in ARM/AArch64 (IIRC) exception handling > (thanks to Ard), and then I thought we'd also deserve it in X64 and > IA-32 platforms. > > What do you think guys? > > BTW, I've tested this only with OVMF (X64 only), using: > - gcc-6.3.0, GCC5, NOOPT > > Any other tests would be really appreciable. I've attached a file to show you how the trace would look like. Thanks! Paulo > > Thanks! > Paulo > > Repo: https://github.com/pcacjr/edk2.git > Branch: stacktrace_x64 > > Cc: Rick Bramley <richard.bramley@hp.com> > Cc: Andrew Fish <afish@apple.com> > Cc: Eric Dong <eric.dong@intel.com> > Cc: Laszlo Ersek <lersek@redhat.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> > --- > > Paulo Alcantara (1): > UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support > > UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 +++++++++++++++++++- > 1 file changed, 342 insertions(+), 2 deletions(-) > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Paul, Sorry, correct some import words in my last mail. “I did NOT finalize my POC”.:-) Jeff ________________________________ From: edk2-devel <edk2-devel-bounces@lists.01.org> on behalf of Fan Jeff <vanjeff_919@hotmail.com> Sent: Tuesday, November 14, 2017 10:03:20 PM To: Paulo Alcantara; edk2-devel@lists.01.org Cc: Rick Bramley; Laszlo Ersek; Andrew Fish; Eric Dong Subject: [edk2] 答复: [RFC 0/1] Stack trace support in X64 exception handling Paul, I like this feature very much. Actually, I did some POC one year ago but I did finalize it. In my POC, I could use EBP to tack the stack frame on IAS32 arch. But for x64, I tried to use �Ckeepexceptiontable flag to explain stack frame from the debug section of image. I may workson MSFT toolchain, but it did now work well for GCC toolchain. I think Eric could help to verify MSFT for your patch. If it works well, that’s will be great! Say again, I like this feature!!!:-) Thanks! Jeff 发件人: Paulo Alcantara<mailto:pcacjr@zytor.com> 发送时间: 2017年11月14日 21:23 收件人: edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org> 抄送: Rick Bramley<mailto:richard.bramley@hp.com>; Laszlo Ersek<mailto:lersek@redhat.com>; Andrew Fish<mailto:afish@apple.com>; Eric Dong<mailto:eric.dong@intel.com> 主题: Re: [edk2] [RFC 0/1] Stack trace support in X64 exception handling Hi, On 14/11/2017 10:47, Paulo Alcantara wrote: > Hi, > > This series adds stack trace support during a X64 CPU exception. > > Informations like back trace, stack contents and image module names > (that were part of the call stack) will be dumped out. > > We already have such support in ARM/AArch64 (IIRC) exception handling > (thanks to Ard), and then I thought we'd also deserve it in X64 and > IA-32 platforms. > > What do you think guys? > > BTW, I've tested this only with OVMF (X64 only), using: > - gcc-6.3.0, GCC5, NOOPT > > Any other tests would be really appreciable. I've attached a file to show you how the trace would look like. Thanks! Paulo > > Thanks! > Paulo > > Repo: https://github.com/pcacjr/edk2.git > Branch: stacktrace_x64 > > Cc: Rick Bramley <richard.bramley@hp.com> > Cc: Andrew Fish <afish@apple.com> > Cc: Eric Dong <eric.dong@intel.com> > Cc: Laszlo Ersek <lersek@redhat.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> > --- > > Paulo Alcantara (1): > UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support > > UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 +++++++++++++++++++- > 1 file changed, 342 insertions(+), 2 deletions(-) > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi Fan, On 14/11/2017 12:03, Fan Jeff wrote: > Paul, > > I like this feature very much. Actually, I did some POC one year ago but > I did finalize it. > > In my POC, I could use EBP to tack the stack frame on IAS32 arch. > > But for x64, I tried to use –keepexceptiontable flag to explain stack > frame from the debug section of image. > > I may workson MSFT toolchain, but it did now work well for GCC toolchain. > > I think Eric could help to verify MSFT for your patch. If it works well, > that’s will be great! > > Say again, I like this feature!!!:-) Cool! Your help would be really appreciable! If we get this working for X64 in both toolchains, that should be easy to port it to IA-32 as well. Thank you very much for willing to help on that. Paulo > > Thanks! > > Jeff > > *发件人: *Paulo Alcantara <mailto:pcacjr@zytor.com> > *发送时间: *2017年11月14日21:23 > *收件人: *edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> > *抄送: *Rick Bramley <mailto:richard.bramley@hp.com>; Laszlo Ersek > <mailto:lersek@redhat.com>; Andrew Fish <mailto:afish@apple.com>; Eric > Dong <mailto:eric.dong@intel.com> > *主题: *Re: [edk2] [RFC 0/1] Stack trace support in X64 exception handling > > Hi, > > On 14/11/2017 10:47, Paulo Alcantara wrote: >> Hi, >> >> This series adds stack trace support during a X64 CPU exception. >> >> Informations like back trace, stack contents and image module names >> (that were part of the call stack) will be dumped out. >> >> We already have such support in ARM/AArch64 (IIRC) exception handling >> (thanks to Ard), and then I thought we'd also deserve it in X64 and >> IA-32 platforms. >> >> What do you think guys? >> >> BTW, I've tested this only with OVMF (X64 only), using: >> - gcc-6.3.0, GCC5, NOOPT >> >> Any other tests would be really appreciable. > > I've attached a file to show you how the trace would look like. > > Thanks! > Paulo > >> >> Thanks! >> Paulo >> >> Repo: https://github.com/pcacjr/edk2.git >> Branch: stacktrace_x64 >> >> Cc: Rick Bramley <richard.bramley@hp.com> >> Cc: Andrew Fish <afish@apple.com> >> Cc: Eric Dong <eric.dong@intel.com> >> Cc: Laszlo Ersek <lersek@redhat.com> >> Contributed-under: TianoCore Contribution Agreement 1.1 >> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> >> --- >> >> Paulo Alcantara (1): >> UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support >> >> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 +++++++++++++++++++- >> 1 file changed, 342 insertions(+), 2 deletions(-) >> > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On 11/14/2017 09:37 AM, Paulo Alcantara wrote: > Hi Fan, > > On 14/11/2017 12:03, Fan Jeff wrote: >> Paul, >> >> I like this feature very much. Actually, I did some POC one year ago >> but I did finalize it. >> >> In my POC, I could use EBP to tack the stack frame on IAS32 arch. >> >> But for x64, I tried to use –keepexceptiontable flag to explain stack >> frame from the debug section of image. >> >> I may workson MSFT toolchain, but it did now work well for GCC toolchain. >> >> I think Eric could help to verify MSFT for your patch. If it works >> well, that’s will be great! >> >> Say again, I like this feature!!!:-) > > Cool! Your help would be really appreciable! If we get this working for > X64 in both toolchains, that should be easy to port it to IA-32 as well. > > Thank you very much for willing to help on that. > > Paulo Great feature! You do need some sort of sanity check on the RIP and RBP values, though, so if the stack gets corrupted or the RIP is nonsense from following a bad pointer, you don't start dereferencing garbage addresses and trigger an exception loop. For at least some versions of Microsoft's IA32 compiler, it's possible to compile using EBP as a stack frame base pointer (like gcc) by using the "/Oy-" switch. The proposed unwind code should work in that case. The X64 compiler doesn't support this switch, though. AFAIK the only way to unwind the stack with Microsoft's X64 compilers is to parse the unwind info in the .pdata and .xdata sections. Genfw.exe usually strips those sections, but the "--keepexceptiontable" flag will preserve them, as Jeff pointed out. I've looked hard for open source code to decode them, but haven't found any, even though the format is well documented. And I haven't gotten around to writing it myself. I'd love it if someone could contribute the code! Another possibility is to use the branch history MSRs available on some x86-family processors. Recent Intel processors can use them as a stack, as opposed to a circular list, so they can record a backtrace directly. (I'm not familiar with AMD processors' capabilities.) You can enable call stack recording like this: #define LBR_ON_FLAG 0x0000000000000001 #define IA32_DEBUGCTL 0x1D9 #define CALL_STACK_SET_FLAG 0x3C4 #define CALL_STACK_CLR_FLAG 0xFC7 #define MSR_LBR_SELECT 0x1C8 // // Enable branch recording // LbControl = AsmReadMsr64 ((UINT32)IA32_DEBUGCTL); LbControl |= LBR_ON_FLAG; AsmWriteMsr64 ((UINT32)IA32_DEBUGCTL, LbControl); // // Configure for call stack // LbSelect = AsmReadMsr64 ((UINT32)MSR_LBR_SELECT); LbSelect &= CALL_STACK_CLR_FLAG; LbSelect |= CALL_STACK_SET_FLAG; AsmWriteMsr64((UINT32)MSR_LBR_SELECT, LbSelect); The EIP/RIP values are logged in MSR_SANDY_BRIDGE_LASTBRANCH_n_FROM_IP and MSR_SANDY_BRIDGE_LASTBRANCH_n_TO_IP, and the current depth is tracked in MSR_LASTBRANCH_TOS. This works quite well. Gen10 (Sky Lake) processors support 32 LASTBRANCH_n MSR pairs, which is sufficient in almost all cases. Different processor generations have different branch recording capabilities, and different numbers of LASTBRANCH_n MSRs; see Intel's manuals for details. Thanks, Brian > >> >> Thanks! >> >> Jeff >> >> *发件人: *Paulo Alcantara <mailto:pcacjr@zytor.com> >> *发送时间: *2017年11月14日21:23 >> *收件人: *edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >> *抄送: *Rick Bramley <mailto:richard.bramley@hp.com>; Laszlo Ersek >> <mailto:lersek@redhat.com>; Andrew Fish <mailto:afish@apple.com>; Eric >> Dong <mailto:eric.dong@intel.com> >> *主题: *Re: [edk2] [RFC 0/1] Stack trace support in X64 exception >> handling >> >> Hi, >> >> On 14/11/2017 10:47, Paulo Alcantara wrote: >>> Hi, >>> >>> This series adds stack trace support during a X64 CPU exception. >>> >>> Informations like back trace, stack contents and image module names >>> (that were part of the call stack) will be dumped out. >>> >>> We already have such support in ARM/AArch64 (IIRC) exception handling >>> (thanks to Ard), and then I thought we'd also deserve it in X64 and >>> IA-32 platforms. >>> >>> What do you think guys? >>> >>> BTW, I've tested this only with OVMF (X64 only), using: >>> - gcc-6.3.0, GCC5, NOOPT >>> >>> Any other tests would be really appreciable. >> >> I've attached a file to show you how the trace would look like. >> >> Thanks! >> Paulo >> >>> >>> Thanks! >>> Paulo >>> >>> Repo: https://github.com/pcacjr/edk2.git >>> Branch: stacktrace_x64 >>> >>> Cc: Rick Bramley <richard.bramley@hp.com> >>> Cc: Andrew Fish <afish@apple.com> >>> Cc: Eric Dong <eric.dong@intel.com> >>> Cc: Laszlo Ersek <lersek@redhat.com> >>> Contributed-under: TianoCore Contribution Agreement 1.1 >>> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> >>> --- >>> >>> Paulo Alcantara (1): >>> UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support >>> >>> >>> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c >>> | 344 +++++++++++++++++++- >>> 1 file changed, 342 insertions(+), 2 deletions(-) >>> >> > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel -- Brian -------------------------------------------------------------------- "Most people would like to be delivered from temptation but would like it to keep in touch." -- Robert Orben _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
> On Nov 14, 2017, at 8:33 AM, Brian J. Johnson <brian.johnson@hpe.com> wrote: > > On 11/14/2017 09:37 AM, Paulo Alcantara wrote: >> Hi Fan, >> On 14/11/2017 12:03, Fan Jeff wrote: >>> Paul, >>> >>> I like this feature very much. Actually, I did some POC one year ago but I did finalize it. >>> >>> In my POC, I could use EBP to tack the stack frame on IAS32 arch. >>> >>> But for x64, I tried to use –keepexceptiontable flag to explain stack frame from the debug section of image. >>> >>> I may workson MSFT toolchain, but it did now work well for GCC toolchain. >>> >>> I think Eric could help to verify MSFT for your patch. If it works well, that’s will be great! >>> >>> Say again, I like this feature!!!:-) >> Cool! Your help would be really appreciable! If we get this working for X64 in both toolchains, that should be easy to port it to IA-32 as well. >> Thank you very much for willing to help on that. >> Paulo > > Great feature! You do need some sort of sanity check on the RIP and RBP values, though, so if the stack gets corrupted or the RIP is nonsense from following a bad pointer, you don't start dereferencing garbage addresses and trigger an exception loop. > Brian, This was a long time ago and my memory might be fuzzy.... I think we talked to some debugger folks about unwinding the stack and they mentioned it was common for the C runtime to have a return address or frame pointer have a zero value so the unwind logic knows when to stop. This is in addition to generic sanity checking. We got an extra push $0 added to the stack switch to help with stack unwind. https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/X64/SwitchStack.S <https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/X64/SwitchStack.S> If might be a good idea to have a PCD for the max number of stack frames to display as a fallback for the error check. For X64 you may also have to add a check for a non-cononical address as that will GP fault. Thanks, Andrew Fish > For at least some versions of Microsoft's IA32 compiler, it's possible to compile using EBP as a stack frame base pointer (like gcc) by using the "/Oy-" switch. The proposed unwind code should work in that case. The X64 compiler doesn't support this switch, though. > > AFAIK the only way to unwind the stack with Microsoft's X64 compilers is to parse the unwind info in the .pdata and .xdata sections. Genfw.exe usually strips those sections, but the "--keepexceptiontable" flag will preserve them, as Jeff pointed out. I've looked hard for open source code to decode them, but haven't found any, even though the format is well documented. And I haven't gotten around to writing it myself. I'd love it if someone could contribute the code! > > Another possibility is to use the branch history MSRs available on some x86-family processors. Recent Intel processors can use them as a stack, as opposed to a circular list, so they can record a backtrace directly. (I'm not familiar with AMD processors' capabilities.) You can enable call stack recording like this: > > #define LBR_ON_FLAG 0x0000000000000001 > #define IA32_DEBUGCTL 0x1D9 > #define CALL_STACK_SET_FLAG 0x3C4 > #define CALL_STACK_CLR_FLAG 0xFC7 > #define MSR_LBR_SELECT 0x1C8 > > // > // Enable branch recording > // > LbControl = AsmReadMsr64 ((UINT32)IA32_DEBUGCTL); > LbControl |= LBR_ON_FLAG; > AsmWriteMsr64 ((UINT32)IA32_DEBUGCTL, LbControl); > > // > // Configure for call stack > // > LbSelect = AsmReadMsr64 ((UINT32)MSR_LBR_SELECT); > LbSelect &= CALL_STACK_CLR_FLAG; > LbSelect |= CALL_STACK_SET_FLAG; > AsmWriteMsr64((UINT32)MSR_LBR_SELECT, LbSelect); > > The EIP/RIP values are logged in MSR_SANDY_BRIDGE_LASTBRANCH_n_FROM_IP and MSR_SANDY_BRIDGE_LASTBRANCH_n_TO_IP, and the current depth is tracked in MSR_LASTBRANCH_TOS. This works quite well. Gen10 (Sky Lake) processors support 32 LASTBRANCH_n MSR pairs, which is sufficient in almost all cases. > > Different processor generations have different branch recording capabilities, and different numbers of LASTBRANCH_n MSRs; see Intel's manuals for details. > > Thanks, > Brian > >>> >>> Thanks! >>> >>> Jeff >>> >>> *发件人: *Paulo Alcantara <mailto:pcacjr@zytor.com> >>> *发送时间: *2017年11月14日21:23 >>> *收件人: *edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >>> *抄送: *Rick Bramley <mailto:richard.bramley@hp.com>; Laszlo Ersek <mailto:lersek@redhat.com>; Andrew Fish <mailto:afish@apple.com>; Eric Dong <mailto:eric.dong@intel.com> >>> *主题: *Re: [edk2] [RFC 0/1] Stack trace support in X64 exception handling >>> >>> Hi, >>> >>> On 14/11/2017 10:47, Paulo Alcantara wrote: >>>> Hi, >>>> >>>> This series adds stack trace support during a X64 CPU exception. >>>> >>>> Informations like back trace, stack contents and image module names >>>> (that were part of the call stack) will be dumped out. >>>> >>>> We already have such support in ARM/AArch64 (IIRC) exception handling >>>> (thanks to Ard), and then I thought we'd also deserve it in X64 and >>>> IA-32 platforms. >>>> >>>> What do you think guys? >>>> >>>> BTW, I've tested this only with OVMF (X64 only), using: >>>> - gcc-6.3.0, GCC5, NOOPT >>>> >>>> Any other tests would be really appreciable. >>> >>> I've attached a file to show you how the trace would look like. >>> >>> Thanks! >>> Paulo >>> >>>> >>>> Thanks! >>>> Paulo >>>> >>>> Repo: https://github.com/pcacjr/edk2.git >>>> Branch: stacktrace_x64 >>>> >>>> Cc: Rick Bramley <richard.bramley@hp.com> >>>> Cc: Andrew Fish <afish@apple.com> >>>> Cc: Eric Dong <eric.dong@intel.com> >>>> Cc: Laszlo Ersek <lersek@redhat.com> >>>> Contributed-under: TianoCore Contribution Agreement 1.1 >>>> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> >>>> --- >>>> >>>> Paulo Alcantara (1): >>>> UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support >>>> >>>> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 +++++++++++++++++++- >>>> 1 file changed, 342 insertions(+), 2 deletions(-) >>>> >>> >> _______________________________________________ >> edk2-devel mailing list >> edk2-devel@lists.01.org >> https://lists.01.org/mailman/listinfo/edk2-devel > > > -- > > Brian > > -------------------------------------------------------------------- > > "Most people would like to be delivered from temptation but would > like it to keep in touch." > -- Robert Orben > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> > https://lists.01.org/mailman/listinfo/edk2-devel <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
On 11/14/2017 11:23 AM, Andrew Fish wrote: > >> On Nov 14, 2017, at 8:33 AM, Brian J. Johnson <brian.johnson@hpe.com >> <mailto:brian.johnson@hpe.com>> wrote: >> >> On 11/14/2017 09:37 AM, Paulo Alcantara wrote: >>> Hi Fan, >>> On 14/11/2017 12:03, Fan Jeff wrote: >>>> Paul, >>>> >>>> I like this feature very much. Actually, I did some POC one year ago >>>> but I did finalize it. >>>> >>>> In my POC, I could use EBP to tack the stack frame on IAS32 arch. >>>> >>>> But for x64, I tried to use –keepexceptiontable flag to explain >>>> stack frame from the debug section of image. >>>> >>>> I may workson MSFT toolchain, but it did now work well for GCC >>>> toolchain. >>>> >>>> I think Eric could help to verify MSFT for your patch. If it works >>>> well, that’s will be great! >>>> >>>> Say again, I like this feature!!!:-) >>> Cool! Your help would be really appreciable! If we get this working >>> for X64 in both toolchains, that should be easy to port it to IA-32 >>> as well. >>> Thank you very much for willing to help on that. >>> Paulo >> >> Great feature! You do need some sort of sanity check on the RIP and >> RBP values, though, so if the stack gets corrupted or the RIP is >> nonsense from following a bad pointer, you don't start dereferencing >> garbage addresses and trigger an exception loop. >> > > Brian, > > This was a long time ago and my memory might be fuzzy.... I think we > talked to some debugger folks about unwinding the stack and they > mentioned it was common for the C runtime to have a return address or > frame pointer have a zero value so the unwind logic knows when to stop. > This is in addition to generic sanity checking. > > We got an extra push $0 added to the stack switch to help with stack > unwind. > https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/X64/SwitchStack.S > > If might be a good idea to have a PCD for the max number of stack frames > to display as a fallback for the error check. For X64 you may also have > to add a check for a non-cononical address as that will GP fault. > Good idea. Regarding sanity checks: I've had good luck validating code locations (EIP values) by using a modified PeCoffExtraActionLib to track the top and bottom of the range where images have been loaded. (I've actually used two ranges: one for code executed from firmware space, and one for code executed from RAM.) I'm not sure offhand if there's a platform-independent way to validate stack pointer values. For most PC-like systems, just ensuring that it's larger than 1 or 2M (to avoid NULL pointers and the legacy spaces) and less than about 3G (or the low memory size, if that's known) may be enough to avoid an exception loop. Brian > Thanks, > > Andrew Fish > > >> For at least some versions of Microsoft's IA32 compiler, it's possible >> to compile using EBP as a stack frame base pointer (like gcc) by using >> the "/Oy-" switch. The proposed unwind code should work in that case. >> The X64 compiler doesn't support this switch, though. >> >> AFAIK the only way to unwind the stack with Microsoft's X64 compilers >> is to parse the unwind info in the .pdata and .xdata sections. >> Genfw.exe usually strips those sections, but the >> "--keepexceptiontable" flag will preserve them, as Jeff pointed out. >> I've looked hard for open source code to decode them, but haven't >> found any, even though the format is well documented. And I haven't >> gotten around to writing it myself. I'd love it if someone could >> contribute the code! >> >> Another possibility is to use the branch history MSRs available on >> some x86-family processors. Recent Intel processors can use them as a >> stack, as opposed to a circular list, so they can record a backtrace >> directly. (I'm not familiar with AMD processors' capabilities.) You >> can enable call stack recording like this: >> >> #define LBR_ON_FLAG 0x0000000000000001 >> #define IA32_DEBUGCTL 0x1D9 >> #define CALL_STACK_SET_FLAG 0x3C4 >> #define CALL_STACK_CLR_FLAG 0xFC7 >> #define MSR_LBR_SELECT 0x1C8 >> >> // >> // Enable branch recording >> // >> LbControl = AsmReadMsr64 ((UINT32)IA32_DEBUGCTL); >> LbControl |= LBR_ON_FLAG; >> AsmWriteMsr64 ((UINT32)IA32_DEBUGCTL, LbControl); >> >> // >> // Configure for call stack >> // >> LbSelect = AsmReadMsr64 ((UINT32)MSR_LBR_SELECT); >> LbSelect &= CALL_STACK_CLR_FLAG; >> LbSelect |= CALL_STACK_SET_FLAG; >> AsmWriteMsr64((UINT32)MSR_LBR_SELECT, LbSelect); >> >> The EIP/RIP values are logged in MSR_SANDY_BRIDGE_LASTBRANCH_n_FROM_IP >> and MSR_SANDY_BRIDGE_LASTBRANCH_n_TO_IP, and the current depth is >> tracked in MSR_LASTBRANCH_TOS. This works quite well. Gen10 (Sky >> Lake) processors support 32 LASTBRANCH_n MSR pairs, which is >> sufficient in almost all cases. >> >> Different processor generations have different branch recording >> capabilities, and different numbers of LASTBRANCH_n MSRs; see Intel's >> manuals for details. >> >> Thanks, >> Brian >> >>>> >>>> Thanks! >>>> >>>> Jeff >>>> >>>> *发件人: *Paulo Alcantara <mailto:pcacjr@zytor.com> >>>> *发送时间: *2017年11月14日21:23 >>>> *收件人: *edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >>>> <mailto:edk2-devel@lists.01.org> >>>> *抄送: *Rick Bramley <mailto:richard.bramley@hp.com>; Laszlo Ersek >>>> <mailto:lersek@redhat.com>; Andrew Fish <mailto:afish@apple.com>; >>>> Eric Dong <mailto:eric.dong@intel.com> >>>> *主题: *Re: [edk2] [RFC 0/1] Stack trace support in X64 exception >>>> handling >>>> >>>> Hi, >>>> >>>> On 14/11/2017 10:47, Paulo Alcantara wrote: >>>>> Hi, >>>>> >>>>> This series adds stack trace support during a X64 CPU exception. >>>>> >>>>> Informations like back trace, stack contents and image module names >>>>> (that were part of the call stack) will be dumped out. >>>>> >>>>> We already have such support in ARM/AArch64 (IIRC) exception handling >>>>> (thanks to Ard), and then I thought we'd also deserve it in X64 and >>>>> IA-32 platforms. >>>>> >>>>> What do you think guys? >>>>> >>>>> BTW, I've tested this only with OVMF (X64 only), using: >>>>> - gcc-6.3.0, GCC5, NOOPT >>>>> >>>>> Any other tests would be really appreciable. >>>> >>>> I've attached a file to show you how the trace would look like. >>>> >>>> Thanks! >>>> Paulo >>>> >>>>> >>>>> Thanks! >>>>> Paulo >>>>> >>>>> Repo: https://github.com/pcacjr/edk2.git >>>>> Branch: stacktrace_x64 >>>>> >>>>> Cc: Rick Bramley <richard.bramley@hp.com >>>>> <mailto:richard.bramley@hp.com>> >>>>> Cc: Andrew Fish <afish@apple.com <mailto:afish@apple.com>> >>>>> Cc: Eric Dong <eric.dong@intel.com <mailto:eric.dong@intel.com>> >>>>> Cc: Laszlo Ersek <lersek@redhat.com <mailto:lersek@redhat.com>> >>>>> Contributed-under: TianoCore Contribution Agreement 1.1 >>>>> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com >>>>> <mailto:pcacjr@zytor.com>> >>>>> --- >>>>> >>>>> Paulo Alcantara (1): >>>>> UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support >>>>> >>>>> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c >>>>> | 344 +++++++++++++++++++- >>>>> 1 file changed, 342 insertions(+), 2 deletions(-) >>>>> >>>> >>> _______________________________________________ >>> edk2-devel mailing list >>> edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >>> https://lists.01.org/mailman/listinfo/edk2-devel >> >> >> -- >> >> Brian >> >> -------------------------------------------------------------------- >> >> "Most people would like to be delivered from temptation but would >> like it to keep in touch." >> -- Robert Orben >> _______________________________________________ >> edk2-devel mailing list >> edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >> https://lists.01.org/mailman/listinfo/edk2-devel > -- Brian J. Johnson Enterprise X86 Lab Hewlett Packard Enterprise brian.johnson@hpe.com _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi, On 14/11/2017 15:41, Brian J. Johnson wrote: > On 11/14/2017 11:23 AM, Andrew Fish wrote: >> >>> On Nov 14, 2017, at 8:33 AM, Brian J. Johnson <brian.johnson@hpe.com >>> <mailto:brian.johnson@hpe.com>> wrote: >>> >>> On 11/14/2017 09:37 AM, Paulo Alcantara wrote: >>>> Hi Fan, >>>> On 14/11/2017 12:03, Fan Jeff wrote: >>>>> Paul, >>>>> >>>>> I like this feature very much. Actually, I did some POC one year >>>>> ago but I did finalize it. >>>>> >>>>> In my POC, I could use EBP to tack the stack frame on IAS32 arch. >>>>> >>>>> But for x64, I tried to use –keepexceptiontable flag to explain >>>>> stack frame from the debug section of image. >>>>> >>>>> I may workson MSFT toolchain, but it did now work well for GCC >>>>> toolchain. >>>>> >>>>> I think Eric could help to verify MSFT for your patch. If it works >>>>> well, that’s will be great! >>>>> >>>>> Say again, I like this feature!!!:-) >>>> Cool! Your help would be really appreciable! If we get this working >>>> for X64 in both toolchains, that should be easy to port it to IA-3 2 >>>> as well. >>>> Thank you very much for willing to help on that. >>>> Paulo >>> >>> Great feature! You do need some sort of sanity check on the RIP and >>> RBP values, though, so if the stack gets corrupted or the RIP is >>> nonsense from following a bad pointer, you don't start dereferencing >>> garbage addresses and trigger an exception loop. >>> >> >> Brian, >> >> This was a long time ago and my memory might be fuzzy.... I think we >> talked to some debugger folks about unwinding the stack and they >> mentioned it was common for the C runtime to have a return address or >> frame pointer have a zero value so the unwind logic knows when to >> stop. This is in addition to generic sanity checking. >> >> We got an extra push $0 added to the stack switch to help with stack >> unwind. >> https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/X64/SwitchStack.S >> >> >> If might be a good idea to have a PCD for the max number of stack >> frames to display as a fallback for the error check. For X64 you may >> also have to add a check for a non-cononical address as that will GP >> fault. >> > > Good idea. > > Regarding sanity checks: I've had good luck validating code locations > (EIP values) by using a modified PeCoffExtraActionLib to track the top > and bottom of the range where images have been loaded. (I've actually > used two ranges: one for code executed from firmware space, and one for > code executed from RAM.) > > I'm not sure offhand if there's a platform-independent way to validate > stack pointer values. For most PC-like systems, just ensuring that it's > larger than 1 or 2M (to avoid NULL pointers and the legacy spaces) and > less than about 3G (or the low memory size, if that's known) may be > enough to avoid an exception loop. Yeah, I agree with you guys. We certainly should be validating the RIP and RSP values and then avoiding the exception loop. For the RIP value, I think we should validate it in PeCoffSearchImageBase(), so if it's outside PE/COFF image's address space, then we should return an address of zero and no trace would be printed out. Since we already have a "SizeOfImage" field in PE/COFF Optional Header and it's available in the process' image, we might end up with checking whether RIP is between ImageBase through ImageBase + SizeOfImage - 1. For the RSP value, I have no idea :-) Thanks! Paulo > > Brian > >> Thanks, >> >> Andrew Fish >> >> >>> For at least some versions of Microsoft's IA32 compiler, it's >>> possible to compile using EBP as a stack frame base pointer (like >>> gcc) by using the "/Oy-" switch. The proposed unwind code should >>> work in that case. The X64 compiler doesn't support this switch, though. >>> >>> AFAIK the only way to unwind the stack with Microsoft's X64 compilers >>> is to parse the unwind info in the .pdata and .xdata sections. >>> Genfw.exe usually strips those sections, but the >>> "--keepexceptiontable" flag will preserve them, as Jeff pointed out. >>> I've looked hard for open source code to decode them, but haven't >>> found any, even though the format is well documented. And I haven't >>> gotten around to writing it myself. I'd love it if someone could >>> contribute the code! >>> >>> Another possibility is to use the branch history MSRs available on >>> some x86-family processors. Recent Intel processors can use them as >>> a stack, as opposed to a circular list, so they can record a >>> backtrace directly. (I'm not familiar with AMD processors' >>> capabilities.) You can enable call stack recording like this: >>> >>> #define LBR_ON_FLAG 0x0000000000000001 >>> #define IA32_DEBUGCTL 0x1D9 >>> #define CALL_STACK_SET_FLAG 0x3C4 >>> #define CALL_STACK_CLR_FLAG 0xFC7 >>> #define MSR_LBR_SELECT 0x1C8 >>> >>> // >>> // Enable branch recording >>> // >>> LbControl = AsmReadMsr64 ((UINT32)IA32_DEBUGCTL); >>> LbControl |= LBR_ON_FLAG; >>> AsmWriteMsr64 ((UINT32)IA32_DEBUGCTL, LbControl); >>> >>> // >>> // Configure for call stack >>> // >>> LbSelect = AsmReadMsr64 ((UINT32)MSR_LBR_SELECT); >>> LbSelect &= CALL_STACK_CLR_FLAG; >>> LbSelect |= CALL_STACK_SET_FLAG; >>> AsmWriteMsr64((UINT32)MSR_LBR_SELECT, LbSelect); >>> >>> The EIP/RIP values are logged in >>> MSR_SANDY_BRIDGE_LASTBRANCH_n_FROM_IP and >>> MSR_SANDY_BRIDGE_LASTBRANCH_n_TO_IP, and the current depth is tracked >>> in MSR_LASTBRANCH_TOS. This works quite well. Gen10 (Sky Lake) >>> processors support 32 LASTBRANCH_n MSR pairs, which is sufficient in >>> almost all cases. >>> >>> Different processor generations have different branch recording >>> capabilities, and different numbers of LASTBRANCH_n MSRs; see Intel's >>> manuals for details. >>> >>> Thanks, >>> Brian >>> >>>>> >>>>> Thanks! >>>>> >>>>> Jeff >>>>> >>>>> *发件人: *Paulo Alcantara <mailto:pcacjr@zytor.com> >>>>> *发送时间: *2017年11月14日21:23 >>>>> *收件人: *edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >>>>> <mailto:edk2-devel@lists.01.org> >>>>> *抄送: *Rick Bramley <mailto:richard.bramley@hp.com>; Laszlo Ersek >>>>> <mailto:lersek@redhat.com>; Andrew Fish <mailto:afish@apple.com>; >>>>> Eric Dong <mailto:eric.dong@intel.com> >>>>> *主题: *Re: [edk2] [RFC 0/1] Stack trace support in X64 exception >>>>> handling >>>>> >>>>> Hi, >>>>> >>>>> On 14/11/2017 10:47, Paulo Alcantara wrote: >>>>>> Hi, >>>>>> >>>>>> This series adds stack trace support during a X64 CPU exception. >>>>>> >>>>>> Informations like back trace, stack contents and image module names >>>>>> (that were part of the call stack) will be dumped out. >>>>>> >>>>>> We already have such support in ARM/AArch64 (IIRC) exception handling >>>>>> (thanks to Ard), and then I thought we'd also deserve it in X64 and >>>>>> IA-32 platforms. >>>>>> >>>>>> What do you think guys? >>>>>> >>>>>> BTW, I've tested this only with OVMF (X64 only), using: >>>>>> - gcc-6.3.0, GCC5, NOOPT >>>>>> >>>>>> Any other tests would be really appreciable. >>>>> >>>>> I've attached a file to show you how the trace would look like. >>>>> >>>>> Thanks! >>>>> Paulo >>>>> >>>>>> >>>>>> Thanks! >>>>>> Paulo >>>>>> >>>>>> Repo: https://github.com/pcacjr/edk2.git >>>>>> Branch: stacktrace_x64 >>>>>> >>>>>> Cc: Rick Bramley <richard.bramley@hp.com >>>>>> <mailto:richard.bramley@hp.com>> >>>>>> Cc: Andrew Fish <afish@apple.com <mailto:afish@apple.com>> >>>>>> Cc: Eric Dong <eric.dong@intel.com <mailto:eric.dong@intel.com>> >>>>>> Cc: Laszlo Ersek <lersek@redhat.com <mailto:lersek@redhat.com>> >>>>>> Contributed-under: TianoCore Contribution Agreement 1.1 >>>>>> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com >>>>>> <mailto:pcacjr@zytor.com>> >>>>>> --- >>>>>> >>>>>> Paulo Alcantara (1): >>>>>> UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support >>>>>> >>>>>> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c >>>>>> | 344 +++++++++++++++++++- >>>>>> 1 file changed, 342 insertions(+), 2 deletions(-) >>>>>> >>>>> >>>> _______________________________________________ >>>> edk2-devel mailing list >>>> edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >>>> https://lists.01.org/mailman/listinfo/edk2-devel >>> >>> >>> -- >>> >>> Brian >>> >>> -------------------------------------------------------------------- >>> >>> "Most people would like to be delivered from temptation but would >>> like it to keep in touch." >>> -- Robert Orben >>> _______________________________________________ >>> edk2-devel mailing list >>> edk2-devel@lists.01.org <mailto: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
Paulo, I will try to validate my code firstly and try to integrate into your patch. Before my part ready, it’s also welcome if you or others provide yours own solution on X64 MSFT toolchain. In my mind, IA32 arch should use the same solution with yours, have you tested your solution on IA32 arch with GCC toolchain? Thanks! Jeff ________________________________ From: Paulo Alcantara <pcacjr@zytor.com> Sent: Tuesday, November 14, 2017 11:37:35 PM To: Fan Jeff; edk2-devel@lists.01.org Cc: Rick Bramley; Laszlo Ersek; Andrew Fish; Eric Dong Subject: Re: 答复: [edk2] [RFC 0/1] Stack trace support in X64 exception handling Hi Fan, On 14/11/2017 12:03, Fan Jeff wrote: > Paul, > > I like this feature very much. Actually, I did some POC one year ago but > I did finalize it. > > In my POC, I could use EBP to tack the stack frame on IAS32 arch. > > But for x64, I tried to use �Ckeepexceptiontable flag to explain stack > frame from the debug section of image. > > I may workson MSFT toolchain, but it did now work well for GCC toolchain. > > I think Eric could help to verify MSFT for your patch. If it works well, > that’s will be great! > > Say again, I like this feature!!!:-) Cool! Your help would be really appreciable! If we get this working for X64 in both toolchains, that should be easy to port it to IA-32 as well. Thank you very much for willing to help on that. Paulo > > Thanks! > > Jeff > > *发件人: *Paulo Alcantara <mailto:pcacjr@zytor.com> > *发送时间: *2017年11月14日21:23 > *收件人: *edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> > *抄送: *Rick Bramley <mailto:richard.bramley@hp.com>; Laszlo Ersek > <mailto:lersek@redhat.com>; Andrew Fish <mailto:afish@apple.com>; Eric > Dong <mailto:eric.dong@intel.com> > *主题: *Re: [edk2] [RFC 0/1] Stack trace support in X64 exception handling > > Hi, > > On 14/11/2017 10:47, Paulo Alcantara wrote: >> Hi, >> >> This series adds stack trace support during a X64 CPU exception. >> >> Informations like back trace, stack contents and image module names >> (that were part of the call stack) will be dumped out. >> >> We already have such support in ARM/AArch64 (IIRC) exception handling >> (thanks to Ard), and then I thought we'd also deserve it in X64 and >> IA-32 platforms. >> >> What do you think guys? >> >> BTW, I've tested this only with OVMF (X64 only), using: >> - gcc-6.3.0, GCC5, NOOPT >> >> Any other tests would be really appreciable. > > I've attached a file to show you how the trace would look like. > > Thanks! > Paulo > >> >> Thanks! >> Paulo >> >> Repo: https://github.com/pcacjr/edk2.git >> Branch: stacktrace_x64 >> >> Cc: Rick Bramley <richard.bramley@hp.com> >> Cc: Andrew Fish <afish@apple.com> >> Cc: Eric Dong <eric.dong@intel.com> >> Cc: Laszlo Ersek <lersek@redhat.com> >> Contributed-under: TianoCore Contribution Agreement 1.1 >> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> >> --- >> >> Paulo Alcantara (1): >> UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support >> >> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 +++++++++++++++++++- >> 1 file changed, 342 insertions(+), 2 deletions(-) >> > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi Fan, On 15/11/2017 11:21, Fan Jeff wrote: > Paulo, > > I will try to validate my code firstly and try to integrate into your > patch. OK. Thank you very much for the effort! > > Before my part ready, it’s also welcome if you or others provide yours > own solution on X64 MSFT toolchain. Yes - that would be great. If I get this working on IA32 with GCC toolchain shortly, then I'll try to come up with a solution for MSVC. > In my mind, IA32 arch should use the same solution with yours, have you > tested your solution on IA32 arch with GCC toolchain? In theory, yes. :-) I haven't tested it yet, but I'll starting working it on now. BTW, do you think it's appropriate to just let you know that I pushed out another commit with IA32 support, or do you think it's better to send a v2 with it? Besides we shouldn't forget the suggestions from Andrew and Brian to validate the RIP and RSP values, as well as to have a kind of PCD to limit the number of stack frames printed out -- which I think that are really important even if unlikely. Thanks! Paulo > > Thanks! > > Jeff > > ------------------------------------------------------------------------ > *From:* Paulo Alcantara <pcacjr@zytor.com> > *Sent:* Tuesday, November 14, 2017 11:37:35 PM > *To:* Fan Jeff; edk2-devel@lists.01.org > *Cc:* Rick Bramley; Laszlo Ersek; Andrew Fish; Eric Dong > *Subject:* Re: 答复: [edk2] [RFC 0/1] Stack trace support in X64 > exception handling > Hi Fan, > > On 14/11/2017 12:03, Fan Jeff wrote: >> Paul, >> >> I like this feature very much. Actually, I did some POC one year ago but >> I did finalize it. >> >> In my POC, I could use EBP to tack the stack frame on IAS32 arch. >> >> But for x64, I tried to use –keepexceptiontable flag to explain stack >> frame from the debug section of image. >> >> I may workson MSFT toolchain, but it did now work well for GCC toolchain. >> >> I think Eric could help to verify MSFT for your patch. If it works well, >> that’s will be great! >> >> Say again, I like this feature!!!:-) > > Cool! Your help would be really appreciable! If we get this working for > X64 in both toolchains, that should be easy to port it to IA-32 as well. > > Thank you very much for willing to help on that. > > Paulo > >> >> Thanks! >> >> Jeff >> >> *发件人: *Paulo Alcantara <mailto:pcacjr@zytor.com> >> *发送时间: *2017年11月14日21:23 >> *收件人: *edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >> *抄送: *Rick Bramley <mailto:richard.bramley@hp.com>; Laszlo Ersek >> <mailto:lersek@redhat.com>; Andrew Fish <mailto:afish@apple.com>; Eric >> Dong <mailto:eric.dong@intel.com> >> *主题: *Re: [edk2] [RFC 0/1] Stack trace support in X64 exception handling >> >> Hi, >> >> On 14/11/2017 10:47, Paulo Alcantara wrote: >>> Hi, >>> >>> This series adds stack trace support during a X64 CPU exception. >>> >>> Informations like back trace, stack contents and image module names >>> (that were part of the call stack) will be dumped out. >>> >>> We already have such support in ARM/AArch64 (IIRC) exception handling >>> (thanks to Ard), and then I thought we'd also deserve it in X64 and >>> IA-32 platforms. >>> >>> What do you think guys? >>> >>> BTW, I've tested this only with OVMF (X64 only), using: >>> - gcc-6.3.0, GCC5, NOOPT >>> >>> Any other tests would be really appreciable. >> >> I've attached a file to show you how the trace would look like. >> >> Thanks! >> Paulo >> >>> >>> Thanks! >>> Paulo >>> >>> Repo: https://github.com/pcacjr/edk2.git >>> Branch: stacktrace_x64 >>> >>> Cc: Rick Bramley <richard.bramley@hp.com> >>> Cc: Andrew Fish <afish@apple.com> >>> Cc: Eric Dong <eric.dong@intel.com> >>> Cc: Laszlo Ersek <lersek@redhat.com> >>> Contributed-under: TianoCore Contribution Agreement 1.1 >>> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> >>> --- >>> >>> Paulo Alcantara (1): >>> UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support >>> >>> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 +++++++++++++++++++- >>> 1 file changed, 342 insertions(+), 2 deletions(-) >>> >> _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Paulo, I have no strong opinion on IA32 support in v2 patch or in separate patch. I think UefiCpuPkg owner/reviewer may provide their own suggestions on this point. Thanks! Jeff ________________________________ From: Paulo Alcantara <pcacjr@zytor.com> Sent: Wednesday, November 15, 2017 10:41:00 PM To: Fan Jeff; edk2-devel@lists.01.org Cc: Rick Bramley; Laszlo Ersek; Andrew Fish; Eric Dong Subject: Re: 答复: 答复: [edk2] [RFC 0/1] Stack trace support in X64 exception handling Hi Fan, On 15/11/2017 11:21, Fan Jeff wrote: > Paulo, > > I will try to validate my code firstly and try to integrate into your > patch. OK. Thank you very much for the effort! > > Before my part ready, it’s also welcome if you or others provide yours > own solution on X64 MSFT toolchain. Yes - that would be great. If I get this working on IA32 with GCC toolchain shortly, then I'll try to come up with a solution for MSVC. > In my mind, IA32 arch should use the same solution with yours, have you > tested your solution on IA32 arch with GCC toolchain? In theory, yes. :-) I haven't tested it yet, but I'll starting working it on now. BTW, do you think it's appropriate to just let you know that I pushed out another commit with IA32 support, or do you think it's better to send a v2 with it? Besides we shouldn't forget the suggestions from Andrew and Brian to validate the RIP and RSP values, as well as to have a kind of PCD to limit the number of stack frames printed out -- which I think that are really important even if unlikely. Thanks! Paulo > > Thanks! > > Jeff > > ------------------------------------------------------------------------ > *From:* Paulo Alcantara <pcacjr@zytor.com> > *Sent:* Tuesday, November 14, 2017 11:37:35 PM > *To:* Fan Jeff; edk2-devel@lists.01.org > *Cc:* Rick Bramley; Laszlo Ersek; Andrew Fish; Eric Dong > *Subject:* Re: 答复: [edk2] [RFC 0/1] Stack trace support in X64 > exception handling > Hi Fan, > > On 14/11/2017 12:03, Fan Jeff wrote: >> Paul, >> >> I like this feature very much. Actually, I did some POC one year ago but >> I did finalize it. >> >> In my POC, I could use EBP to tack the stack frame on IAS32 arch. >> >> But for x64, I tried to use �Ckeepexceptiontable flag to explain stack >> frame from the debug section of image. >> >> I may workson MSFT toolchain, but it did now work well for GCC toolchain. >> >> I think Eric could help to verify MSFT for your patch. If it works well, >> that’s will be great! >> >> Say again, I like this feature!!!:-) > > Cool! Your help would be really appreciable! If we get this working for > X64 in both toolchains, that should be easy to port it to IA-32 as well. > > Thank you very much for willing to help on that. > > Paulo > >> >> Thanks! >> >> Jeff >> >> *发件人: *Paulo Alcantara <mailto:pcacjr@zytor.com> >> *发送时间: *2017年11月14日21:23 >> *收件人: *edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >> *抄送: *Rick Bramley <mailto:richard.bramley@hp.com>; Laszlo Ersek >> <mailto:lersek@redhat.com>; Andrew Fish <mailto:afish@apple.com>; Eric >> Dong <mailto:eric.dong@intel.com> >> *主题: *Re: [edk2] [RFC 0/1] Stack trace support in X64 exception handling >> >> Hi, >> >> On 14/11/2017 10:47, Paulo Alcantara wrote: >>> Hi, >>> >>> This series adds stack trace support during a X64 CPU exception. >>> >>> Informations like back trace, stack contents and image module names >>> (that were part of the call stack) will be dumped out. >>> >>> We already have such support in ARM/AArch64 (IIRC) exception handling >>> (thanks to Ard), and then I thought we'd also deserve it in X64 and >>> IA-32 platforms. >>> >>> What do you think guys? >>> >>> BTW, I've tested this only with OVMF (X64 only), using: >>> - gcc-6.3.0, GCC5, NOOPT >>> >>> Any other tests would be really appreciable. >> >> I've attached a file to show you how the trace would look like. >> >> Thanks! >> Paulo >> >>> >>> Thanks! >>> Paulo >>> >>> Repo: https://github.com/pcacjr/edk2.git >>> Branch: stacktrace_x64 >>> >>> Cc: Rick Bramley <richard.bramley@hp.com> >>> Cc: Andrew Fish <afish@apple.com> >>> Cc: Eric Dong <eric.dong@intel.com> >>> Cc: Laszlo Ersek <lersek@redhat.com> >>> Contributed-under: TianoCore Contribution Agreement 1.1 >>> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> >>> --- >>> >>> Paulo Alcantara (1): >>> UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support >>> >>> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 344 +++++++++++++++++++- >>> 1 file changed, 342 insertions(+), 2 deletions(-) >>> >> _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi, This series adds stack trace support during a X64 CPU exception. Informations like back trace, stack contents and image module names (that were part of the call stack) will be dumped out. We already have such support in ARM/AArch64 (IIRC) exception handling (thanks to Ard), and then I thought we'd also deserve it in X64 and IA-32 platforms. What do you think guys? BTW, I've tested this only with OVMF (X64 only), using: - gcc-6.3.0, GCC5, NOOPT Any other tests would be really appreciable. Thanks! Paulo Repo: https://github.com/pcacjr/edk2.git Branch: stacktrace_v2 Cc: Rick Bramley <richard.bramley@hp.com> Cc: Andrew Fish <afish@apple.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: "Brian J. Johnson" <brian.johnson@hpe.com> Cc: Jeff Fan <jeff.fan@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> --- v1 -> v2: * Add IA32 arch support (GCC toolchain only) * Replace hard-coded stack alignment value (16) with CPU_STACK_ALIGNMENT. * Check for proper stack and frame pointer alignments. * Fix initialization of UnwoundStacksCount to 1. * Move GetPdbFileName() to common code since it will be used by both IA32 and X64 implementations. Paulo Alcantara (3): UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support UefiCpuPkg/CpuExceptionHandlerLib: Export GetPdbFileName() UefiCpuPkg/CpuExceptionHandlerLib/Ia32: Add stack trace support UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c | 102 ++++--- UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h | 25 +- UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c | 303 ++++++++++++++++++- UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 310 +++++++++++++++++++- 4 files changed, 682 insertions(+), 58 deletions(-) -- 2.14.3 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi, On 11/15/2017 11:18 PM, Paulo Alcantara wrote: > Hi, > > This series adds stack trace support during a X64 CPU exception. > > Informations like back trace, stack contents and image module names > (that were part of the call stack) will be dumped out. > > We already have such support in ARM/AArch64 (IIRC) exception handling > (thanks to Ard), and then I thought we'd also deserve it in X64 and > IA-32 platforms. > > What do you think guys? > > BTW, I've tested this only with OVMF (X64 only), using: > - gcc-6.3.0, GCC5, NOOPT > > Any other tests would be really appreciable. > > Thanks! > Paulo > > Repo: https://github.com/pcacjr/edk2.git > Branch: stacktrace_v2 > > Cc: Rick Bramley <richard.bramley@hp.com> > Cc: Andrew Fish <afish@apple.com> > Cc: Eric Dong <eric.dong@intel.com> > Cc: Laszlo Ersek <lersek@redhat.com> > Cc: "Brian J. Johnson" <brian.johnson@hpe.com> > Cc: Jeff Fan <jeff.fan@intel.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> > --- > > v1 -> v2: > * Add IA32 arch support (GCC toolchain only) > * Replace hard-coded stack alignment value (16) with > CPU_STACK_ALIGNMENT. > * Check for proper stack and frame pointer alignments. > * Fix initialization of UnwoundStacksCount to 1. > * Move GetPdbFileName() to common code since it will be used by both > IA32 and X64 implementations. Sorry for the delay in sending v2. It's holiday here :-) FWIW, I've attached two files which contain stack trace dumps of IA32 and X64 exceptions. The new IA32 arch support is still limited to GCC only (that is, relying on frame pointers), but I'll start investing in a new solution that would work on both MSVC and GCC toolchains -- probably this weekend. If I come up with something, I'll let you know. On IA32, I performed the same test as in X64 to trigger an NMI interrupt manually with: asm ("int $0x2") in PartitionDxe driver and watched out the call stack. The difference between the two dumps, regardless the CPU context, etc. is that we don't see the calls from PeiCore.dll. Then I figured out that the EIP gets a value of 0 before jumping to PartitionDxe's entry point. I guess that's related to the "push $0" that Andrew mentioned earlier so the debugger knows when to stop unwinding. Although I can't see a "push 0" equivalent neither in SwitchStack.nasm nor in SwitchStack.asm for X64 -- so we're able to see the calls within PeiCore.dll. Thanks! Paulo !!!! X64 Exception Type - 02(NMI Interrupt) CPU Apic ID - 00000000 !!!! RIP - 000000007EC30266, CS - 0000000000000038, RFLAGS - 0000000000000202 RAX - 000000007FE71018, RCX - 000000007F34F498, RDX - 000000007FE71018 RBX - 0000000000810248, RSP - 000000007FEE4C70, RBP - 000000007FEE4CB0 RSI - 0000000000000007, RDI - 000000007F34E018 R8 - 000000007EC32DC8, R9 - 000000007F34E298, R10 - 0000000000000036 R11 - 00000000000000D7, R12 - 0000000000000000, R13 - 0000000000000000 R14 - 0000000000000000, R15 - 0000000000000000 DS - 0000000000000030, ES - 0000000000000030, FS - 0000000000000030 GS - 0000000000000030, SS - 0000000000000030 CR0 - 0000000080010033, CR2 - 0000000000000000, CR3 - 000000007FE83000 CR4 - 0000000000000668, CR8 - 0000000000000000 DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000 DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400 GDTR - 000000007FE71A98 0000000000000047, LDTR - 0000000000000000 IDTR - 000000007F7AB018 0000000000000FFF, TR - 0000000000000000 FXSAVE_STATE - 000000007FEE48D0 Call trace: 0 0x000000007EC30266 @ 0x000000007EC28000+0x8265 (0x000000007FEE4CB0) in PartitionDxe.dll 1 0x000000007EC3063D @ 0x000000007EC28000+0x863C (0x000000007FEE4CE0) in PartitionDxe.dll 2 0x000000007EC2B116 @ 0x000000007EC28000+0x3115 (0x000000007FEE4D20) in PartitionDxe.dll 3 0x000000007FEF8A15 @ 0x000000007EC28000+0x12D0A14 (0x000000007FEE4DB0) in PartitionDxe.dll 4 0x000000007FF10F0A @ 0x000000007EC28000+0x12E8F09 (0x000000007FEE4E30) in PartitionDxe.dll 5 0x000000007FF13445 @ 0x000000007EC28000+0x12EB444 (0x000000007FEE4F60) in PartitionDxe.dll 6 0x000000007FF13BC9 @ 0x000000007EC28000+0x12EBBC8 (0x000000007FEE4F90) in PartitionDxe.dll 7 0x000000007FEE9DDE @ 0x000000007EC28000+0x12C1DDD (0x000000007FEE4FC0) in PartitionDxe.dll 8 0x000000007FF5B75F @ 0x000000007EC28000+0x133375E (0x000000007BFDC840) in PartitionDxe.dll 9 0x000000007FF61551 @ 0x000000007EC28000+0x1339550 (0x000000007BFDC8C0) in PartitionDxe.dll 10 0x000000007FF6031D @ 0x000000007EC28000+0x133831C (0x000000007BFDCA30) in PartitionDxe.dll 11 0x000000007FF6CDCB @ 0x000000007EC28000+0x1344DCA (0x000000007BFDCF80) in PartitionDxe.dll 12 0x00000000008286F4 @ 0x0000000000820140+0x85B3 (0x000000007BFDD4D0) in PeiCore.dll 13 0x0000000000830940 @ 0x0000000000820140+0x107FF (0x0000000000817600) in PeiCore.dll 14 0x0000000000831585 @ 0x0000000000820140+0x11444 (0x00000000008176D0) in PeiCore.dll 15 0x0000000000828DAD @ 0x0000000000820140+0x8C6C (0x0000000000817C20) in PeiCore.dll 16 0x0000000000832392 @ 0x0000000000820140+0x12251 (0x0000000000817C50) in PeiCore.dll 17 0x0000000000824313 @ 0x0000000000820140+0x41D2 (0x0000000000817C80) in PeiCore.dll 18 0x00000000FFFD42F1 @ 0x0000000000820140+0xFF7B41B0 (0x0000000000817CE0) in PeiCore.dll 19 0x00000000FFFCF578 @ 0x0000000000820140+0xFF7AF437 (0x0000000000817D10) in PeiCore.dll 20 0x00000000FFFD428C @ 0x0000000000820140+0xFF7B414B (0x0000000000817FD0) in PeiCore.dll 21 0x00000000FFFD44E9 @ 0x0000000000820140+0xFF7B43A8 (0x00000000FFFCC000) in PeiCore.dll PartitionDxe.dll (ImageBase=0x000000007EC28000, EntryPoint=0x000000007EC2B01F): /home/pcacjr/src/edk2/Build/OvmfX64/NOOPT_GCC5/X64/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe/DEBUG/PartitionDxe.dll PeiCore.dll (ImageBase=0x0000000000820140, EntryPoint=0x00000000008242ED): /home/pcacjr/src/edk2/Build/OvmfX64/NOOPT_GCC5/X64/MdeModulePkg/Core/Pei/PeiMain/DEBUG/PeiCore.dll Stack dump: 0x000000007FEE4C70: 000000007EC32B20 0000000000000000 0x000000007FEE4C80: 000000007EC32DC8 0000000000000100 0x000000007FEE4C90: 000000007FEE4CB0 0000000000000000 0x000000007FEE4CA0: 000000007FEE4CE0 000000007EC305B7 0x000000007FEE4CB0: 000000007FEE4CE0 000000007EC3063D 0x000000007FEE4CC0: 000000007F34F498 000000007FE71018 0x000000007FEE4CD0: 000000077FEF88F5 0000000000000000 0x000000007FEE4CE0: 000000007FEE4D20 000000007EC2B116 0x000000007FEE4CF0: 000000007F34F498 000000007FE71018 0x000000007FEE4D00: 0000000000000000 0000000000000000 0x000000007FEE4D10: 0000000000000000 0000000000000000 0x000000007FEE4D20: 000000007FEE4DB0 000000007FEF8A15 0x000000007FEE4D30: 000000007F34F498 000000007FE71018 0x000000007FEE4D40: 0000000000000000 0000000000000004 0x000000007FEE4D50: 000000007FF1C1A8 000000007FF1CF90 0x000000007FEE4D60: 000000007FEE4DB0 0000000000000000 0x000000007FEE4D70: 000000007FF1C180 00000000000000B0 0x000000007FEE4D80: 0000000000000000 000000007F34E018 0x000000007FEE4D90: 000000007F34F498 0000000000000000 0x000000007FEE4DA0: 000000007FF1C1A8 000000007FF1CF90 0x000000007FEE4DB0: 000000007FEE4E30 000000007FF10F0A 0x000000007FEE4DC0: 000000007F34F498 0000000000000000 !!!! IA32 Exception Type - 02(NMI Interrupt) CPU Apic ID - 00000000 !!!! EIP - 7DBD41BB, CS - 00000010, EFLAGS - 00000206 EAX - 00000000, ECX - 7EEC8CFF, EDX - 7ED9C220, EBX - 00000000 ESP - 7EEC8DE4, EBP - 7EEC8DFC, ESI - 00000004, EDI - 00000000 DS - 00000008, ES - 00000008, FS - 00000008, GS - 00000008, SS - 00000008 CR0 - 00000033, CR2 - 00000000, CR3 - 00000000, CR4 - 00000640 DR0 - 00000000, DR1 - 00000000, DR2 - 00000000, DR3 - 00000000 DR6 - FFFF0FF0, DR7 - 00000400 GDTR - 7EE97A90 00000047, IDTR - 7E65B010 000007FF LDTR - 00000000, TR - 00000000 FXSAVE_STATE - 7EEC8B20 Call trace: 0 0x7DBD41BB @ 0x7DBCD000+0x71BA (0x7EEC8DFC) in PartitionDxe.dll 1 0x7DBD4569 @ 0x7DBCD000+0x7568 (0x7EEC8E1C) in PartitionDxe.dll 2 0x7DBCF7F4 @ 0x7DBCD000+0x27F3 (0x7EEC8E4C) in PartitionDxe.dll 3 0x7EED9EA0 @ 0x7DBCD000+0x130CE9F (0x7EEC8E9C) in PartitionDxe.dll 4 0x7EEF1A88 @ 0x7DBCD000+0x1324A87 (0x7EEC8EDC) in PartitionDxe.dll 5 0x7EEF3DCC @ 0x7DBCD000+0x1326DCB (0x7EEC8FAC) in PartitionDxe.dll 6 0x7EEF44A1 @ 0x7DBCD000+0x13274A0 (0x7EEC8FCC) in PartitionDxe.dll 7 0x7EECD272 @ 0x7DBCD000+0x1300271 (0x7EEC8FEC) in PartitionDxe.dll PartitionDxe.dll (ImageBase=0x7DBCD000, EntryPoint=0x7DBCF71B): /home/pcacjr/src/edk2/Build/OvmfIa32/NOOPT_GCC5/IA32/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe/DEBUG/PartitionDxe.dll Stack dump: 0x7EEC8DE4: 7EAA1690 7EEFC520 0x7EEC8DE8: 7EEFC520 7EEC8E1C 0x7EEC8DEC: 7EEC8E1C 7DBD44E7 0x7EEC8DF0: 7DBD44E7 7E10E010 0x7EEC8DF4: 7E10E010 7EE97010 0x7EEC8DF8: 7EE97010 7EEC8E1C 0x7EEC8DFC: 7EEC8E1C 7DBD4569 0x7EEC8E00: 7DBD4569 7E10E010 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Paulo, Those attached stack traces don't look right. Thanks, Andrew Fish > On Nov 15, 2017, at 5:46 PM, Paulo Alcantara <pcacjr@zytor.com> wrote: > > Hi, > > On 11/15/2017 11:18 PM, Paulo Alcantara wrote: >> Hi, >> This series adds stack trace support during a X64 CPU exception. >> Informations like back trace, stack contents and image module names >> (that were part of the call stack) will be dumped out. >> We already have such support in ARM/AArch64 (IIRC) exception handling >> (thanks to Ard), and then I thought we'd also deserve it in X64 and >> IA-32 platforms. >> What do you think guys? >> BTW, I've tested this only with OVMF (X64 only), using: >> - gcc-6.3.0, GCC5, NOOPT >> Any other tests would be really appreciable. >> Thanks! >> Paulo >> Repo: https://github.com/pcacjr/edk2.git >> Branch: stacktrace_v2 >> Cc: Rick Bramley <richard.bramley@hp.com> >> Cc: Andrew Fish <afish@apple.com> >> Cc: Eric Dong <eric.dong@intel.com> >> Cc: Laszlo Ersek <lersek@redhat.com> >> Cc: "Brian J. Johnson" <brian.johnson@hpe.com> >> Cc: Jeff Fan <jeff.fan@intel.com> >> Contributed-under: TianoCore Contribution Agreement 1.1 >> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> >> --- >> v1 -> v2: >> * Add IA32 arch support (GCC toolchain only) >> * Replace hard-coded stack alignment value (16) with >> CPU_STACK_ALIGNMENT. >> * Check for proper stack and frame pointer alignments. >> * Fix initialization of UnwoundStacksCount to 1. >> * Move GetPdbFileName() to common code since it will be used by both >> IA32 and X64 implementations. > > Sorry for the delay in sending v2. It's holiday here :-) > > FWIW, I've attached two files which contain stack trace dumps of IA32 and X64 exceptions. > > The new IA32 arch support is still limited to GCC only (that is, relying on frame pointers), but I'll start investing in a new solution that would work on both MSVC and GCC toolchains -- probably this weekend. If I come up with something, I'll let you know. > > On IA32, I performed the same test as in X64 to trigger an NMI interrupt manually with: asm ("int $0x2") in PartitionDxe driver and watched out the call stack. The difference between the two dumps, regardless the CPU context, etc. is that we don't see the calls from PeiCore.dll. Then I figured out that the EIP gets a value of 0 before jumping to PartitionDxe's entry point. > > I guess that's related to the "push $0" that Andrew mentioned earlier so the debugger knows when to stop unwinding. Although I can't see a "push 0" equivalent neither in SwitchStack.nasm nor in SwitchStack.asm for X64 > -- so we're able to see the calls within PeiCore.dll. > > Thanks! > Paulo > <x64_dump.txt><ia32_dump.txt>_______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> > https://lists.01.org/mailman/listinfo/edk2-devel <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 Andrew, On Thu, November 16, 2017 3:01 am, Andrew Fish wrote: > Paulo, > > Those attached stack traces don't look right. What about the new ones? Thanks! Paulo > > Thanks, > > Andrew Fish > >> On Nov 15, 2017, at 5:46 PM, Paulo Alcantara <pcacjr@zytor.com> wrote: >> >> Hi, >> >> On 11/15/2017 11:18 PM, Paulo Alcantara wrote: >>> Hi, >>> This series adds stack trace support during a X64 CPU exception. >>> Informations like back trace, stack contents and image module names >>> (that were part of the call stack) will be dumped out. >>> We already have such support in ARM/AArch64 (IIRC) exception handling >>> (thanks to Ard), and then I thought we'd also deserve it in X64 and >>> IA-32 platforms. >>> What do you think guys? >>> BTW, I've tested this only with OVMF (X64 only), using: >>> - gcc-6.3.0, GCC5, NOOPT >>> Any other tests would be really appreciable. >>> Thanks! >>> Paulo >>> Repo: https://github.com/pcacjr/edk2.git >>> Branch: stacktrace_v2 >>> Cc: Rick Bramley <richard.bramley@hp.com> >>> Cc: Andrew Fish <afish@apple.com> >>> Cc: Eric Dong <eric.dong@intel.com> >>> Cc: Laszlo Ersek <lersek@redhat.com> >>> Cc: "Brian J. Johnson" <brian.johnson@hpe.com> >>> Cc: Jeff Fan <jeff.fan@intel.com> >>> Contributed-under: TianoCore Contribution Agreement 1.1 >>> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> >>> --- >>> v1 -> v2: >>> * Add IA32 arch support (GCC toolchain only) >>> * Replace hard-coded stack alignment value (16) with >>> CPU_STACK_ALIGNMENT. >>> * Check for proper stack and frame pointer alignments. >>> * Fix initialization of UnwoundStacksCount to 1. >>> * Move GetPdbFileName() to common code since it will be used by both >>> IA32 and X64 implementations. >> >> Sorry for the delay in sending v2. It's holiday here :-) >> >> FWIW, I've attached two files which contain stack trace dumps of IA32 >> and X64 exceptions. >> >> The new IA32 arch support is still limited to GCC only (that is, relying >> on frame pointers), but I'll start investing in a new solution that >> would work on both MSVC and GCC toolchains -- probably this weekend. If >> I come up with something, I'll let you know. >> >> On IA32, I performed the same test as in X64 to trigger an NMI interrupt >> manually with: asm ("int $0x2") in PartitionDxe driver and watched out >> the call stack. The difference between the two dumps, regardless the CPU >> context, etc. is that we don't see the calls from PeiCore.dll. Then I >> figured out that the EIP gets a value of 0 before jumping to >> PartitionDxe's entry point. >> >> I guess that's related to the "push $0" that Andrew mentioned earlier so >> the debugger knows when to stop unwinding. Although I can't see a "push >> 0" equivalent neither in SwitchStack.nasm nor in SwitchStack.asm for X64 >> -- so we're able to see the calls within PeiCore.dll. >> >> Thanks! >> Paulo >> <x64_dump.txt><ia32_dump.txt>_______________________________________________ >> edk2-devel mailing list >> edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >> https://lists.01.org/mailman/listinfo/edk2-devel >> <https://lists.01.org/mailman/listinfo/edk2-devel> > -- Paulo Alcantara, HP Inc. Speaking for myself only.!!!! IA32 Exception Type - 03(#BP - Breakpoint) CPU Apic ID - 00000000 !!!! EIP - 7DBCD580, CS - 00000010, EFLAGS - 00000206 EAX - 00000000, ECX - 7EEC8CFF, EDX - 7ED9C220, EBX - 00000000 ESP - 7EEC8DDC, EBP - 7EEC8DDC, ESI - 00000004, EDI - 00000000 DS - 00000008, ES - 00000008, FS - 00000008, GS - 00000008, SS - 00000008 CR0 - 00000033, CR2 - 00000000, CR3 - 00000000, CR4 - 00000640 DR0 - 00000000, DR1 - 00000000, DR2 - 00000000, DR3 - 00000000 DR6 - FFFF0FF0, DR7 - 00000400 GDTR - 7EE97A90 00000047, IDTR - 7E65B010 000007FF LDTR - 00000000, TR - 00000000 FXSAVE_STATE - 7EEC8B20 Call trace: 0 0x7DBCD580 @ 0x7DBCD000+0x57F (0x7EEC8DDC) in PartitionDxe.dll 1 0x7DBD41BE @ 0x7DBCD000+0x71BD (0x7EEC8DFC) in PartitionDxe.dll 2 0x7DBD456C @ 0x7DBCD000+0x756B (0x7EEC8E1C) in PartitionDxe.dll 3 0x7DBCF7F4 @ 0x7DBCD000+0x27F3 (0x7EEC8E4C) in PartitionDxe.dll 4 0x7EED9EA4 @ 0x7EEC9000+0x10EA3 (0x7EEC8E9C) in DxeCore.dll 5 0x7EEF1A8C @ 0x7EEC9000+0x28A8B (0x7EEC8EDC) in DxeCore.dll 6 0x7EEF3DD0 @ 0x7EEC9000+0x2ADCF (0x7EEC8FAC) in DxeCore.dll 7 0x7EEF44A5 @ 0x7EEC9000+0x2B4A4 (0x7EEC8FCC) in DxeCore.dll 8 0x7EECD272 @ 0x7EEC9000+0x4271 (0x7EEC8FEC) in DxeCore.dll PartitionDxe.dll (ImageBase=0x7DBCD000, EntryPoint=0x7DBCF71B): /home/pcacjr/src/edk2/Build/OvmfIa32/NOOPT_GCC5/IA32/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe/DEBUG/PartitionDxe.dll DxeCore.dll (ImageBase=0x7EEC9000, EntryPoint=0x7EECD259): /home/pcacjr/src/edk2/Build/OvmfIa32/NOOPT_GCC5/IA32/MdeModulePkg/Core/Dxe/DxeMain/DEBUG/DxeCore.dll Stack dump: 0x7EEC8DDC: 7EEC8DFC 7DBD41BE 0x7EEC8DE0: 7DBD41BE 7EAA1690 0x7EEC8DE4: 7EAA1690 7EEFC520 0x7EEC8DE8: 7EEFC520 7EEC8E1C 0x7EEC8DEC: 7EEC8E1C 7DBD44EA 0x7EEC8DF0: 7DBD44EA 7E10E010 0x7EEC8DF4: 7E10E010 7EE97010 0x7EEC8DF8: 7EE97010 7EEC8E1C 0x7EEC8DFC: 7EEC8E1C 7DBD456C!!!! X64 Exception Type - 03(#BP - Breakpoint) CPU Apic ID - 00000000 !!!! RIP - 000000007EC28791, CS - 0000000000000038, RFLAGS - 0000000000000202 RAX - 000000007FE71018, RCX - 000000007F34F498, RDX - 000000007FE71018 RBX - 0000000000810248, RSP - 000000007FEE4C60, RBP - 000000007FEE4C60 RSI - 0000000000000007, RDI - 000000007F34E018 R8 - 000000007EC32DC8, R9 - 000000007F34E298, R10 - 0000000000000036 R11 - 00000000000000D7, R12 - 0000000000000000, R13 - 0000000000000000 R14 - 0000000000000000, R15 - 0000000000000000 DS - 0000000000000030, ES - 0000000000000030, FS - 0000000000000030 GS - 0000000000000030, SS - 0000000000000030 CR0 - 0000000080010033, CR2 - 0000000000000000, CR3 - 000000007FE83000 CR4 - 0000000000000668, CR8 - 0000000000000000 DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000 DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400 GDTR - 000000007FE71A98 0000000000000047, LDTR - 0000000000000000 IDTR - 000000007F7AB018 0000000000000FFF, TR - 0000000000000000 FXSAVE_STATE - 000000007FEE48C0 Call trace: 0 0x000000007EC28791 @ 0x000000007EC28000+0x790 (0x000000007FEE4C60) in PartitionDxe.dll 1 0x000000007EC30269 @ 0x000000007EC28000+0x8268 (0x000000007FEE4CB0) in PartitionDxe.dll 2 0x000000007EC30640 @ 0x000000007EC28000+0x863F (0x000000007FEE4CE0) in PartitionDxe.dll 3 0x000000007EC2B116 @ 0x000000007EC28000+0x3115 (0x000000007FEE4D20) in PartitionDxe.dll 4 0x000000007FEF8A1B @ 0x000000007FEE5000+0x13A1A (0x000000007FEE4DB0) in DxeCore.dll 5 0x000000007FF10F10 @ 0x000000007FEE5000+0x2BF0F (0x000000007FEE4E30) in DxeCore.dll 6 0x000000007FF1344B @ 0x000000007FEE5000+0x2E44A (0x000000007FEE4F60) in DxeCore.dll 7 0x000000007FF13BCF @ 0x000000007FEE5000+0x2EBCE (0x000000007FEE4F90) in DxeCore.dll 8 0x000000007FEE9DDE @ 0x000000007FEE5000+0x4DDD (0x000000007FEE4FC0) in DxeCore.dll 9 0x000000007FF5B75F @ 0x000000007FF5B000+0x75E (0x000000007BFDC840) in DxeIpl.dll 10 0x000000007FF61551 @ 0x000000007FF5B000+0x6550 (0x000000007BFDC8C0) in DxeIpl.dll 11 0x000000007FF6031D @ 0x000000007FF5B000+0x531C (0x000000007BFDCA30) in DxeIpl.dll 12 0x000000007FF6CDCB @ 0x000000007FF64000+0x8DCA (0x000000007BFDCF80) in PeiCore.dll 13 0x00000000008286F4 @ 0x0000000000820140+0x85B3 (0x000000007BFDD4D0) in PeiCore.dll 14 0x0000000000830940 @ 0x0000000000820140+0x107FF (0x0000000000817600) in PeiCore.dll 15 0x0000000000831585 @ 0x0000000000820140+0x11444 (0x00000000008176D0) in PeiCore.dll 16 0x0000000000828DAD @ 0x0000000000820140+0x8C6C (0x0000000000817C20) in PeiCore.dll 17 0x0000000000832392 @ 0x0000000000820140+0x12251 (0x0000000000817C50) in PeiCore.dll 18 0x0000000000824313 @ 0x0000000000820140+0x41D2 (0x0000000000817C80) in PeiCore.dll 19 0x00000000FFFD42F1 @ 0x00000000FFFCC094+0x825C (0x0000000000817CE0) in SecMain.dll 20 0x00000000FFFCF578 @ 0x00000000FFFCC094+0x34E3 (0x0000000000817D10) in SecMain.dll 21 0x00000000FFFD428C @ 0x00000000FFFCC094+0x81F7 (0x0000000000817FD0) in SecMain.dll 22 0x00000000FFFD44E9 @ 0x00000000FFFCC094+0x8454 (0x00000000FFFCC000) in SecMain.dll PartitionDxe.dll (ImageBase=0x000000007EC28000, EntryPoint=0x000000007EC2B01F): /home/pcacjr/src/edk2/Build/OvmfX64/NOOPT_GCC5/X64/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe/DEBUG/PartitionDxe.dll DxeCore.dll (ImageBase=0x000000007FEE5000, EntryPoint=0x000000007FEE9DBE): /home/pcacjr/src/edk2/Build/OvmfX64/NOOPT_GCC5/X64/MdeModulePkg/Core/Dxe/DxeMain/DEBUG/DxeCore.dll DxeIpl.dll (ImageBase=0x000000007FF5B000, EntryPoint=0x000000007FF5F87F): /home/pcacjr/src/edk2/Build/OvmfX64/NOOPT_GCC5/X64/MdeModulePkg/Core/DxeIplPeim/DxeIpl/DEBUG/DxeIpl.dll PeiCore.dll (ImageBase=0x000000007FF64000, EntryPoint=0x000000007FF681AD): /home/pcacjr/src/edk2/Build/OvmfX64/NOOPT_GCC5/X64/MdeModulePkg/Core/Pei/PeiMain/DEBUG/PeiCore.dll PeiCore.dll (ImageBase=0x0000000000820140, EntryPoint=0x00000000008242ED): /home/pcacjr/src/edk2/Build/OvmfX64/NOOPT_GCC5/X64/MdeModulePkg/Core/Pei/PeiMain/DEBUG/PeiCore.dll SecMain.dll (ImageBase=0x00000000FFFCC094, EntryPoint=0x00000000FFFD44D4): /home/pcacjr/src/edk2/Build/OvmfX64/NOOPT_GCC5/X64/OvmfPkg/Sec/SecMain/DEBUG/SecMain.dll Stack dump: 0x000000007FEE4C60: 000000007FEE4CB0 000000007EC30269 0x000000007FEE4C70: 000000007EC32B20 0000000000000000 0x000000007FEE4C80: 000000007EC32DC8 0000000000000100 0x000000007FEE4C90: 000000007FEE4CB0 0000000000000000 0x000000007FEE4CA0: 000000007FEE4CE0 000000007EC305BA 0x000000007FEE4CB0: 000000007FEE4CE0 000000007EC30640 0x000000007FEE4CC0: 000000007F34F498 000000007FE71018 0x000000007FEE4CD0: 000000077FEF88FB 0000000000000000 0x000000007FEE4CE0: 000000007FEE4D20 000000007EC2B116 0x000000007FEE4CF0: 000000007F34F498 000000007FE71018 0x000000007FEE4D00: 0000000000000000 0000000000000000 0x000000007FEE4D10: 0000000000000000 0000000000000000 0x000000007FEE4D20: 000000007FEE4DB0 000000007FEF8A1B 0x000000007FEE4D30: 000000007F34F498 000000007FE71018 0x000000007FEE4D40: 0000000000000000 0000000000000004 0x000000007FEE4D50: 000000007FF1C1A8 000000007FF1CF90 0x000000007FEE4D60: 000000007FEE4DB0 0000000000000000 0x000000007FEE4D70: 000000007FF1C180 00000000000000B0 0x000000007FEE4D80: 0000000000000000 000000007F34E018 0x000000007FEE4D90: 000000007F34F498 0000000000000000 0x000000007FEE4DA0: 000000007FF1C1A8 000000007FF1CF90 0x000000007FEE4DB0: 000000007FEE4E30 000000007FF10F10 0x000000007FEE4DC0: 000000007F34F498 0000000000000000_______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi, This series adds stack trace support during a X64 CPU exception. Informations like back trace, stack contents and image module names (that were part of the call stack) will be dumped out. We already have such support in ARM/AArch64 (IIRC) exception handling (thanks to Ard), and then I thought we'd also deserve it in X64 and IA-32 platforms. What do you think guys? BTW, I've tested this only with OVMF (X64 only), using: - gcc-6.3.0, GCC5, NOOPT Any other tests would be really appreciable. Thanks! Paulo Repo: https://github.com/pcacjr/edk2.git Branch: stacktrace_v2 Cc: Rick Bramley <richard.bramley@hp.com> Cc: Andrew Fish <afish@apple.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: brian.johnson@hpe.com Cc: jiewen.yao@intel.com Cc: Jeff Fan <jeff.fan@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> --- v1 -> v2: * Add IA32 arch support (GCC toolchain only) * Replace hard-coded stack alignment value (16) with CPU_STACK_ALIGNMENT. * Check for proper stack and frame pointer alignments. * Fix initialization of UnwoundStacksCount to 1. * Move GetPdbFileName() to common code since it will be used by both IA32 and X64 implementations. v2 -> v3: * Fixed wrong assumption about "RIP < ImageBase" to start searching for another PE/COFF image. That is, RIP may point to lower and higher addresses for any other PE/COFF images. Both IA32 & X64. (Thanks Andrew & Jiewen) * Fixed typo: unwond -> unwound. Both IA32 & X64. (Thanks Brian) Brian: I didn't have a chance to investigate on how to validate the RIP and RSP values yet as you've suggested, sorry. But I will any time soon. NOTE: This RFC for stack trace in IA32 & X64 supports *only* GCC at the moment. Paulo Alcantara (3): UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support UefiCpuPkg/CpuExceptionHandlerLib: Export GetPdbFileName() UefiCpuPkg/CpuExceptionHandlerLib/Ia32: Add stack trace support UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c | 102 ++++--- UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h | 25 +- UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c | 310 ++++++++++++++++++- UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 317 +++++++++++++++++++- 4 files changed, 696 insertions(+), 58 deletions(-) -- 2.14.3 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
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 | 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 65f0cff680..fe776ccc2d 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.
@@ -242,6 +247,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.
@@ -254,9 +610,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 don't understand why you - 1 when calculating EIP offset in image, it confused me.
+ 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
+ );
+
Jeff
________________________________
发件人: edk2-devel <edk2-devel-bounces@lists.01.org> 代表 Paulo Alcantara <pcacjr@zytor.com>
发送时间: 2017年11月17日 5:56
收件人: edk2-devel@lists.01.org
抄送: Laszlo Ersek; Eric Dong
主题: [edk2] [RFC v3 1/3] 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 <pcacjr@zytor.com>
---
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 65f0cff680..fe776ccc2d 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.
@@ -242,6 +247,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.
@@ -254,9 +610,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 Info Page - 01.org<https://lists.01.org/mailman/listinfo/edk2-devel>
lists.01.org
Your email address: Your name (optional): You may enter a privacy password below. This provides only mild security, but should prevent others from messing ...
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Hi Jeff, (sorry for the late response) On 11/17/2017 5:24 AM, Fan Jeff wrote: > Paulo, > > > I don't understand why you - 1 when calculating EIP offset in image, it > confused me. That's an offset relative to the PE/COFF image base: 0 - (ImageBase + ImageBaseSize - 1) Doesn't that look right to you? Thanks Paulo > > > + 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 > + ); > + > > Jeff > > > > > ------------------------------------------------------------------------ > *发件人:* edk2-devel <edk2-devel-bounces@lists.01.org> 代表 Paulo > Alcantara <pcacjr@zytor.com> > *发送时间:* 2017年11月17日 5:56 > *收件人:* edk2-devel@lists.01.org > *抄送:* Laszlo Ersek; Eric Dong > *主题:* [edk2] [RFC v3 1/3] 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 <pcacjr@zytor.com> > --- > 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 65f0cff680..fe776ccc2d 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. > @@ -242,6 +247,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. > > @@ -254,9 +610,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 Info Page - 01.org > <https://lists.01.org/mailman/listinfo/edk2-devel> > lists.01.org > Your email address: Your name (optional): You may enter a privacy > password below. This provides only mild security, but should prevent > others from messing ... > > > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi Paulo, I’d like to clarify my question. The following call trace information is abstracted from your x64 dump contents. Call trace: 0 0x7DBCD580 @ 0x7DBCD000+0x57F (0x7EEC8DDC) in PartitionDxe.dll 1 0x7DBD41BE @ 0x7DBCD000+0x71BD (0x7EEC8DFC) in PartitionDxe.dll I guess you used CpuBreakpoint() to do your validation. For 0x7DBCD580, it is return address followed by “int 3” from your case. If we dump obj file, we would see the following asm code. 000000007DBCD57F: CC int 3 000000007DBCD580: C3 ret (On case 0, the code at offset 0x57F is int 3) 000000007DBD41B9: E8 AF 2A 00 00 call CpuBreakpoint 000000007DBD41BE: XX XX XX XX XXX XXXXXX (On case 1, what’s the code at offset 0x71BD??) If the upper asm code is not correct, please copy your obj file here. If the upper asm code is correct, I think we should show the return address as below, since we cannot calculate the calling IP address on most cases. (return address �C 1 is not always the calling IP address on IA arch). 0 0x7DBCD580 @ 0x7DBCD000+0x580 (0x7EEC8DDC) in PartitionDxe.dll 1 0x7DBD41BE @ 0x7DBCD000+0x71BE (0x7EEC8DFC) in PartitionDxe.dll Thanks! Jeff ________________________________ From: Paulo Alcantara <pcacjr@zytor.com> Sent: Monday, November 20, 2017 10:59:41 PM To: Fan Jeff; edk2-devel@lists.01.org Cc: Laszlo Ersek; Eric Dong Subject: Re: 答复: [edk2] [RFC v3 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support Hi Jeff, (sorry for the late response) On 11/17/2017 5:24 AM, Fan Jeff wrote: > Paulo, > > > I don't understand why you - 1 when calculating EIP offset in image, it > confused me. That's an offset relative to the PE/COFF image base: 0 - (ImageBase + ImageBaseSize - 1) Doesn't that look right to you? Thanks Paulo > > > + 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 > + ); > + > > Jeff > > > > > ------------------------------------------------------------------------ > *发件人:* edk2-devel <edk2-devel-bounces@lists.01.org> 代表 Paulo > Alcantara <pcacjr@zytor.com> > *发送时间:* 2017年11月17日 5:56 > *收件人:* edk2-devel@lists.01.org > *抄送:* Laszlo Ersek; Eric Dong > *主题:* [edk2] [RFC v3 1/3] 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 <pcacjr@zytor.com> > --- > 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 65f0cff680..fe776ccc2d 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. > @@ -242,6 +247,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. > > @@ -254,9 +610,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 Info Page - 01.org > <https://lists.01.org/mailman/listinfo/edk2-devel> > lists.01.org > Your email address: Your name (optional): You may enter a privacy > password below. This provides only mild security, but should prevent > others from messing ... > > > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
> On Nov 23, 2017, at 6:27 AM, Fan Jeff <vanjeff_919@hotmail.com <mailto:vanjeff_919@hotmail.com>> wrote: > > Hi Paulo, > > > > I’d like to clarify my question. > > The following call trace information is abstracted from your x64 dump contents. > > Call trace: > > 0 0x7DBCD580 @ 0x7DBCD000+0x57F (0x7EEC8DDC) in PartitionDxe.dll > > 1 0x7DBD41BE @ 0x7DBCD000+0x71BD (0x7EEC8DFC) in PartitionDxe.dll > > > > I guess you used CpuBreakpoint() to do your validation. > > For 0x7DBCD580, it is return address followed by “int 3” from your case. > > If we dump obj file, we would see the following asm code. > > 000000007DBCD57F: CC int 3 > > 000000007DBCD580: C3 ret > Jeff, Can you walk the stack without a frame pointer? I don't think the common nasm code supports that. For x86 GCC and clang use %rbp as the frame pointer. The common nasm code may be why his walk is off? As you can see when emit frame pointer is on you get: pushq %rbp movq %rsp, %rbp ... popq %rbp retq vs. this without the frame pointer, like your example above. ... retq Without a frame pointer you need debug symbols as you don't know how deep the return address is on the stack in any given location in a function. Simple frame pointer example with clang: ~/work/Compiler>cat breakpoint.c void CpuBreakpoint ( void ) { __asm__ __volatile__ ("int $3"); } ~/work/Compiler>clang breakpoint.c -S ~/work/Compiler>cat breakpoint.S .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _CpuBreakpoint .p2align 4, 0x90 _CpuBreakpoint: ## @CpuBreakpoint .cfi_startproc ## BB#0: pushq %rbp Lcfi0: .cfi_def_cfa_offset 16 Lcfi1: .cfi_offset %rbp, -16 movq %rsp, %rbp Lcfi2: .cfi_def_cfa_register %rbp ## InlineAsm Start int3 ## InlineAsm End popq %rbp retq .cfi_endproc .subsections_via_symbols ~/work/Compiler> Thanks, Andrew Fish PS some lldb Python that walks an x86 stack frame, assuming you have a stack pointer. Given dereferencing a non-canonical addresses causes a General Protection fault it is good to error check for them if your stack walk code can not tolerate exceptions. EFI_BAD_POINTER, aka 0xAFAFAFAFAFAFAFAF, is the most common thing you hit (Thanks to Vincent Zimmer making sure EFI faults have my initials in them, not to mention the header for TE images is VZ). def NotCanonicalAddress(addr, start=0x00007FFFFFFFFFFF, end=0xFF800000000000000): return addr > start and addr < end def print_raw_stacktrace(debugger, fp, pc, address = 0, verbose = False): # Do a raw stack trace stride =4 SBTarget = debugger.GetSelectedTarget() if SBTarget: Triple = SBTarget.triple if Triple.find ("x86_64") != -1: stride = 8 frame_num = 0 if address != 0: frame_addr = readPointer (debugger, address + 0) frame_pc = readPointer (debugger, address + stride) else: frame_addr = fp frame_pc = pc while frame_num < 50: print "0x%x: 0x%x: %s" % (frame_addr, frame_pc, disassembleInstruction (debugger, frame_pc)) if verbose: str = efiSymbolicate (debugger, None, frame_pc, False) if str != '': print " %s" % str frame_pc = readPointer (debugger, frame_addr + stride) frame_addr = readPointer (debugger, frame_addr + 0) frame_num += 1 if frame_pc == 0: break if NotCanonicalAddress(frame_pc) or NotCanonicalAddress(frame_addr): break return frame_num > (On case 0, the code at offset 0x57F is int 3) > > 000000007DBD41B9: E8 AF 2A 00 00 call CpuBreakpoint > > 000000007DBD41BE: XX XX XX XX XXX XXXXXX > > (On case 1, what’s the code at offset 0x71BD??) > > > > If the upper asm code is not correct, please copy your obj file here. > > > > If the upper asm code is correct, I think we should show the return address as below, since we cannot calculate the calling IP address on most cases. (return address – 1 is not always the calling IP address on IA arch). > > 0 0x7DBCD580 @ 0x7DBCD000+0x580 (0x7EEC8DDC) in PartitionDxe.dll > > 1 0x7DBD41BE @ 0x7DBCD000+0x71BE (0x7EEC8DFC) in PartitionDxe.dll > > > > Thanks! > > Jeff > > > > ________________________________ > From: Paulo Alcantara <pcacjr@zytor.com <mailto:pcacjr@zytor.com>> > Sent: Monday, November 20, 2017 10:59:41 PM > To: Fan Jeff; edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> > Cc: Laszlo Ersek; Eric Dong > Subject: Re: 答复: [edk2] [RFC v3 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support > > Hi Jeff, > > (sorry for the late response) > > On 11/17/2017 5:24 AM, Fan Jeff wrote: >> Paulo, >> >> >> I don't understand why you - 1 when calculating EIP offset in image, it >> confused me. > > That's an offset relative to the PE/COFF image base: 0 - (ImageBase + > ImageBaseSize - 1) > > Doesn't that look right to you? > > Thanks > Paulo > >> >> >> + 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 >> + ); >> + >> >> Jeff >> >> >> >> >> ------------------------------------------------------------------------ >> *发件人:* edk2-devel <edk2-devel-bounces@lists.01.org <mailto:edk2-devel-bounces@lists.01.org>> 代表 Paulo >> Alcantara <pcacjr@zytor.com <mailto:pcacjr@zytor.com>> >> *发送时间:* 2017年11月17日 5:56 >> *收件人:* edk2-devel@lists.01.org <mailto:edk2-devel@lists.01.org> >> *抄送:* Laszlo Ersek; Eric Dong >> *主题:* [edk2] [RFC v3 1/3] 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 <mailto:eric.dong@intel.com>> >> Cc: Laszlo Ersek <lersek@redhat.com <mailto:lersek@redhat.com>> >> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com <mailto:pcacjr@zytor.com>> >> --- >> 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 65f0cff680..fe776ccc2d 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. >> @@ -242,6 +247,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. >> >> @@ -254,9 +610,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 <mailto:edk2-devel@lists.01.org> >> https://lists.01.org/mailman/listinfo/edk2-devel >> >> edk2-devel Info Page - 01.org >> <https://lists.01.org/mailman/listinfo/edk2-devel> >> lists.01.org >> Your email address: Your name (optional): You may enter a privacy >> password below. This provides only mild security, but should prevent >> others from messing ... >> >> >> > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org <mailto: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
Andrew, I agreed msft x64 compiler would not use ebp to save stack frame. In my part, I am trying to make use of exception data section to calculate the stack frame. I just used Paulo’s gcc x64 case to show my question on return address display issue. It maybe not a good example:) It’better Paulo could provide his gcc reassembly code. Thanks! Jeff 发自我的 iPhone 在 2017年11月24日,上午2:34,Andrew Fish <afish@apple.com<mailto:afish@apple.com>> 写道: On Nov 23, 2017, at 6:27 AM, Fan Jeff <vanjeff_919@hotmail.com<mailto:vanjeff_919@hotmail.com>> wrote: Hi Paulo, I’d like to clarify my question. The following call trace information is abstracted from your x64 dump contents. Call trace: 0 0x7DBCD580 @ 0x7DBCD000+0x57F (0x7EEC8DDC) in PartitionDxe.dll 1 0x7DBD41BE @ 0x7DBCD000+0x71BD (0x7EEC8DFC) in PartitionDxe.dll I guess you used CpuBreakpoint() to do your validation. For 0x7DBCD580, it is return address followed by “int 3” from your case. If we dump obj file, we would see the following asm code. 000000007DBCD57F: CC int 3 000000007DBCD580: C3 ret Jeff, Can you walk the stack without a frame pointer? I don't think the common nasm code supports that. For x86 GCC and clang use %rbp as the frame pointer. The common nasm code may be why his walk is off? As you can see when emit frame pointer is on you get: pushq %rbp movq %rsp, %rbp ... popq %rbp retq vs. this without the frame pointer, like your example above. ... retq Without a frame pointer you need debug symbols as you don't know how deep the return address is on the stack in any given location in a function. Simple frame pointer example with clang: ~/work/Compiler>cat breakpoint.c void CpuBreakpoint ( void ) { __asm__ __volatile__ ("int $3"); } ~/work/Compiler>clang breakpoint.c -S ~/work/Compiler>cat breakpoint.S .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 12 .globl _CpuBreakpoint .p2align 4, 0x90 _CpuBreakpoint: ## @CpuBreakpoint .cfi_startproc ## BB#0: pushq %rbp Lcfi0: .cfi_def_cfa_offset 16 Lcfi1: .cfi_offset %rbp, -16 movq %rsp, %rbp Lcfi2: .cfi_def_cfa_register %rbp ## InlineAsm Start int3 ## InlineAsm End popq %rbp retq .cfi_endproc .subsections_via_symbols ~/work/Compiler> Thanks, Andrew Fish PS some lldb Python that walks an x86 stack frame, assuming you have a stack pointer. Given dereferencing a non-canonical addresses causes a General Protection fault it is good to error check for them if your stack walk code can not tolerate exceptions. EFI_BAD_POINTER, aka 0xAFAFAFAFAFAFAFAF, is the most common thing you hit (Thanks to Vincent Zimmer making sure EFI faults have my initials in them, not to mention the header for TE images is VZ). def NotCanonicalAddress(addr, start=0x00007FFFFFFFFFFF, end=0xFF800000000000000): return addr > start and addr < end def print_raw_stacktrace(debugger, fp, pc, address = 0, verbose = False): # Do a raw stack trace stride =4 SBTarget = debugger.GetSelectedTarget() if SBTarget: Triple = SBTarget.triple if Triple.find ("x86_64") != -1: stride = 8 frame_num = 0 if address != 0: frame_addr = readPointer (debugger, address + 0) frame_pc = readPointer (debugger, address + stride) else: frame_addr = fp frame_pc = pc while frame_num < 50: print "0x%x: 0x%x: %s" % (frame_addr, frame_pc, disassembleInstruction (debugger, frame_pc)) if verbose: str = efiSymbolicate (debugger, None, frame_pc, False) if str != '': print " %s" % str frame_pc = readPointer (debugger, frame_addr + stride) frame_addr = readPointer (debugger, frame_addr + 0) frame_num += 1 if frame_pc == 0: break if NotCanonicalAddress(frame_pc) or NotCanonicalAddress(frame_addr): break return frame_num (On case 0, the code at offset 0x57F is int 3) 000000007DBD41B9: E8 AF 2A 00 00 call CpuBreakpoint 000000007DBD41BE: XX XX XX XX XXX XXXXXX (On case 1, what’s the code at offset 0x71BD??) If the upper asm code is not correct, please copy your obj file here. If the upper asm code is correct, I think we should show the return address as below, since we cannot calculate the calling IP address on most cases. (return address – 1 is not always the calling IP address on IA arch). 0 0x7DBCD580 @ 0x7DBCD000+0x580 (0x7EEC8DDC) in PartitionDxe.dll 1 0x7DBD41BE @ 0x7DBCD000+0x71BE (0x7EEC8DFC) in PartitionDxe.dll Thanks! Jeff ________________________________ From: Paulo Alcantara <pcacjr@zytor.com<mailto:pcacjr@zytor.com>> Sent: Monday, November 20, 2017 10:59:41 PM To: Fan Jeff; edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org> Cc: Laszlo Ersek; Eric Dong Subject: Re: 答复: [edk2] [RFC v3 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support Hi Jeff, (sorry for the late response) On 11/17/2017 5:24 AM, Fan Jeff wrote: Paulo, I don't understand why you - 1 when calculating EIP offset in image, it confused me. That's an offset relative to the PE/COFF image base: 0 - (ImageBase + ImageBaseSize - 1) Doesn't that look right to you? Thanks Paulo + 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 + ); + Jeff ------------------------------------------------------------------------ *发件人:* edk2-devel <edk2-devel-bounces@lists.01.org<mailto:edk2-devel-bounces@lists.01.org>> 代表 Paulo Alcantara <pcacjr@zytor.com<mailto:pcacjr@zytor.com>> *发送时间:* 2017年11月17日 5:56 *收件人:* edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org> *抄送:* Laszlo Ersek; Eric Dong *主题:* [edk2] [RFC v3 1/3] 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<mailto:eric.dong@intel.com>> Cc: Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com<mailto:pcacjr@zytor.com>> --- 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 65f0cff680..fe776ccc2d 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. @@ -242,6 +247,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. @@ -254,9 +610,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<mailto:edk2-devel@lists.01.org> https://lists.01.org/mailman/listinfo/edk2-devel edk2-devel Info Page - 01.org<http://01.org> <https://lists.01.org/mailman/listinfo/edk2-devel> lists.01.org<http://lists.01.org> Your email address: Your name (optional): You may enter a privacy password below. This provides only mild security, but should prevent others from messing ... _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org<mailto: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
This function will be used by both IA32 and X64 exception handling in
order to print out image module names during stack unwinding.
Cc: Eric Dong <eric.dong@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
---
UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c | 60 +++++++++++++++++++-
UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h | 14 +++++
UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 59 -------------------
3 files changed, 73 insertions(+), 60 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
index dbfaae1d30..f62ab8c48c 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
@@ -54,6 +54,11 @@ CONST CHAR8 *mExceptionNameStr[] = {
#define EXCEPTION_KNOWN_NAME_NUM (sizeof (mExceptionNameStr) / sizeof (CHAR8 *))
+//
+// Unknown PDB file name
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mUnknownPdbFileName = "????";
+
/**
Get ASCII format string exception name by exception type.
@@ -177,4 +182,57 @@ ReadAndVerifyVectorInfo (
VectorInfo ++;
}
return EFI_SUCCESS;
-}
\ No newline at end of file
+}
+
+/**
+ 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.
+**/
+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;
+ }
+ }
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
index 740a58828b..042207025e 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
@@ -288,5 +288,19 @@ CommonExceptionHandlerWorker (
IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
);
+/**
+ 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.
+**/
+VOID
+GetPdbFileName (
+ IN UINTN ImageBase,
+ OUT CHAR8 **PdbAbsoluteFilePath,
+ OUT CHAR8 **PdbFileName
+ );
+
#endif
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
index fe776ccc2d..7f8ec65e1d 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
@@ -14,11 +14,6 @@
#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.
@@ -247,60 +242,6 @@ 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.
--
2.14.3
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
This patch adds stack trace support during a IA32 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/CpuExceptionCommon.c | 42 ---
UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h | 11 -
UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c | 310 +++++++++++++++++++-
3 files changed, 308 insertions(+), 55 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
index f62ab8c48c..867c5c01d6 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
@@ -109,48 +109,6 @@ InternalPrintMessage (
SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
}
-/**
- Find and display image base address and return image base and its entry point.
-
- @param CurrentEip Current instruction pointer.
-
-**/
-VOID
-DumpModuleImageInfo (
- IN UINTN CurrentEip
- )
-{
- EFI_STATUS Status;
- UINTN Pe32Data;
- VOID *PdbPointer;
- VOID *EntryPoint;
-
- Pe32Data = PeCoffSearchImageBase (CurrentEip);
- if (Pe32Data == 0) {
- InternalPrintMessage ("!!!! Can't find image information. !!!!\n");
- } else {
- //
- // Find Image Base entry point
- //
- Status = PeCoffLoaderGetEntryPoint ((VOID *) Pe32Data, &EntryPoint);
- if (EFI_ERROR (Status)) {
- EntryPoint = NULL;
- }
- InternalPrintMessage ("!!!! Find image ");
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);
- if (PdbPointer != NULL) {
- InternalPrintMessage ("%a", PdbPointer);
- } else {
- InternalPrintMessage ("(No PDB) " );
- }
- InternalPrintMessage (
- " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n",
- (VOID *) Pe32Data,
- EntryPoint
- );
- }
-}
-
/**
Read and save reserved vector information
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
index 042207025e..478374d003 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
@@ -119,17 +119,6 @@ InternalPrintMessage (
...
);
-/**
- Find and display image base address and return image base and its entry point.
-
- @param CurrentEip Current instruction pointer.
-
-**/
-VOID
-DumpModuleImageInfo (
- IN UINTN CurrentEip
- );
-
/**
Display CPU information.
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
index f2c39eb193..db8013a5af 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
@@ -210,6 +210,296 @@ DumpCpuContext (
);
}
+/**
+ 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
+ )
+{
+ UINT32 Eip;
+ UINT32 Ebp;
+ UINTN ImageBase;
+ CHAR8 *PdbFileName;
+
+ //
+ // Set current EIP address
+ //
+ Eip = SystemContext.SystemContextIa32->Eip;
+
+ //
+ // Set current frame pointer address
+ //
+ Ebp = SystemContext.SystemContextIa32->Ebp;
+
+ //
+ // Check for proper frame pointer alignment
+ //
+ if (((UINTN)Ebp & (CPU_STACK_ALIGNMENT - 1)) != 0) {
+ InternalPrintMessage ("!!!! Unaligned frame pointer. !!!!\n");
+ return;
+ }
+
+ //
+ // Get initial PE/COFF image base address from current EIP
+ //
+ ImageBase = PeCoffSearchImageBase (Eip);
+ 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:
+ //
+ // # <EIP> @ <ImageBase>+<RelOffset> (EBP) in [<ModuleName> | ????]
+ //
+ InternalPrintMessage (
+ "%d 0x%08x @ 0x%08x+0x%x (0x%08x) in %a\n",
+ *UnwoundStacksCount - 1,
+ Eip,
+ ImageBase,
+ Eip - ImageBase - 1,
+ Ebp,
+ PdbFileName
+ );
+
+ //
+ // Set EIP with return address from current stack frame
+ //
+ Eip = *(UINT32 *)((UINTN)Ebp + 4);
+
+ //
+ // If EIP is zero, then stop unwinding the stack
+ //
+ if (Eip == 0) {
+ break;
+ }
+
+ //
+ // Search for the respective PE/COFF image based on EIP
+ //
+ ImageBase = PeCoffSearchImageBase (Eip);
+ if (ImageBase == 0) {
+ //
+ // Stop stack trace
+ //
+ break;
+ }
+
+ //
+ // Get PDB file name
+ //
+ GetPdbFileName (ImageBase, NULL, &PdbFileName);
+
+ //
+ // Unwind the stack
+ //
+ Ebp = *(UINT32 *)(UINTN)Ebp;
+
+ //
+ // Increment count of unwound stacks
+ //
+ (*UnwoundStacksCount)++;
+ }
+}
+
+/**
+ 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;
+ UINT32 Eip;
+ UINT32 Ebp;
+ UINTN ImageBase;
+ VOID *EntryPoint;
+ CHAR8 *PdbAbsoluteFilePath;
+ CHAR8 *PdbFileName;
+ UINTN LastImageBase;
+
+ //
+ // Set current EIP address
+ //
+ Eip = SystemContext.SystemContextIa32->Eip;
+
+ //
+ // Set current frame pointer address
+ //
+ Ebp = SystemContext.SystemContextIa32->Ebp;
+
+ //
+ // Get initial PE/COFF image base address from current EIP
+ //
+ ImageBase = PeCoffSearchImageBase (Eip);
+ 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%08x, EntryPoint=0x%08x):\n",
+ PdbFileName,
+ ImageBase,
+ (UINTN)EntryPoint
+ );
+ InternalPrintMessage ("%a\n", PdbAbsoluteFilePath);
+ }
+
+ //
+ // Walk through call stack and find next module names
+ //
+ for (;;) {
+ //
+ // Set EIP with return address from current stack frame
+ //
+ Eip = *(UINT32 *)((UINTN)Ebp + 4);
+
+ //
+ // Search for the respective PE/COFF image based on Eip
+ //
+ ImageBase = PeCoffSearchImageBase (Eip);
+ if (ImageBase == 0) {
+ //
+ // Stop stack trace
+ //
+ break;
+ }
+
+ //
+ // If EIP 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%08x, EntryPoint=0x%08x):\n",
+ PdbFileName,
+ ImageBase,
+ (UINTN)EntryPoint
+ );
+ InternalPrintMessage ("%a\n", PdbAbsoluteFilePath);
+ }
+
+ //
+ // Save last PE/COFF image base address
+ //
+ LastImageBase = ImageBase;
+ }
+
+ //
+ // Unwind the stack
+ //
+ Ebp = *(UINT32 *)(UINTN)Ebp;
+ }
+}
+
+/**
+ Dump stack contents.
+
+ @param[in] CurrentEsp Current stack pointer address.
+ @param[in] UnwoundStacksCount Count of unwound stack frames.
+**/
+STATIC
+VOID
+DumpStackContents (
+ IN UINT32 CurrentEsp,
+ IN INTN UnwoundStacksCount
+ )
+{
+ //
+ // Check for proper stack alignment
+ //
+ if (((UINTN)CurrentEsp & (CPU_STACK_ALIGNMENT - 1)) != 0) {
+ InternalPrintMessage ("!!!! Unaligned stack pointer. !!!!\n");
+ return;
+ }
+
+ //
+ // Dump out stack contents
+ //
+ InternalPrintMessage ("\nStack dump:\n");
+ while (UnwoundStacksCount-- > 0) {
+ InternalPrintMessage (
+ "0x%08x: %08x %08x\n",
+ CurrentEsp,
+ *(UINT32 *)CurrentEsp,
+ *(UINT32 *)((UINTN)CurrentEsp + 4)
+ );
+
+ //
+ // Point to next stack
+ //
+ CurrentEsp += CPU_STACK_ALIGNMENT;
+ }
+}
+
/**
Display CPU information.
@@ -222,9 +512,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 EIP
+ // Dump stack contents
//
- DumpModuleImageInfo (SystemContext.SystemContextIa32->Eip);
+ DumpStackContents (SystemContext.SystemContextIa32->Esp, UnwoundStacksCount);
}
--
2.14.3
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
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 | 369 +++++++++++++++++++-
1 file changed, 367 insertions(+), 2 deletions(-)
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 @@
#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.
@@ -242,6 +247,350 @@ 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] 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)) != 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 += 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 = 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;
+ }
+
+ //
+ // 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;
+ }
+
+ //
+ // 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;
+
+ //
+ // 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 unwond stacks
+ //
+ *UnwondStacksCount = 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",
+ *UnwondStacksCount - 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;
+ }
+
+ //
+ // 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.
@@ -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
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
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 MSVC, or GCC? 2) Would you please let us know which phase is validated? Such as PEI PreMemory, 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 code 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 fail 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 Paulo > Alcantara > Sent: Thursday, November 16, 2017 9:18 AM > To: edk2-devel@lists.01.org > Cc: Laszlo Ersek <lersek@redhat.com>; Dong, Eric <eric.dong@intel.com> > Subject: [edk2] [RFC v2 1/3] 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 <pcacjr@zytor.com> > --- > UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 369 > +++++++++++++++++++- > 1 file changed, 367 insertions(+), 2 deletions(-) > > 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 @@ > > #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. > @@ -242,6 +247,350 @@ 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] 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)) != 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 += 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 = 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; > + } > + > + // > + // 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; > + } > + > + // > + // 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; > + > + // > + // 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 unwond stacks > + // > + *UnwondStacksCount = 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", > + *UnwondStacksCount - 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; > + } > + > + // > + // 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. > > @@ -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 > > _______________________________________________ > 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 Jiewen, On Wed, November 15, 2017 11:57 pm, Yao, Jiewen wrote: > 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 > MSVC, or GCC? GCC only. This should not work on MSVC because it relies on frame pointers. > 2) Would you please let us know which phase is validated? Such as PEI > PreMemory, PEI PostMemory, DXE, SMM? DXE. I'm currently testing it by placing a random "CpuBreakpoint ()" in PartitionDxe driver. > 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 code during mode switch, etc. > I ask this because I have seen lots of discussion on sanity check, to > avoid double exception. At the moment I'm only ensuring proper aligned RSP and ESP values. But we still need to validate the RIP values, etc. as Andrew and Brian suggested. > 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 > fail to the non-present page? Sorry. I have no idea :-( I'd hope to get some help from you guys. > 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? That check was a wrong assumption that I had in the beginning. RIP may point to either lower or higher addresses where the other PE/COFF images are located. Fixed it in v3. Sorry for the delay in the response. I'm only able to work on this in my free time. Thanks! Paulo >> + // >> + // 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 >> Paulo >> Alcantara >> Sent: Thursday, November 16, 2017 9:18 AM >> To: edk2-devel@lists.01.org >> Cc: Laszlo Ersek <lersek@redhat.com>; Dong, Eric <eric.dong@intel.com> >> Subject: [edk2] [RFC v2 1/3] 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 <pcacjr@zytor.com> >> --- >> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | >> 369 >> +++++++++++++++++++- >> 1 file changed, 367 insertions(+), 2 deletions(-) >> >> 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 @@ >> >> #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. >> @@ -242,6 +247,350 @@ 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] 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)) != 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 += 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 = 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; >> + } >> + >> + // >> + // 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; >> + } >> + >> + // >> + // 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; >> + >> + // >> + // 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 unwond stacks >> + // >> + *UnwondStacksCount = 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", >> + *UnwondStacksCount - 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; >> + } >> + >> + // >> + // 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. >> >> @@ -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 >> >> _______________________________________________ >> edk2-devel mailing list >> edk2-devel@lists.01.org >> https://lists.01.org/mailman/listinfo/edk2-devel > > -- Paulo Alcantara, HP Inc. Speaking for myself only. _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Thanks for your reply. Comments below: > -----Original Message----- > From: Paulo Alcantara [mailto:pcacjr@zytor.com] > Sent: Friday, November 17, 2017 6:13 AM > To: Yao, Jiewen <jiewen.yao@intel.com> > Cc: Paulo Alcantara <pcacjr@zytor.com>; edk2-devel@lists.01.org; Laszlo Ersek > <lersek@redhat.com>; Dong, Eric <eric.dong@intel.com> > Subject: RE: [edk2] [RFC v2 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add > stack trace support > > Hi Jiewen, > > On Wed, November 15, 2017 11:57 pm, Yao, Jiewen wrote: > > 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 > > MSVC, or GCC? > > GCC only. This should not work on MSVC because it relies on frame pointers. [Jiewen] Not work is OK. But my question is more about: Have you tested? Or have you tried? Do you see basic exception information can be dumped without any problem for MSVC? Or do you see system crash immediately for MSVC? > > 2) Would you please let us know which phase is validated? Such as PEI > > PreMemory, PEI PostMemory, DXE, SMM? > > DXE. I'm currently testing it by placing a random "CpuBreakpoint ()" in > PartitionDxe driver. > [Jiewen] Ummm. Based upon the fact that the code you update may be used in all those phases. I recommend to validate them in the final patch. > > 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 code during mode switch, etc. > > I ask this because I have seen lots of discussion on sanity check, to > > avoid double exception. > > At the moment I'm only ensuring proper aligned RSP and ESP values. But we > still need to validate the RIP values, etc. as Andrew and Brian suggested. [Jiewen] OK. I look forward to seeing your patch to validate more. Same as #2. I suggest you validate all those corner cases in the final patch. > > 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 > > fail to the non-present page? > > Sorry. I have no idea :-( I'd hope to get some help from you guys. [Jiewen] One possible solution is to scan page table, before access this address, to make sure you are accessing present page. You can also filer invalid address directly by checking CPUID physical address bit before that. The invalid address will cause #GP instead of #PF. All I all, I would like to clarify the goal for exception lib: whatever exception condition the BIOS meets, the exception handler can always dump the *basic* exception information and halt. The missing of advanced symbol info is acceptable. But system crash, when we want to dump the advanced info, is not the best choice. > > 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? > > That check was a wrong assumption that I had in the beginning. RIP may > point to either lower or higher addresses where the other PE/COFF images > are located. Fixed it in v3. [Jiewen] Great. Thanks. > Sorry for the delay in the response. I'm only able to work on this in my > free time. > > Thanks! > Paulo > > >> + // > >> + // 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 > >> Paulo > >> Alcantara > >> Sent: Thursday, November 16, 2017 9:18 AM > >> To: edk2-devel@lists.01.org > >> Cc: Laszlo Ersek <lersek@redhat.com>; Dong, Eric <eric.dong@intel.com> > >> Subject: [edk2] [RFC v2 1/3] 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 <pcacjr@zytor.com> > >> --- > >> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | > >> 369 > >> +++++++++++++++++++- > >> 1 file changed, 367 insertions(+), 2 deletions(-) > >> > >> 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 @@ > >> > >> #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. > >> @@ -242,6 +247,350 @@ 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] 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)) != 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 += 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 = 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; > >> + } > >> + > >> + // > >> + // 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; > >> + } > >> + > >> + // > >> + // 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; > >> + > >> + // > >> + // 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 unwond stacks > >> + // > >> + *UnwondStacksCount = 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", > >> + *UnwondStacksCount - 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; > >> + } > >> + > >> + // > >> + // 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. > >> > >> @@ -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 > >> > >> _______________________________________________ > >> edk2-devel mailing list > >> edk2-devel@lists.01.org > >> https://lists.01.org/mailman/listinfo/edk2-devel > > > > > > > -- > Paulo Alcantara, HP Inc. > Speaking for myself only. _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi Jiewen, (sorry for the late response) On 11/17/2017 1:43 AM, Yao, Jiewen wrote: > Thanks for your reply. Comments below: > >> -----Original Message----- >> From: Paulo Alcantara [mailto:pcacjr@zytor.com] >> Sent: Friday, November 17, 2017 6:13 AM >> To: Yao, Jiewen <jiewen.yao@intel.com> >> Cc: Paulo Alcantara <pcacjr@zytor.com>; edk2-devel@lists.01.org; Laszlo Ersek >> <lersek@redhat.com>; Dong, Eric <eric.dong@intel.com> >> Subject: RE: [edk2] [RFC v2 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add >> stack trace support >> >> Hi Jiewen, >> >> On Wed, November 15, 2017 11:57 pm, Yao, Jiewen wrote: >>> 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 >>> MSVC, or GCC? >> >> GCC only. This should not work on MSVC because it relies on frame pointers. > > [Jiewen] Not work is OK. > But my question is more about: Have you tested? Or have you tried? > Do you see basic exception information can be dumped without any problem for MSVC? > Or do you see system crash immediately for MSVC? No, I haven't tried it. I built it with VS2015 and just run 'objdump -x -D' in an arbitrary .efi to check whether RBP was being used in function's prologues. They weren't and then I didn't even give it try. I'll test it though and then let you know its behavior. > > > >>> 2) Would you please let us know which phase is validated? Such as PEI >>> PreMemory, PEI PostMemory, DXE, SMM? >> >> DXE. I'm currently testing it by placing a random "CpuBreakpoint ()" in >> PartitionDxe driver. >> > > [Jiewen] Ummm. > Based upon the fact that the code you update may be used in all those phases. > I recommend to validate them in the final patch. Sure. > > >>> 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 code during mode switch, etc. >>> I ask this because I have seen lots of discussion on sanity check, to >>> avoid double exception. >> >> At the moment I'm only ensuring proper aligned RSP and ESP values. But we >> still need to validate the RIP values, etc. as Andrew and Brian suggested. > > [Jiewen] OK. I look forward to seeing your patch to validate more. > Same as #2. I suggest you validate all those corner cases in the final patch. I will for sure. > >>> 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 >>> fail to the non-present page? >> >> Sorry. I have no idea :-( I'd hope to get some help from you guys. > > > [Jiewen] One possible solution is to scan page table, before access this address, to make sure you are accessing present page. > You can also filer invalid address directly by checking CPUID physical address bit before that. The invalid address will cause #GP instead of #PF. Oh, looks like a great solution. I'll try them out and let you know if it worked. Thank you!! > > All I all, I would like to clarify the goal for exception lib: whatever exception condition the BIOS meets, the exception handler can always dump the *basic* exception information and halt. > The missing of advanced symbol info is acceptable. But system crash, when we want to dump the advanced info, is not the best choice. You're right. I'll make sure to validate it as much as possible and avoid such issues. Please, give me some more time because currently I've got pretty busy with something else. I really appreciate your help. Thanks! Paulo > > > >>> 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? >> >> That check was a wrong assumption that I had in the beginning. RIP may >> point to either lower or higher addresses where the other PE/COFF images >> are located. Fixed it in v3. > > > [Jiewen] Great. Thanks. > > >> Sorry for the delay in the response. I'm only able to work on this in my >> free time. >> >> Thanks! >> Paulo >> >>>> + // >>>> + // 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 >>>> Paulo >>>> Alcantara >>>> Sent: Thursday, November 16, 2017 9:18 AM >>>> To: edk2-devel@lists.01.org >>>> Cc: Laszlo Ersek <lersek@redhat.com>; Dong, Eric <eric.dong@intel.com> >>>> Subject: [edk2] [RFC v2 1/3] 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 <pcacjr@zytor.com> >>>> --- >>>> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | >>>> 369 >>>> +++++++++++++++++++- >>>> 1 file changed, 367 insertions(+), 2 deletions(-) >>>> >>>> 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 @@ >>>> >>>> #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. >>>> @@ -242,6 +247,350 @@ 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] 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)) != 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 += 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 = 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; >>>> + } >>>> + >>>> + // >>>> + // 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; >>>> + } >>>> + >>>> + // >>>> + // 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; >>>> + >>>> + // >>>> + // 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 unwond stacks >>>> + // >>>> + *UnwondStacksCount = 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", >>>> + *UnwondStacksCount - 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; >>>> + } >>>> + >>>> + // >>>> + // 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. >>>> >>>> @@ -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 >>>> >>>> _______________________________________________ >>>> edk2-devel mailing list >>>> edk2-devel@lists.01.org >>>> https://lists.01.org/mailman/listinfo/edk2-devel >>> >>> >> >> >> -- >> Paulo Alcantara, HP Inc. >> Speaking for myself only. > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On 11/15/2017 07:18 PM, 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 <eric.dong@intel.com> > Cc: Laszlo Ersek <lersek@redhat.com> > Signed-off-by: Paulo Alcantara <pcacjr@zytor.com> (These comments apply to patch 3/3 as well.) Typo: UnwondStacksCount should be UnwoundStacksCount It's good to check the alignment of the stack, as you're doing. But I'll reiterate that you absolutely need some better sanity checking of the stack and IP addresses before you dereference them. Remember that they could be absolutely *anything* at the entry to this code. Something caused an error, and it may have been one of those registers. Also, if the code was built with a compiler which isn't using RBP as a base pointer, RBP is unlikely to contain a stack address. That will cause issues if you use it for unwinding without a sanity check. Thanks, Brian > --- > UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 369 +++++++++++++++++++- > 1 file changed, 367 insertions(+), 2 deletions(-) > > 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 @@ > > #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. > @@ -242,6 +247,350 @@ 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] 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)) != 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 += 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 = 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; > + } > + > + // > + // 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; > + } > + > + // > + // 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; > + > + // > + // 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 unwond stacks > + // > + *UnwondStacksCount = 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", > + *UnwondStacksCount - 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; > + } > + > + // > + // 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. > > @@ -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); > } > -- Brian J. Johnson Enterprise X86 Lab Hewlett Packard Enterprise brian.johnson@hpe.com _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi Brijan, On Thu, November 16, 2017 1:43 pm, Brian J. Johnson > > (These comments apply to patch 3/3 as well.) > > Typo: UnwondStacksCount should be UnwoundStacksCount Fixed in v3. Thanks! > > It's good to check the alignment of the stack, as you're doing. But > I'll reiterate that you absolutely need some better sanity checking of > the stack and IP addresses before you dereference them. Remember that > they could be absolutely *anything* at the entry to this code. > Something caused an error, and it may have been one of those registers. Yes - you're absolutely right. I currently have no idea how to validate those values as well as didn't have time to do so. Sorry. I hope to get to it ASAP or someone could help me with that. > > Also, if the code was built with a compiler which isn't using RBP as a > base pointer, RBP is unlikely to contain a stack address. That will > cause issues if you use it for unwinding without a sanity check. Yes. I haven't figured out how to do that yet. It's also in my TODO list. Thank you very much for the suggestions! Paulo > > Thanks, > Brian > >> --- >> UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | >> 369 +++++++++++++++++++- >> 1 file changed, 367 insertions(+), 2 deletions(-) >> >> 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 @@ >> >> #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. >> @@ -242,6 +247,350 @@ 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] 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)) != 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 += 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 = 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; >> + } >> + >> + // >> + // 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; >> + } >> + >> + // >> + // 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; >> + >> + // >> + // 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 unwond stacks >> + // >> + *UnwondStacksCount = 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", >> + *UnwondStacksCount - 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; >> + } >> + >> + // >> + // 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. >> >> @@ -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); >> } >> > > > -- > Brian J. Johnson > Enterprise X86 Lab > > Hewlett Packard Enterprise > > brian.johnson@hpe.com > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel > -- Paulo Alcantara, HP Inc. Speaking for myself only. _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
This function will be used by both IA32 and X64 exception handling in
order to print out image module names during stack unwinding.
Cc: Eric Dong <eric.dong@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
---
UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c | 60 +++++++++++++++++++-
UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h | 14 +++++
UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c | 59 -------------------
3 files changed, 73 insertions(+), 60 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
index dbfaae1d30..f62ab8c48c 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
@@ -54,6 +54,11 @@ CONST CHAR8 *mExceptionNameStr[] = {
#define EXCEPTION_KNOWN_NAME_NUM (sizeof (mExceptionNameStr) / sizeof (CHAR8 *))
+//
+// Unknown PDB file name
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mUnknownPdbFileName = "????";
+
/**
Get ASCII format string exception name by exception type.
@@ -177,4 +182,57 @@ ReadAndVerifyVectorInfo (
VectorInfo ++;
}
return EFI_SUCCESS;
-}
\ No newline at end of file
+}
+
+/**
+ 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.
+**/
+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;
+ }
+ }
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
index 740a58828b..042207025e 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
@@ -288,5 +288,19 @@ CommonExceptionHandlerWorker (
IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
);
+/**
+ 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.
+**/
+VOID
+GetPdbFileName (
+ IN UINTN ImageBase,
+ OUT CHAR8 **PdbAbsoluteFilePath,
+ OUT CHAR8 **PdbFileName
+ );
+
#endif
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
index 11cd7c9e1c..ace835c02c 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
@@ -14,11 +14,6 @@
#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.
@@ -247,60 +242,6 @@ 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.
--
2.14.3
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
This patch adds stack trace support during a IA32 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/CpuExceptionCommon.c | 42 ---
UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h | 11 -
UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c | 303 +++++++++++++++++++-
3 files changed, 301 insertions(+), 55 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
index f62ab8c48c..867c5c01d6 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
@@ -109,48 +109,6 @@ InternalPrintMessage (
SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
}
-/**
- Find and display image base address and return image base and its entry point.
-
- @param CurrentEip Current instruction pointer.
-
-**/
-VOID
-DumpModuleImageInfo (
- IN UINTN CurrentEip
- )
-{
- EFI_STATUS Status;
- UINTN Pe32Data;
- VOID *PdbPointer;
- VOID *EntryPoint;
-
- Pe32Data = PeCoffSearchImageBase (CurrentEip);
- if (Pe32Data == 0) {
- InternalPrintMessage ("!!!! Can't find image information. !!!!\n");
- } else {
- //
- // Find Image Base entry point
- //
- Status = PeCoffLoaderGetEntryPoint ((VOID *) Pe32Data, &EntryPoint);
- if (EFI_ERROR (Status)) {
- EntryPoint = NULL;
- }
- InternalPrintMessage ("!!!! Find image ");
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);
- if (PdbPointer != NULL) {
- InternalPrintMessage ("%a", PdbPointer);
- } else {
- InternalPrintMessage ("(No PDB) " );
- }
- InternalPrintMessage (
- " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n",
- (VOID *) Pe32Data,
- EntryPoint
- );
- }
-}
-
/**
Read and save reserved vector information
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
index 042207025e..478374d003 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
@@ -119,17 +119,6 @@ InternalPrintMessage (
...
);
-/**
- Find and display image base address and return image base and its entry point.
-
- @param CurrentEip Current instruction pointer.
-
-**/
-VOID
-DumpModuleImageInfo (
- IN UINTN CurrentEip
- );
-
/**
Display CPU information.
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
index f2c39eb193..169a0b660e 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
@@ -210,6 +210,289 @@ DumpCpuContext (
);
}
+/**
+ 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
+ )
+{
+ UINT32 Eip;
+ UINT32 Ebp;
+ UINTN ImageBase;
+ CHAR8 *PdbFileName;
+
+ //
+ // Set current EIP address
+ //
+ Eip = SystemContext.SystemContextIa32->Eip;
+
+ //
+ // Set current frame pointer address
+ //
+ Ebp = SystemContext.SystemContextIa32->Ebp;
+
+ //
+ // Check for proper frame pointer alignment
+ //
+ if (((UINTN)Ebp & (CPU_STACK_ALIGNMENT - 1)) != 0) {
+ InternalPrintMessage ("!!!! Unaligned frame pointer. !!!!\n");
+ return;
+ }
+
+ //
+ // Get initial PE/COFF image base address from current EIP
+ //
+ ImageBase = PeCoffSearchImageBase (Eip);
+ 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 unwond stacks
+ //
+ *UnwondStacksCount = 1;
+
+ //
+ // Print out back trace
+ //
+ InternalPrintMessage ("\nCall trace:\n");
+
+ for (;;) {
+ //
+ // Print stack frame in the following format:
+ //
+ // # <EIP> @ <ImageBase>+<RelOffset> (EBP) in [<ModuleName> | ????]
+ //
+ InternalPrintMessage (
+ "%d 0x%08x @ 0x%08x+0x%x (0x%08x) in %a\n",
+ *UnwondStacksCount - 1,
+ Eip,
+ ImageBase,
+ Eip - ImageBase - 1,
+ Ebp,
+ PdbFileName
+ );
+
+ //
+ // Set EIP with return address from current stack frame
+ //
+ Eip = *(UINT32 *)((UINTN)Ebp + 4);
+
+ //
+ // If EIP is zero, then stop unwinding the stack
+ //
+ if (Eip == 0) {
+ break;
+ }
+
+ //
+ // Check if EIP is within another PE/COFF image base address
+ //
+ if (Eip < ImageBase) {
+ //
+ // Search for the respective PE/COFF image based on EIP
+ //
+ ImageBase = PeCoffSearchImageBase (Eip);
+ if (ImageBase == 0) {
+ //
+ // Stop stack trace
+ //
+ break;
+ }
+
+ //
+ // Get PDB file name
+ //
+ GetPdbFileName (ImageBase, NULL, &PdbFileName);
+ }
+
+ //
+ // Unwind the stack
+ //
+ Ebp = *(UINT32 *)(UINTN)Ebp;
+
+ //
+ // Increment count of unwond stacks
+ //
+ (*UnwondStacksCount)++;
+ }
+}
+
+/**
+ 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;
+ UINT32 Eip;
+ UINT32 Ebp;
+ UINTN ImageBase;
+ VOID *EntryPoint;
+ CHAR8 *PdbAbsoluteFilePath;
+ CHAR8 *PdbFileName;
+
+ //
+ // Set current EIP address
+ //
+ Eip = SystemContext.SystemContextIa32->Eip;
+
+ //
+ // Set current frame pointer address
+ //
+ Ebp = SystemContext.SystemContextIa32->Ebp;
+
+ //
+ // Get initial PE/COFF image base address from current EIP
+ //
+ ImageBase = PeCoffSearchImageBase (Eip);
+ 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%08x, EntryPoint=0x%08x):\n",
+ PdbFileName,
+ ImageBase,
+ (UINTN)EntryPoint
+ );
+ InternalPrintMessage ("%a\n", PdbAbsoluteFilePath);
+ }
+
+ //
+ // Walk through call stack and find next module names
+ //
+ for (;;) {
+ //
+ // Set EIP with return address from current stack frame
+ //
+ Eip = *(UINT32 *)((UINTN)Ebp + 4);
+
+ //
+ // Check if EIP is within another PE/COFF image base address
+ //
+ if (Eip < ImageBase) {
+ //
+ // Search for the respective PE/COFF image based on Eip
+ //
+ ImageBase = PeCoffSearchImageBase (Eip);
+ 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%08x, EntryPoint=0x%08x):\n",
+ PdbFileName,
+ ImageBase,
+ (UINTN)EntryPoint
+ );
+ InternalPrintMessage ("%a\n", PdbAbsoluteFilePath);
+ }
+ }
+
+ //
+ // Unwind the stack
+ //
+ Ebp = *(UINT32 *)(UINTN)Ebp;
+ }
+}
+
+/**
+ Dump stack contents.
+
+ @param[in] CurrentEsp Current stack pointer address.
+ @param[in] UnwondStacksCount Count of unwond stack frames.
+**/
+STATIC
+VOID
+DumpStackContents (
+ IN UINT32 CurrentEsp,
+ IN INTN UnwondStacksCount
+ )
+{
+ //
+ // Check for proper stack alignment
+ //
+ if (((UINTN)CurrentEsp & (CPU_STACK_ALIGNMENT - 1)) != 0) {
+ InternalPrintMessage ("!!!! Unaligned stack pointer. !!!!\n");
+ return;
+ }
+
+ //
+ // Dump out stack contents
+ //
+ InternalPrintMessage ("\nStack dump:\n");
+ while (UnwondStacksCount-- > 0) {
+ InternalPrintMessage (
+ "0x%08x: %08x %08x\n",
+ CurrentEsp,
+ *(UINT32 *)CurrentEsp,
+ *(UINT32 *)((UINTN)CurrentEsp + 4)
+ );
+
+ //
+ // Point to next stack
+ //
+ CurrentEsp += CPU_STACK_ALIGNMENT;
+ }
+}
+
/**
Display CPU information.
@@ -222,9 +505,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 EIP
+ // Dump stack contents
//
- DumpModuleImageInfo (SystemContext.SystemContextIa32->Eip);
+ DumpStackContents (SystemContext.SystemContextIa32->Esp, UnwondStacksCount);
}
--
2.14.3
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2024 Red Hat, Inc.