summaryrefslogtreecommitdiff
path: root/src/debug/inc/common.h
blob: 3bbf0a6f08dabee9d49d019159b423556fc09f32 (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
// 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.

#ifndef DEBUGGER_COMMON_H
#define DEBUGGER_COMMON_H

//
// Conversions between pointers and CORDB_ADDRESS
// These are 3gb safe - we use zero-extension for CORDB_ADDRESS.
// Note that this is a different semantics from CLRDATA_ADDRESS which is sign-extended.
// 
// @dbgtodo : This confuses the host and target address spaces.  Ideally we'd have
// conversions between PTR types (eg. DPTR) and CORDB_ADDRESS, and not need conversions
// from host pointer types to CORDB_ADDRESS.
//
#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
inline CORDB_ADDRESS PTR_TO_CORDB_ADDRESS(const void* ptr)
{
    SUPPORTS_DAC;
    // Cast a void* to a ULONG is not 64-bit safe and triggers compiler warning C3411. 
    // But this is x86 only, so we know it's ok. Use PtrToUlong to do the conversion 
    // without invoking the error.
    return (CORDB_ADDRESS)(PtrToUlong(ptr));
}
inline CORDB_ADDRESS PTR_TO_CORDB_ADDRESS(UINT_PTR ptr)
{
    SUPPORTS_DAC;
    // PtrToUlong 
    return (CORDB_ADDRESS)(ULONG)(ptr);
}
#else
#define PTR_TO_CORDB_ADDRESS(_ptr) (CORDB_ADDRESS)(ULONG_PTR)(_ptr)
#endif //_TARGET_X86_ || _TARGET_ARM_

#define CORDB_ADDRESS_TO_PTR(_cordb_addr) ((LPVOID)(SIZE_T)(_cordb_addr))


// Determine if an exception record is for a CLR debug event, and get the payload.
CORDB_ADDRESS IsEventDebuggerNotification(const EXCEPTION_RECORD * pRecord, CORDB_ADDRESS pClrBaseAddress);
#if defined(FEATURE_DBGIPC_TRANSPORT_DI) || defined(FEATURE_DBGIPC_TRANSPORT_VM)
struct DebuggerIPCEvent;
void InitEventForDebuggerNotification(DEBUG_EVENT *      pDebugEvent,
                                      CORDB_ADDRESS      pClrBaseAddress,
                                      DebuggerIPCEvent * pIPCEvent);
#endif // (FEATURE_DBGIPC_TRANSPORT_DI || FEATURE_DBGIPC_TRANSPORT_VM)


void GetPidDecoratedName(__out_z __out_ecount(cBufSizeInChars) WCHAR * pBuf,
                         int cBufSizeInChars,
                         const WCHAR * pPrefix,
                         DWORD pid);


//
// This macro is used in CORDbgCopyThreadContext().
//
// CORDbgCopyThreadContext() does an intelligent copy
// from pSrc to pDst, respecting the ContextFlags of both contexts.
//
#define CopyContextChunk(_t, _f, _end, _flag)                                  \
{                                                                              \
    LOG((LF_CORDB, LL_INFO1000000,                                             \
         "CP::CTC: copying " #_flag  ":" FMT_ADDR "<---" FMT_ADDR "(%d)\n",    \
         DBG_ADDR(_t), DBG_ADDR(_f), ((UINT_PTR)(_end) - (UINT_PTR)_t)));      \
    memcpy((_t), (_f), ((UINT_PTR)(_end) - (UINT_PTR)(_t)));                     \
}

//
// CORDbgCopyThreadContext() does an intelligent copy from pSrc to pDst,
// respecting the ContextFlags of both contexts.
//
struct DebuggerREGDISPLAY;

extern void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc);
extern void CORDbgSetDebuggerREGDISPLAYFromContext(DebuggerREGDISPLAY *pDRD,
                                                   DT_CONTEXT* pContext);

//---------------------------------------------------------------------------------------
//
// Return the size of the CONTEXT required for the specified context flags.
//
// Arguments:
//    flags - this is the equivalent of the ContextFlags field of a CONTEXT
//
// Return Value:
//    size of the CONTEXT required
//
// Notes:
//    On WIN64 platforms this function will always return sizeof(CONTEXT).
//

inline 
ULONG32 ContextSizeForFlags(ULONG32 flags)
{
#if defined(CONTEXT_EXTENDED_REGISTERS) && defined(_TARGET_X86_)
    // Older platforms didn't have extended registers in
    // the context definition so only enforce that size
    // if the extended register flag is set.
    if ((flags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS)
    {
        return offsetof(T_CONTEXT, ExtendedRegisters);
    }
    else
#endif // _TARGET_X86_
    {
        return sizeof(T_CONTEXT);
    }
}

//---------------------------------------------------------------------------------------
//
// Given the size of a buffer and the context flags, check whether the buffer is sufficient large 
// to hold the CONTEXT.
//
// Arguments:
//    size  - size of a buffer 
//    flags - this is the equivalent of the ContextFlags field of a CONTEXT
//
// Return Value:
//    TRUE if the buffer is large enough to hold the CONTEXT
//

inline
BOOL CheckContextSizeForFlags(ULONG32 size, ULONG32 flags)
{
    return (size >= ContextSizeForFlags(flags));
}

//---------------------------------------------------------------------------------------
//
// Given the size of a buffer and the BYTE array representation of a CONTEXT, 
// check whether the buffer is sufficient large to hold the CONTEXT.
//
// Arguments:
//    size  - size of a buffer
//    flags - this is the equivalent of the ContextFlags field of a CONTEXT
//
// Return Value:
//    TRUE if the buffer is large enough to hold the CONTEXT
//

inline
BOOL CheckContextSizeForBuffer(ULONG32 size, const BYTE * pbBuffer)
{
    return ( ( size >= (offsetof(T_CONTEXT, ContextFlags) + sizeof(ULONG32)) ) &&
             CheckContextSizeForFlags(size, (reinterpret_cast<const T_CONTEXT *>(pbBuffer))->ContextFlags) );
}

/* ------------------------------------------------------------------------- *
 * Constant declarations
 * ------------------------------------------------------------------------- */

enum
{
    NULL_THREAD_ID = -1,
    NULL_PROCESS_ID = -1
};

/* ------------------------------------------------------------------------- *
 * Macros
 * ------------------------------------------------------------------------- */

//
// CANNOT USE IsBad*Ptr() methods here.  They are *banned* APIs because of various
// reasons (see http://winweb/wincet/bannedapis.htm).
//

#define VALIDATE_POINTER_TO_OBJECT(ptr, type)                                \
if ((ptr) == NULL)                                                           \
{                                                                            \
    return E_INVALIDARG;                                                     \
}

#define VALIDATE_POINTER_TO_OBJECT_OR_NULL(ptr, type)

//
// CANNOT USE IsBad*Ptr() methods here.  They are *banned* APIs because of various
// reasons (see http://winweb/wincet/bannedapis.htm).
//
#define VALIDATE_POINTER_TO_OBJECT_ARRAY(ptr, type, cElt, fRead, fWrite)     \
if ((ptr) == NULL)                                                           \
{                                                                            \
    return E_INVALIDARG;                                                     \
}

#define VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(ptr, type,cElt,fRead,fWrite)

/* ------------------------------------------------------------------------- *
 * Function Prototypes
 * ------------------------------------------------------------------------- */



// Linear search through an array of NativeVarInfos, to find
// the variable of index dwIndex, valid at the given ip.
//
// returns CORDBG_E_IL_VAR_NOT_AVAILABLE if the variable isn't
// valid at the given ip.
//
// This should be inlined
HRESULT FindNativeInfoInILVariableArray(DWORD dwIndex,
                                        SIZE_T ip,
                                        ICorDebugInfo::NativeVarInfo **ppNativeInfo,
                                        unsigned int nativeInfoCount,
                                        ICorDebugInfo::NativeVarInfo *nativeInfo);


#define VALIDATE_HEAP
//HeapValidate(GetProcessHeap(), 0, NULL);

//  struct DebuggerILToNativeMap:   Holds the IL to Native offset map
//  Great pains are taken to ensure that this each entry corresponds to the
//  first IL instruction in a source line.  It isn't actually a mapping
//  of _every_ IL instruction in a method, just those for source lines.
//  SIZE_T ilOffset:  IL offset of a source line.
//  SIZE_T nativeStartOffset:  Offset within the method where the native
//      instructions corresponding to the IL offset begin.
//  SIZE_T nativeEndOffset:  Offset within the method where the native
//      instructions corresponding to the IL offset end.
//
//  Note: any changes to this struct need to be reflected in
//  COR_DEBUG_IL_TO_NATIVE_MAP in CorDebug.idl. These structs must
//  match exactly.
//
struct DebuggerILToNativeMap
{
    ULONG ilOffset;
    ULONG nativeStartOffset;
    ULONG nativeEndOffset;
    ICorDebugInfo::SourceTypes source;
};

void ExportILToNativeMap(ULONG32 cMap,
             COR_DEBUG_IL_TO_NATIVE_MAP mapExt[],
             struct DebuggerILToNativeMap mapInt[],
             SIZE_T sizeOfCode);
             
#include <primitives.h>

// ----------------------------------------------------------------------------
// IsPatchInRequestedRange
//
// Description: 
//    This function checks if a patch falls (fully or partially) in the requested range of memory.
//
// Arguments:
//    * requestedAddr - the address of the memory range
//    * requestedSize - the size of the memory range
//    * patchAddr     - the address of the patch
//    * pPRD          - the opcode of the patch
//
// Return Value:
//    Return TRUE if the patch is fully or partially in the requested memory range.
//
// Notes:
//    Currently this function is called both from the RS (via code:CordbProcess.ReadMemory and 
//    code:CordbProcess.WriteMemory) and from DAC.  When we DACize the two functions mentioned above,
//    this function should be called from DAC only, and we should use a MemoryRange here.
//

inline bool IsPatchInRequestedRange(CORDB_ADDRESS requestedAddr,
                                    SIZE_T requestedSize,
                                    CORDB_ADDRESS patchAddr)
{
    SUPPORTS_DAC;

    if (requestedAddr == 0)
        return false;

    // Note that patchEnd points to the byte immediately AFTER the patch, so patchEnd is NOT
    // part of the patch.
    CORDB_ADDRESS patchEnd = GetPatchEndAddr(patchAddr);

    // We have three cases:
    // 1) the entire patch is in the requested range
    // 2) the beginning of the requested range is covered by the patch
    // 3) the end of the requested range is covered by the patch
    //
    // Note that on x86, since the break instruction only takes up one byte, the following condition
    // degenerates to case 1 only.
    return (((requestedAddr <= patchAddr) && (patchEnd <= (requestedAddr + requestedSize))) ||
            ((patchAddr <= requestedAddr) && (requestedAddr < patchEnd)) ||
            ((patchAddr <= (requestedAddr + requestedSize - 1)) && ((requestedAddr + requestedSize - 1) < patchEnd)));
}

inline CORDB_ADDRESS ALIGN_ADDRESS( CORDB_ADDRESS val, CORDB_ADDRESS alignment )
{
    LIMITED_METHOD_DAC_CONTRACT;
    
    // alignment must be a power of 2 for this implementation to work (need modulo otherwise)
    _ASSERTE( 0 == (alignment & (alignment - 1)) ); 
    CORDB_ADDRESS result = (val + (alignment - 1)) & ~(alignment - 1);
    _ASSERTE( result >= val );      // check for overflow
    return result;
}

#include "dacprivate.h" // for MSLAYOUT
#include "dumpcommon.h"

#endif //DEBUGGER_COMMON_H