[edk2] [RFC v2 0/3] Stack trace support in X64 exception handling

Paulo Alcantara posted 3 patches 6 years, 5 months ago
Failed in applying to current master (apply log)
There is a newer version of this series
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(-)
[edk2] [RFC v2 0/3] Stack trace support in X64 exception handling
Posted by Paulo Alcantara 6 years, 5 months ago
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
Re: [edk2] [RFC v2 0/3] Stack trace support in X64 exception handling
Posted by Paulo Alcantara 6 years, 5 months ago
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
Re: [edk2] [RFC v2 0/3] Stack trace support in X64 exception handling
Posted by Andrew Fish 6 years, 5 months ago
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
Re: [edk2] [RFC v2 0/3] Stack trace support in X64 exception handling
Posted by Paulo Alcantara 6 years, 5 months ago
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
[edk2] [RFC v3 0/3] Stack trace support in X64 exception handling
Posted by Paulo Alcantara 6 years, 5 months ago
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
[edk2] [RFC v3 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support
Posted by Paulo Alcantara 6 years, 5 months ago
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] 答复: [RFC v3 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support
Posted by Fan Jeff 6 years, 5 months ago
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
Re: [edk2] 答复: [RFC v3 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support
Posted by Paulo Alcantara 6 years, 5 months ago
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
[edk2] 答复: 答复: [RFC v3 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support
Posted by Fan Jeff 6 years, 5 months ago
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
Re: [edk2] [RFC v3 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support
Posted by Andrew Fish 6 years, 5 months ago
> 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
Re: [edk2] [RFC v3 1/3] UefiCpuPkg/CpuExceptionHandlerLib/X64: Add stack trace support
Posted by Fan Jeff 6 years, 5 months ago
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
[edk2] [RFC v3 2/3] UefiCpuPkg/CpuExceptionHandlerLib: Export GetPdbFileName()
Posted by Paulo Alcantara 6 years, 5 months ago
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
[edk2] [RFC v3 3/3] UefiCpuPkg/CpuExceptionHandlerLib/Ia32: Add stack trace support
Posted by Paulo Alcantara 6 years, 5 months ago
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