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// File: frameinfo.h
6//
7
8//
9// Debugger stack walker
10//
11//*****************************************************************************
12
13#ifndef FRAMEINFO_H_
14#define FRAMEINFO_H_
15
16/* ========================================================================= */
17
18/* ------------------------------------------------------------------------- *
19 * Classes
20 * ------------------------------------------------------------------------- */
21
22class DebuggerJitInfo;
23
24// struct FrameInfo: Contains the information that will be handed to
25// DebuggerStackCallback functions (along with their own, individual
26// pData pointers).
27//
28// Frame *frame: The current explicit frame. NULL implies that
29// the method frame is frameless, meaning either unmanaged or managed. This
30// is set to be FRAME_TOP (0xFFffFFff) if the frame is the topmost, EE
31// placed frame.
32//
33// MethodDesc *md: MetdhodDesc for the method that's
34// executing in this method frame. Will be NULL if there is no MethodDesc
35// If we're in generic code this may be a representative (i.e. canonical)
36// MD, and extra information is available in the exactGenericArgsToken.
37// For explicit frames, this may point to the method the explicit frame refers to
38// (i.e. the method being jitted, or the interface method being called through
39// COM interop), however it must always point to a method within the same
40// domain of the explicit frame. Therefore, it is not used to point to the target of
41// FuncEval frames since the target may be in a different domain.
42//
43// void *fp: frame pointer. Actually filled in from
44// caller (parent) frame, so the DebuggerStackWalkProc must delay
45// the user callback for one frame. This is not technically necessary on WIN64, but
46// we follow the x86 model to keep things simpler. We should really consider changing
47// the real stackwalker on x86 to unwind one frame ahead of time like the 64-bit one.
48struct FrameInfo
49{
50public:
51 Frame *frame;
52 MethodDesc *md;
53
54 // the register set of the frame being reported
55 REGDISPLAY registers;
56 FramePointer fp;
57
58 // This field is propagated to the right side to become CordbRegisterSet::m_quicklyUnwind.
59 // If it is true, then the registers reported in the REGDISPLAY are invalid. It is only set to
60 // true in InitForEnterManagedChain(). In that case, we are passing a NULL REGDISPLAY anyway.
61 // This is such a misnomer.
62 bool quickUnwind;
63
64 // Set to true if we are dealing with an internal explicit frame. Currently this is only true
65 // for prestub frames, security frames, funceval frames, and certain debugger-specific frames
66 // (e.g. DebuggerClassInitMarkFrame, DebuggerSecurityCodeMarkFrame).
67 // This affects HasMethodFrame() below.
68 bool internal;
69
70 // whether the state contained in the FrameInfo represents a managed or unmanaged method frame/stub/chain;
71 // corresponds to ICorDebugChain::IsManaged()
72 bool managed;
73
74 // Native offset from beginning of the method.
75 ULONG relOffset;
76
77 // The ambient stackpointer. This can be use to compute esp-relative local variables,
78 // which can be common in frameless methods.
79 TADDR ambientSP;
80
81 // These two fields are only set for managed method frames.
82 IJitManager *pIJM;
83 METHODTOKEN MethodToken;
84
85 // This represents the current domain of the frame itself, and which
86 // the method specified by 'md' is executing in.
87 AppDomain *currentAppDomain;
88
89 // only set for stackwalking, not stepping
90 void *exactGenericArgsToken;
91
92#if defined(WIN64EXCEPTIONS)
93 // This field is only used on IA64 to determine which registers are available and
94 // whether we need to adjust the IP.
95 bool fIsLeaf;
96
97 // These two fields are used for funclets.
98 bool fIsFunclet;
99 bool fIsFilter;
100
101 bool IsFuncletFrame() { return fIsFunclet; }
102 bool IsFilterFrame() { return fIsFilter; }
103 bool IsNonFilterFuncletFrame() { return (fIsFunclet && !fIsFilter); }
104#endif // WIN64EXCEPTIONS
105
106
107 // A ridiculous flag that is targetting a very narrow fix at issue 650903 (4.5.1/Blue).
108 // This is set when the currently walked frame is a ComPlusMethodFrameGeneric. If the
109 // dude doing the walking is trying to ignore such frames (see
110 // code:ControllerStackInfo::m_suppressUMChainFromComPlusMethodFrameGeneric), AND
111 // this is set, then the walker just continues on to the next frame, without
112 // erroneously identifying this frame as the target frame. Only used during "Step
113 // Out" to a managed frame (i.e., managed-only debugging).
114 bool fIgnoreThisFrameIfSuppressingUMChainFromComPlusMethodFrameGeneric;
115
116 // In addition to a Method, a FrameInfo may also represent either a Chain or a Stub (but not both).
117 // chainReason corresponds to ICorDebugChain::GetReason().
118 CorDebugChainReason chainReason;
119 CorDebugInternalFrameType eStubFrameType;
120
121 // Helpers for initializing a FrameInfo for a chain or a stub frame.
122 void InitForM2UInternalFrame(CrawlFrame * pCF);
123 void InitForU2MInternalFrame(CrawlFrame * pCF);
124 void InitForADTransition(CrawlFrame * pCF);
125 void InitForDynamicMethod(CrawlFrame * pCF);
126 void InitForFuncEval(CrawlFrame * pCF);
127 void InitForThreadStart(Thread *thread, REGDISPLAY * pRDSrc);
128 void InitForUMChain(FramePointer fpRoot, REGDISPLAY * pRDSrc);
129 void InitForEnterManagedChain(FramePointer fpRoot);
130
131 // Does this FrameInfo represent a method frame? (aka a frameless frame)
132 // This may be combined w/ both StubFrames and ChainMarkers.
133 bool HasMethodFrame() { return md != NULL && !internal; }
134
135 // Is this frame for a stub?
136 // This is mutually exclusive w/ Chain Markers.
137 // StubFrames may also have a method frame as a "hint". Ex, a stub frame for a
138 // M2U transition may have the Method for the Managed Wrapper for the unmanaged call.
139 // Stub frames map to internal frames on the RS. They use the same enum
140 // (CorDebugInternalFrameType) to represent the type of the frame.
141 bool HasStubFrame() { return eStubFrameType != STUBFRAME_NONE; }
142
143 // Does this FrameInfo mark the start of a new chain? (A Frame info may both
144 // start a chain and represent a method)
145 bool HasChainMarker() { return chainReason != CHAIN_NONE; }
146
147 // Helper functions for retrieving the DJI and the DMI
148 DebuggerJitInfo * GetJitInfoFromFrame();
149 DebuggerMethodInfo * GetMethodInfoFromFrameOrThrow();
150
151 // Debug helper which nops in retail; and asserts invariants in debug.
152#ifdef _DEBUG
153 void AssertValid();
154
155 // Debug helpers to get name of frame. Useful in asserts + log statements.
156 LPCUTF8 DbgGetClassName();
157 LPCUTF8 DbgGetMethodName();
158#endif
159
160protected:
161 // These are common internal helpers shared by the other Init*() helpers above.
162 void InitForScratchFrameInfo();
163 void InitFromStubHelper(CrawlFrame * pCF, MethodDesc * pMDHint, CorDebugInternalFrameType type);
164
165};
166
167//StackWalkAction (*DebuggerStackCallback): This callback will
168// be invoked by DebuggerWalkStackProc at each method frame and explicit frame, passing the FrameInfo
169// and callback-defined pData to the method. The callback then returns a
170// SWA - if SWA_ABORT is returned then the walk stops immediately. If
171// SWA_CONTINUE is called, then the frame is walked & the next higher frame
172// will be used. If the current explicit frame is at the root of the stack, then
173// in the next iteration, DSC will be invoked with FrameInfo::frame == FRAME_TOP
174typedef StackWalkAction (*DebuggerStackCallback)(FrameInfo *frame, void *pData);
175
176//StackWalkAction DebuggerWalkStack(): Sets up everything for a
177// stack walk for the debugger, starts the stack walk (via
178// g_pEEInterface->StackWalkFramesEx), then massages the output. Note that it
179// takes a DebuggerStackCallback as an argument, but at each method frame and explicit frame
180// DebuggerWalkStackProc gets called, which in turn calls the
181// DebuggerStackCallback.
182// Thread * thread: the thread on which to do a stackwalk
183// void *targetFP: If you're looking for a specific frame, then
184// this should be set to the fp for that frame, and the callback won't
185// be called until that frame is reached. Otherwise, set it to LEAF_MOST_FRAME &
186// the callback will be called on every frame.
187// CONTEXT *context: Never NULL, b/c the callbacks require the
188// CONTEXT as a place to store some information. Either it points to an
189// uninitialized CONTEXT (contextValid should be false), or
190// a pointer to a valid CONTEXT for the thread. If it's NULL, InitRegDisplay
191// will fill it in for us, so we shouldn't go out of our way to set this up.
192// bool contextValid: TRUE if context points to a valid CONTEXT, FALSE
193// otherwise.
194// DebuggerStackCallback pCallback: User supplied callback to
195// be invoked at every frame that's at targetFP or higher.
196// void *pData: User supplied data that we shuffle around,
197// and then hand to pCallback.
198// BOOL fIgnoreNonmethodFrames: Generally true for end user stackwalking (e.g. displaying a stack trace) and
199// false for stepping (e.g. stepping out).
200
201StackWalkAction DebuggerWalkStack(Thread *thread,
202 FramePointer targetFP,
203 T_CONTEXT *pContext,
204 BOOL contextValid,
205 DebuggerStackCallback pCallback,
206 void *pData,
207 BOOL fIgnoreNonmethodFrames);
208
209#endif // FRAMEINFO_H_
210