1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | #ifndef __STACKFRAME_H |
6 | #define __STACKFRAME_H |
7 | |
8 | #include "regdisp.h" |
9 | |
10 | |
11 | struct StackFrame |
12 | { |
13 | const static UINT_PTR maxVal = (UINT_PTR)(INT_PTR)-1; |
14 | StackFrame() : SP(NULL) |
15 | { |
16 | } |
17 | |
18 | StackFrame(UINT_PTR sp) |
19 | { |
20 | SP = sp; |
21 | } |
22 | |
23 | void Clear() |
24 | { |
25 | SP = NULL; |
26 | } |
27 | |
28 | void SetMaxVal() |
29 | { |
30 | SP = maxVal; |
31 | } |
32 | |
33 | bool IsNull() |
34 | { |
35 | return (SP == NULL); |
36 | } |
37 | |
38 | bool IsMaxVal() |
39 | { |
40 | return (SP == maxVal); |
41 | } |
42 | |
43 | bool operator==(StackFrame sf) |
44 | { |
45 | return (SP == sf.SP); |
46 | } |
47 | |
48 | bool operator!=(StackFrame sf) |
49 | { |
50 | return (SP != sf.SP); |
51 | } |
52 | |
53 | bool operator<(StackFrame sf) |
54 | { |
55 | return (SP < sf.SP); |
56 | } |
57 | |
58 | bool operator<=(StackFrame sf) |
59 | { |
60 | return (SP <= sf.SP); |
61 | } |
62 | |
63 | bool operator>(StackFrame sf) |
64 | { |
65 | return (SP > sf.SP); |
66 | } |
67 | |
68 | bool operator>=(StackFrame sf) |
69 | { |
70 | return (SP >= sf.SP); |
71 | } |
72 | |
73 | static inline StackFrame FromEstablisherFrame(UINT_PTR EstablisherFrame) |
74 | { |
75 | return StackFrame(EstablisherFrame); |
76 | } |
77 | |
78 | static inline StackFrame FromRegDisplay(REGDISPLAY* pRD) |
79 | { |
80 | return StackFrame(GetRegdisplaySP(pRD)); |
81 | } |
82 | |
83 | UINT_PTR SP; |
84 | }; |
85 | |
86 | |
87 | //--------------------------------------------------------------------------------------- |
88 | // |
89 | // On WIN64, all the stack range tracking done by the Exception Handling (EH) subsystem is based on the |
90 | // establisher frame given by the OS. On IA64, the establisher frame is the caller SP and the current BSP. |
91 | // On X64, it is the initial SP before any dynamic stack allocation, i.e. it is the SP when a function exits |
92 | // the prolog. The EH subsystem uses the same format. |
93 | // |
94 | // The stackwalker needs to get information from the EH subsystem in order to skip funclets. Unfortunately, |
95 | // stackwalking is based on the current SP, i.e. the SP when the control flow leaves a function via a |
96 | // function call. Thus, for stack frames with dynamic stack allocations on X64, the SP values used by the |
97 | // stackwalker and the EH subsystem don't match. |
98 | // |
99 | // To work around this problem, we need to somehow bridge the different SP values. We do so by using the |
100 | // caller SP instead of the current SP for comparisons during a stackwalk on X64. Creating a new type |
101 | // explicitly spells out the important distinction that this is NOT in the same format as the |
102 | // OS establisher frame. |
103 | // |
104 | // Notes: |
105 | // In the long term, we should look at merging the two SP formats and have one consistent abstraction. |
106 | // |
107 | |
108 | struct CallerStackFrame : StackFrame |
109 | { |
110 | CallerStackFrame() : StackFrame() |
111 | { |
112 | } |
113 | |
114 | CallerStackFrame(UINT_PTR sp) : StackFrame(sp) |
115 | { |
116 | } |
117 | |
118 | #ifdef WIN64EXCEPTIONS |
119 | static inline CallerStackFrame FromRegDisplay(REGDISPLAY* pRD) |
120 | { |
121 | _ASSERTE(pRD->IsCallerSPValid || pRD->IsCallerContextValid); |
122 | return CallerStackFrame(GetSP(pRD->pCallerContext)); |
123 | } |
124 | #endif // WIN64EXCEPTIONS |
125 | }; |
126 | |
127 | #endif // __STACKFRAME_H |
128 | |