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
11struct 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
108struct 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