summaryrefslogtreecommitdiff
path: root/src/debug/ee/debugger.inl
blob: 54ac8b93163b79dfcf5a36c9f42e0d15f947d5cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//*****************************************************************************
// File: debugger.inl
// 

//
// Inline definitions for the Left-Side of the CLR debugging services
// This is logically part of the header file. 
//
//*****************************************************************************

#ifndef DEBUGGER_INL_
#define DEBUGGER_INL_

//=============================================================================
// Inlined methods for Debugger.
//=============================================================================
inline bool Debugger::HasLazyData()
{
    LIMITED_METHOD_CONTRACT;
    return (m_pLazyData != NULL);
}
inline RCThreadLazyInit *Debugger::GetRCThreadLazyData()
{
    LIMITED_METHOD_CONTRACT;
    return &(GetLazyData()->m_RCThread);
}

inline DebuggerLazyInit *Debugger::GetLazyData() 
{ 
    LIMITED_METHOD_DAC_CONTRACT;
    _ASSERTE(m_pLazyData != NULL); 
    return m_pLazyData; 
}

inline DebuggerModuleTable * Debugger::GetModuleTable() 
{ 
    LIMITED_METHOD_CONTRACT;

    return m_pModules; 
}


//=============================================================================
// Inlined methods for DebuggerModule.
//=============================================================================


//-----------------------------------------------------------------------------
// Constructor for a Debugger-Module.
// @dbgtodo inspection - get rid of this entire class as we move things out-of-proc. 
//-----------------------------------------------------------------------------
inline DebuggerModule::DebuggerModule(Module *      pRuntimeModule, 
                                      DomainFile *  pDomainFile, 
                                      AppDomain *   pAppDomain) :
        m_enableClassLoadCallbacks(FALSE),
        m_pPrimaryModule(NULL),
        m_pRuntimeModule(pRuntimeModule),
        m_pRuntimeDomainFile(pDomainFile),
        m_pAppDomain(pAppDomain)
{
    LOG((LF_CORDB,LL_INFO10000, "DM::DM this:0x%x Module:0x%x DF:0x%x AD:0x%x\n",
        this, pRuntimeModule, pDomainFile, pAppDomain));

    // Pick a primary module.
    // Arguably, this could be in DebuggerModuleTable::AddModule
    PickPrimaryModule();


    // Do we have any optimized code?   
    DWORD dwDebugBits = pRuntimeModule->GetDebuggerInfoBits();
    m_fHasOptimizedCode = CORDebuggerAllowJITOpts(dwDebugBits);    

    // Dynamic modules must receive ClassLoad callbacks in order to receive metadata updates as the module
    // evolves. So we force this on here and refuse to change it for all dynamic modules.
    if (pRuntimeModule->IsReflection())
    {
        EnableClassLoadCallbacks(TRUE);
    }
}
    
//-----------------------------------------------------------------------------
// Returns true if we have any optimized code in the module.
// 
// Notes:
//    JMC-probes aren't emitted in optimized code. 
//    <TODO> Life would be nice if the Jit tracked this. </TODO>
//-----------------------------------------------------------------------------
inline bool DebuggerModule::HasAnyOptimizedCode() 
{ 
    LIMITED_METHOD_CONTRACT;
    Module * pModule = this->GetPrimaryModule()->GetRuntimeModule();    
    DWORD dwDebugBits = pModule->GetDebuggerInfoBits();
    return CORDebuggerAllowJITOpts(dwDebugBits);    
}

//-----------------------------------------------------------------------------
// Return true if we've enabled class-load callbacks.
//-----------------------------------------------------------------------------
inline BOOL DebuggerModule::ClassLoadCallbacksEnabled(void) 
{ 
    return m_enableClassLoadCallbacks; 
}

//-----------------------------------------------------------------------------
// Set whether we should enable class-load callbacks for this module.
//-----------------------------------------------------------------------------
inline void DebuggerModule::EnableClassLoadCallbacks(BOOL f) 
{ 
    if (m_enableClassLoadCallbacks != f)
    {
        if (f)
        {
            _ASSERTE(g_pDebugger != NULL);
            g_pDebugger->IncrementClassLoadCallbackCount();
        }
        else
        {
            _ASSERTE(g_pDebugger != NULL);
            g_pDebugger->DecrementClassLoadCallbackCount();
        }

        m_enableClassLoadCallbacks = f;
    }    
}

//-----------------------------------------------------------------------------
// Return the appdomain that this module exists in.
//-----------------------------------------------------------------------------
inline AppDomain* DebuggerModule::GetAppDomain() 
{
    return m_pAppDomain;
}

//-----------------------------------------------------------------------------
// Return the EE module that this module corresponds to.
//-----------------------------------------------------------------------------
inline Module * DebuggerModule::GetRuntimeModule()
{
    LIMITED_METHOD_DAC_CONTRACT;
    return m_pRuntimeModule;
}

//-----------------------------------------------------------------------------
// <TODO> (8/12/2002)
// Currently we create a new DebuggerModules for each appdomain a shared
// module lives in. We then pretend there aren't any shared modules.
// This is bad. We need to move away from this.
// Once we stop lying, then every module will be it's own PrimaryModule. :)
//
// Currently, Module* is 1:n w/ DebuggerModule. 
// We add a notion of PrimaryModule so that:
// Module* is 1:1 w/ DebuggerModule::GetPrimaryModule(); 
// This should help transition towards exposing shared modules.
// If the Runtime module is shared, then this gives a common DM.
// If the runtime module is not shared, then this is an identity function.
// </TODO>
//-----------------------------------------------------------------------------
inline DebuggerModule * DebuggerModule::GetPrimaryModule() 
{
    _ASSERTE(m_pPrimaryModule != NULL);
    return m_pPrimaryModule; 
}

//-----------------------------------------------------------------------------
// This is called by DebuggerModuleTable to set our primary module.
//-----------------------------------------------------------------------------
inline void DebuggerModule::SetPrimaryModule(DebuggerModule * pPrimary)
{
    _ASSERTE(pPrimary != NULL);
    // Our primary module must by definition refer to the same runtime module as us 
    _ASSERTE(pPrimary->GetRuntimeModule() == this->GetRuntimeModule());

    LOG((LF_CORDB, LL_EVERYTHING, "DM::SetPrimaryModule - this=%p, pPrimary=%p\n", this, pPrimary));
    m_pPrimaryModule = pPrimary;        
}

inline DebuggerEval * FuncEvalFrame::GetDebuggerEval()
{
    LIMITED_METHOD_DAC_CONTRACT;
    return m_pDebuggerEval;
}

inline unsigned FuncEvalFrame::GetFrameAttribs(void)
{
    LIMITED_METHOD_DAC_CONTRACT;

    if (GetDebuggerEval()->m_evalDuringException)
    {
        return FRAME_ATTR_NONE;
    }
    else
    {
        return FRAME_ATTR_RESUMABLE;    // Treat the next frame as the top frame.
    }
}

inline TADDR FuncEvalFrame::GetReturnAddressPtr()
{
    LIMITED_METHOD_DAC_CONTRACT;

    if (GetDebuggerEval()->m_evalDuringException)
    {
        return NULL;
    }
    else
    {
        return PTR_HOST_MEMBER_TADDR(FuncEvalFrame, this, m_ReturnAddress);
    }
}

//
// This updates the register display for a FuncEvalFrame.
//
inline void FuncEvalFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
{
    SUPPORTS_DAC;
    DebuggerEval * pDE = GetDebuggerEval();

    // No context to update if we're doing a func eval from within exception processing.
    if (pDE->m_evalDuringException)
    {
        return;
    }

#if !defined(_WIN64)
    // Reset pContext; it's only valid for active (top-most) frame.
    pRD->pContext = NULL;
#endif // !_WIN64


#ifdef _TARGET_X86_
    // Update all registers in the reg display from the CONTEXT we stored when the thread was hijacked for this func
    // eval. We have to update all registers, not just the callee saved registers, because we can hijack a thread at any
    // point for a func eval, not just at a call site.
    pRD->pEdi = &(pDE->m_context.Edi);
    pRD->pEsi = &(pDE->m_context.Esi);
    pRD->pEbx = &(pDE->m_context.Ebx);
    pRD->pEdx = &(pDE->m_context.Edx);
    pRD->pEcx = &(pDE->m_context.Ecx);
    pRD->pEax = &(pDE->m_context.Eax);
    pRD->pEbp = &(pDE->m_context.Ebp);
    pRD->SP   = (DWORD)GetSP(&pDE->m_context);
    pRD->PCTAddr = GetReturnAddressPtr();
    pRD->ControlPC = *PTR_PCODE(pRD->PCTAddr);

#elif defined(_TARGET_AMD64_)
    pRD->IsCallerContextValid = FALSE;
    pRD->IsCallerSPValid      = FALSE;        // Don't add usage of this flag.  This is only temporary.

    memcpy(pRD->pCurrentContext, &(pDE->m_context), sizeof(CONTEXT));

    pRD->pCurrentContextPointers->Rax = &(pDE->m_context.Rax);
    pRD->pCurrentContextPointers->Rcx = &(pDE->m_context.Rcx);
    pRD->pCurrentContextPointers->Rdx = &(pDE->m_context.Rdx);
    pRD->pCurrentContextPointers->R8  = &(pDE->m_context.R8);
    pRD->pCurrentContextPointers->R9  = &(pDE->m_context.R9);
    pRD->pCurrentContextPointers->R10 = &(pDE->m_context.R10);
    pRD->pCurrentContextPointers->R11 = &(pDE->m_context.R11);

    pRD->pCurrentContextPointers->Rbx = &(pDE->m_context.Rbx);
    pRD->pCurrentContextPointers->Rsi = &(pDE->m_context.Rsi);
    pRD->pCurrentContextPointers->Rdi = &(pDE->m_context.Rdi);
    pRD->pCurrentContextPointers->Rbp = &(pDE->m_context.Rbp);
    pRD->pCurrentContextPointers->R12 = &(pDE->m_context.R12);
    pRD->pCurrentContextPointers->R13 = &(pDE->m_context.R13);
    pRD->pCurrentContextPointers->R14 = &(pDE->m_context.R14);
    pRD->pCurrentContextPointers->R15 = &(pDE->m_context.R15);

    // SyncRegDisplayToCurrentContext() sets the pRD->SP and pRD->ControlPC on AMD64.
    SyncRegDisplayToCurrentContext(pRD);

#elif defined(_TARGET_ARM_)
    pRD->IsCallerContextValid = FALSE;
    pRD->IsCallerSPValid      = FALSE;        // Don't add usage of this flag.  This is only temporary.

    memcpy(pRD->pCurrentContext, &(pDE->m_context), sizeof(T_CONTEXT));
    
    pRD->pCurrentContextPointers->R4 = &(pDE->m_context.R4);
    pRD->pCurrentContextPointers->R5 = &(pDE->m_context.R5);
    pRD->pCurrentContextPointers->R6 = &(pDE->m_context.R6);
    pRD->pCurrentContextPointers->R7 = &(pDE->m_context.R7);
    pRD->pCurrentContextPointers->R8 = &(pDE->m_context.R8);
    pRD->pCurrentContextPointers->R9 = &(pDE->m_context.R9);
    pRD->pCurrentContextPointers->R10 = &(pDE->m_context.R10);
    pRD->pCurrentContextPointers->R11 = &(pDE->m_context.R11);
    pRD->pCurrentContextPointers->Lr = &(pDE->m_context.Lr);

    pRD->volatileCurrContextPointers.R0 = &(pDE->m_context.R0);
    pRD->volatileCurrContextPointers.R1 = &(pDE->m_context.R1);
    pRD->volatileCurrContextPointers.R2 = &(pDE->m_context.R2);
    pRD->volatileCurrContextPointers.R3 = &(pDE->m_context.R3);
    pRD->volatileCurrContextPointers.R12 = &(pDE->m_context.R12);

    SyncRegDisplayToCurrentContext(pRD);
#else 
    PORTABILITY_ASSERT("FuncEvalFrame::UpdateRegDisplay is not implemented on this platform.");
#endif
}

#endif  // DEBUGGER_INL_