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 * DbgIPCEvents.h -- header file for private Debugger data shared by various
6//
7
8 * debugger components.
9 * ------------------------------------------------------------------------- */
10
11#ifndef _DbgIPCEvents_h_
12#define _DbgIPCEvents_h_
13
14#include <new.hpp>
15#include <cor.h>
16#include <cordebug.h>
17#include <corjit.h> // for ICorDebugInfo::VarLocType & VarLoc
18#include <specstrings.h>
19
20#include "dbgtargetcontext.h"
21
22
23// Get version numbers for IPCHeader stamp
24#include "ndpversion.h"
25
26#include "dbgappdomain.h"
27
28#include "./common.h"
29
30//-----------------------------------------------------------------------------
31// V3 additions to IPC protocol between LS and RS.
32//-----------------------------------------------------------------------------
33
34// Special Exception code for LS to communicate with RS.
35// LS will raise this exception to communicate managed debug events to the RS.
36// Exception codes can't use bit 0x10000000, that's reserved by OS.
37#define CLRDBG_NOTIFICATION_EXCEPTION_CODE ((DWORD) 0x04242420)
38
39// This is exception argument 0 included in debugger notification events.
40// The debugger uses this as a sanity check.
41// This could be very volatile data that changes between builds.
42#define CLRDBG_EXCEPTION_DATA_CHECKSUM ((DWORD) 0x31415927)
43
44
45// Reasons for hijack.
46namespace EHijackReason
47{
48 enum EHijackReason
49 {
50 kUnhandledException = 1,
51 kM2UHandoff = 2,
52 kFirstChanceSuspend = 3,
53 kGenericHijack = 4,
54 kMax
55 };
56 inline bool IsValid(EHijackReason value)
57 {
58 SUPPORTS_DAC;
59 return (value > 0) && (value < kMax);
60 }
61}
62
63
64
65#define MAX_LOG_SWITCH_NAME_LEN 256
66
67//-----------------------------------------------------------------------------
68// Versioning note:
69// This file describes the IPC communication protocol between the LS (mscorwks)
70// and the RS (mscordbi). For Desktop builds, it is private and can change on a
71// daily basis. The version of the LS will always match the version of the RS
72// (but see the discussion of CoreCLR below). They are like a single conceptual
73// DLL split across 2 processes.
74// The only restriction is that it should be flavor agnostic - so don't change
75// layout based off '#ifdef DEBUG'. This lets us drop a Debug flavor RS onto
76// a retail installation w/o any further installation woes. That's very useful
77// for debugging.
78//-----------------------------------------------------------------------------
79
80
81// We want this available for DbgInterface.h - put it here.
82typedef enum
83{
84 IPC_TARGET_OUTOFPROC,
85 IPC_TARGET_COUNT,
86} IpcTarget;
87
88//
89// Names of the setup sync event and shared memory used for IPC between the Left Side and the Right Side. NOTE: these
90// names must include a %d for the process id. The process id used is the process id of the debuggee.
91//
92
93#define CorDBIPCSetupSyncEventName W("CorDBIPCSetupSyncEvent_%d")
94
95//
96// This define controls whether we always pass first chance exceptions to the in-process first chance hijack filter
97// during interop debugging or if we try to short-circuit and make the decision out-of-process as much as possible.
98//
99#define CorDB_Short_Circuit_First_Chance_Ownership 1
100
101//
102// Defines for current version numbers for the left and right sides
103//
104#define CorDB_LeftSideProtocolCurrent 2
105#define CorDB_LeftSideProtocolMinSupported 2
106#define CorDB_RightSideProtocolCurrent 2
107#define CorDB_RightSideProtocolMinSupported 2
108
109//
110// The remaining data structures in this file can be shared between two processes and for network transport
111// based debugging this can mean two different platforms as well. The two platforms that can share these
112// data structures must have identical layouts for them (each field must lie at the same offset and have the
113// same length). The MSLAYOUT macro should be applied to each structure to avoid any compiler packing differences.
114//
115
116//
117// DebuggerIPCRuntimeOffsets contains addresses and offsets of important global variables, functions, and fields in
118// Runtime objects. This is populated during Left Side initialization and is read by the Right Side. This struct is
119// mostly to facilitate unmanaged debugging support, but it may have some small uses for managed debugging.
120//
121struct MSLAYOUT DebuggerIPCRuntimeOffsets
122{
123#ifdef FEATURE_INTEROP_DEBUGGING
124 void *m_genericHijackFuncAddr;
125 void *m_signalHijackStartedBPAddr;
126 void *m_excepForRuntimeHandoffStartBPAddr;
127 void *m_excepForRuntimeHandoffCompleteBPAddr;
128 void *m_signalHijackCompleteBPAddr;
129 void *m_excepNotForRuntimeBPAddr;
130 void *m_notifyRSOfSyncCompleteBPAddr;
131 void *m_raiseExceptionAddr; // The address of kernel32!RaiseException in the debuggee
132 DWORD m_debuggerWordTLSIndex; // The TLS slot for the debugger word used in the debugger hijack functions
133#endif // FEATURE_INTEROP_DEBUGGING
134 SIZE_T m_TLSIndex; // The TLS index the CLR is using to hold Thread objects
135 SIZE_T m_TLSIsSpecialIndex; // The index into the Predef block of the the "IsSpecial" status for a thread.
136 SIZE_T m_TLSCantStopIndex; // The index into the Predef block of the the Can't-Stop count.
137 SIZE_T m_EEThreadStateOffset; // Offset of m_state in a Thread
138 SIZE_T m_EEThreadStateNCOffset; // Offset of m_stateNC in a Thread
139 SIZE_T m_EEThreadPGCDisabledOffset; // Offset of the bit for whether PGC is disabled or not in a Thread
140 DWORD m_EEThreadPGCDisabledValue; // Value at m_EEThreadPGCDisabledOffset that equals "PGC disabled".
141 SIZE_T m_EEThreadFrameOffset; // Offset of the Frame ptr in a Thread
142 SIZE_T m_EEThreadMaxNeededSize; // Max memory to read to get what we need out of a Thread object
143 DWORD m_EEThreadSteppingStateMask; // Mask for Thread::TSNC_DebuggerIsStepping
144 DWORD m_EEMaxFrameValue; // The max Frame value
145 SIZE_T m_EEThreadDebuggerFilterContextOffset; // Offset of debugger's filter context within a Thread Object.
146 SIZE_T m_EEThreadCantStopOffset; // Offset of the can't stop count in a Thread
147 SIZE_T m_EEFrameNextOffset; // Offset of the next ptr in a Frame
148 DWORD m_EEIsManagedExceptionStateMask; // Mask for Thread::TSNC_DebuggerIsManagedException
149 void *m_pPatches; // Addr of patch table
150 BOOL *m_pPatchTableValid; // Addr of g_patchTableValid
151 SIZE_T m_offRgData; // Offset of m_pcEntries
152 SIZE_T m_offCData; // Offset of count of m_pcEntries
153 SIZE_T m_cbPatch; // Size per patch entry
154 SIZE_T m_offAddr; // Offset within patch of target addr
155 SIZE_T m_offOpcode; // Offset within patch of target opcode
156 SIZE_T m_cbOpcode; // Max size of opcode
157 SIZE_T m_offTraceType; // Offset of the trace.type within a patch
158 DWORD m_traceTypeUnmanaged; // TRACE_UNMANAGED
159
160 DebuggerIPCRuntimeOffsets()
161 {
162 ZeroMemory(this, sizeof(DebuggerIPCRuntimeOffsets));
163 }
164};
165
166//
167// The size of the send and receive IPC buffers.
168// These must be big enough to fit a DebuggerIPCEvent. Also, the bigger they are, the fewer events
169// it takes to send variable length stuff like the stack trace.
170// But for perf reasons, they need to be small enough to not just push us over a page boundary in an IPC block.
171// Unfortunately, there's a lot of other goo in the IPC block, so we can't use some clean formula. So we
172// have to resort to just tuning things.
173//
174
175// When using a network transport rather than shared memory buffers CorDBIPC_BUFFER_SIZE is the upper bound
176// for a single DebuggerIPCEvent structure. This now relates to the maximal size of a network message and is
177// orthogonal to the host's page size. Because of this we defer definition of CorDBIPC_BUFFER_SIZE until we've
178// declared DebuggerIPCEvent at the end of this header (and we can do so because in the transport case there
179// aren't any embedded buffers in the DebuggerIPCControlBlock).
180
181#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_ARM)
182#ifdef _WIN64
183#define CorDBIPC_BUFFER_SIZE 2104
184#else
185#define CorDBIPC_BUFFER_SIZE 2092
186#endif
187#else // !_TARGET_X86_ && !_TARGET_ARM_
188// This is the size of a DebuggerIPCEvent. You will hit an assert in Cordb::Initialize() (di\rsmain.cpp)
189// if this is not defined correctly. AMD64 actually has a page size of 0x1000, not 0x2000.
190#define CorDBIPC_BUFFER_SIZE 4016 // (4016 + 6) * 2 + 148 = 8192 (two (DebuggerIPCEvent + alignment padding) + other fields = page size)
191#endif // DBG_TARGET_X86 || DBG_TARGET_ARM
192
193//
194// DebuggerIPCControlBlock describes the layout of the shared memory shared between the Left Side and the Right
195// Side. This includes error information, handles for the IPC channel, and space for the send/receive buffers.
196//
197struct MSLAYOUT DebuggerIPCControlBlock
198{
199 // Version data should be first in the control block to ensure that we can read it even if the control block
200 // changes.
201 SIZE_T m_DCBSize; // note this field is used as a semaphore to indicate the DCB is initialized
202 ULONG m_verMajor; // CLR build number for the Left Side.
203 ULONG m_verMinor; // CLR build number for the Left Side.
204
205 // This next stuff fits in a DWORD.
206 bool m_checkedBuild; // CLR build type for the Left Side.
207 // using the first padding byte to indicate if hosted in fiber mode.
208 // We actually just need one bit. So if needed, can turn this to a bit.
209 // BYTE padding1;
210 bool m_bHostingInFiber;
211 BYTE padding2;
212 BYTE padding3;
213
214 ULONG m_leftSideProtocolCurrent; // Current protocol version for the Left Side.
215 ULONG m_leftSideProtocolMinSupported; // Minimum protocol the Left Side can support.
216
217 ULONG m_rightSideProtocolCurrent; // Current protocol version for the Right Side.
218 ULONG m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires.
219
220 HRESULT m_errorHR;
221 unsigned int m_errorCode;
222
223#if defined(DBG_TARGET_WIN64)
224 // 64-bit needs this padding to make the handles after this aligned.
225 // But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0.
226 ULONG padding4;
227#endif // DBG_TARGET_WIN64
228
229
230 RemoteHANDLE m_rightSideEventAvailable;
231 RemoteHANDLE m_rightSideEventRead;
232
233 // @dbgtodo inspection - this is where LSEA and LSER used to be. We need to the padding to maintain binary compatibility.
234 // Eventually, we expect to remove this whole block.
235 RemoteHANDLE m_paddingObsoleteLSEA;
236 RemoteHANDLE m_paddingObsoleteLSER;
237
238 RemoteHANDLE m_rightSideProcessHandle;
239
240 //.............................................................................
241 // Everything above this point must have the exact same binary layout as v1.1.
242 // See protocol details below.
243 //.............................................................................
244
245 RemoteHANDLE m_leftSideUnmanagedWaitEvent;
246
247
248
249 // This is set immediately when the helper thread is created.
250 // This will be set even if there's a temporary helper thread or if the real helper
251 // thread is not yet pumping (eg, blocked on a loader lock).
252 DWORD m_realHelperThreadId;
253
254 // This is only published once the helper thread starts running in its main loop.
255 // Thus we can use this field to see if the real helper thread is actually pumping.
256 DWORD m_helperThreadId;
257
258 // This is non-zero if the LS has a temporary helper thread.
259 DWORD m_temporaryHelperThreadId;
260
261 // ID of the Helper's canary thread.
262 DWORD m_CanaryThreadId;
263
264 DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets;
265 void *m_helperThreadStartAddr;
266 void *m_helperRemoteStartAddr;
267 DWORD *m_specialThreadList;
268
269 BYTE m_receiveBuffer[CorDBIPC_BUFFER_SIZE];
270 BYTE m_sendBuffer[CorDBIPC_BUFFER_SIZE];
271
272 DWORD m_specialThreadListLength;
273 bool m_shutdownBegun;
274 bool m_rightSideIsWin32Debugger; // RS status
275 bool m_specialThreadListDirty;
276
277 bool m_rightSideShouldCreateHelperThread;
278
279 // NOTE The Init method works since there are no virtual functions - don't add any virtual functions without
280 // changing this!
281 // Only initialized by the LS, opened by the RS.
282 HRESULT Init(
283 HANDLE rsea,
284 HANDLE rser,
285 HANDLE lsea,
286 HANDLE lser,
287 HANDLE lsuwe
288 );
289
290};
291
292#if defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
293
294// We need an alternate definition for the control block if using the transport, because the control block has to be sent over the transport
295// In particular we can't nest the send/receive buffers inside of it and we don't use any of the remote handles
296
297struct MSLAYOUT DebuggerIPCControlBlockTransport
298{
299 // Version data should be first in the control block to ensure that we can read it even if the control block
300 // changes.
301 SIZE_T m_DCBSize; // note this field is used as a semaphore to indicate the DCB is initialized
302 ULONG m_verMajor; // CLR build number for the Left Side.
303 ULONG m_verMinor; // CLR build number for the Left Side.
304
305 // This next stuff fits in a DWORD.
306 bool m_checkedBuild; // CLR build type for the Left Side.
307 // using the first padding byte to indicate if hosted in fiber mode.
308 // We actually just need one bit. So if needed, can turn this to a bit.
309 // BYTE padding1;
310 bool m_bHostingInFiber;
311 BYTE padding2;
312 BYTE padding3;
313
314 ULONG m_leftSideProtocolCurrent; // Current protocol version for the Left Side.
315 ULONG m_leftSideProtocolMinSupported; // Minimum protocol the Left Side can support.
316
317 ULONG m_rightSideProtocolCurrent; // Current protocol version for the Right Side.
318 ULONG m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires.
319
320 HRESULT m_errorHR;
321 unsigned int m_errorCode;
322
323#if defined(DBG_TARGET_WIN64)
324 // 64-bit needs this padding to make the handles after this aligned.
325 // But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0.
326 ULONG padding4;
327#endif // DBG_TARGET_WIN64
328
329 // This is set immediately when the helper thread is created.
330 // This will be set even if there's a temporary helper thread or if the real helper
331 // thread is not yet pumping (eg, blocked on a loader lock).
332 DWORD m_realHelperThreadId;
333
334 // This is only published once the helper thread starts running in its main loop.
335 // Thus we can use this field to see if the real helper thread is actually pumping.
336 DWORD m_helperThreadId;
337
338 // This is non-zero if the LS has a temporary helper thread.
339 DWORD m_temporaryHelperThreadId;
340
341 // ID of the Helper's canary thread.
342 DWORD m_CanaryThreadId;
343
344 DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets;
345 void *m_helperThreadStartAddr;
346 void *m_helperRemoteStartAddr;
347 DWORD *m_specialThreadList;
348
349 DWORD m_specialThreadListLength;
350 bool m_shutdownBegun;
351 bool m_rightSideIsWin32Debugger; // RS status
352 bool m_specialThreadListDirty;
353
354 bool m_rightSideShouldCreateHelperThread;
355
356 // NOTE The Init method works since there are no virtual functions - don't add any virtual functions without
357 // changing this!
358 // Only initialized by the LS, opened by the RS.
359 HRESULT Init();
360
361};
362
363#endif // defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
364
365#if defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
366#include "dbgtransportsession.h"
367#endif // defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
368
369#if defined(DBG_TARGET_X86) && !defined(FEATURE_CORESYSTEM)
370// We have an versioning requirement.
371// Certain portions of the v1.0 and v1.1 IPC block are shared. This is b/c a v1.1 debugger needs to be able
372// to look at a v2.0 app enough to recognize the version mismatch.
373// This check is only necessary for platforms that ran on v1.1 (Win32-x86)
374
375// Just to catch any potential illegal change in the IPC block, we assert the offsets against the offsets from v1.1.
376// The constants here are pulled from v1.1.
377// The RS will look at these versioning fields, so they absolutely must line up.
378static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_leftSideProtocolCurrent) == 0x10);
379static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_leftSideProtocolMinSupported) == 0x14);
380static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProtocolCurrent) == 0x18);
381static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProtocolMinSupported) == 0x1c);
382
383// Unfortunately, on detecting such failure, v1.1 will also null out LSEA, LSER and RSPH.
384// If these get adjusted, a version-mismatch attach will effectively null out random fields.
385static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_paddingObsoleteLSEA) == 0x30);
386static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_paddingObsoleteLSER) == 0x34);
387static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProcessHandle) == 0x38);
388
389
390
391#endif
392
393#define INITIAL_APP_DOMAIN_INFO_LIST_SIZE 16
394
395
396//-----------------------------------------------------------------------------
397// Provide some Type-safety in the IPC block when we pass remote pointers around.
398//-----------------------------------------------------------------------------
399
400
401//-----------------------------------------------------------------------------
402// This is the same in both the LS & RS.
403// Definitions on the LS & RS should be binary compatible. So all storage is
404// declared in GeneralLsPointer, and then the Ls & RS each have their own
405// derived accessors.
406//-----------------------------------------------------------------------------
407class MSLAYOUT GeneralLsPointer
408{
409protected:
410 friend ULONG_PTR LsPtrToCookie(GeneralLsPointer p);
411 void * m_ptr;
412
413public:
414 bool IsNull() { return m_ptr == NULL; }
415};
416
417class MSLAYOUT GeneralRsPointer
418{
419protected:
420 UINT m_data;
421
422public:
423 bool IsNull() { return m_data == 0; }
424};
425
426// In some cases, we need to get a uuid from a pointer (ie, in a hash)
427inline ULONG_PTR LsPtrToCookie(GeneralLsPointer p) {
428 return (ULONG_PTR) p.m_ptr;
429}
430#define VmPtrToCookie(vm) LsPtrToCookie((vm).ToLsPtr())
431
432
433#ifdef RIGHT_SIDE_COMPILE
434//-----------------------------------------------------------------------------
435// Infrasturcture for RS Definitions
436//-----------------------------------------------------------------------------
437
438// On the RS, we don't have the LS classes defined, so we can't templatize that
439// in terms of <class T>, but we still want things to be unique.
440// So we create an empty enum for each LS type and then templatize it in terms
441// of the enum.
442template <typename T>
443class MSLAYOUT LsPointer : public GeneralLsPointer
444{
445public:
446 void Set(void * p)
447 {
448 m_ptr = p;
449 }
450 void * UnsafeGet()
451 {
452 return m_ptr;
453 }
454
455 static LsPointer<T> NullPtr()
456 {
457 return MakePtr(NULL);
458 }
459
460 static LsPointer<T> MakePtr(T* p)
461 {
462#ifdef _PREFAST_
463#pragma warning(push)
464#pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
465#endif // _PREFAST_
466
467 LsPointer<T> t;
468 t.Set(p);
469 return t;
470
471#ifdef _PREFAST_
472#pragma warning(pop)
473#endif // _PREFAST_
474 }
475
476 bool operator!= (void * p) { return m_ptr != p; }
477 bool operator== (void * p) { return m_ptr == p; }
478 bool operator==(LsPointer<T> p) { return p.m_ptr == this->m_ptr; }
479
480 // We should never UnWrap() them in the RS, so we don't define that here.
481};
482
483class CordbProcess;
484template <class T> UINT AllocCookie(CordbProcess * pProc, T * p);
485template <class T> T * UnwrapCookie(CordbProcess * pProc, UINT cookie);
486
487UINT AllocCookieCordbEval(CordbProcess * pProc, class CordbEval * p);
488class CordbEval * UnwrapCookieCordbEval(CordbProcess * pProc, UINT cookie);
489
490template <class CordbEval> UINT AllocCookie(CordbProcess * pProc, CordbEval * p)
491{
492 return AllocCookieCordbEval(pProc, p);
493}
494template <class CordbEval> CordbEval * UnwrapCookie(CordbProcess * pProc, UINT cookie)
495{
496 return UnwrapCookieCordbEval(pProc, cookie);
497}
498
499
500
501// This is how the RS sees the pointers in the IPC block.
502template<class T>
503class MSLAYOUT RsPointer : public GeneralRsPointer
504{
505public:
506 // Since we're being used inside a union, we can't have a ctor.
507
508 static RsPointer<T> NullPtr()
509 {
510 RsPointer<T> t;
511 t.m_data = 0;
512 return t;
513 }
514
515 bool AllocHandle(CordbProcess *pProc, T* p)
516 {
517 // This will force validation.
518 m_data = AllocCookie<T>(pProc, p);
519 return (m_data != 0);
520 }
521
522 bool operator==(RsPointer<T> p) { return p.m_data == this->m_data; }
523
524 T* UnWrapAndRemove(CordbProcess *pProc)
525 {
526 return UnwrapCookie<T>(pProc, m_data);
527 }
528
529protected:
530};
531
532// Forward declare a class so that each type of LS pointer can have
533// its own type. We use the real class name to be compatible with VMPTRs.
534#define DEFINE_LSPTR_TYPE(ls_type, ptr_name) \
535 ls_type; \
536 typedef LsPointer<ls_type> ptr_name;
537
538
539#define DEFINE_RSPTR_TYPE(rs_type, ptr_name) \
540 class rs_type; \
541 typedef RsPointer<rs_type> ptr_name;
542
543#else // !RIGHT_SIDE_COMPILE
544//-----------------------------------------------------------------------------
545// Infrastructure for LS Definitions
546//-----------------------------------------------------------------------------
547
548// This is how the LS sees the pointers in the IPC block.
549template<typename T>
550class MSLAYOUT LsPointer : public GeneralLsPointer
551{
552public:
553 // Since we're being used inside a union, we can't have a ctor.
554 //LsPointer() { }
555
556 static LsPointer<T> NullPtr()
557 {
558 return MakePtr(NULL);
559 }
560
561 static LsPointer<T> MakePtr(T * p)
562 {
563#ifdef _PREFAST_
564#pragma warning(push)
565#pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
566#endif // _PREFAST_
567
568 LsPointer<T> t;
569 t.Set(p);
570 return t;
571
572#ifdef _PREFAST_
573#pragma warning(pop)
574#endif // _PREFAST_
575 }
576
577 bool operator!= (void * p) { return m_ptr != p; }
578 bool operator== (void * p) { return m_ptr == p; }
579 bool operator==(LsPointer<T> p) { return p.m_ptr == this->m_ptr; }
580
581 // @todo - we want to be able to swap out Set + Unwrap functions
582 void Set(T * p)
583 {
584 SUPPORTS_DAC;
585 // We could validate the pointer here.
586 m_ptr = p;
587 }
588
589 T * UnWrap()
590 {
591 // If we wanted to validate the pointer, here's our chance.
592 return static_cast<T*>(m_ptr);
593 }
594};
595
596template <class n>
597class MSLAYOUT RsPointer : public GeneralRsPointer
598{
599public:
600 static RsPointer<n> NullPtr()
601 {
602 RsPointer<n> t;
603 t.m_data = 0;
604 return t;
605 }
606
607 bool operator==(RsPointer<n> p) { return p.m_data == this->m_data; }
608
609 // We should never UnWrap() them in the LS, so we don't define that here.
610};
611
612#define DEFINE_LSPTR_TYPE(ls_type, ptr_name) \
613 ls_type; \
614 typedef LsPointer<ls_type> ptr_name;
615
616#define DEFINE_RSPTR_TYPE(rs_type, ptr_name) \
617 enum __RS__##rs_type { }; \
618 typedef RsPointer<__RS__##rs_type> ptr_name;
619
620#endif // !RIGHT_SIDE_COMPILE
621
622// We must be binary compatible w/ a pointer.
623static_assert_no_msg(sizeof(LsPointer<void>) == sizeof(GeneralLsPointer));
624
625static_assert_no_msg(sizeof(void*) == sizeof(GeneralLsPointer));
626
627
628
629//-----------------------------------------------------------------------------
630// Definitions for Left-Side ptrs.
631// NOTE: Use VMPTR instead of LSPTR. Don't add new LSPTR types.
632//
633//-----------------------------------------------------------------------------
634
635
636
637DEFINE_LSPTR_TYPE(class Assembly, LSPTR_ASSEMBLY);
638DEFINE_LSPTR_TYPE(class DebuggerJitInfo, LSPTR_DJI);
639DEFINE_LSPTR_TYPE(class DebuggerMethodInfo, LSPTR_DMI);
640DEFINE_LSPTR_TYPE(class MethodDesc, LSPTR_METHODDESC);
641DEFINE_LSPTR_TYPE(class DebuggerBreakpoint, LSPTR_BREAKPOINT);
642DEFINE_LSPTR_TYPE(class DebuggerDataBreakpoint, LSPTR_DATA_BREAKPOINT);
643DEFINE_LSPTR_TYPE(class DebuggerEval, LSPTR_DEBUGGEREVAL);
644DEFINE_LSPTR_TYPE(class DebuggerStepper, LSPTR_STEPPER);
645
646// Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct.
647#if defined(RIGHT_SIDE_COMPILE)
648typedef LsPointer<DT_CONTEXT> LSPTR_CONTEXT;
649#else // RIGHT_SIDE_COMPILE
650typedef LsPointer<DT_CONTEXT> LSPTR_CONTEXT;
651#endif // RIGHT_SIDE_COMPILE
652
653DEFINE_LSPTR_TYPE(struct OBJECTHANDLE__, LSPTR_OBJECTHANDLE);
654DEFINE_LSPTR_TYPE(class TypeHandleDummyPtr, LSPTR_TYPEHANDLE); // TypeHandle in the LS is not a direct pointer.
655
656//-----------------------------------------------------------------------------
657// Definitions for Right-Side ptrs.
658//-----------------------------------------------------------------------------
659DEFINE_RSPTR_TYPE(CordbEval, RSPTR_CORDBEVAL);
660
661
662//---------------------------------------------------------------------------------------
663// VMPTR_Base is the base type for an abstraction over pointers into the VM so
664// that DBI can treat them as opaque handles. Classes will derive from it to
665// provide type-safe Target pointers, which ICD will view as opaque handles.
666//
667// Lifetimes:
668// VMPTR_ objects survive across flushing the DAC cache. Therefore, the underlying
669// storage must be a target-pointer (and not a marshalled host pointer).
670// The RS must ensure they're still in sync with the LS (eg, by
671// tracking unload events).
672//
673//
674// Assumptions:
675// These handles are TADDR pointers and must not require any cleanup from DAC/DBI.
676// For direct untyped pointers into the VM, use CORDB_ADDRESS.
677//
678// Notes:
679// 1. This helps enforce that DBI goes through the primitives interface
680// for all access (and that it doesn't accidentally start calling
681// dac-ized methods on the objects)
682// 2. This isolates DBI from VM headers.
683// 3. This isolates DBI from the dac implementation (of DAC_Ptr)
684// 4. This is distinct from LSPTR because LSPTRs are truly opaque handles, whereas VMPtrs
685// move across VM, DAC, and DBI, exposing proper functionality in each component.
686// 5. VMPTRs are blittable because they are Target Addresses which act as opaque
687// handles outside of the Target / Dac-marshaller.
688//
689//---------------------------------------------------------------------------------------
690
691
692template <typename TTargetPtr, typename TDacPtr>
693class MSLAYOUT VMPTR_Base
694{
695 // Underlying pointer into Target address space.
696 // Target pointers are blittable.
697 // - In Target: can be used as normal local pointers.
698 // - In DAC: must be marshalled to a host-pointer and then they can be used via DAC
699 // - In RS: opaque handles.
700private:
701 TADDR m_addr;
702
703public:
704 typedef VMPTR_Base<TTargetPtr,TDacPtr> VMPTR_This;
705
706 // For DBI, VMPTRs are opaque handles.
707 // But the DAC side is allowed to inspect the handles to get at the raw pointer.
708#if defined(ALLOW_VMPTR_ACCESS)
709 //
710 // Case 1: Using in DAcDbi implementation
711 //
712
713 // DAC accessor
714 TDacPtr GetDacPtr() const
715 {
716 SUPPORTS_DAC;
717 return TDacPtr(m_addr);
718 }
719
720
721 // This will initialize the handle to a given target-pointer.
722 // We choose TADDR to make it explicit that it's a target pointer and avoid the risk
723 // of it accidentally getting marshalled to a host pointer.
724 void SetDacTargetPtr(TADDR addr)
725 {
726 SUPPORTS_DAC;
727 m_addr = addr;
728 }
729
730 void SetHostPtr(const TTargetPtr * pObject)
731 {
732 SUPPORTS_DAC;
733 m_addr = PTR_HOST_TO_TADDR(pObject);
734 }
735
736
737#elif !defined(RIGHT_SIDE_COMPILE)
738 //
739 // Case 2: Used in Left-side. Can get/set from local pointers.
740 //
741
742 // This will set initialize from a Target pointer. Since this is happening in the
743 // Left-side (Target), the pointer is local.
744 // This is commonly used by the Left-side to create a VMPTR_ for a notification event.
745 void SetRawPtr(TTargetPtr * ptr)
746 {
747 m_addr = reinterpret_cast<TADDR>(ptr);
748 }
749
750 // This will get the raw underlying target pointer.
751 // This can be used by inproc Left-side code to unwrap a VMPTR (Eg, for a func-eval
752 // hijack or in-proc worker threads)
753 TTargetPtr * GetRawPtr()
754 {
755 return reinterpret_cast<TTargetPtr*>(m_addr);
756 }
757
758 // Convenience for converting TTargetPtr --> VMPTR
759 static VMPTR_This MakePtr(TTargetPtr * ptr)
760 {
761#ifdef _PREFAST_
762#pragma warning(push)
763#pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
764#endif // _PREFAST_
765
766 VMPTR_This t;
767 t.SetRawPtr(ptr);
768 return t;
769
770#ifdef _PREFAST_
771#pragma warning(pop)
772#endif // _PREFAST_
773 }
774
775
776#else
777 //
778 // Case 3: Used in RS. Opaque handles only.
779 //
780#endif
781
782
783#ifndef DACCESS_COMPILE
784 // For compatibility, these can be converted to LSPTRs on the RS or LS (case 2 and 3). We don't allow
785 // this in the DAC case because it's a cast between address spaces which we're trying to eliminate
786 // in the DAC code.
787 // @dbgtodo inspection: LSPTRs will go away entirely once we've moved completely over to DAC
788 LsPointer<TTargetPtr> ToLsPtr()
789 {
790 return LsPointer<TTargetPtr>::MakePtr( reinterpret_cast<TTargetPtr *>(m_addr));
791 }
792#endif
793
794 //
795 // Operators to emulate Pointer semantics.
796 //
797 bool IsNull() { SUPPORTS_DAC; return m_addr == NULL; }
798
799 static VMPTR_This NullPtr()
800 {
801 SUPPORTS_DAC;
802
803#ifdef _PREFAST_
804#pragma warning(push)
805#pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
806#endif // _PREFAST_
807
808 VMPTR_This dummy;
809 dummy.m_addr = NULL;
810 return dummy;
811
812#ifdef _PREFAST_
813#pragma warning(pop)
814#endif // _PREFAST_
815 }
816
817 bool operator!= (VMPTR_This vmOther) const { SUPPORTS_DAC; return this->m_addr != vmOther.m_addr; }
818 bool operator== (VMPTR_This vmOther) const { SUPPORTS_DAC; return this->m_addr == vmOther.m_addr; }
819};
820
821#if defined(ALLOW_VMPTR_ACCESS)
822// Helper macro to define a VMPTR.
823// This is used in the DAC case, so this definition connects the pointers up to their DAC values.
824#define DEFINE_VMPTR(ls_type, dac_ptr_type, ptr_name) \
825 ls_type; \
826 typedef VMPTR_Base<ls_type, dac_ptr_type> ptr_name;
827
828#else
829// Helper macro to define a VMPTR.
830// This is used in the Right-side and Left-side (but not DAC) case.
831// This definition explicitly ignores dac_ptr_type to prevent accidental DAC usage.
832#define DEFINE_VMPTR(ls_type, dac_ptr_type, ptr_name) \
833 ls_type; \
834 typedef VMPTR_Base<ls_type, void> ptr_name;
835
836#endif
837
838// Declare VMPTRs.
839// The naming convention for instantiating a VMPTR is a 'vm' prefix.
840//
841// VM definition, DAC definition, pretty name for VMPTR
842DEFINE_VMPTR(class AppDomain, PTR_AppDomain, VMPTR_AppDomain);
843
844// Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct.
845// DEFINE_VMPTR(struct _CONTEXT, PTR_CONTEXT, VMPTR_CONTEXT);
846#if defined(ALLOW_VMPTR_ACCESS)
847typedef VMPTR_Base<DT_CONTEXT, PTR_CONTEXT> VMPTR_CONTEXT;
848#else
849typedef VMPTR_Base<DT_CONTEXT, void > VMPTR_CONTEXT;
850#endif
851
852// DomainFile is a base-class for a CLR module, with app-domain affinity.
853// For domain-neutral modules (like mscorlib), there is a DomainFile instance
854// for each appdomain the module lives in.
855// This is the canonical handle ICorDebug uses to a CLR module.
856DEFINE_VMPTR(class DomainFile, PTR_DomainFile, VMPTR_DomainFile);
857DEFINE_VMPTR(class Module, PTR_Module, VMPTR_Module);
858
859// DomainAssembly derives from DomainFile and represents a manifest module.
860DEFINE_VMPTR(class DomainAssembly, PTR_DomainAssembly, VMPTR_DomainAssembly);
861DEFINE_VMPTR(class Assembly, PTR_Assembly, VMPTR_Assembly);
862
863DEFINE_VMPTR(class PEFile, PTR_PEFile, VMPTR_PEFile);
864DEFINE_VMPTR(class MethodDesc, PTR_MethodDesc, VMPTR_MethodDesc);
865DEFINE_VMPTR(class FieldDesc, PTR_FieldDesc, VMPTR_FieldDesc);
866
867// ObjectHandle is a safe way to represent an object into the GC heap. It gets updated
868// when a GC occurs.
869DEFINE_VMPTR(struct OBJECTHANDLE__, TADDR, VMPTR_OBJECTHANDLE);
870
871DEFINE_VMPTR(class TypeHandle, PTR_TypeHandle, VMPTR_TypeHandle);
872
873// A VMPTR_Thread represents a thread that has entered the runtime at some point.
874// It may or may not have executed managed code yet; and it may or may not have managed code
875// on its callstack.
876DEFINE_VMPTR(class Thread, PTR_Thread, VMPTR_Thread);
877
878DEFINE_VMPTR(class Object, PTR_Object, VMPTR_Object);
879
880DEFINE_VMPTR(class CrstBase, PTR_Crst, VMPTR_Crst);
881DEFINE_VMPTR(class SimpleRWLock, PTR_SimpleRWLock, VMPTR_SimpleRWLock);
882DEFINE_VMPTR(class SimpleRWLock, PTR_SimpleRWLock, VMPTR_RWLock);
883DEFINE_VMPTR(struct ReJitInfo, PTR_ReJitInfo, VMPTR_ReJitInfo);
884DEFINE_VMPTR(struct SharedReJitInfo, PTR_SharedReJitInfo, VMPTR_SharedReJitInfo);
885DEFINE_VMPTR(class NativeCodeVersionNode, PTR_NativeCodeVersionNode, VMPTR_NativeCodeVersionNode);
886DEFINE_VMPTR(class ILCodeVersionNode, PTR_ILCodeVersionNode, VMPTR_ILCodeVersionNode);
887
888typedef CORDB_ADDRESS GENERICS_TYPE_TOKEN;
889
890
891//-----------------------------------------------------------------------------
892// We pass some fixed size strings in the IPC block.
893// Helper class to wrap the buffer and protect against buffer overflows.
894// This should be binary compatible w/ a wchar[] array.
895//-----------------------------------------------------------------------------
896
897template <int nMaxLengthIncludingNull>
898class MSLAYOUT EmbeddedIPCString
899{
900public:
901 // Set, caller responsibility that wcslen(pData) < nMaxLengthIncludingNull
902 void SetString(const WCHAR * pData)
903 {
904 // If the string doesn't fit into the buffer, that's an issue (and so this is a real
905 // assert, not just a simplifying assumption). To fix it, either:
906 // - make the buffer larger
907 // - don't pass the string as an embedded string in the IPC block.
908 // This will truncate (rather than AV on the RS).
909 int ret;
910 ret = SafeCopy(pData);
911
912 // See comment above - caller should guarantee that buffer is large enough.
913 _ASSERTE(ret != STRUNCATE);
914 }
915
916 // Set a string from a substring. This will truncate if necessary.
917 void SetStringTruncate(const WCHAR * pData)
918 {
919 // ignore return value because truncation is ok.
920 SafeCopy(pData);
921 }
922
923 const WCHAR * GetString()
924 {
925 // For a null-termination just in case an issue in the debuggee process
926 // yields a malformed string.
927 m_data[nMaxLengthIncludingNull - 1] = W('\0');
928 return &m_data[0];
929 }
930 int GetMaxSize() const { return nMaxLengthIncludingNull; }
931
932private:
933 int SafeCopy(const WCHAR * pData)
934 {
935 return wcsncpy_s(
936 m_data, nMaxLengthIncludingNull,
937 pData, _TRUNCATE);
938 }
939 WCHAR m_data[nMaxLengthIncludingNull];
940};
941
942//
943// Types of events that can be sent between the Runtime Controller and
944// the Debugger Interface. Some of these events are one way only, while
945// others go both ways. The grouping of the event numbers is an attempt
946// to show this distinction and perhaps even allow generic operations
947// based on the type of the event.
948//
949enum DebuggerIPCEventType
950{
951#define IPC_EVENT_TYPE0(type, val) type = val,
952#define IPC_EVENT_TYPE1(type, val) type = val,
953#define IPC_EVENT_TYPE2(type, val) type = val,
954#include "dbgipceventtypes.h"
955#undef IPC_EVENT_TYPE2
956#undef IPC_EVENT_TYPE1
957#undef IPC_EVENT_TYPE0
958};
959
960#ifdef _DEBUG
961
962// This is a static debugging structure to help breaking at the right place.
963// Debug only. This is to track the number of events that have been happened so far.
964// User can choose to set break point base on the number of events.
965// Variables are named as the event name with prefix m_iDebugCount. For example
966// m_iDebugCount_DB_IPCE_BREAKPOINT if for event DB_IPCE_BREAKPOINT.
967struct MSLAYOUT DebugEventCounter
968{
969// we don't need the event type 0
970#define IPC_EVENT_TYPE0(type, val)
971#define IPC_EVENT_TYPE1(type, val) int m_iDebugCount_##type;
972#define IPC_EVENT_TYPE2(type, val) int m_iDebugCount_##type;
973#include "dbgipceventtypes.h"
974#undef IPC_EVENT_TYPE2
975#undef IPC_EVENT_TYPE1
976#undef IPC_EVENT_TYPE0
977};
978#endif // _DEBUG
979
980
981#if !defined(DACCESS_COMPILE)
982
983struct MSLAYOUT IPCEventTypeNameMapping
984 {
985 DebuggerIPCEventType eventType;
986 const char * eventName;
987};
988
989extern const IPCEventTypeNameMapping DECLSPEC_SELECTANY DbgIPCEventTypeNames[] =
990{
991 #define IPC_EVENT_TYPE0(type, val) { type, #type },
992 #define IPC_EVENT_TYPE1(type, val) { type, #type },
993 #define IPC_EVENT_TYPE2(type, val) { type, #type },
994 #include "dbgipceventtypes.h"
995 #undef IPC_EVENT_TYPE2
996 #undef IPC_EVENT_TYPE1
997 #undef IPC_EVENT_TYPE0
998 { DB_IPCE_INVALID_EVENT, "DB_IPCE_Error" }
999};
1000
1001const size_t nameCount = sizeof(DbgIPCEventTypeNames) / sizeof(DbgIPCEventTypeNames[0]);
1002
1003
1004struct MSLAYOUT IPCENames // We use a class/struct so that the function can remain in a shared header file
1005{
1006 static DebuggerIPCEventType GetEventType(__in_z char * strEventType)
1007 {
1008 // pass in the string of event name and find the matching enum value
1009 // This is a linear search which is pretty slow. However, this is only used
1010 // at startup time when debug assert is turn on and with registry key set. So it is not that bad.
1011 //
1012 for (size_t i = 0; i < nameCount; i++)
1013 {
1014 if (_stricmp(DbgIPCEventTypeNames[i].eventName, strEventType) == 0)
1015 return DbgIPCEventTypeNames[i].eventType;
1016 }
1017 return DB_IPCE_INVALID_EVENT;
1018 }
1019 static const char * GetName(DebuggerIPCEventType eventType)
1020 {
1021
1022 enum DbgIPCEventTypeNum
1023 {
1024 #define IPC_EVENT_TYPE0(type, val) type##_Num,
1025 #define IPC_EVENT_TYPE1(type, val) type##_Num,
1026 #define IPC_EVENT_TYPE2(type, val) type##_Num,
1027 #include "dbgipceventtypes.h"
1028 #undef IPC_EVENT_TYPE2
1029 #undef IPC_EVENT_TYPE1
1030 #undef IPC_EVENT_TYPE0
1031 };
1032
1033 unsigned int i, lim;
1034
1035 if (eventType < DB_IPCE_DEBUGGER_FIRST)
1036 {
1037 i = DB_IPCE_RUNTIME_FIRST_Num + 1;
1038 lim = DB_IPCE_DEBUGGER_FIRST_Num;
1039 }
1040 else
1041 {
1042 i = DB_IPCE_DEBUGGER_FIRST_Num + 1;
1043 lim = nameCount;
1044 }
1045
1046 for (/**/; i < lim; i++)
1047 {
1048 if (DbgIPCEventTypeNames[i].eventType == eventType)
1049 return DbgIPCEventTypeNames[i].eventName;
1050 }
1051
1052 return DbgIPCEventTypeNames[nameCount - 1].eventName;
1053 }
1054};
1055
1056#endif // !DACCESS_COMPILE
1057
1058//
1059// NOTE: CPU-specific values below!
1060//
1061// DebuggerREGDISPLAY is very similar to the EE REGDISPLAY structure. It holds
1062// register values that can be saved over calls for each frame in a stack
1063// trace.
1064//
1065// DebuggerIPCE_FloatCount is the number of doubles in the processor's
1066// floating point stack.
1067//
1068// <TODO>Note: We used to just pass the values of the registers for each frame to the Right Side, but I had to add in the
1069// address of each register, too, to support using enregistered variables on non-leaf frames as args to a func eval. Its
1070// very, very possible that we would rework the entire code base to just use the register's address instead of passing
1071// both, but its way, way too late in V1 to undertake that, so I'm just using these addresses to suppport our one func
1072// eval case. Clearly, this needs to be cleaned up post V1.
1073//
1074// -- Fri Feb 09 11:21:24 2001</TODO>
1075//
1076
1077struct MSLAYOUT DebuggerREGDISPLAY
1078{
1079#if defined(DBG_TARGET_X86)
1080 #define DebuggerIPCE_FloatCount 8
1081
1082 SIZE_T Edi;
1083 void *pEdi;
1084 SIZE_T Esi;
1085 void *pEsi;
1086 SIZE_T Ebx;
1087 void *pEbx;
1088 SIZE_T Edx;
1089 void *pEdx;
1090 SIZE_T Ecx;
1091 void *pEcx;
1092 SIZE_T Eax;
1093 void *pEax;
1094 SIZE_T FP;
1095 void *pFP;
1096 SIZE_T SP;
1097 SIZE_T PC;
1098
1099#elif defined(DBG_TARGET_AMD64)
1100 #define DebuggerIPCE_FloatCount 16
1101
1102 SIZE_T Rax;
1103 void *pRax;
1104 SIZE_T Rcx;
1105 void *pRcx;
1106 SIZE_T Rdx;
1107 void *pRdx;
1108 SIZE_T Rbx;
1109 void *pRbx;
1110 SIZE_T Rbp;
1111 void *pRbp;
1112 SIZE_T Rsi;
1113 void *pRsi;
1114 SIZE_T Rdi;
1115 void *pRdi;
1116
1117 SIZE_T R8;
1118 void *pR8;
1119 SIZE_T R9;
1120 void *pR9;
1121 SIZE_T R10;
1122 void *pR10;
1123 SIZE_T R11;
1124 void *pR11;
1125 SIZE_T R12;
1126 void *pR12;
1127 SIZE_T R13;
1128 void *pR13;
1129 SIZE_T R14;
1130 void *pR14;
1131 SIZE_T R15;
1132 void *pR15;
1133
1134 SIZE_T SP;
1135 SIZE_T PC;
1136#elif defined(DBG_TARGET_ARM)
1137 #define DebuggerIPCE_FloatCount 32
1138
1139 SIZE_T R0;
1140 void *pR0;
1141 SIZE_T R1;
1142 void *pR1;
1143 SIZE_T R2;
1144 void *pR2;
1145 SIZE_T R3;
1146 void *pR3;
1147 SIZE_T R4;
1148 void *pR4;
1149 SIZE_T R5;
1150 void *pR5;
1151 SIZE_T R6;
1152 void *pR6;
1153 SIZE_T R7;
1154 void *pR7;
1155 SIZE_T R8;
1156 void *pR8;
1157 SIZE_T R9;
1158 void *pR9;
1159 SIZE_T R10;
1160 void *pR10;
1161 SIZE_T R11;
1162 void *pR11;
1163 SIZE_T R12;
1164 void *pR12;
1165 SIZE_T SP;
1166 void *pSP;
1167 SIZE_T LR;
1168 void *pLR;
1169 SIZE_T PC;
1170 void *pPC;
1171#elif defined(DBG_TARGET_ARM64)
1172 #define DebuggerIPCE_FloatCount 32
1173
1174 SIZE_T X[29];
1175 SIZE_T SP;
1176 SIZE_T FP;
1177 SIZE_T LR;
1178 SIZE_T PC;
1179#else
1180 #define DebuggerIPCE_FloatCount 1
1181
1182 SIZE_T PC;
1183 SIZE_T FP;
1184 SIZE_T SP;
1185 void *pFP;
1186#endif
1187};
1188
1189inline LPVOID GetSPAddress(const DebuggerREGDISPLAY * display)
1190{
1191 return (LPVOID)&display->SP;
1192}
1193
1194#if !defined(DBG_TARGET_AMD64) && !defined(DBG_TARGET_ARM)
1195inline LPVOID GetFPAddress(const DebuggerREGDISPLAY * display)
1196{
1197 return (LPVOID)&display->FP;
1198}
1199#endif // !DBG_TARGET_AMD64
1200
1201
1202class MSLAYOUT FramePointer
1203{
1204friend bool IsCloserToLeaf(FramePointer fp1, FramePointer fp2);
1205friend bool IsCloserToRoot(FramePointer fp1, FramePointer fp2);
1206friend bool IsEqualOrCloserToLeaf(FramePointer fp1, FramePointer fp2);
1207friend bool IsEqualOrCloserToRoot(FramePointer fp1, FramePointer fp2);
1208
1209public:
1210
1211 static FramePointer MakeFramePointer(LPVOID sp)
1212 {
1213 LIMITED_METHOD_DAC_CONTRACT;
1214 FramePointer fp;
1215 fp.m_sp = sp;
1216 return fp;
1217 }
1218
1219 static FramePointer MakeFramePointer(UINT_PTR sp)
1220 {
1221 SUPPORTS_DAC;
1222 return MakeFramePointer((LPVOID)sp);
1223 }
1224
1225 inline bool operator==(FramePointer fp)
1226 {
1227 return (m_sp == fp.m_sp);
1228 }
1229
1230 inline bool operator!=(FramePointer fp)
1231 {
1232 return !(*this == fp);
1233 }
1234
1235 // This is needed because on the RS, the m_id values of CordbFrame and
1236 // CordbChain are really FramePointers.
1237 LPVOID GetSPValue() const
1238 {
1239 return m_sp;
1240 }
1241
1242
1243private:
1244 // Declare some private constructors which signatures matching common usage of FramePointer
1245 // to prevent people from accidentally assigning a pointer to a FramePointer().
1246 FramePointer &operator=(LPVOID sp);
1247 FramePointer &operator=(BYTE* sp);
1248 FramePointer &operator=(const BYTE* sp);
1249
1250 LPVOID m_sp;
1251};
1252
1253// For non-IA64 platforms, we use stack pointers as frame pointers.
1254// (Stack grows towards smaller address.)
1255#define LEAF_MOST_FRAME FramePointer::MakeFramePointer((LPVOID)NULL)
1256#define ROOT_MOST_FRAME FramePointer::MakeFramePointer((LPVOID)-1)
1257
1258static_assert_no_msg(sizeof(FramePointer) == sizeof(void*));
1259
1260
1261inline bool IsCloserToLeaf(FramePointer fp1, FramePointer fp2)
1262{
1263 return (fp1.m_sp < fp2.m_sp);
1264}
1265
1266inline bool IsCloserToRoot(FramePointer fp1, FramePointer fp2)
1267{
1268 return (fp1.m_sp > fp2.m_sp);
1269}
1270
1271inline bool IsEqualOrCloserToLeaf(FramePointer fp1, FramePointer fp2)
1272{
1273 return !IsCloserToRoot(fp1, fp2);
1274}
1275
1276inline bool IsEqualOrCloserToRoot(FramePointer fp1, FramePointer fp2)
1277{
1278 return !IsCloserToLeaf(fp1, fp2);
1279}
1280
1281
1282// struct DebuggerIPCE_FuncData: DebuggerIPCE_FuncData holds data
1283// to describe a given function, its
1284// class, and a little bit about the code for the function. This is used
1285// in the stack trace result data to pass function information back that
1286// may be needed. Its also used when getting data about a specific function.
1287//
1288// void* nativeStartAddressPtr: Ptr to CORDB_ADDRESS, which is
1289// the address of the real start address of the native code.
1290// This field will be NULL only if the method hasn't been JITted
1291// yet (and thus no code is available). Otherwise, it will be
1292// the adress of a CORDB_ADDRESS in the remote memory. This
1293// CORDB_ADDRESS may be NULL, in which case the code is unavailable
1294// has been pitched (return CORDBG_E_CODE_NOT_AVAILABLE)
1295//
1296// SIZE_T nVersion: The version of the code that this instance of the
1297// function is using.
1298struct MSLAYOUT DebuggerIPCE_FuncData
1299{
1300 mdMethodDef funcMetadataToken;
1301 VMPTR_DomainFile vmDomainFile;
1302
1303 mdTypeDef classMetadataToken;
1304
1305 void* ilStartAddress;
1306 SIZE_T ilSize;
1307
1308 SIZE_T currentEnCVersion;
1309
1310 mdSignature localVarSigToken;
1311
1312
1313};
1314
1315// struct DebuggerIPCE_JITFuncData: DebuggerIPCE_JITFuncData holds
1316// a little bit about the JITted code for the function.
1317//
1318// void* nativeStartAddressPtr: Ptr to CORDB_ADDRESS, which is
1319// the address of the real start address of the native code.
1320// This field will be NULL only if the method hasn't been JITted
1321// yet (and thus no code is available). Otherwise, it will be
1322// the address of a CORDB_ADDRESS in the remote memory. This
1323// CORDB_ADDRESS may be NULL, in which case the code is unavailable
1324// or has been pitched (return CORDBG_E_CODE_NOT_AVAILABLE)
1325//
1326// SIZE_T nativeSize: Size of the native code.
1327//
1328// SIZE_T nativeOffset: Offset from the beginning of the function,
1329// in bytes. This may be non-zero even when nativeStartAddressPtr
1330// is NULL
1331// void * nativeCodeJITInfoToken: An opaque value to hand back to the left
1332// side when fetching the JITInfo for the native code, i.e. the
1333// IL->native maps for the variables. This may be NULL if no JITInfo is available.
1334// void * nativeCodeMethodDescToken: An opaque value to hand back to the left
1335// side when fetching the code. In addition this token can act as the
1336// unique identity for the native code in the case where there are
1337// multiple blobs of native code per IL method (i.e. if the method is
1338// generic code of some kind)
1339// BOOL isInstantiatedGeneric: Indicates if the method is
1340// generic code of some kind.
1341// BOOL jsutAfterILThrow: indicates that code just threw a software exception and
1342// nativeOffset points to an instruction just after [call IL_Throw].
1343// This is being used to figure out a real offset of the exception origin.
1344// By subtracting STACKWALK_CONTROLPC_ADJUST_OFFSET from nativeOffset you can get
1345// an address somewhere inside [call IL_Throw] instruction.
1346// void *ilToNativeMapAddr etc.: If nativeCodeJITInfoToken is not NULL then these
1347// specify the table giving the mapping of IPs.
1348struct MSLAYOUT DebuggerIPCE_JITFuncData
1349{
1350 TADDR nativeStartAddressPtr;
1351 SIZE_T nativeHotSize;
1352
1353 // If we have a cold region, need its size & the pointer to where starts.
1354 TADDR nativeStartAddressColdPtr;
1355 SIZE_T nativeColdSize;
1356
1357
1358 SIZE_T nativeOffset;
1359 LSPTR_DJI nativeCodeJITInfoToken;
1360 VMPTR_MethodDesc vmNativeCodeMethodDescToken;
1361
1362#ifdef WIN64EXCEPTIONS
1363 BOOL fIsFilterFrame;
1364 SIZE_T parentNativeOffset;
1365 FramePointer fpParentOrSelf;
1366#endif // WIN64EXCEPTIONS
1367
1368 // indicates if the MethodDesc is a generic function or a method inside a generic class (or
1369 // both!).
1370 BOOL isInstantiatedGeneric;
1371
1372 // this is the version of the jitted code
1373 SIZE_T enCVersion;
1374
1375 BOOL jsutAfterILThrow;
1376};
1377
1378//
1379// DebuggerIPCE_STRData holds data for each stack frame or chain. This data is passed
1380// from the RC to the DI during a stack walk.
1381//
1382#if defined(_MSC_VER)
1383#pragma warning( push )
1384#pragma warning( disable:4324 ) // the compiler pads a structure to comply with alignment requirements
1385#endif // ARM context structures have a 16-byte alignment requirement
1386struct MSLAYOUT DebuggerIPCE_STRData
1387{
1388 FramePointer fp;
1389 // @dbgtodo stackwalker/shim- Ideally we should be able to get rid of the DebuggerREGDISPLAY and just use the CONTEXT.
1390 DT_CONTEXT ctx;
1391 DebuggerREGDISPLAY rd;
1392 bool quicklyUnwound;
1393
1394 VMPTR_AppDomain vmCurrentAppDomainToken;
1395
1396
1397 enum EType
1398 {
1399 cMethodFrame = 0,
1400 cChain,
1401 cStubFrame,
1402 cRuntimeNativeFrame
1403 } eType;
1404
1405 union MSLAYOUT
1406 {
1407 // Data for a chain
1408 struct MSLAYOUT
1409 {
1410 CorDebugChainReason chainReason;
1411 bool managed;
1412 } u;
1413
1414 // Data for a Method
1415 struct MSLAYOUT
1416 {
1417 struct DebuggerIPCE_FuncData funcData;
1418 struct DebuggerIPCE_JITFuncData jitFuncData;
1419 SIZE_T ILOffset;
1420 CorDebugMappingResult mapping;
1421
1422 bool fVarArgs;
1423
1424 // Indicates whether the managed method has any metadata.
1425 // Some dynamic methods such as IL stubs and LCG methods don't have any metadata.
1426 // This is used only by the V3 stackwalker, not the V2 one, because we only
1427 // expose dynamic methods as real stack frames in V3.
1428 bool fNoMetadata;
1429
1430 TADDR taAmbientESP;
1431
1432 GENERICS_TYPE_TOKEN exactGenericArgsToken;
1433 DWORD dwExactGenericArgsTokenIndex;
1434
1435 } v;
1436
1437 // Data for an Stub Frame.
1438 struct MSLAYOUT
1439 {
1440 mdMethodDef funcMetadataToken;
1441 VMPTR_DomainFile vmDomainFile;
1442 VMPTR_MethodDesc vmMethodDesc;
1443 CorDebugInternalFrameType frameType;
1444 } stubFrame;
1445
1446 };
1447};
1448#if defined(_MSC_VER)
1449#pragma warning( pop )
1450#endif
1451
1452//
1453// DebuggerIPCE_BasicTypeData and DebuggerIPCE_ExpandedTypeData
1454// hold data for each type sent across the
1455// boundary, whether it be a constructed type List<String> or a non-constructed
1456// type such as String, Foo or Object.
1457//
1458// Logically speaking DebuggerIPCE_BasicTypeData might just be "typeHandle", as
1459// we could then send further events to ask what the elementtype, typeToken and moduleToken
1460// are for the type handle. But as
1461// nearly all types are non-generic we send across even the basic type information in
1462// the slightly expanded form shown below, sending the element type and the
1463// tokens with the type handle itself. The fields debuggerModuleToken, metadataToken and typeHandle
1464// are only used as follows:
1465// elementType debuggerModuleToken metadataToken typeHandle
1466// E_T_INT8 : E_T_INT8 No No No
1467// Boxed E_T_INT8: E_T_CLASS No No No
1468// E_T_CLASS, non-generic class: E_T_CLASS Yes Yes No
1469// E_T_VALUETYPE, non-generic: E_T_VALUETYPE Yes Yes No
1470// E_T_CLASS, generic class: E_T_CLASS Yes Yes Yes
1471// E_T_VALUETYPE, generic class: E_T_VALUETYPE Yes Yes Yes
1472// E_T_BYREF : E_T_BYREF No No Yes
1473// E_T_PTR : E_T_PTR No No Yes
1474// E_T_ARRAY etc. : E_T_ARRAY No No Yes
1475// E_T_FNPTR etc. : E_T_FNPTR No No Yes
1476// This allows us to always set "typeHandle" to NULL except when dealing with highly nested
1477// types or function-pointer types (the latter are too complexe to transfer over in one hit).
1478//
1479
1480struct MSLAYOUT DebuggerIPCE_BasicTypeData
1481{
1482 CorElementType elementType;
1483 mdTypeDef metadataToken;
1484 VMPTR_Module vmModule;
1485 VMPTR_DomainFile vmDomainFile;
1486 VMPTR_TypeHandle vmTypeHandle;
1487};
1488
1489// DebuggerIPCE_ExpandedTypeData contains more information showing further
1490// details for array types, byref types etc.
1491// Whenever you fetch type information from the left-side
1492// you get back one of these. These in turn contain further
1493// DebuggerIPCE_BasicTypeData's and typeHandles which you can
1494// then query to get further information about the type parameters.
1495// This copes with the nested cases, e.g. jagged arrays,
1496// String ****, &(String*), Pair<String,Pair<String>>
1497// and so on.
1498//
1499// So this type information is not "fully expanded", it's just a little
1500// more detail then DebuggerIPCE_BasicTypeData. For type
1501// instantiatons (e.g. List<int>) and
1502// function pointer types you will need to make further requests for
1503// information about the type parameters.
1504// For array types there is always only one type parameter so
1505// we include that as part of the expanded data.
1506//
1507//
1508struct MSLAYOUT DebuggerIPCE_ExpandedTypeData
1509{
1510 CorElementType elementType; // Note this is _never_ E_T_VAR, E_T_WITH or E_T_MVAR
1511 union MSLAYOUT
1512 {
1513 // used for E_T_CLASS and E_T_VALUECLASS, E_T_PTR, E_T_BYREF etc.
1514 // For non-constructed E_T_CLASS or E_T_VALUECLASS the tokens will be set and the typeHandle will be NULL
1515 // For constructed E_T_CLASS or E_T_VALUECLASS the tokens will be set and the typeHandle will be non-NULL
1516 // For E_T_PTR etc. the tokens will be NULL and the typeHandle will be non-NULL.
1517 struct MSLAYOUT
1518 {
1519 mdTypeDef metadataToken;
1520 VMPTR_Module vmModule;
1521 VMPTR_DomainFile vmDomainFile;
1522 VMPTR_TypeHandle typeHandle; // if non-null then further fetches will be needed to get type arguments
1523 } ClassTypeData;
1524
1525 // used for E_T_PTR, E_T_BYREF etc.
1526 struct MSLAYOUT
1527 {
1528 DebuggerIPCE_BasicTypeData unaryTypeArg; // used only when sending back to debugger
1529 } UnaryTypeData;
1530
1531
1532 // used for E_T_ARRAY etc.
1533 struct MSLAYOUT
1534 {
1535 DebuggerIPCE_BasicTypeData arrayTypeArg; // used only when sending back to debugger
1536 DWORD arrayRank;
1537 } ArrayTypeData;
1538
1539 // used for E_T_FNPTR
1540 struct MSLAYOUT
1541 {
1542 VMPTR_TypeHandle typeHandle; // if non-null then further fetches needed to get type arguments
1543 } NaryTypeData;
1544
1545 };
1546};
1547
1548// DebuggerIPCE_TypeArgData is used when sending type arguments
1549// across to a funceval. It contains the DebuggerIPCE_ExpandedTypeData describing the
1550// essence of the type, but the typeHandle and other
1551// BasicTypeData fields should be zero and will be ignored.
1552// The DebuggerIPCE_ExpandedTypeData is then followed
1553// by the required number of type arguments, each of which
1554// will be a further DebuggerIPCE_TypeArgData record in the stream of
1555// flattened type argument data.
1556struct MSLAYOUT DebuggerIPCE_TypeArgData
1557{
1558 DebuggerIPCE_ExpandedTypeData data;
1559 unsigned int numTypeArgs; // number of immediate children on the type tree
1560};
1561
1562
1563//
1564// DebuggerIPCE_ObjectData holds the results of a
1565// GetAndSendObjectInfo, i.e., all the info about an object that the
1566// Right Side would need to access it. (This include array, string,
1567// and nstruct info.)
1568//
1569struct MSLAYOUT DebuggerIPCE_ObjectData
1570{
1571 void *objRef;
1572 bool objRefBad;
1573 SIZE_T objSize;
1574
1575 // Offset from the beginning of the object to the beginning of the first field
1576 SIZE_T objOffsetToVars;
1577
1578 // The type of the object....
1579 struct DebuggerIPCE_ExpandedTypeData objTypeData;
1580
1581 union MSLAYOUT
1582 {
1583 struct MSLAYOUT
1584 {
1585 SIZE_T length;
1586 SIZE_T offsetToStringBase;
1587 } stringInfo;
1588
1589 struct MSLAYOUT
1590 {
1591 SIZE_T rank;
1592 SIZE_T offsetToArrayBase;
1593 SIZE_T offsetToLowerBounds; // 0 if not present
1594 SIZE_T offsetToUpperBounds; // 0 if not present
1595 SIZE_T componentCount;
1596 SIZE_T elementSize;
1597 } arrayInfo;
1598
1599 struct MSLAYOUT
1600 {
1601 struct DebuggerIPCE_BasicTypeData typedByrefType; // the type of the thing contained in a typedByref...
1602 } typedByrefInfo;
1603 };
1604};
1605
1606//
1607// Remote enregistered info used by CordbValues and for passing
1608// variable homes between the left and right sides during a func eval.
1609//
1610
1611enum RemoteAddressKind
1612{
1613 RAK_NONE = 0,
1614 RAK_REG,
1615 RAK_REGREG,
1616 RAK_REGMEM,
1617 RAK_MEMREG,
1618 RAK_FLOAT,
1619 RAK_END
1620};
1621
1622const CORDB_ADDRESS kLeafFrameRegAddr = 0;
1623const CORDB_ADDRESS kNonLeafFrameRegAddr = (CORDB_ADDRESS)(-1);
1624
1625struct MSLAYOUT RemoteAddress
1626{
1627 RemoteAddressKind kind;
1628 void *frame;
1629
1630 CorDebugRegister reg1;
1631 void *reg1Addr;
1632 SIZE_T reg1Value; // this is the actual value of the register
1633
1634 union MSLAYOUT
1635 {
1636 struct MSLAYOUT
1637 {
1638 CorDebugRegister reg2;
1639 void *reg2Addr;
1640 SIZE_T reg2Value; // this is the actual value of the register
1641 } u;
1642
1643 CORDB_ADDRESS addr;
1644 DWORD floatIndex;
1645 };
1646};
1647
1648//
1649// DebuggerIPCE_FuncEvalType specifies the type of a function
1650// evaluation that will occur.
1651//
1652enum DebuggerIPCE_FuncEvalType
1653{
1654 DB_IPCE_FET_NORMAL,
1655 DB_IPCE_FET_NEW_OBJECT,
1656 DB_IPCE_FET_NEW_OBJECT_NC,
1657 DB_IPCE_FET_NEW_STRING,
1658 DB_IPCE_FET_NEW_ARRAY,
1659 DB_IPCE_FET_RE_ABORT
1660};
1661
1662
1663enum NameChangeType
1664{
1665 APP_DOMAIN_NAME_CHANGE,
1666 THREAD_NAME_CHANGE
1667};
1668
1669//
1670// DebuggerIPCE_FuncEvalArgData holds data for each argument to a
1671// function evaluation.
1672//
1673struct MSLAYOUT DebuggerIPCE_FuncEvalArgData
1674{
1675 RemoteAddress argHome; // enregistered variable home
1676 void *argAddr; // address if not enregistered
1677 CorElementType argElementType;
1678 unsigned int fullArgTypeNodeCount; // Pointer to LS (DebuggerIPCE_TypeArgData *) buffer holding full description of the argument type (if needed - only needed for struct types)
1679 void *fullArgType; // Pointer to LS (DebuggerIPCE_TypeArgData *) buffer holding full description of the argument type (if needed - only needed for struct types)
1680 BYTE argLiteralData[8]; // copy of generic value data
1681 bool argIsLiteral; // true if value is in argLiteralData
1682 bool argIsHandleValue; // true if argAddr is OBJECTHANDLE
1683};
1684
1685
1686//
1687// DebuggerIPCE_FuncEvalInfo holds info necessary to setup a func eval
1688// operation.
1689//
1690struct MSLAYOUT DebuggerIPCE_FuncEvalInfo
1691{
1692 VMPTR_Thread vmThreadToken;
1693 DebuggerIPCE_FuncEvalType funcEvalType;
1694 mdMethodDef funcMetadataToken;
1695 mdTypeDef funcClassMetadataToken;
1696 VMPTR_DomainFile vmDomainFile;
1697 RSPTR_CORDBEVAL funcEvalKey;
1698 bool evalDuringException;
1699
1700 unsigned int argCount;
1701 unsigned int genericArgsCount;
1702 unsigned int genericArgsNodeCount;
1703
1704 SIZE_T stringSize;
1705
1706 SIZE_T arrayRank;
1707};
1708
1709
1710//
1711// Used in DebuggerIPCFirstChanceData. This tells the LS what action to take within the hijack
1712//
1713enum HijackAction
1714{
1715 HIJACK_ACTION_EXIT_UNHANDLED,
1716 HIJACK_ACTION_EXIT_HANDLED,
1717 HIJACK_ACTION_WAIT
1718};
1719
1720//
1721// DebuggerIPCFirstChanceData holds info communicated from the LS to the RS when signaling that an exception does not
1722// belong to the runtime from a first chance hijack. This is used when Win32 debugging only.
1723//
1724struct MSLAYOUT DebuggerIPCFirstChanceData
1725{
1726 LSPTR_CONTEXT pLeftSideContext;
1727 HijackAction action;
1728 UINT debugCounter;
1729};
1730
1731//
1732// DebuggerIPCSecondChanceData holds info communicated from the RS
1733// to the LS when setting up a second chance exception hijack. This is
1734// used when Win32 debugging only.
1735//
1736struct MSLAYOUT DebuggerIPCSecondChanceData
1737{
1738 DT_CONTEXT threadContext;
1739};
1740
1741
1742
1743//-----------------------------------------------------------------------------
1744// This struct holds pointer from the LS and needs to copy to
1745// the RS. We have to free the memory on the RS.
1746// The transfer function is called when the RS first reads the event. At this point,
1747// the LS is stopped while sending the event. Thus the LS pointers only need to be
1748// valid while the LS is in SendIPCEvent.
1749//
1750// Since this data is in an IPC/Marshallable block, it can't have any Ctors (holders)
1751// in it.
1752//-----------------------------------------------------------------------------
1753struct MSLAYOUT Ls_Rs_BaseBuffer
1754{
1755#ifdef RIGHT_SIDE_COMPILE
1756protected:
1757 // copy data can happen on both LS and RS. In LS case,
1758 // ReadProcessMemory is really reading from its own process memory.
1759 //
1760 void CopyLSDataToRSWorker(ICorDebugDataTarget * pTargethProcess);
1761
1762 // retrieve the RS data and own it
1763 BYTE *TransferRSDataWorker()
1764 {
1765 BYTE *pbRS = m_pbRS;
1766 m_pbRS = NULL;
1767 return pbRS;
1768 }
1769public:
1770
1771
1772 void CleanUp()
1773 {
1774 if (m_pbRS != NULL)
1775 {
1776 delete [] m_pbRS;
1777 m_pbRS = NULL;
1778 }
1779 }
1780#else
1781public:
1782 // Only LS can call this API
1783 void SetLsData(BYTE *pbLS, DWORD cbSize)
1784 {
1785 m_pbRS = NULL;
1786 m_pbLS = pbLS;
1787 m_cbSize = cbSize;
1788 }
1789#endif // RIGHT_SIDE_COMPILE
1790
1791public:
1792 // Common APIs.
1793 DWORD GetSize() { return m_cbSize; }
1794
1795
1796
1797protected:
1798 // Size of data in bytes
1799 DWORD m_cbSize;
1800
1801 // If this is non-null, pointer into LS for buffer.
1802 // LS can free this after the debug event is continued.
1803 BYTE *m_pbLS; // @dbgtodo cross-plat- for cross-platform purposes, this should be a TADDR
1804
1805 // If this is non-null, pointer into RS for buffer. RS must then free this.
1806 // This buffer was copied from the LS (via CopyLSDataToRSWorker).
1807 BYTE *m_pbRS;
1808};
1809
1810//-----------------------------------------------------------------------------
1811// Byte wrapper around the buffer.
1812//-----------------------------------------------------------------------------
1813struct MSLAYOUT Ls_Rs_ByteBuffer : public Ls_Rs_BaseBuffer
1814{
1815#ifdef RIGHT_SIDE_COMPILE
1816 BYTE *GetRSPointer()
1817 {
1818 return m_pbRS;
1819 }
1820
1821 void CopyLSDataToRS(ICorDebugDataTarget * pTarget);
1822 BYTE *TransferRSData()
1823 {
1824 return TransferRSDataWorker();
1825 }
1826#endif
1827};
1828
1829//-----------------------------------------------------------------------------
1830// Wrapper around a Ls_rS_Buffer to get it as a string.
1831// This can also do some sanity checking.
1832//-----------------------------------------------------------------------------
1833struct MSLAYOUT Ls_Rs_StringBuffer : public Ls_Rs_BaseBuffer
1834{
1835#ifdef RIGHT_SIDE_COMPILE
1836 const WCHAR * GetString()
1837 {
1838 return reinterpret_cast<const WCHAR*> (m_pbRS);
1839 }
1840
1841 // Copy over the string.
1842 void CopyLSDataToRS(ICorDebugDataTarget * pTarget);
1843
1844 // Caller will pick up ownership.
1845 // Since caller will delete this data, we can't give back a constant pointer.
1846 WCHAR * TransferStringData()
1847 {
1848 return reinterpret_cast<WCHAR*> (TransferRSDataWorker());
1849 }
1850#endif
1851};
1852
1853
1854// Data for an Managed Debug Assistant Probe (MDA).
1855struct MSLAYOUT DebuggerMDANotification
1856{
1857 Ls_Rs_StringBuffer szName;
1858 Ls_Rs_StringBuffer szDescription;
1859 Ls_Rs_StringBuffer szXml;
1860 DWORD dwOSThreadId;
1861 CorDebugMDAFlags flags;
1862};
1863
1864
1865// The only remaining problem is that register number mappings are different for each platform. It turns out
1866// that the debugger only uses REGNUM_SP and REGNUM_AMBIENT_SP though, so we can just virtualize these two for
1867// the target platform.
1868// Keep this is sync with the definitions in inc/corinfo.h.
1869#if defined(DBG_TARGET_X86)
1870#define DBG_TARGET_REGNUM_SP 4
1871#define DBG_TARGET_REGNUM_AMBIENT_SP 9
1872#ifdef _TARGET_X86_
1873static_assert_no_msg(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
1874static_assert_no_msg(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
1875#endif // _TARGET_X86_
1876#elif defined(DBG_TARGET_AMD64)
1877#define DBG_TARGET_REGNUM_SP 4
1878#define DBG_TARGET_REGNUM_AMBIENT_SP 17
1879#ifdef _TARGET_AMD64_
1880static_assert_no_msg(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
1881static_assert_no_msg(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
1882#endif // _TARGET_AMD64_
1883#elif defined(DBG_TARGET_ARM)
1884#define DBG_TARGET_REGNUM_SP 13
1885#define DBG_TARGET_REGNUM_AMBIENT_SP 17
1886#ifdef _TARGET_ARM_
1887C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
1888C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
1889#endif // _TARGET_ARM_
1890#elif defined(DBG_TARGET_ARM64)
1891#define DBG_TARGET_REGNUM_SP 31
1892#define DBG_TARGET_REGNUM_AMBIENT_SP 34
1893#ifdef _TARGET_ARM64_
1894C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
1895C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
1896#endif // _TARGET_ARM64_
1897#else
1898#error Target registers are not defined for this platform
1899#endif
1900
1901
1902//
1903// Event structure that is passed between the Runtime Controller and the
1904// Debugger Interface. Some types of events are a fixed size and have
1905// entries in the main union, while others are variable length and have
1906// more specialized data structures that are attached to the end of this
1907// structure.
1908//
1909struct MSLAYOUT DebuggerIPCEvent
1910{
1911 DebuggerIPCEvent* next;
1912 DebuggerIPCEventType type;
1913 DWORD processId;
1914 DWORD threadId;
1915 VMPTR_AppDomain vmAppDomain;
1916 VMPTR_Thread vmThread;
1917
1918 HRESULT hr;
1919 bool replyRequired;
1920 bool asyncSend;
1921
1922 union MSLAYOUT
1923 {
1924 struct MSLAYOUT
1925 {
1926 // Pointer to a BOOL in the target.
1927 CORDB_ADDRESS pfBeingDebugged;
1928 } LeftSideStartupData;
1929
1930 struct MSLAYOUT
1931 {
1932 // Module whos metadata is being updated
1933 // This tells the RS that the metadata for that module has become invalid.
1934 VMPTR_DomainFile vmDomainFile;
1935
1936 } MetadataUpdateData;
1937
1938 struct MSLAYOUT
1939 {
1940 // Handle to CLR's internal appdomain object.
1941 VMPTR_AppDomain vmAppDomain;
1942 } AppDomainData;
1943
1944 struct MSLAYOUT
1945 {
1946 VMPTR_DomainAssembly vmDomainAssembly;
1947 } AssemblyData;
1948
1949#ifdef TEST_DATA_CONSISTENCY
1950 // information necessary for testing whether the LS holds a lock on data
1951 // the RS needs to inspect. See code:DataTest::TestDataSafety and
1952 // code:IDacDbiInterface::TestCrst for more information
1953 struct MSLAYOUT
1954 {
1955 // the lock to be tested
1956 VMPTR_Crst vmCrst;
1957 // indicates whether the LS holds the lock
1958 bool fOkToTake;
1959 } TestCrstData;
1960
1961 // information necessary for testing whether the LS holds a lock on data
1962 // the RS needs to inspect. See code:DataTest::TestDataSafety and
1963 // code:IDacDbiInterface::TestCrst for more information
1964 struct MSLAYOUT
1965 {
1966 // the lock to be tested
1967 VMPTR_SimpleRWLock vmRWLock;
1968 // indicates whether the LS holds the lock
1969 bool fOkToTake;
1970 } TestRWLockData;
1971#endif // TEST_DATA_CONSISTENCY
1972
1973 // Debug event that a module has been loaded
1974 struct MSLAYOUT
1975 {
1976 // Module that was just loaded.
1977 VMPTR_DomainFile vmDomainFile;
1978 }LoadModuleData;
1979
1980
1981 struct MSLAYOUT
1982 {
1983 VMPTR_DomainFile vmDomainFile;
1984 LSPTR_ASSEMBLY debuggerAssemblyToken;
1985 } UnloadModuleData;
1986
1987
1988 // The given module's pdb has been updated.
1989 // Queury PDB from OOP
1990 struct MSLAYOUT
1991 {
1992 VMPTR_DomainFile vmDomainFile;
1993 } UpdateModuleSymsData;
1994
1995 DebuggerMDANotification MDANotification;
1996
1997 struct MSLAYOUT
1998 {
1999 LSPTR_BREAKPOINT breakpointToken;
2000 mdMethodDef funcMetadataToken;
2001 VMPTR_DomainFile vmDomainFile;
2002 bool isIL;
2003 SIZE_T offset;
2004 SIZE_T encVersion;
2005 LSPTR_METHODDESC nativeCodeMethodDescToken; // points to the MethodDesc if !isIL
2006 } BreakpointData;
2007
2008 struct MSLAYOUT
2009 {
2010 LSPTR_BREAKPOINT breakpointToken;
2011 } BreakpointSetErrorData;
2012
2013 struct MSLAYOUT
2014 {
2015#ifdef FEATURE_DATABREAKPOINT
2016 CONTEXT context;
2017#else
2018 int dummy;
2019#endif
2020 } DataBreakpointData;
2021
2022 struct MSLAYOUT
2023 {
2024 LSPTR_STEPPER stepperToken;
2025 VMPTR_Thread vmThreadToken;
2026 FramePointer frameToken;
2027 bool stepIn;
2028 bool rangeIL;
2029 bool IsJMCStop;
2030 unsigned int totalRangeCount;
2031 CorDebugStepReason reason;
2032 CorDebugUnmappedStop rgfMappingStop;
2033 CorDebugIntercept rgfInterceptStop;
2034 unsigned int rangeCount;
2035 COR_DEBUG_STEP_RANGE range; //note that this is an array
2036 } StepData;
2037
2038 struct MSLAYOUT
2039 {
2040 // An unvalidated GC-handle
2041 VMPTR_OBJECTHANDLE GCHandle;
2042 } GetGCHandleInfo;
2043
2044 struct MSLAYOUT
2045 {
2046 // An unvalidated GC-handle for which we're returning the results
2047 LSPTR_OBJECTHANDLE GCHandle;
2048
2049 // The following are initialized by the LS in response to our query:
2050 VMPTR_AppDomain vmAppDomain; // AD that handle is in (only applicable if fValid).
2051 bool fValid; // Did the LS determine the GC handle to be valid?
2052 } GetGCHandleInfoResult;
2053
2054 // Allocate memory on the left-side
2055 struct MSLAYOUT
2056 {
2057 ULONG bufSize; // number of bytes to allocate
2058 } GetBuffer;
2059
2060 // Memory allocated on the left-side
2061 struct MSLAYOUT
2062 {
2063 void *pBuffer; // LS pointer to the buffer allocated
2064 HRESULT hr; // success / failure
2065 } GetBufferResult;
2066
2067 // Free a buffer allocated on the left-side with GetBuffer
2068 struct MSLAYOUT
2069 {
2070 void *pBuffer; // Pointer previously returned in GetBufferResult
2071 } ReleaseBuffer;
2072
2073 struct MSLAYOUT
2074 {
2075 HRESULT hr;
2076 } ReleaseBufferResult;
2077
2078 // Apply an EnC edit
2079 struct MSLAYOUT
2080 {
2081 VMPTR_DomainFile vmDomainFile; // Module to edit
2082 DWORD cbDeltaMetadata; // size of blob pointed to by pDeltaMetadata
2083 CORDB_ADDRESS pDeltaMetadata; // pointer to delta metadata in debuggee
2084 // it's the RS's responsibility to allocate and free
2085 // this (and pDeltaIL) using GetBuffer / ReleaseBuffer
2086 CORDB_ADDRESS pDeltaIL; // pointer to delta IL in debugee
2087 DWORD cbDeltaIL; // size of blob pointed to by pDeltaIL
2088 } ApplyChanges;
2089
2090 struct MSLAYOUT
2091 {
2092 HRESULT hr;
2093 } ApplyChangesResult;
2094
2095 struct MSLAYOUT
2096 {
2097 mdTypeDef classMetadataToken;
2098 VMPTR_DomainFile vmDomainFile;
2099 LSPTR_ASSEMBLY classDebuggerAssemblyToken;
2100 } LoadClass;
2101
2102 struct MSLAYOUT
2103 {
2104 mdTypeDef classMetadataToken;
2105 VMPTR_DomainFile vmDomainFile;
2106 LSPTR_ASSEMBLY classDebuggerAssemblyToken;
2107 } UnloadClass;
2108
2109 struct MSLAYOUT
2110 {
2111 VMPTR_DomainFile vmDomainFile;
2112 bool flag;
2113 } SetClassLoad;
2114
2115 struct MSLAYOUT
2116 {
2117 VMPTR_OBJECTHANDLE vmExceptionHandle;
2118 bool firstChance;
2119 bool continuable;
2120 } Exception;
2121
2122 struct MSLAYOUT
2123 {
2124 VMPTR_Thread vmThreadToken;
2125 } ClearException;
2126
2127 struct MSLAYOUT
2128 {
2129 void *address;
2130 } IsTransitionStub;
2131
2132 struct MSLAYOUT
2133 {
2134 bool isStub;
2135 } IsTransitionStubResult;
2136
2137 struct MSLAYOUT
2138 {
2139 CORDB_ADDRESS startAddress;
2140 bool fCanSetIPOnly;
2141 VMPTR_Thread vmThreadToken;
2142 VMPTR_DomainFile vmDomainFile;
2143 mdMethodDef mdMethod;
2144 VMPTR_MethodDesc vmMethodDesc;
2145 SIZE_T offset;
2146 bool fIsIL;
2147 void * firstExceptionHandler;
2148 } SetIP; // this is also used for CanSetIP
2149
2150 struct MSLAYOUT
2151 {
2152 int iLevel;
2153
2154 EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szCategory;
2155 Ls_Rs_StringBuffer szContent;
2156 } FirstLogMessage;
2157
2158 struct MSLAYOUT
2159 {
2160 int iLevel;
2161 int iReason;
2162
2163 EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szSwitchName;
2164 EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szParentSwitchName;
2165 } LogSwitchSettingMessage;
2166
2167 // information needed to send to the RS as part of a custom notification from the target
2168 struct MSLAYOUT
2169 {
2170 // Domain file for the domain in which the notification occurred
2171 VMPTR_DomainFile vmDomainFile;
2172
2173 // metadata token for the type of the CustomNotification object's type
2174 mdTypeDef classToken;
2175 } CustomNotification;
2176
2177 struct MSLAYOUT
2178 {
2179 VMPTR_Thread vmThreadToken;
2180 CorDebugThreadState debugState;
2181 } SetAllDebugState;
2182
2183 DebuggerIPCE_FuncEvalInfo FuncEval;
2184
2185 struct MSLAYOUT
2186 {
2187 CORDB_ADDRESS argDataArea;
2188 LSPTR_DEBUGGEREVAL debuggerEvalKey;
2189 } FuncEvalSetupComplete;
2190
2191 struct MSLAYOUT
2192 {
2193 RSPTR_CORDBEVAL funcEvalKey;
2194 bool successful;
2195 bool aborted;
2196 void *resultAddr;
2197
2198 // AppDomain that the result is in.
2199 VMPTR_AppDomain vmAppDomain;
2200
2201 VMPTR_OBJECTHANDLE vmObjectHandle;
2202 DebuggerIPCE_ExpandedTypeData resultType;
2203 } FuncEvalComplete;
2204
2205 struct MSLAYOUT
2206 {
2207 LSPTR_DEBUGGEREVAL debuggerEvalKey;
2208 } FuncEvalAbort;
2209
2210 struct MSLAYOUT
2211 {
2212 LSPTR_DEBUGGEREVAL debuggerEvalKey;
2213 } FuncEvalRudeAbort;
2214
2215 struct MSLAYOUT
2216 {
2217 LSPTR_DEBUGGEREVAL debuggerEvalKey;
2218 } FuncEvalCleanup;
2219
2220 struct MSLAYOUT
2221 {
2222 void *objectRefAddress;
2223 VMPTR_OBJECTHANDLE vmObjectHandle;
2224 void *newReference;
2225 } SetReference;
2226
2227 struct MSLAYOUT
2228 {
2229 NameChangeType eventType;
2230 VMPTR_AppDomain vmAppDomain;
2231 VMPTR_Thread vmThread;
2232 } NameChange;
2233
2234 struct MSLAYOUT
2235 {
2236 VMPTR_DomainFile vmDomainFile;
2237 BOOL fAllowJitOpts;
2238 BOOL fEnableEnC;
2239 } JitDebugInfo;
2240
2241 // EnC Remap opportunity
2242 struct MSLAYOUT
2243 {
2244 VMPTR_DomainFile vmDomainFile;
2245 mdMethodDef funcMetadataToken ; // methodDef of function with remap opportunity
2246 SIZE_T currentVersionNumber; // version currently executing
2247 SIZE_T resumeVersionNumber; // latest version
2248 SIZE_T currentILOffset; // the IL offset of the current IP
2249 SIZE_T *resumeILOffset; // pointer into left-side where an offset to resume
2250 // to should be written if remap is desired.
2251 } EnCRemap;
2252
2253 // EnC Remap has taken place
2254 struct MSLAYOUT
2255 {
2256 VMPTR_DomainFile vmDomainFile;
2257 mdMethodDef funcMetadataToken; // methodDef of function that was remapped
2258 } EnCRemapComplete;
2259
2260 // Notification that the LS is about to update a CLR data structure to account for a
2261 // specific edit made by EnC (function add/update or field add).
2262 struct MSLAYOUT
2263 {
2264 VMPTR_DomainFile vmDomainFile;
2265 mdToken memberMetadataToken; // Either a methodDef token indicating the function that
2266 // was updated/added, or a fieldDef token indicating the
2267 // field which was added.
2268 mdTypeDef classMetadataToken; // TypeDef token of the class in which the update was made
2269 SIZE_T newVersionNumber; // The new function/module version
2270 } EnCUpdate;
2271
2272 struct MSLAYOUT
2273 {
2274 void *oldData;
2275 void *newData;
2276 DebuggerIPCE_BasicTypeData type;
2277 } SetValueClass;
2278
2279
2280 // Event used to tell LS if a single function is user or non-user code.
2281 // Same structure used to get function status.
2282 // @todo - Perhaps we can bundle these up so we can set multiple funcs w/ 1 event?
2283 struct MSLAYOUT
2284 {
2285 VMPTR_DomainFile vmDomainFile;
2286 mdMethodDef funcMetadataToken;
2287 DWORD dwStatus;
2288 } SetJMCFunctionStatus;
2289
2290 struct MSLAYOUT
2291 {
2292 TASKID taskid;
2293 } GetThreadForTaskId;
2294
2295 struct MSLAYOUT
2296 {
2297 VMPTR_Thread vmThreadToken;
2298 } GetThreadForTaskIdResult;
2299
2300 struct MSLAYOUT
2301 {
2302 CONNID connectionId;
2303 } ConnectionChange;
2304
2305 struct MSLAYOUT
2306 {
2307 CONNID connectionId;
2308 EmbeddedIPCString<MAX_LONGPATH> wzConnectionName;
2309 } CreateConnection;
2310
2311 struct MSLAYOUT
2312 {
2313 void *objectToken;
2314 BOOL fStrong;
2315 } CreateHandle;
2316
2317 struct MSLAYOUT
2318 {
2319 VMPTR_OBJECTHANDLE vmObjectHandle;
2320 } CreateHandleResult;
2321
2322 // used in DB_IPCE_DISPOSE_HANDLE event
2323 struct MSLAYOUT
2324 {
2325 VMPTR_OBJECTHANDLE vmObjectHandle;
2326 BOOL fStrong;
2327 } DisposeHandle;
2328
2329 struct MSLAYOUT
2330 {
2331 FramePointer framePointer;
2332 SIZE_T nOffset;
2333 CorDebugExceptionCallbackType eventType;
2334 DWORD dwFlags;
2335 VMPTR_OBJECTHANDLE vmExceptionHandle;
2336 } ExceptionCallback2;
2337
2338 struct MSLAYOUT
2339 {
2340 CorDebugExceptionUnwindCallbackType eventType;
2341 DWORD dwFlags;
2342 } ExceptionUnwind;
2343
2344 struct MSLAYOUT
2345 {
2346 VMPTR_Thread vmThreadToken;
2347 FramePointer frameToken;
2348 } InterceptException;
2349
2350 struct MSLAYOUT
2351 {
2352 VMPTR_Module vmModule;
2353 void * pMetadataStart;
2354 ULONG nMetadataSize;
2355 } MetadataUpdateRequest;
2356 };
2357};
2358
2359
2360// When using a network transport rather than shared memory buffers CorDBIPC_BUFFER_SIZE is the upper bound
2361// for a single DebuggerIPCEvent structure. This now relates to the maximal size of a network message and is
2362// orthogonal to the host's page size. Round the buffer size up to a multiple of 8 since MSVC seems more
2363// aggressive in this regard than gcc.
2364#define CorDBIPC_TRANSPORT_BUFFER_SIZE (((sizeof(DebuggerIPCEvent) + 7) / 8) * 8)
2365
2366// A DebuggerIPCEvent must fit in the send & receive buffers, which are CorDBIPC_BUFFER_SIZE bytes.
2367static_assert_no_msg(sizeof(DebuggerIPCEvent) <= CorDBIPC_BUFFER_SIZE);
2368static_assert_no_msg(CorDBIPC_TRANSPORT_BUFFER_SIZE <= CorDBIPC_BUFFER_SIZE);
2369
2370// 2*sizeof(WCHAR) for the two string terminating characters in the FirstLogMessage
2371#define LOG_MSG_PADDING 4
2372
2373#endif /* _DbgIPCEvents_h_ */
2374