summaryrefslogtreecommitdiff
path: root/src/vm/debugdebugger.h
blob: dc71a3d3db6253365a0a01fd604cb242c38c71a3 (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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

/*============================================================
**
** Header: DebugDebugger.h
**
** Purpose: Native methods on System.Debug.Debugger
**
**

===========================================================*/

#ifndef __DEBUG_DEBUGGER_h__
#define __DEBUG_DEBUGGER_h__
#include <object.h>


// ! WARNING !
// The following constants mirror the constants 
// declared in the class LoggingLevelEnum in the 
// System.Diagnostic package. Any changes here will also
// need to be made there.
#define     TraceLevel0     0
#define     TraceLevel1     1
#define     TraceLevel2     2
#define     TraceLevel3     3
#define     TraceLevel4     4
#define     StatusLevel0    20
#define     StatusLevel1    21
#define     StatusLevel2    22
#define     StatusLevel3    23
#define     StatusLevel4    24
#define     WarningLevel    40
#define     ErrorLevel      50
#define     PanicLevel      100

// ! WARNING !
// The following constants mirror the constants 
// declared in the class AssertLevelEnum in the 
// System.Diagnostic package. Any changes here will also
// need to be made there.
#define     FailDebug           0
#define     FailIgnore          1
#define     FailTerminate       2
#define     FailContinueFilter  3

#define     MAX_LOG_SWITCH_NAME_LEN     256

class DebugDebugger
{
public:
    static FCDECL0(void,  Break);
    static FCDECL0(FC_BOOL_RET, Launch);
    static FCDECL0(FC_BOOL_RET, IsDebuggerAttached);
    static FCDECL3(void,  Log, INT32 Level, StringObject* strModule, StringObject* strMessage);

    // receives a custom notification object from the target and sends it to the RS via 
    // code:Debugger::SendCustomDebuggerNotification
    static FCDECL1(void,  CustomNotification, Object * dataUNSAFE); 

    static FCDECL0(FC_BOOL_RET, IsLogging);

protected:
    static BOOL IsLoggingHelper();
};




class StackFrameHelper:public Object
{
    // READ ME:
    // Modifying the order or fields of this object may require other changes to the
    // classlib defintion of the StackFrameHelper class.
public:
    THREADBASEREF TargetThread;
    I4ARRAYREF rgiOffset;
    I4ARRAYREF rgiILOffset;
    BASEARRAYREF rgMethodBase; 
    PTRARRAYREF dynamicMethods;    
    BASEARRAYREF rgMethodHandle; 
    PTRARRAYREF rgFilename;
    I4ARRAYREF rgiLineNumber;
    I4ARRAYREF rgiColumnNumber;
#if defined(FEATURE_EXCEPTIONDISPATCHINFO)
    BOOLARRAYREF rgiLastFrameFromForeignExceptionStackTrace;
#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO)
    int iFrameCount;
    CLR_BOOL fNeedFileInfo;

protected:
    StackFrameHelper() {}
    ~StackFrameHelper() {}

public:
    void SetFrameCount (int iCount) 
    { 
        iFrameCount = iCount;
    }

    int  GetFrameCount (void) 
    { 
        return iFrameCount;
    }

};

#ifdef USE_CHECKED_OBJECTREFS
typedef REF <StackFrameHelper> STACKFRAMEHELPERREF;
#else
typedef StackFrameHelper* STACKFRAMEHELPERREF;
#endif


class DebugStackTrace
{   
public:

#ifndef DACCESS_COMPILE
// the DAC directly uses the GetStackFramesData and DebugStackTraceElement types
private:
#endif // DACCESS_COMPILE
    struct DebugStackTraceElement {
        DWORD dwOffset;  // native offset
        DWORD dwILOffset;
        MethodDesc *pFunc;
        PCODE ip;
#if defined(FEATURE_EXCEPTIONDISPATCHINFO)
        // TRUE if this element represents the last frame of the foreign
        // exception stack trace.
        BOOL			fIsLastFrameFromForeignStackTrace;
#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO)

        // Initialization done under TSL.
        // This is used when first collecting the stack frame data.
        void InitPass1(
            DWORD dwNativeOffset,
            MethodDesc *pFunc,
            PCODE ip
#if defined(FEATURE_EXCEPTIONDISPATCHINFO)
            , BOOL			fIsLastFrameFromForeignStackTrace = FALSE
#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO)
			);

        // Initialization done outside the TSL.
        // This will init the dwILOffset field (and potentially anything else
        // that can't be done under the TSL).
        void InitPass2();
    };

public:

    struct GetStackFramesData {

        // Used for the integer-skip version
        INT32   skip;
        INT32   NumFramesRequested;
        INT32   cElementsAllocated;
        INT32   cElements;
        DebugStackTraceElement* pElements;
        THREADBASEREF   TargetThread;
        AppDomain *pDomain;
#if defined(FEATURE_EXCEPTIONDISPATCHINFO)
        BOOL	fDoWeHaveAnyFramesFromForeignStackTrace;
#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO)


        GetStackFramesData() :  skip(0), 
                                NumFramesRequested (0),
                                cElementsAllocated(0), 
                                cElements(0), 
                                pElements(NULL),
                                TargetThread((THREADBASEREF)(TADDR)NULL)
        { 
            LIMITED_METHOD_CONTRACT;
#if defined(FEATURE_EXCEPTIONDISPATCHINFO)
            fDoWeHaveAnyFramesFromForeignStackTrace = FALSE;
#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO)

        }

        ~GetStackFramesData()
        {
            delete [] pElements;
        }
    };

    static FCDECL3(void, 
                   GetStackFramesInternal, 
                   StackFrameHelper* pStackFrameHelper, 
                   INT32 iSkip, 
                   Object* pException
                  );

    static void GetStackFramesFromException(OBJECTREF * e, GetStackFramesData *pData, PTRARRAYREF * pDynamicMethodArray = NULL);

#ifndef DACCESS_COMPILE
// the DAC directly calls GetStackFramesFromException
private:
#endif
    
    static void GetStackFramesHelper(Frame *pStartFrame, void* pStopStack, GetStackFramesData *pData);

    static void GetStackFrames(Frame *pStartFrame, void* pStopStack, GetStackFramesData *pData);    

    static StackWalkAction GetStackFramesCallback(CrawlFrame* pCf, VOID* data);

};

class DebuggerAssert
{
private:

public:

    static FCDECL4(INT32, 
                   ShowDefaultAssertDialog, 
                   StringObject* strConditionUNSAFE, 
                   StringObject* strMessageUNSAFE,
                   StringObject* strStackTraceUNSAFE,
                   StringObject* strWindowTitleUNSAFE
                  );

};


// The following code is taken from object.h and modified to suit 
// LogSwitchBaseObject 
//  
class LogSwitchObject : public Object
{
  protected:
    // README:
    // Modifying the order or fields of this object may require other changes to the
    //  classlib class defintion of the LogSwitch object.

    STRINGREF m_strName;
    STRINGREF strDescription;
    OBJECTREF m_ParentSwitch;   
    INT32 m_iLevel;
    INT32 m_iOldLevel;

  protected:
    LogSwitchObject() {}
   ~LogSwitchObject() {}
   
  public:
    // check for classes that wrap Ole classes 

    void SetLevel(INT32 iLevel)
    {
        m_iLevel = iLevel;
    }

    INT32 GetLevel(void) 
    {
        return m_iLevel;
    }

    OBJECTREF GetParent (void) 
    { 
        return m_ParentSwitch;
    }

    STRINGREF GetName (void) 
    { 
        return m_strName;
    }
};

#ifdef USE_CHECKED_OBJECTREFS
typedef REF <LogSwitchObject> LOGSWITCHREF;
#else
typedef LogSwitchObject* LOGSWITCHREF;
#endif


#define MAX_KEY_LENGTH      64
#define MAX_HASH_BUCKETS    20

class HashElement
{
private:

    OBJECTHANDLE m_pData;
    SString      m_strKey;
    HashElement *m_pNext;

public:
    
    HashElement () 
    {
        LIMITED_METHOD_CONTRACT;
        m_pData = NULL;
        m_pNext = NULL;
    }

    ~HashElement()
    {
        if (m_pNext!= NULL)
        {
            delete m_pNext;
        }

        m_pNext=NULL;

    }// ~HashElement

    void SetData (OBJECTHANDLE pData, const WCHAR *pKey) 
    {
        m_pData = pData;
        m_strKey.Set(pKey);
    }

    OBJECTHANDLE GetData (void) 
    { 
        return m_pData;
    }

    const WCHAR *GetKey (void) 
    { 
        return m_strKey.GetUnicode();
    }
    
    void SetNext (HashElement *pNext) 
    { 
        m_pNext = pNext;
    }

    HashElement *GetNext (void) 
    { 
        return m_pNext;
    }

};

class LogHashTable
{
private:

    HashElement *m_Buckets [MAX_HASH_BUCKETS];

public:
    // static global object, no constructors/destructors, assumes zero initialized memory

    HRESULT AddEntryToHashTable (const WCHAR *pKey, OBJECTHANDLE pData);
    
    OBJECTHANDLE GetEntryFromHashTable (const WCHAR *pKey);
    
};

extern LogHashTable g_sLogHashTable;


class Log
{
private:

public:
    static FCDECL1(void, AddLogSwitch, LogSwitchObject * m_LogSwitch);
    
    static FCDECL3(void, 
                   ModifyLogSwitch, 
                   INT32 Level, 
                   StringObject* strLogSwitchNameUNSAFE, 
                   StringObject* strParentNameUNSAFE
                  );

    // The following method is called when the level of a log switch is modified
    // from the debugger. It is not an ecall.
    static void DebuggerModifyingLogSwitch (int iNewLevel, const WCHAR *pLogSwitchName);

};

//
// Returns a textual representation of the current stack trace. The format of the stack
// trace is the same as returned by StackTrace.ToString.
//
void GetManagedStackTraceString(BOOL fNeedFileInfo, SString &result);

#endif  // __DEBUG_DEBUGGER_h__