| 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 | |