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: debugger.inl |
6 | // |
7 | |
8 | // |
9 | // Inline definitions for the Left-Side of the CLR debugging services |
10 | // This is logically part of the header file. |
11 | // |
12 | //***************************************************************************** |
13 | |
14 | #ifndef DEBUGGER_INL_ |
15 | #define DEBUGGER_INL_ |
16 | |
17 | //============================================================================= |
18 | // Inlined methods for Debugger. |
19 | //============================================================================= |
20 | inline bool Debugger::HasLazyData() |
21 | { |
22 | LIMITED_METHOD_CONTRACT; |
23 | return (m_pLazyData != NULL); |
24 | } |
25 | inline RCThreadLazyInit *Debugger::GetRCThreadLazyData() |
26 | { |
27 | LIMITED_METHOD_CONTRACT; |
28 | return &(GetLazyData()->m_RCThread); |
29 | } |
30 | |
31 | inline DebuggerLazyInit *Debugger::GetLazyData() |
32 | { |
33 | LIMITED_METHOD_DAC_CONTRACT; |
34 | _ASSERTE(m_pLazyData != NULL); |
35 | return m_pLazyData; |
36 | } |
37 | |
38 | inline DebuggerModuleTable * Debugger::GetModuleTable() |
39 | { |
40 | LIMITED_METHOD_CONTRACT; |
41 | |
42 | return m_pModules; |
43 | } |
44 | |
45 | |
46 | //============================================================================= |
47 | // Inlined methods for DebuggerModule. |
48 | //============================================================================= |
49 | |
50 | |
51 | //----------------------------------------------------------------------------- |
52 | // Constructor for a Debugger-Module. |
53 | // @dbgtodo inspection - get rid of this entire class as we move things out-of-proc. |
54 | //----------------------------------------------------------------------------- |
55 | inline DebuggerModule::DebuggerModule(Module * pRuntimeModule, |
56 | DomainFile * pDomainFile, |
57 | AppDomain * pAppDomain) : |
58 | m_enableClassLoadCallbacks(FALSE), |
59 | m_pPrimaryModule(NULL), |
60 | m_pRuntimeModule(pRuntimeModule), |
61 | m_pRuntimeDomainFile(pDomainFile), |
62 | m_pAppDomain(pAppDomain) |
63 | { |
64 | LOG((LF_CORDB,LL_INFO10000, "DM::DM this:0x%x Module:0x%x DF:0x%x AD:0x%x\n" , |
65 | this, pRuntimeModule, pDomainFile, pAppDomain)); |
66 | |
67 | // Pick a primary module. |
68 | // Arguably, this could be in DebuggerModuleTable::AddModule |
69 | PickPrimaryModule(); |
70 | |
71 | |
72 | // Do we have any optimized code? |
73 | DWORD dwDebugBits = pRuntimeModule->GetDebuggerInfoBits(); |
74 | m_fHasOptimizedCode = CORDebuggerAllowJITOpts(dwDebugBits); |
75 | |
76 | // Dynamic modules must receive ClassLoad callbacks in order to receive metadata updates as the module |
77 | // evolves. So we force this on here and refuse to change it for all dynamic modules. |
78 | if (pRuntimeModule->IsReflection()) |
79 | { |
80 | EnableClassLoadCallbacks(TRUE); |
81 | } |
82 | } |
83 | |
84 | //----------------------------------------------------------------------------- |
85 | // Returns true if we have any optimized code in the module. |
86 | // |
87 | // Notes: |
88 | // JMC-probes aren't emitted in optimized code. |
89 | // <TODO> Life would be nice if the Jit tracked this. </TODO> |
90 | //----------------------------------------------------------------------------- |
91 | inline bool DebuggerModule::HasAnyOptimizedCode() |
92 | { |
93 | LIMITED_METHOD_CONTRACT; |
94 | Module * pModule = this->GetPrimaryModule()->GetRuntimeModule(); |
95 | DWORD dwDebugBits = pModule->GetDebuggerInfoBits(); |
96 | return CORDebuggerAllowJITOpts(dwDebugBits); |
97 | } |
98 | |
99 | //----------------------------------------------------------------------------- |
100 | // Return true if we've enabled class-load callbacks. |
101 | //----------------------------------------------------------------------------- |
102 | inline BOOL DebuggerModule::ClassLoadCallbacksEnabled(void) |
103 | { |
104 | return m_enableClassLoadCallbacks; |
105 | } |
106 | |
107 | //----------------------------------------------------------------------------- |
108 | // Set whether we should enable class-load callbacks for this module. |
109 | //----------------------------------------------------------------------------- |
110 | inline void DebuggerModule::EnableClassLoadCallbacks(BOOL f) |
111 | { |
112 | if (m_enableClassLoadCallbacks != f) |
113 | { |
114 | if (f) |
115 | { |
116 | _ASSERTE(g_pDebugger != NULL); |
117 | g_pDebugger->IncrementClassLoadCallbackCount(); |
118 | } |
119 | else |
120 | { |
121 | _ASSERTE(g_pDebugger != NULL); |
122 | g_pDebugger->DecrementClassLoadCallbackCount(); |
123 | } |
124 | |
125 | m_enableClassLoadCallbacks = f; |
126 | } |
127 | } |
128 | |
129 | //----------------------------------------------------------------------------- |
130 | // Return the appdomain that this module exists in. |
131 | //----------------------------------------------------------------------------- |
132 | inline AppDomain* DebuggerModule::GetAppDomain() |
133 | { |
134 | return m_pAppDomain; |
135 | } |
136 | |
137 | //----------------------------------------------------------------------------- |
138 | // Return the EE module that this module corresponds to. |
139 | //----------------------------------------------------------------------------- |
140 | inline Module * DebuggerModule::GetRuntimeModule() |
141 | { |
142 | LIMITED_METHOD_DAC_CONTRACT; |
143 | return m_pRuntimeModule; |
144 | } |
145 | |
146 | //----------------------------------------------------------------------------- |
147 | // <TODO> (8/12/2002) |
148 | // Currently we create a new DebuggerModules for each appdomain a shared |
149 | // module lives in. We then pretend there aren't any shared modules. |
150 | // This is bad. We need to move away from this. |
151 | // Once we stop lying, then every module will be it's own PrimaryModule. :) |
152 | // |
153 | // Currently, Module* is 1:n w/ DebuggerModule. |
154 | // We add a notion of PrimaryModule so that: |
155 | // Module* is 1:1 w/ DebuggerModule::GetPrimaryModule(); |
156 | // This should help transition towards exposing shared modules. |
157 | // If the Runtime module is shared, then this gives a common DM. |
158 | // If the runtime module is not shared, then this is an identity function. |
159 | // </TODO> |
160 | //----------------------------------------------------------------------------- |
161 | inline DebuggerModule * DebuggerModule::GetPrimaryModule() |
162 | { |
163 | _ASSERTE(m_pPrimaryModule != NULL); |
164 | return m_pPrimaryModule; |
165 | } |
166 | |
167 | //----------------------------------------------------------------------------- |
168 | // This is called by DebuggerModuleTable to set our primary module. |
169 | //----------------------------------------------------------------------------- |
170 | inline void DebuggerModule::SetPrimaryModule(DebuggerModule * pPrimary) |
171 | { |
172 | _ASSERTE(pPrimary != NULL); |
173 | // Our primary module must by definition refer to the same runtime module as us |
174 | _ASSERTE(pPrimary->GetRuntimeModule() == this->GetRuntimeModule()); |
175 | |
176 | LOG((LF_CORDB, LL_EVERYTHING, "DM::SetPrimaryModule - this=%p, pPrimary=%p\n" , this, pPrimary)); |
177 | m_pPrimaryModule = pPrimary; |
178 | } |
179 | |
180 | inline DebuggerEval * FuncEvalFrame::GetDebuggerEval() |
181 | { |
182 | LIMITED_METHOD_DAC_CONTRACT; |
183 | return m_pDebuggerEval; |
184 | } |
185 | |
186 | inline unsigned FuncEvalFrame::GetFrameAttribs(void) |
187 | { |
188 | LIMITED_METHOD_DAC_CONTRACT; |
189 | |
190 | if (GetDebuggerEval()->m_evalDuringException) |
191 | { |
192 | return FRAME_ATTR_NONE; |
193 | } |
194 | else |
195 | { |
196 | return FRAME_ATTR_RESUMABLE; // Treat the next frame as the top frame. |
197 | } |
198 | } |
199 | |
200 | inline TADDR FuncEvalFrame::GetReturnAddressPtr() |
201 | { |
202 | LIMITED_METHOD_DAC_CONTRACT; |
203 | |
204 | if (GetDebuggerEval()->m_evalDuringException) |
205 | { |
206 | return NULL; |
207 | } |
208 | else |
209 | { |
210 | return PTR_HOST_MEMBER_TADDR(FuncEvalFrame, this, m_ReturnAddress); |
211 | } |
212 | } |
213 | |
214 | // |
215 | // This updates the register display for a FuncEvalFrame. |
216 | // |
217 | inline void FuncEvalFrame::UpdateRegDisplay(const PREGDISPLAY pRD) |
218 | { |
219 | SUPPORTS_DAC; |
220 | DebuggerEval * pDE = GetDebuggerEval(); |
221 | |
222 | // No context to update if we're doing a func eval from within exception processing. |
223 | if (pDE->m_evalDuringException) |
224 | { |
225 | return; |
226 | } |
227 | |
228 | #ifndef WIN64EXCEPTIONS |
229 | // Reset pContext; it's only valid for active (top-most) frame. |
230 | pRD->pContext = NULL; |
231 | #endif // !_WIN64 |
232 | |
233 | |
234 | #ifdef _TARGET_X86_ |
235 | // Update all registers in the reg display from the CONTEXT we stored when the thread was hijacked for this func |
236 | // eval. We have to update all registers, not just the callee saved registers, because we can hijack a thread at any |
237 | // point for a func eval, not just at a call site. |
238 | pRD->SetEdiLocation(&(pDE->m_context.Edi)); |
239 | pRD->SetEsiLocation(&(pDE->m_context.Esi)); |
240 | pRD->SetEbxLocation(&(pDE->m_context.Ebx)); |
241 | pRD->SetEdxLocation(&(pDE->m_context.Edx)); |
242 | pRD->SetEcxLocation(&(pDE->m_context.Ecx)); |
243 | pRD->SetEaxLocation(&(pDE->m_context.Eax)); |
244 | pRD->SetEbpLocation(&(pDE->m_context.Ebp)); |
245 | pRD->SP = (DWORD)GetSP(&pDE->m_context); |
246 | pRD->PCTAddr = GetReturnAddressPtr(); |
247 | pRD->ControlPC = *PTR_PCODE(pRD->PCTAddr); |
248 | |
249 | #elif defined(_TARGET_AMD64_) |
250 | pRD->IsCallerContextValid = FALSE; |
251 | pRD->IsCallerSPValid = FALSE; // Don't add usage of this flag. This is only temporary. |
252 | |
253 | memcpy(pRD->pCurrentContext, &(pDE->m_context), sizeof(CONTEXT)); |
254 | |
255 | pRD->pCurrentContextPointers->Rax = &(pDE->m_context.Rax); |
256 | pRD->pCurrentContextPointers->Rcx = &(pDE->m_context.Rcx); |
257 | pRD->pCurrentContextPointers->Rdx = &(pDE->m_context.Rdx); |
258 | pRD->pCurrentContextPointers->R8 = &(pDE->m_context.R8); |
259 | pRD->pCurrentContextPointers->R9 = &(pDE->m_context.R9); |
260 | pRD->pCurrentContextPointers->R10 = &(pDE->m_context.R10); |
261 | pRD->pCurrentContextPointers->R11 = &(pDE->m_context.R11); |
262 | |
263 | pRD->pCurrentContextPointers->Rbx = &(pDE->m_context.Rbx); |
264 | pRD->pCurrentContextPointers->Rsi = &(pDE->m_context.Rsi); |
265 | pRD->pCurrentContextPointers->Rdi = &(pDE->m_context.Rdi); |
266 | pRD->pCurrentContextPointers->Rbp = &(pDE->m_context.Rbp); |
267 | pRD->pCurrentContextPointers->R12 = &(pDE->m_context.R12); |
268 | pRD->pCurrentContextPointers->R13 = &(pDE->m_context.R13); |
269 | pRD->pCurrentContextPointers->R14 = &(pDE->m_context.R14); |
270 | pRD->pCurrentContextPointers->R15 = &(pDE->m_context.R15); |
271 | |
272 | // SyncRegDisplayToCurrentContext() sets the pRD->SP and pRD->ControlPC on AMD64. |
273 | SyncRegDisplayToCurrentContext(pRD); |
274 | |
275 | #elif defined(_TARGET_ARM_) |
276 | pRD->IsCallerContextValid = FALSE; |
277 | pRD->IsCallerSPValid = FALSE; // Don't add usage of this flag. This is only temporary. |
278 | |
279 | memcpy(pRD->pCurrentContext, &(pDE->m_context), sizeof(T_CONTEXT)); |
280 | |
281 | pRD->pCurrentContextPointers->R4 = &(pDE->m_context.R4); |
282 | pRD->pCurrentContextPointers->R5 = &(pDE->m_context.R5); |
283 | pRD->pCurrentContextPointers->R6 = &(pDE->m_context.R6); |
284 | pRD->pCurrentContextPointers->R7 = &(pDE->m_context.R7); |
285 | pRD->pCurrentContextPointers->R8 = &(pDE->m_context.R8); |
286 | pRD->pCurrentContextPointers->R9 = &(pDE->m_context.R9); |
287 | pRD->pCurrentContextPointers->R10 = &(pDE->m_context.R10); |
288 | pRD->pCurrentContextPointers->R11 = &(pDE->m_context.R11); |
289 | pRD->pCurrentContextPointers->Lr = &(pDE->m_context.Lr); |
290 | |
291 | pRD->volatileCurrContextPointers.R0 = &(pDE->m_context.R0); |
292 | pRD->volatileCurrContextPointers.R1 = &(pDE->m_context.R1); |
293 | pRD->volatileCurrContextPointers.R2 = &(pDE->m_context.R2); |
294 | pRD->volatileCurrContextPointers.R3 = &(pDE->m_context.R3); |
295 | pRD->volatileCurrContextPointers.R12 = &(pDE->m_context.R12); |
296 | |
297 | SyncRegDisplayToCurrentContext(pRD); |
298 | |
299 | #elif defined(_TARGET_ARM64_) |
300 | pRD->IsCallerContextValid = FALSE; |
301 | pRD->IsCallerSPValid = FALSE; // Don't add usage of this flag. This is only temporary. |
302 | |
303 | memcpy(pRD->pCurrentContext, &(pDE->m_context), sizeof(T_CONTEXT)); |
304 | |
305 | pRD->pCurrentContextPointers->X19 = &(pDE->m_context.X19); |
306 | pRD->pCurrentContextPointers->X20 = &(pDE->m_context.X20); |
307 | pRD->pCurrentContextPointers->X21 = &(pDE->m_context.X21); |
308 | pRD->pCurrentContextPointers->X22 = &(pDE->m_context.X22); |
309 | pRD->pCurrentContextPointers->X23 = &(pDE->m_context.X23); |
310 | pRD->pCurrentContextPointers->X24 = &(pDE->m_context.X24); |
311 | pRD->pCurrentContextPointers->X25 = &(pDE->m_context.X25); |
312 | pRD->pCurrentContextPointers->X26 = &(pDE->m_context.X26); |
313 | pRD->pCurrentContextPointers->X27 = &(pDE->m_context.X27); |
314 | pRD->pCurrentContextPointers->X28 = &(pDE->m_context.X28); |
315 | pRD->pCurrentContextPointers->Lr = &(pDE->m_context.Lr); |
316 | pRD->pCurrentContextPointers->Fp = &(pDE->m_context.Fp); |
317 | |
318 | pRD->volatileCurrContextPointers.X0 = &(pDE->m_context.X0); |
319 | pRD->volatileCurrContextPointers.X1 = &(pDE->m_context.X1); |
320 | pRD->volatileCurrContextPointers.X2 = &(pDE->m_context.X2); |
321 | pRD->volatileCurrContextPointers.X3 = &(pDE->m_context.X3); |
322 | pRD->volatileCurrContextPointers.X4 = &(pDE->m_context.X4); |
323 | pRD->volatileCurrContextPointers.X5 = &(pDE->m_context.X5); |
324 | pRD->volatileCurrContextPointers.X6 = &(pDE->m_context.X6); |
325 | pRD->volatileCurrContextPointers.X7 = &(pDE->m_context.X7); |
326 | pRD->volatileCurrContextPointers.X8 = &(pDE->m_context.X8); |
327 | pRD->volatileCurrContextPointers.X9 = &(pDE->m_context.X9); |
328 | pRD->volatileCurrContextPointers.X10 = &(pDE->m_context.X10); |
329 | pRD->volatileCurrContextPointers.X11 = &(pDE->m_context.X11); |
330 | pRD->volatileCurrContextPointers.X12 = &(pDE->m_context.X12); |
331 | pRD->volatileCurrContextPointers.X13 = &(pDE->m_context.X13); |
332 | pRD->volatileCurrContextPointers.X14 = &(pDE->m_context.X14); |
333 | pRD->volatileCurrContextPointers.X15 = &(pDE->m_context.X15); |
334 | pRD->volatileCurrContextPointers.X16 = &(pDE->m_context.X16); |
335 | pRD->volatileCurrContextPointers.X17 = &(pDE->m_context.X17); |
336 | |
337 | SyncRegDisplayToCurrentContext(pRD); |
338 | #else |
339 | PORTABILITY_ASSERT("FuncEvalFrame::UpdateRegDisplay is not implemented on this platform." ); |
340 | #endif |
341 | } |
342 | |
343 | #endif // DEBUGGER_INL_ |
344 | |