summaryrefslogtreecommitdiff
path: root/src/debug/inc/dbgipcevents.h
blob: 6ace36e011f89736c5f5c68ed4f889535205c522 (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
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
// 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.
/* ------------------------------------------------------------------------- *
 * DbgIPCEvents.h -- header file for private Debugger data shared by various
// 

 *                   debugger components.
 * ------------------------------------------------------------------------- */

#ifndef _DbgIPCEvents_h_
#define _DbgIPCEvents_h_

#include <new.hpp>
#include <cor.h>
#include <cordebug.h>
#include <corjit.h> // for ICorDebugInfo::VarLocType & VarLoc
#include <specstrings.h>

#include "dbgtargetcontext.h"


// Get version numbers for IPCHeader stamp
#include "ndpversion.h"

#include "dbgappdomain.h"

#include "./common.h"

//-----------------------------------------------------------------------------
// V3 additions to IPC protocol between LS and RS.
//-----------------------------------------------------------------------------

// Special Exception code for LS to communicate with RS. 
// LS will raise this exception to communicate managed debug events to the RS.
// Exception codes can't use bit 0x10000000, that's reserved by OS.
#define CLRDBG_NOTIFICATION_EXCEPTION_CODE  ((DWORD) 0x04242420)

// This is exception argument 0 included in debugger notification events. 
// The debugger uses this as a sanity check.
// This could be very volatile data that changes between builds.
#define CLRDBG_EXCEPTION_DATA_CHECKSUM ((DWORD) 0x31415927)


// Reasons for hijack.
namespace EHijackReason
{
    enum EHijackReason
    {
        kUnhandledException = 1,
        kM2UHandoff = 2,
        kFirstChanceSuspend = 3,
        kGenericHijack = 4,
        kMax
    };
    inline bool IsValid(EHijackReason value)
    {
        SUPPORTS_DAC;
        return (value > 0) && (value < kMax);
    }
}



#define     MAX_LOG_SWITCH_NAME_LEN     256

//-----------------------------------------------------------------------------
// Versioning note:
// This file describes the IPC communication protocol between the LS (mscorwks)
// and the RS (mscordbi). For Desktop builds, it is private and can change on a 
// daily basis. The version of the LS will always match the version of the RS 
// (but see the discussion of CoreCLR below). They are like a single conceptual 
// DLL split across 2 processes. 
// The only restriction is that it should be flavor agnostic - so don't change
// layout based off '#ifdef DEBUG'. This lets us drop a Debug flavor RS onto
// a retail installation w/o any further installation woes. That's very useful
// for debugging.
//-----------------------------------------------------------------------------


// We want this available for DbgInterface.h - put it here.
typedef enum
{
    IPC_TARGET_OUTOFPROC,
    IPC_TARGET_COUNT,
} IpcTarget;

//
// Names of the setup sync event and shared memory used for IPC between the Left Side and the Right Side. NOTE: these
// names must include a %d for the process id. The process id used is the process id of the debuggee.
//

#define CorDBIPCSetupSyncEventName W("CorDBIPCSetupSyncEvent_%d")

//
// This define controls whether we always pass first chance exceptions to the in-process first chance hijack filter
// during interop debugging or if we try to short-circuit and make the decision out-of-process as much as possible.
//
#define CorDB_Short_Circuit_First_Chance_Ownership 1

//
// Defines for current version numbers for the left and right sides
//
#define CorDB_LeftSideProtocolCurrent           2
#define CorDB_LeftSideProtocolMinSupported      2
#define CorDB_RightSideProtocolCurrent          2
#define CorDB_RightSideProtocolMinSupported     2

//
// The remaining data structures in this file can be shared between two processes and for network transport
// based debugging this can mean two different platforms as well.  The two platforms that can share these 
// data structures must have identical layouts for them (each field must lie at the same offset and have the 
// same length). The MSLAYOUT macro should be applied to each structure to avoid any compiler packing differences.
//

//
// DebuggerIPCRuntimeOffsets contains addresses and offsets of important global variables, functions, and fields in
// Runtime objects. This is populated during Left Side initialization and is read by the Right Side. This struct is
// mostly to facilitate unmanaged debugging support, but it may have some small uses for managed debugging.
//
struct MSLAYOUT DebuggerIPCRuntimeOffsets
{
#ifdef FEATURE_INTEROP_DEBUGGING
    void   *m_genericHijackFuncAddr;
    void   *m_signalHijackStartedBPAddr;
    void   *m_excepForRuntimeHandoffStartBPAddr;
    void   *m_excepForRuntimeHandoffCompleteBPAddr;
    void   *m_signalHijackCompleteBPAddr;
    void   *m_excepNotForRuntimeBPAddr;
    void   *m_notifyRSOfSyncCompleteBPAddr;
    void   *m_raiseExceptionAddr;                       // The address of kernel32!RaiseException in the debuggee
#endif // FEATURE_INTEROP_DEBUGGING
    SIZE_T  m_TLSIndex;                                 // The TLS index the CLR is using to hold Thread objects
    SIZE_T  m_TLSIsSpecialIndex;                        // The index into the Predef block of the the "IsSpecial" status for a thread.
    SIZE_T  m_TLSCantStopIndex;                         // The index into the Predef block of the the Can't-Stop count.
    SIZE_T  m_TLSIndexOfPredefs;                        // The TLS index of the Predef block.
    SIZE_T  m_EEThreadStateOffset;                      // Offset of m_state in a Thread
    SIZE_T  m_EEThreadStateNCOffset;                    // Offset of m_stateNC in a Thread
    SIZE_T  m_EEThreadPGCDisabledOffset;                // Offset of the bit for whether PGC is disabled or not in a Thread
    DWORD   m_EEThreadPGCDisabledValue;                 // Value at m_EEThreadPGCDisabledOffset that equals "PGC disabled".
    SIZE_T  m_EEThreadDebuggerWordOffset;               // Offset of debugger word in a Thread
    SIZE_T  m_EEThreadFrameOffset;                      // Offset of the Frame ptr in a Thread
    SIZE_T  m_EEThreadMaxNeededSize;                    // Max memory to read to get what we need out of a Thread object
    DWORD   m_EEThreadSteppingStateMask;                // Mask for Thread::TSNC_DebuggerIsStepping
    DWORD   m_EEMaxFrameValue;                          // The max Frame value
    SIZE_T  m_EEThreadDebuggerFilterContextOffset;      // Offset of debugger's filter context within a Thread Object.
    SIZE_T  m_EEThreadCantStopOffset;                   // Offset of the can't stop count in a Thread
    SIZE_T  m_EEFrameNextOffset;                        // Offset of the next ptr in a Frame
    DWORD   m_EEIsManagedExceptionStateMask;            // Mask for Thread::TSNC_DebuggerIsManagedException
    void   *m_pPatches;                                 // Addr of patch table
    BOOL   *m_pPatchTableValid;                         // Addr of g_patchTableValid
    SIZE_T  m_offRgData;                                // Offset of m_pcEntries
    SIZE_T  m_offCData;                                 // Offset of count of m_pcEntries
    SIZE_T  m_cbPatch;                                  // Size per patch entry
    SIZE_T  m_offAddr;                                  // Offset within patch of target addr
    SIZE_T  m_offOpcode;                                // Offset within patch of target opcode
    SIZE_T  m_cbOpcode;                                 // Max size of opcode
    SIZE_T  m_offTraceType;                             // Offset of the trace.type within a patch
    DWORD   m_traceTypeUnmanaged;                       // TRACE_UNMANAGED

    DebuggerIPCRuntimeOffsets()
    {
        ZeroMemory(this, sizeof(DebuggerIPCRuntimeOffsets));
    }
};

//
// The size of the send and receive IPC buffers.
// These must be big enough to fit a DebuggerIPCEvent. Also, the bigger they are, the fewer events
// it takes to send variable length stuff like the stack trace.
// But for perf reasons, they need to be small enough to not just push us over a page boundary in an IPC block.
// Unfortunately, there's a lot of other goo in the IPC block, so we can't use some clean formula. So we
// have to resort to just tuning things.
//

// When using a network transport rather than shared memory buffers CorDBIPC_BUFFER_SIZE is the upper bound
// for a single DebuggerIPCEvent structure. This now relates to the maximal size of a network message and is
// orthogonal to the host's page size. Because of this we defer definition of CorDBIPC_BUFFER_SIZE until we've
// declared DebuggerIPCEvent at the end of this header (and we can do so because in the transport case there
// aren't any embedded buffers in the DebuggerIPCControlBlock).

#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_ARM)
#define CorDBIPC_BUFFER_SIZE (2088) // hand tuned to ensure that ipc block in IPCHeader.h fits in 1 page.
#else  // !_TARGET_X86_ && !_TARGET_ARM_
// This is the size of a DebuggerIPCEvent.  You will hit an assert in Cordb::Initialize() (DI\process.cpp)
// if this is not defined correctly.  AMD64 actually has a page size of 0x1000, not 0x2000.
#define CorDBIPC_BUFFER_SIZE 4016 // (4016 + 6) * 2 + 148 = 8192 (two (DebuggerIPCEvent + alignment padding) +
                                  //                              other fields = page size)
#endif // DBG_TARGET_X86 || DBG_TARGET_ARM

//
// DebuggerIPCControlBlock describes the layout of the shared memory shared between the Left Side and the Right
// Side. This includes error information, handles for the IPC channel, and space for the send/receive buffers.
//
struct MSLAYOUT DebuggerIPCControlBlock
{
    // Version data should be first in the control block to ensure that we can read it even if the control block
    // changes.
    SIZE_T                     m_DCBSize;           // note this field is used as a semaphore to indicate the DCB is initialized
    ULONG                      m_verMajor;          // CLR build number for the Left Side.
    ULONG                      m_verMinor;          // CLR build number for the Left Side.

    // This next stuff fits in a  DWORD.
    bool                       m_checkedBuild;      // CLR build type for the Left Side.
    // using the first padding byte to indicate if hosted in fiber mode.
    // We actually just need one bit. So if needed, can turn this to a bit.
    // BYTE padding1;
    bool                       m_bHostingInFiber;
    BYTE padding2;
    BYTE padding3;

    ULONG                      m_leftSideProtocolCurrent;       // Current protocol version for the Left Side.
    ULONG                      m_leftSideProtocolMinSupported;  // Minimum protocol the Left Side can support.

    ULONG                      m_rightSideProtocolCurrent;      // Current protocol version for the Right Side.
    ULONG                      m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires.

    HRESULT                    m_errorHR;
    unsigned int               m_errorCode;

#if defined(DBG_TARGET_WIN64)
    // 64-bit needs this padding to make the handles after this aligned.
    // But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0.
    ULONG padding4;
#endif // DBG_TARGET_WIN64


    RemoteHANDLE               m_rightSideEventAvailable;
    RemoteHANDLE               m_rightSideEventRead;

    // @dbgtodo  inspection - this is where LSEA and LSER used to be. We need to the padding to maintain binary compatibility.
    // Eventually, we expect to remove this whole block.
    RemoteHANDLE               m_paddingObsoleteLSEA;
    RemoteHANDLE               m_paddingObsoleteLSER;

    RemoteHANDLE               m_rightSideProcessHandle;

    //.............................................................................
    // Everything above this point must have the exact same binary layout as v1.1.
    // See protocol details below.
    //.............................................................................

    RemoteHANDLE               m_leftSideUnmanagedWaitEvent;
    


    // This is set immediately when the helper thread is created.
    // This will be set even if there's a temporary helper thread or if the real helper
    // thread is not yet pumping (eg, blocked on a loader lock).
    DWORD                      m_realHelperThreadId;

    // This is only published once the helper thread starts running in its main loop.
    // Thus we can use this field to see if the real helper thread is actually pumping.
    DWORD                      m_helperThreadId;

    // This is non-zero if the LS has a temporary helper thread.
    DWORD                      m_temporaryHelperThreadId;

    // ID of the Helper's canary thread.
    DWORD                      m_CanaryThreadId;

    DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets;
    void                      *m_helperThreadStartAddr;
    void                      *m_helperRemoteStartAddr;
    DWORD                     *m_specialThreadList;

    BYTE                       m_receiveBuffer[CorDBIPC_BUFFER_SIZE];
    BYTE                       m_sendBuffer[CorDBIPC_BUFFER_SIZE];

    DWORD                      m_specialThreadListLength;
    bool                       m_shutdownBegun;
    bool                       m_rightSideIsWin32Debugger;  // RS status
    bool                       m_specialThreadListDirty;

    bool                       m_rightSideShouldCreateHelperThread;

    // NOTE The Init method works since there are no virtual functions - don't add any virtual functions without
    // changing this!
    // Only initialized by the LS, opened by the RS.
    HRESULT Init(
                 HANDLE rsea, 
                 HANDLE rser, 
                 HANDLE lsea, 
                 HANDLE lser,
                 HANDLE lsuwe
                );

};

#if defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)

// We need an alternate definition for the control block if using the transport, because the control block has to be sent over the transport
// In particular we can't nest the send/receive buffers inside of it and we don't use any of the remote handles

struct MSLAYOUT DebuggerIPCControlBlockTransport
{
    // Version data should be first in the control block to ensure that we can read it even if the control block
    // changes.
    SIZE_T                     m_DCBSize;           // note this field is used as a semaphore to indicate the DCB is initialized
    ULONG                      m_verMajor;          // CLR build number for the Left Side.
    ULONG                      m_verMinor;          // CLR build number for the Left Side.

    // This next stuff fits in a  DWORD.
    bool                       m_checkedBuild;      // CLR build type for the Left Side.
    // using the first padding byte to indicate if hosted in fiber mode.
    // We actually just need one bit. So if needed, can turn this to a bit.
    // BYTE padding1;
    bool                       m_bHostingInFiber;
    BYTE padding2;
    BYTE padding3;

    ULONG                      m_leftSideProtocolCurrent;       // Current protocol version for the Left Side.
    ULONG                      m_leftSideProtocolMinSupported;  // Minimum protocol the Left Side can support.

    ULONG                      m_rightSideProtocolCurrent;      // Current protocol version for the Right Side.
    ULONG                      m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires.

    HRESULT                    m_errorHR;
    unsigned int               m_errorCode;

#if defined(DBG_TARGET_WIN64)
    // 64-bit needs this padding to make the handles after this aligned.
    // But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0.
    ULONG padding4;
#endif // DBG_TARGET_WIN64

    // This is set immediately when the helper thread is created.
    // This will be set even if there's a temporary helper thread or if the real helper
    // thread is not yet pumping (eg, blocked on a loader lock).
    DWORD                      m_realHelperThreadId;

    // This is only published once the helper thread starts running in its main loop.
    // Thus we can use this field to see if the real helper thread is actually pumping.
    DWORD                      m_helperThreadId;

    // This is non-zero if the LS has a temporary helper thread.
    DWORD                      m_temporaryHelperThreadId;

    // ID of the Helper's canary thread.
    DWORD                      m_CanaryThreadId;

    DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets;
    void                      *m_helperThreadStartAddr;
    void                      *m_helperRemoteStartAddr;
    DWORD                     *m_specialThreadList;

    DWORD                      m_specialThreadListLength;
    bool                       m_shutdownBegun;
    bool                       m_rightSideIsWin32Debugger;  // RS status
    bool                       m_specialThreadListDirty;

    bool                       m_rightSideShouldCreateHelperThread;

    // NOTE The Init method works since there are no virtual functions - don't add any virtual functions without
    // changing this!
    // Only initialized by the LS, opened by the RS.
    HRESULT Init();

};

#endif // defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)

#if defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
#include "dbgtransportsession.h"
#endif // defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)

#if defined(DBG_TARGET_X86) && !defined(FEATURE_CORESYSTEM)
// We have an versioning requirement.
// 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
// to look at a v2.0 app enough to recognize the version mismatch.
// This check is only necessary for platforms that ran on v1.1 (Win32-x86)

// Just to catch any potential illegal change in the IPC block, we assert the offsets against the offsets from v1.1.
// The constants here are pulled from v1.1.
// The RS will look at these versioning fields, so they absolutely must line up.
static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_leftSideProtocolCurrent) == 0x10);
static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_leftSideProtocolMinSupported) == 0x14);
static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProtocolCurrent) == 0x18);
static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProtocolMinSupported) == 0x1c);

// Unfortunately, on detecting such failure, v1.1 will also null out LSEA, LSER and RSPH.
// If these get adjusted, a version-mismatch attach  will effectively null out random fields.
static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_paddingObsoleteLSEA) == 0x30);
static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_paddingObsoleteLSER) == 0x34);
static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProcessHandle) == 0x38);



#endif

#define INITIAL_APP_DOMAIN_INFO_LIST_SIZE   16


//-----------------------------------------------------------------------------
// Provide some Type-safety in the IPC block when we pass remote pointers around.
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// This is the same in both the LS & RS.
// Definitions on the LS & RS should be binary compatible. So all storage is
// declared in GeneralLsPointer, and then the Ls & RS each have their own
// derived accessors.
//-----------------------------------------------------------------------------
class MSLAYOUT GeneralLsPointer
{
protected:
    friend ULONG_PTR LsPtrToCookie(GeneralLsPointer p);
    void * m_ptr;

public:
    bool IsNull() { return m_ptr == NULL; }
};

class MSLAYOUT GeneralRsPointer
{
protected:
    UINT m_data;

public:
    bool IsNull() { return m_data == 0; }
};

// In some cases, we need to get a uuid from a pointer (ie, in a hash)
inline ULONG_PTR LsPtrToCookie(GeneralLsPointer p) {
    return (ULONG_PTR) p.m_ptr;
}
#define VmPtrToCookie(vm) LsPtrToCookie((vm).ToLsPtr())


#ifdef RIGHT_SIDE_COMPILE
//-----------------------------------------------------------------------------
// Infrasturcture for RS Definitions
//-----------------------------------------------------------------------------

// On the RS, we don't have the LS classes defined, so we can't templatize that
// in terms of <class T>, but we still want things to be unique.
// So we create an empty enum for each LS type and then templatize it in terms
// of the enum.
template <typename T>
class MSLAYOUT LsPointer : public GeneralLsPointer
{
public:
    void Set(void * p)
    {
        m_ptr = p;
    }
    void * UnsafeGet()
    {
        return m_ptr;
    }

    static LsPointer<T> NullPtr()
    {
        return MakePtr(NULL);
    }

    static LsPointer<T> MakePtr(T* p)
    {
#ifdef _PREFAST_
#pragma warning(push)
#pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
#endif // _PREFAST_

        LsPointer<T> t;
        t.Set(p);
        return t;

#ifdef _PREFAST_
#pragma warning(pop)
#endif // _PREFAST_
    }

    bool operator!= (void * p) { return m_ptr != p; }
    bool operator== (void * p) { return m_ptr == p; }
    bool operator==(LsPointer<T> p) { return p.m_ptr == this->m_ptr; }

    // We should never UnWrap() them in the RS, so we don't define that here.
};

class CordbProcess;
template <class T> UINT AllocCookie(CordbProcess * pProc, T * p);
template <class T> T * UnwrapCookie(CordbProcess * pProc, UINT cookie);

UINT AllocCookieCordbEval(CordbProcess * pProc, class CordbEval * p);
class CordbEval * UnwrapCookieCordbEval(CordbProcess * pProc, UINT cookie);

template <class CordbEval> UINT AllocCookie(CordbProcess * pProc, CordbEval * p)
{
    return AllocCookieCordbEval(pProc, p);
}
template <class CordbEval> CordbEval * UnwrapCookie(CordbProcess * pProc, UINT cookie)
{
    return UnwrapCookieCordbEval(pProc, cookie);
}



// This is how the RS sees the pointers in the IPC block.
template<class T>
class MSLAYOUT RsPointer : public GeneralRsPointer
{
public:
    // Since we're being used inside a union, we can't have a ctor.

    static RsPointer<T> NullPtr()
    {
        RsPointer<T> t;
        t.m_data = 0;
        return t;        
    }

    bool AllocHandle(CordbProcess *pProc, T* p)
    {    
        // This will force validation.
        m_data = AllocCookie<T>(pProc, p);
        return (m_data != 0);       
    }

    bool operator==(RsPointer<T> p) { return p.m_data == this->m_data; }

    T* UnWrapAndRemove(CordbProcess *pProc)
    {
        return UnwrapCookie<T>(pProc, m_data);
    }
    
protected:
};

// Forward declare a class so that each type of LS pointer can have
// its own type.  We use the real class name to be compatible with VMPTRs.
#define DEFINE_LSPTR_TYPE(ls_type, ptr_name) \
    ls_type; \
    typedef LsPointer<ls_type> ptr_name;


#define DEFINE_RSPTR_TYPE(rs_type, ptr_name) \
    class rs_type; \
    typedef RsPointer<rs_type> ptr_name;

#else // !RIGHT_SIDE_COMPILE
//-----------------------------------------------------------------------------
// Infrastructure for LS Definitions
//-----------------------------------------------------------------------------

// This is how the LS sees the pointers in the IPC block.
template<typename T>
class MSLAYOUT LsPointer : public GeneralLsPointer
{
public:
    // Since we're being used inside a union, we can't have a ctor.
    //LsPointer() { }

    static LsPointer<T> NullPtr()
    {
        return MakePtr(NULL);
    }

    static LsPointer<T> MakePtr(T * p)
    {
#ifdef _PREFAST_
#pragma warning(push)
#pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
#endif // _PREFAST_

        LsPointer<T> t;
        t.Set(p);
        return t;

#ifdef _PREFAST_
#pragma warning(pop)
#endif // _PREFAST_
    }

    bool operator!= (void * p) { return m_ptr != p; }
    bool operator== (void * p) { return m_ptr == p; }
    bool operator==(LsPointer<T> p) { return p.m_ptr == this->m_ptr; }

    // @todo - we want to be able to swap out Set + Unwrap functions
    void Set(T * p)
    {
        SUPPORTS_DAC;
        // We could validate the pointer here.
        m_ptr = p;
    }

    T * UnWrap()
    {
        // If we wanted to validate the pointer, here's our chance.
        return static_cast<T*>(m_ptr);        
    }
};

template <class n>
class MSLAYOUT RsPointer : public GeneralRsPointer
{
public:
    static RsPointer<n> NullPtr()
    {
        RsPointer<n> t;
        t.m_data = 0;
        return t;
    }

    bool operator==(RsPointer<n> p) { return p.m_data == this->m_data; }

    // We should never UnWrap() them in the LS, so we don't define that here.
};

#define DEFINE_LSPTR_TYPE(ls_type, ptr_name) \
    ls_type; \
    typedef LsPointer<ls_type> ptr_name;

#define DEFINE_RSPTR_TYPE(rs_type, ptr_name) \
    enum __RS__##rs_type { };  \
    typedef RsPointer<__RS__##rs_type> ptr_name;

#endif // !RIGHT_SIDE_COMPILE

// We must be binary compatible w/ a pointer.
static_assert_no_msg(sizeof(LsPointer<void>) == sizeof(GeneralLsPointer));

static_assert_no_msg(sizeof(void*) == sizeof(GeneralLsPointer));



//-----------------------------------------------------------------------------
// Definitions for Left-Side ptrs.
// NOTE: Use VMPTR instead of LSPTR. Don't add new LSPTR types.
// 
//-----------------------------------------------------------------------------



DEFINE_LSPTR_TYPE(class Assembly,  LSPTR_ASSEMBLY);
DEFINE_LSPTR_TYPE(class DebuggerJitInfo, LSPTR_DJI);
DEFINE_LSPTR_TYPE(class DebuggerMethodInfo, LSPTR_DMI);
DEFINE_LSPTR_TYPE(class MethodDesc,         LSPTR_METHODDESC);
DEFINE_LSPTR_TYPE(class DebuggerBreakpoint, LSPTR_BREAKPOINT);
DEFINE_LSPTR_TYPE(class DebuggerEval,       LSPTR_DEBUGGEREVAL);
DEFINE_LSPTR_TYPE(class DebuggerStepper,    LSPTR_STEPPER);

// Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct.
#if defined(RIGHT_SIDE_COMPILE)
typedef LsPointer<DT_CONTEXT> LSPTR_CONTEXT;
#else  // RIGHT_SIDE_COMPILE
typedef LsPointer<DT_CONTEXT> LSPTR_CONTEXT;
#endif // RIGHT_SIDE_COMPILE

DEFINE_LSPTR_TYPE(struct OBJECTHANDLE__,    LSPTR_OBJECTHANDLE);
DEFINE_LSPTR_TYPE(class TypeHandleDummyPtr, LSPTR_TYPEHANDLE); // TypeHandle in the LS is not a direct pointer.

//-----------------------------------------------------------------------------
// Definitions for Right-Side ptrs.
//-----------------------------------------------------------------------------
DEFINE_RSPTR_TYPE(CordbEval,               RSPTR_CORDBEVAL);


//---------------------------------------------------------------------------------------
// VMPTR_Base is the base type for an abstraction over pointers into the VM so 
// that DBI can treat them as opaque handles. Classes will derive from it to 
// provide type-safe Target pointers, which ICD will view as opaque handles.
//
// Lifetimes:  
//   VMPTR_ objects survive across flushing the DAC cache. Therefore, the underlying
//   storage must be a target-pointer (and not a marshalled host pointer).
//   The RS must ensure they're still in sync with the LS (eg, by
//   tracking unload events).
//  
//
// Assumptions:
//    These handles are TADDR pointers and must not require any cleanup from DAC/DBI.
//    For direct untyped pointers into the VM, use CORDB_ADDRESS.
//
// Notes:
//  1. This helps enforce that DBI goes through the primitives interface
//     for all access (and that it doesn't accidentally start calling
//     dac-ized methods on the objects)
//  2. This isolates DBI from VM headers. 
//  3. This isolates DBI from the dac implementation (of DAC_Ptr)
//  4. This is distinct from LSPTR because LSPTRs are truly opaque handles, whereas VMPtrs
//     move across VM, DAC, and DBI, exposing proper functionality in each component.
//  5. VMPTRs are blittable because they are Target Addresses which act as opaque
//     handles outside of the Target / Dac-marshaller.  
//
//---------------------------------------------------------------------------------------


template <typename TTargetPtr, typename TDacPtr>
class MSLAYOUT VMPTR_Base
{
    // Underlying pointer into Target address space.
    // Target pointers are blittable. 
    // - In Target: can be used as normal local pointers.
    // - In DAC: must be marshalled to a host-pointer and then they can be used via DAC
    // - In RS: opaque handles.
private:
    TADDR m_addr;

public:
    typedef VMPTR_Base<TTargetPtr,TDacPtr> VMPTR_This;

    // For DBI, VMPTRs are opaque handles.
    // But the DAC side is allowed to inspect the handles to get at the raw pointer.
#if defined(ALLOW_VMPTR_ACCESS)
    // 
    // Case 1: Using in DAcDbi implementation
    //

    // DAC accessor
    TDacPtr GetDacPtr() const
    {
        SUPPORTS_DAC;
        return TDacPtr(m_addr);
    }


    // This will initialize the handle to a given target-pointer. 
    // We choose TADDR to make it explicit that it's a target pointer and avoid the risk
    // of it accidentally getting marshalled to a host pointer. 
    void SetDacTargetPtr(TADDR addr)
    {
        SUPPORTS_DAC;
        m_addr = addr;
    }
    
    void SetHostPtr(const TTargetPtr * pObject)
    {
        SUPPORTS_DAC;
        m_addr = PTR_HOST_TO_TADDR(pObject);        
    }


#elif !defined(RIGHT_SIDE_COMPILE)
    //
    // Case 2: Used in Left-side. Can get/set from local pointers.
    //

    // This will set initialize from a Target pointer. Since this is happening in the 
    // Left-side (Target), the pointer is local.
    // This is commonly used by the Left-side to create a VMPTR_ for a notification event.
    void SetRawPtr(TTargetPtr * ptr) 
    {
        m_addr = reinterpret_cast<TADDR>(ptr);
    }

    // This will get the raw underlying target pointer. 
    // This can be used by inproc Left-side code to unwrap a VMPTR (Eg, for a func-eval
    // hijack or in-proc worker threads)
    TTargetPtr * GetRawPtr()
    {
        return reinterpret_cast<TTargetPtr*>(m_addr);
    }

    // Convenience for converting TTargetPtr --> VMPTR
    static VMPTR_This MakePtr(TTargetPtr * ptr)
    {
#ifdef _PREFAST_
#pragma warning(push)
#pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
#endif // _PREFAST_

        VMPTR_This t;
        t.SetRawPtr(ptr);
        return t;

#ifdef _PREFAST_
#pragma warning(pop)
#endif // _PREFAST_
    }


#else
    //
    // Case 3: Used in RS. Opaque handles only.
    //
#endif


#ifndef DACCESS_COMPILE
    // For compatibility, these can be converted to LSPTRs on the RS or LS (case 2 and 3).  We don't allow
    // this in the DAC case because it's a cast between address spaces which we're trying to eliminate
    // in the DAC code.
    // @dbgtodo  inspection: LSPTRs will go away entirely once we've moved completely over to DAC
    LsPointer<TTargetPtr> ToLsPtr()
    {
        return LsPointer<TTargetPtr>::MakePtr( reinterpret_cast<TTargetPtr *>(m_addr));
    }
#endif
    
    //
    // Operators to emulate Pointer semantics.
    //
    bool IsNull() { SUPPORTS_DAC; return m_addr == NULL; }

    static VMPTR_This NullPtr()
    {
        SUPPORTS_DAC;

#ifdef _PREFAST_
#pragma warning(push)
#pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
#endif // _PREFAST_

        VMPTR_This dummy;
        dummy.m_addr = NULL;
        return dummy;

#ifdef _PREFAST_
#pragma warning(pop)
#endif // _PREFAST_
    }

    bool operator!= (VMPTR_This vmOther) const { SUPPORTS_DAC; return this->m_addr != vmOther.m_addr; }
    bool operator== (VMPTR_This vmOther) const { SUPPORTS_DAC; return this->m_addr == vmOther.m_addr; }
};

#if defined(ALLOW_VMPTR_ACCESS)
// Helper macro to define a VMPTR.
// This is used in the DAC case, so this definition connects the pointers up to their DAC values.
#define DEFINE_VMPTR(ls_type, dac_ptr_type, ptr_name) \
    ls_type;  \
    typedef VMPTR_Base<ls_type, dac_ptr_type> ptr_name;

#else
// Helper macro to define a VMPTR.
// This is used in the Right-side and Left-side (but not DAC) case.
// This definition explicitly ignores dac_ptr_type to prevent accidental DAC usage.
#define DEFINE_VMPTR(ls_type, dac_ptr_type, ptr_name) \
    ls_type;  \
    typedef VMPTR_Base<ls_type, void> ptr_name;

#endif

// Declare VMPTRs.
// The naming convention for instantiating a VMPTR is a 'vm' prefix. 
//
//           VM definition,         DAC definition,     pretty name for VMPTR
DEFINE_VMPTR(class AppDomain,       PTR_AppDomain,      VMPTR_AppDomain);

// Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct.
// DEFINE_VMPTR(struct _CONTEXT,       PTR_CONTEXT,        VMPTR_CONTEXT);
#if defined(ALLOW_VMPTR_ACCESS)
typedef VMPTR_Base<DT_CONTEXT, PTR_CONTEXT> VMPTR_CONTEXT;
#else
typedef VMPTR_Base<DT_CONTEXT, void > VMPTR_CONTEXT;
#endif

// DomainFile is a base-class for a CLR module, with app-domain affinity.
// For domain-neutral modules (like mscorlib), there is a DomainFile instance
// for each appdomain the module lives in. 
// This is the canonical handle ICorDebug uses to a CLR module. 
DEFINE_VMPTR(class DomainFile,      PTR_DomainFile,     VMPTR_DomainFile);
DEFINE_VMPTR(class Module,          PTR_Module,         VMPTR_Module);

// DomainAssembly derives from DomainFile and represents a manifest module. 
DEFINE_VMPTR(class DomainAssembly,  PTR_DomainAssembly, VMPTR_DomainAssembly);
DEFINE_VMPTR(class Assembly,        PTR_Assembly,       VMPTR_Assembly);

DEFINE_VMPTR(class PEFile,          PTR_PEFile,         VMPTR_PEFile); 
DEFINE_VMPTR(class MethodDesc,      PTR_MethodDesc,     VMPTR_MethodDesc);
DEFINE_VMPTR(class FieldDesc,       PTR_FieldDesc,      VMPTR_FieldDesc);

// ObjectHandle is a safe way to represent an object into the GC heap. It gets updated
// when a GC occurs.
DEFINE_VMPTR(struct OBJECTHANDLE__, TADDR,              VMPTR_OBJECTHANDLE);

DEFINE_VMPTR(class TypeHandle,      PTR_TypeHandle,     VMPTR_TypeHandle);   

// A VMPTR_Thread represents a thread that has entered the runtime at some point. 
// It may or may not have executed managed code yet; and it may or may not have managed code
// on its callstack.
DEFINE_VMPTR(class Thread,          PTR_Thread,         VMPTR_Thread);

DEFINE_VMPTR(class Object,          PTR_Object,         VMPTR_Object);

DEFINE_VMPTR(class CrstBase,        PTR_Crst,           VMPTR_Crst);
DEFINE_VMPTR(class SimpleRWLock,    PTR_SimpleRWLock,   VMPTR_SimpleRWLock);
DEFINE_VMPTR(class SimpleRWLock,    PTR_SimpleRWLock,   VMPTR_RWLock);
DEFINE_VMPTR(struct ReJitInfo,       PTR_ReJitInfo,      VMPTR_ReJitInfo);
DEFINE_VMPTR(struct SharedReJitInfo, PTR_SharedReJitInfo, VMPTR_SharedReJitInfo);


typedef CORDB_ADDRESS GENERICS_TYPE_TOKEN;


//-----------------------------------------------------------------------------
// We pass some fixed size strings in the IPC block.
// Helper class to wrap the buffer and protect against buffer overflows.
// This should be binary compatible w/ a wchar[] array.
//-----------------------------------------------------------------------------

template <int nMaxLengthIncludingNull>
class MSLAYOUT EmbeddedIPCString
{
public:
    // Set, caller responsibility that wcslen(pData) < nMaxLengthIncludingNull
    void SetString(const WCHAR * pData)
    {
        // If the string doesn't fit into the buffer, that's an issue (and so this is a real
        // assert, not just a simplifying assumption). To fix it, either:
        // - make the buffer larger
        // - don't pass the string as an embedded string in the IPC block.
        // This will truncate (rather than AV on the RS).
        int ret;
        ret = SafeCopy(pData);

        // See comment above - caller should guarantee that buffer is large enough.
        _ASSERTE(ret != STRUNCATE);
    }

    // Set a string from a substring. This will truncate if necessary.
    void SetStringTruncate(const WCHAR * pData)
    {
        // ignore return value because truncation is ok.
        SafeCopy(pData);
    }

    const WCHAR * GetString()
    {
        // For a null-termination just in case an issue in the debuggee process
        // yields a malformed string.
        m_data[nMaxLengthIncludingNull - 1] = W('\0');
        return &m_data[0];
    }
    int GetMaxSize() const { return nMaxLengthIncludingNull; }

private:
    int SafeCopy(const WCHAR * pData)
    {
        return wcsncpy_s(
            m_data, nMaxLengthIncludingNull,
            pData, _TRUNCATE);
    }
    WCHAR m_data[nMaxLengthIncludingNull];
};

//
// Types of events that can be sent between the Runtime Controller and
// the Debugger Interface. Some of these events are one way only, while
// others go both ways. The grouping of the event numbers is an attempt
// to show this distinction and perhaps even allow generic operations
// based on the type of the event.
//
enum DebuggerIPCEventType
{
#define IPC_EVENT_TYPE0(type, val)  type = val,
#define IPC_EVENT_TYPE1(type, val)  type = val,
#define IPC_EVENT_TYPE2(type, val)  type = val,
#include "dbgipceventtypes.h"
#undef IPC_EVENT_TYPE2
#undef IPC_EVENT_TYPE1
#undef IPC_EVENT_TYPE0
};

#ifdef _DEBUG

// This is a static debugging structure to help breaking at the right place.
// Debug only. This is to track the number of events that have been happened so far.
// User can choose to set break point base on the number of events.
// Variables are named as the event name with prefix m_iDebugCount. For example
// m_iDebugCount_DB_IPCE_BREAKPOINT if for event DB_IPCE_BREAKPOINT.
struct MSLAYOUT DebugEventCounter
{
// we don't need the event type 0
#define IPC_EVENT_TYPE0(type, val)
#define IPC_EVENT_TYPE1(type, val)  int m_iDebugCount_##type;
#define IPC_EVENT_TYPE2(type, val)  int m_iDebugCount_##type;
#include "dbgipceventtypes.h"
#undef IPC_EVENT_TYPE2
#undef IPC_EVENT_TYPE1
#undef IPC_EVENT_TYPE0
};
#endif // _DEBUG


#if !defined(DACCESS_COMPILE)

struct MSLAYOUT IPCEventTypeNameMapping
    {
            DebuggerIPCEventType    eventType;
            const char *            eventName;
};

extern const IPCEventTypeNameMapping DECLSPEC_SELECTANY DbgIPCEventTypeNames[] =
{
    #define IPC_EVENT_TYPE0(type, val)  { type, #type },
    #define IPC_EVENT_TYPE1(type, val)  { type, #type },
    #define IPC_EVENT_TYPE2(type, val)  { type, #type },
    #include "dbgipceventtypes.h"
    #undef IPC_EVENT_TYPE2
    #undef IPC_EVENT_TYPE1
    #undef IPC_EVENT_TYPE0
    { DB_IPCE_INVALID_EVENT, "DB_IPCE_Error" }
};

const size_t nameCount = sizeof(DbgIPCEventTypeNames) / sizeof(DbgIPCEventTypeNames[0]);


struct MSLAYOUT IPCENames // We use a class/struct so that the function can remain in a shared header file
{
    static const DebuggerIPCEventType GetEventType(__in_z char * strEventType)
    {
        // pass in the string of event name and find the matching enum value
        // This is a linear search which is pretty slow. However, this is only used
        // at startup time when debug assert is turn on and with registry key set. So it is not that bad.
        //
        for (size_t i = 0; i < nameCount; i++)
        {
            if (_stricmp(DbgIPCEventTypeNames[i].eventName, strEventType) == 0)
                return DbgIPCEventTypeNames[i].eventType;
        }
        return DB_IPCE_INVALID_EVENT;
    }
    static const char * GetName(DebuggerIPCEventType eventType)
    {

        enum DbgIPCEventTypeNum
        {
        #define IPC_EVENT_TYPE0(type, val)  type##_Num,
        #define IPC_EVENT_TYPE1(type, val)  type##_Num,
        #define IPC_EVENT_TYPE2(type, val)  type##_Num,
        #include "dbgipceventtypes.h"
        #undef IPC_EVENT_TYPE2
        #undef IPC_EVENT_TYPE1
        #undef IPC_EVENT_TYPE0
        };

        unsigned int i, lim;

        if (eventType < DB_IPCE_DEBUGGER_FIRST)
        {
            i = DB_IPCE_RUNTIME_FIRST_Num + 1;
            lim = DB_IPCE_DEBUGGER_FIRST_Num;
        }
        else
        {
            i = DB_IPCE_DEBUGGER_FIRST_Num + 1;
            lim = nameCount;
        }

        for (/**/; i < lim; i++)
        {
            if (DbgIPCEventTypeNames[i].eventType == eventType)
                return DbgIPCEventTypeNames[i].eventName;
        }

        return DbgIPCEventTypeNames[nameCount - 1].eventName;
    }
};

#endif // !DACCESS_COMPILE

//
// NOTE:  CPU-specific values below!
//
// DebuggerREGDISPLAY is very similar to the EE REGDISPLAY structure. It holds
// register values that can be saved over calls for each frame in a stack
// trace.
//
// DebuggerIPCE_FloatCount is the number of doubles in the processor's
// floating point stack.
//
// <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
// address of each register, too, to support using enregistered variables on non-leaf frames as args to a func eval. Its
// very, very possible that we would rework the entire code base to just use the register's address instead of passing
// both, but its way, way too late in V1 to undertake that, so I'm just using these addresses to suppport our one func
// eval case. Clearly, this needs to be cleaned up post V1.
//
// -- Fri Feb 09 11:21:24 2001</TODO>
//

struct MSLAYOUT DebuggerREGDISPLAY
{
#if defined(DBG_TARGET_X86)
    #define DebuggerIPCE_FloatCount 8

    SIZE_T  Edi;
    void   *pEdi;
    SIZE_T  Esi;
    void   *pEsi;
    SIZE_T  Ebx;
    void   *pEbx;
    SIZE_T  Edx;
    void   *pEdx;
    SIZE_T  Ecx;
    void   *pEcx;
    SIZE_T  Eax;
    void   *pEax;
    SIZE_T  FP;
    void   *pFP;
    SIZE_T  SP;
    SIZE_T  PC;

#elif defined(DBG_TARGET_AMD64)
    #define DebuggerIPCE_FloatCount 16

    SIZE_T  Rax;
    void   *pRax;
    SIZE_T  Rcx;
    void   *pRcx;
    SIZE_T  Rdx;
    void   *pRdx;
    SIZE_T  Rbx;
    void   *pRbx;
    SIZE_T  Rbp;
    void   *pRbp;
    SIZE_T  Rsi;
    void   *pRsi;
    SIZE_T  Rdi;
    void   *pRdi;

    SIZE_T  R8;
    void   *pR8;
    SIZE_T  R9;
    void   *pR9;
    SIZE_T  R10;
    void   *pR10;
    SIZE_T  R11;
    void   *pR11;
    SIZE_T  R12;
    void   *pR12;
    SIZE_T  R13;
    void   *pR13;
    SIZE_T  R14;
    void   *pR14;
    SIZE_T  R15;
    void   *pR15;

    SIZE_T  SP;
    SIZE_T  PC;
#elif defined(DBG_TARGET_ARM)
    #define DebuggerIPCE_FloatCount 32

    SIZE_T  R0;
    void   *pR0;
    SIZE_T  R1;
    void   *pR1;
    SIZE_T  R2;
    void   *pR2;
    SIZE_T  R3;
    void   *pR3;
    SIZE_T  R4;
    void   *pR4;
    SIZE_T  R5;
    void   *pR5;
    SIZE_T  R6;
    void   *pR6;
    SIZE_T  R7;
    void   *pR7;
    SIZE_T  R8;
    void   *pR8;
    SIZE_T  R9;
    void   *pR9;
    SIZE_T  R10;
    void   *pR10;
    SIZE_T  R11;
    void   *pR11;
    SIZE_T  R12;
    void   *pR12;
    SIZE_T  SP;
    void   *pSP;
    SIZE_T  LR;
    void   *pLR;
    SIZE_T  PC;
    void   *pPC;
#elif defined(DBG_TARGET_ARM64)
    #define DebuggerIPCE_FloatCount 32

    SIZE_T  X[29];
    SIZE_T  SP;
    SIZE_T  FP;
    SIZE_T  LR;
    SIZE_T  PC;
#else
    #define DebuggerIPCE_FloatCount 1

    SIZE_T PC;
    SIZE_T FP;
    SIZE_T SP;
    void   *pFP;
#endif
};

inline LPVOID GetSPAddress(const DebuggerREGDISPLAY * display)
{
    return (LPVOID)&display->SP;
}

#if !defined(DBG_TARGET_AMD64) && !defined(DBG_TARGET_ARM)
inline LPVOID GetFPAddress(const DebuggerREGDISPLAY * display)
{
    return (LPVOID)&display->FP;
}
#endif // !DBG_TARGET_AMD64


class MSLAYOUT FramePointer
{
friend bool IsCloserToLeaf(FramePointer fp1, FramePointer fp2);
friend bool IsCloserToRoot(FramePointer fp1, FramePointer fp2);
friend bool IsEqualOrCloserToLeaf(FramePointer fp1, FramePointer fp2);
friend bool IsEqualOrCloserToRoot(FramePointer fp1, FramePointer fp2);

public:

    static FramePointer MakeFramePointer(LPVOID sp)
    {
        LIMITED_METHOD_DAC_CONTRACT;
        FramePointer fp;
        fp.m_sp = sp;
        return fp;
    }

    static FramePointer MakeFramePointer(UINT_PTR sp)
    {
        SUPPORTS_DAC;
        return MakeFramePointer((LPVOID)sp);
    }

    inline bool operator==(FramePointer fp)
    {
        return (m_sp == fp.m_sp);
    }

    inline bool operator!=(FramePointer fp)
    {
        return !(*this == fp);
    }

    // This is needed because on the RS, the m_id values of CordbFrame and
    // CordbChain are really FramePointers.
    LPVOID GetSPValue() const
    {
        return m_sp;
    }


private:
    // Declare some private constructors which signatures matching common usage of FramePointer
    // to prevent people from accidentally assigning a pointer to a FramePointer().
    FramePointer &operator=(LPVOID sp);
    FramePointer &operator=(BYTE* sp);
    FramePointer &operator=(const BYTE* sp);

    LPVOID m_sp;
};

// For non-IA64 platforms, we use stack pointers as frame pointers.
// (Stack grows towards smaller address.)
#define LEAF_MOST_FRAME FramePointer::MakeFramePointer((LPVOID)NULL)
#define ROOT_MOST_FRAME FramePointer::MakeFramePointer((LPVOID)-1)

static_assert_no_msg(sizeof(FramePointer) == sizeof(void*));


inline bool IsCloserToLeaf(FramePointer fp1, FramePointer fp2)
{
    return (fp1.m_sp < fp2.m_sp);
}

inline bool IsCloserToRoot(FramePointer fp1, FramePointer fp2)
{
    return (fp1.m_sp > fp2.m_sp);
}

inline bool IsEqualOrCloserToLeaf(FramePointer fp1, FramePointer fp2)
{
    return !IsCloserToRoot(fp1, fp2);
}

inline bool IsEqualOrCloserToRoot(FramePointer fp1, FramePointer fp2)
{
    return !IsCloserToLeaf(fp1, fp2);
}


// struct DebuggerIPCE_FuncData:   DebuggerIPCE_FuncData holds data
// to describe a given function, its
// class, and a little bit about the code for the function. This is used
// in the stack trace result data to pass function information back that
// may be needed. Its also used when getting data about a specific function.
//
// void* nativeStartAddressPtr: Ptr to CORDB_ADDRESS, which is
//          the address of the real start address of the native code.
//          This field will be NULL only if the method hasn't been JITted
//          yet (and thus no code is available).  Otherwise, it will be
//          the adress of a CORDB_ADDRESS in the remote memory.  This
//          CORDB_ADDRESS may be NULL, in which case the code is unavailable
//          has been pitched (return CORDBG_E_CODE_NOT_AVAILABLE)
//
// SIZE_T nVersion: The version of the code that this instance of the
//          function is using.
struct MSLAYOUT DebuggerIPCE_FuncData
{
    mdMethodDef funcMetadataToken;
    VMPTR_DomainFile vmDomainFile;

    mdTypeDef   classMetadataToken;

    void*       ilStartAddress;
    SIZE_T      ilSize;

    SIZE_T      currentEnCVersion;

    mdSignature  localVarSigToken;


};

// struct DebuggerIPCE_JITFuncData:   DebuggerIPCE_JITFuncData holds
// a little bit about the JITted code for the function.
//
// void* nativeStartAddressPtr: Ptr to CORDB_ADDRESS, which is
//          the address of the real start address of the native code.
//          This field will be NULL only if the method hasn't been JITted
//          yet (and thus no code is available).  Otherwise, it will be
//          the address of a CORDB_ADDRESS in the remote memory.  This
//          CORDB_ADDRESS may be NULL, in which case the code is unavailable
//          or has been pitched (return CORDBG_E_CODE_NOT_AVAILABLE)
//
// SIZE_T nativeSize: Size of the native code.
//
// SIZE_T nativeOffset: Offset from the beginning of the function,
//          in bytes.  This may be non-zero even when nativeStartAddressPtr
//          is NULL
// void * nativeCodeJITInfoToken: An opaque value to hand back to the left
//          side when fetching the JITInfo for the native code, i.e. the
//          IL->native maps for the variables.  This may be NULL if no JITInfo is available.
// void * nativeCodeMethodDescToken: An opaque value to hand back to the left
//          side when fetching the code.  In addition this token can act as the
//          unique identity for the native code in the case where there are
//          multiple blobs of native code per IL method (i.e. if the method is
//          generic code of some kind)
// BOOL isInstantiatedGeneric: Indicates if the method is
//          generic code of some kind.
// BOOL jsutAfterILThrow: indicates that code just threw a software exception and
//          nativeOffset points to an instruction just after [call IL_Throw].
//          This is being used to figure out a real offset of the exception origin.  
//          By subtracting STACKWALK_CONTROLPC_ADJUST_OFFSET from nativeOffset you can get 
//          an address somewhere inside [call IL_Throw] instruction.
// void *ilToNativeMapAddr etc.: If nativeCodeJITInfoToken is not NULL then these
//          specify the table giving the mapping of IPs.
struct MSLAYOUT DebuggerIPCE_JITFuncData
{
    TADDR       nativeStartAddressPtr;
    SIZE_T      nativeHotSize;

    // If we have a cold region, need its size & the pointer to where starts.
    TADDR       nativeStartAddressColdPtr;
    SIZE_T      nativeColdSize;


    SIZE_T      nativeOffset;
    LSPTR_DJI   nativeCodeJITInfoToken;
    VMPTR_MethodDesc vmNativeCodeMethodDescToken;

#if defined(DBG_TARGET_WIN64) || defined(DBG_TARGET_ARM)
    BOOL         fIsFilterFrame;
    SIZE_T       parentNativeOffset;
    FramePointer fpParentOrSelf;
#endif // DBG_TARGET_WIN64 || DBG_TARGET_ARM

    // indicates if the MethodDesc is a generic function or a method inside a generic class (or
    // both!).
    BOOL         isInstantiatedGeneric;

    // this is the version of the jitted code
    SIZE_T       enCVersion;

    BOOL         jsutAfterILThrow;
};

//
// DebuggerIPCE_STRData holds data for each stack frame or chain. This data is passed
// from the RC to the DI during a stack walk.
//
#if defined(_MSC_VER)
#pragma warning( push )
#pragma warning( disable:4324 ) // the compiler pads a structure to comply with alignment requirements
#endif                          // ARM context structures have a 16-byte alignment requirement
struct MSLAYOUT DebuggerIPCE_STRData
{
    FramePointer            fp;
    // @dbgtodo  stackwalker/shim- Ideally we should be able to get rid of the DebuggerREGDISPLAY and just use the CONTEXT.
    DT_CONTEXT              ctx;
    DebuggerREGDISPLAY      rd;
    bool                    quicklyUnwound;

    VMPTR_AppDomain         vmCurrentAppDomainToken;


    enum EType
    {
        cMethodFrame = 0,
        cChain,
        cStubFrame,
        cRuntimeNativeFrame
    } eType;

    union MSLAYOUT
    {
        // Data for a chain
        struct MSLAYOUT
        {
            CorDebugChainReason chainReason;
            bool                managed;
        } u;

        // Data for a Method
        struct MSLAYOUT
        {
            struct DebuggerIPCE_FuncData funcData;
            struct DebuggerIPCE_JITFuncData jitFuncData;
            SIZE_T                       ILOffset;
            CorDebugMappingResult        mapping;

            bool        fVarArgs;

            // Indicates whether the managed method has any metadata.
            // Some dynamic methods such as IL stubs and LCG methods don't have any metadata.
            // This is used only by the V3 stackwalker, not the V2 one, because we only 
            // expose dynamic methods as real stack frames in V3.
            bool        fNoMetadata;

            TADDR       taAmbientESP;

            GENERICS_TYPE_TOKEN exactGenericArgsToken;
            DWORD               dwExactGenericArgsTokenIndex;

        } v;

        // Data for an Stub Frame.
        struct MSLAYOUT
        {
            mdMethodDef funcMetadataToken;
            VMPTR_DomainFile vmDomainFile;
            VMPTR_MethodDesc vmMethodDesc;
            CorDebugInternalFrameType frameType;
        } stubFrame;

    };
};
#if defined(_MSC_VER)
#pragma warning( pop )
#endif

//
// DebuggerIPCE_BasicTypeData and DebuggerIPCE_ExpandedTypeData
// hold data for each type sent across the
// boundary, whether it be a constructed type List<String> or a non-constructed
// type such as String, Foo or Object.
//
// Logically speaking DebuggerIPCE_BasicTypeData might just be "typeHandle", as
// we could then send further events to ask what the elementtype, typeToken and moduleToken
// are for the type handle.  But as
// nearly all types are non-generic we send across even the basic type information in
// the slightly expanded form shown below, sending the element type and the
// tokens with the type handle itself. The fields debuggerModuleToken, metadataToken and typeHandle
// are only used as follows:
//                                   elementType    debuggerModuleToken metadataToken      typeHandle
//     E_T_INT8    :                  E_T_INT8         No                     No              No
//     Boxed E_T_INT8:                E_T_CLASS        No                     No              No
//     E_T_CLASS, non-generic class:  E_T_CLASS       Yes                    Yes              No
//     E_T_VALUETYPE, non-generic:    E_T_VALUETYPE   Yes                    Yes              No
//     E_T_CLASS,     generic class:  E_T_CLASS       Yes                    Yes             Yes
//     E_T_VALUETYPE, generic class:  E_T_VALUETYPE   Yes                    Yes             Yes
//     E_T_BYREF                   :  E_T_BYREF        No                     No             Yes
//     E_T_PTR                     :  E_T_PTR          No                     No             Yes
//     E_T_ARRAY etc.              :  E_T_ARRAY        No                     No             Yes
//     E_T_FNPTR etc.              :  E_T_FNPTR        No                     No             Yes
// This allows us to always set "typeHandle" to NULL except when dealing with highly nested
// types or function-pointer types (the latter are too complexe to transfer over in one hit).
//

struct MSLAYOUT DebuggerIPCE_BasicTypeData
{
    CorElementType  elementType;
    mdTypeDef       metadataToken;
    VMPTR_Module     vmModule;
    VMPTR_DomainFile vmDomainFile;
    VMPTR_TypeHandle vmTypeHandle;
};

// DebuggerIPCE_ExpandedTypeData contains more information showing further
// details for array types, byref types etc.
// Whenever you fetch type information from the left-side
// you get back one of these.  These in turn contain further
// DebuggerIPCE_BasicTypeData's and typeHandles which you can
// then query to get further information about the type parameters.
// This copes with the nested cases, e.g. jagged arrays,
// String ****, &(String*), Pair<String,Pair<String>>
// and so on.
//
// So this type information is not "fully expanded", it's just a little
// more detail then DebuggerIPCE_BasicTypeData.  For type
// instantiatons (e.g. List<int>) and
// function pointer types you will need to make further requests for
// information about the type parameters.
// For array types there is always only one type parameter so
// we include that as part of the expanded data.
//
//
struct MSLAYOUT DebuggerIPCE_ExpandedTypeData
{
    CorElementType  elementType; // Note this is _never_ E_T_VAR, E_T_WITH or E_T_MVAR
    union MSLAYOUT
    {
        // used for E_T_CLASS and E_T_VALUECLASS, E_T_PTR, E_T_BYREF etc.
        // For non-constructed E_T_CLASS or E_T_VALUECLASS the tokens will be set and the typeHandle will be NULL
        // For constructed E_T_CLASS or E_T_VALUECLASS the tokens will be set and the typeHandle will be non-NULL
        // For E_T_PTR etc. the tokens will be NULL and the typeHandle will be non-NULL.
        struct MSLAYOUT
         {
            mdTypeDef       metadataToken;
            VMPTR_Module vmModule;
            VMPTR_DomainFile vmDomainFile;
            VMPTR_TypeHandle typeHandle; // if non-null then further fetches will be needed to get type arguments
        } ClassTypeData;

        // used for E_T_PTR, E_T_BYREF etc.
        struct MSLAYOUT
         {
            DebuggerIPCE_BasicTypeData unaryTypeArg;  // used only when sending back to debugger
        } UnaryTypeData;


        // used for E_T_ARRAY etc.
        struct MSLAYOUT
        {
          DebuggerIPCE_BasicTypeData arrayTypeArg; // used only when sending back to debugger
            DWORD           arrayRank;
        } ArrayTypeData;

        // used for E_T_FNPTR
        struct MSLAYOUT
         {
            VMPTR_TypeHandle typeHandle; // if non-null then further fetches needed to get type arguments
        } NaryTypeData;

    };
};

// DebuggerIPCE_TypeArgData is used when sending type arguments
// across to a funceval.  It contains the DebuggerIPCE_ExpandedTypeData describing the
// essence of the type, but the typeHandle and other
// BasicTypeData fields should be zero and will be ignored.
// The DebuggerIPCE_ExpandedTypeData is then followed
// by the required number of type arguments, each of which
// will be a further DebuggerIPCE_TypeArgData record in the stream of
// flattened type argument data.
struct MSLAYOUT DebuggerIPCE_TypeArgData
{
    DebuggerIPCE_ExpandedTypeData  data;
    unsigned int                   numTypeArgs; // number of immediate children on the type tree
};


//
// DebuggerIPCE_ObjectData holds the results of a
// GetAndSendObjectInfo, i.e., all the info about an object that the
// Right Side would need to access it. (This include array, string,
// and nstruct info.)
//
struct MSLAYOUT DebuggerIPCE_ObjectData
{
    void           *objRef;
    bool            objRefBad;
    SIZE_T          objSize;

    // Offset from the beginning of the object to the beginning of the first field
    SIZE_T          objOffsetToVars;

    // The type of the object....
    struct DebuggerIPCE_ExpandedTypeData objTypeData;

    union MSLAYOUT
    {
        struct MSLAYOUT
        {
            SIZE_T          length;
            SIZE_T          offsetToStringBase;
        } stringInfo;

        struct MSLAYOUT
        {
            SIZE_T          rank;
            SIZE_T          offsetToArrayBase;
            SIZE_T          offsetToLowerBounds; // 0 if not present
            SIZE_T          offsetToUpperBounds; // 0 if not present
            SIZE_T          componentCount;
            SIZE_T          elementSize;
        } arrayInfo;

        struct MSLAYOUT
        {
            struct DebuggerIPCE_BasicTypeData typedByrefType; // the type of the thing contained in a typedByref...
        } typedByrefInfo;
    };
};

//
// Remote enregistered info used by CordbValues and for passing
// variable homes between the left and right sides during a func eval.
//

enum RemoteAddressKind
{
    RAK_NONE = 0,
    RAK_REG,
    RAK_REGREG,
    RAK_REGMEM,
    RAK_MEMREG,
    RAK_FLOAT,
    RAK_END
};

const CORDB_ADDRESS kLeafFrameRegAddr = 0;
const CORDB_ADDRESS kNonLeafFrameRegAddr = (CORDB_ADDRESS)(-1);

struct MSLAYOUT RemoteAddress
{
    RemoteAddressKind    kind;
    void                *frame;

    CorDebugRegister     reg1;
    void                *reg1Addr;
    SIZE_T               reg1Value;         // this is the actual value of the register

    union MSLAYOUT
    {
        struct MSLAYOUT
        {
            CorDebugRegister  reg2;
            void             *reg2Addr;
            SIZE_T            reg2Value;    // this is the actual value of the register
        } u;

        CORDB_ADDRESS    addr;
        DWORD            floatIndex;
    };
};

//
// DebuggerIPCE_FuncEvalType specifies the type of a function
// evaluation that will occur.
//
enum DebuggerIPCE_FuncEvalType
{
    DB_IPCE_FET_NORMAL,
    DB_IPCE_FET_NEW_OBJECT,
    DB_IPCE_FET_NEW_OBJECT_NC,
    DB_IPCE_FET_NEW_STRING,
    DB_IPCE_FET_NEW_ARRAY,
    DB_IPCE_FET_RE_ABORT
};


enum NameChangeType
{
    APP_DOMAIN_NAME_CHANGE,
    THREAD_NAME_CHANGE
};

//
// DebuggerIPCE_FuncEvalArgData holds data for each argument to a
// function evaluation.
//
struct MSLAYOUT DebuggerIPCE_FuncEvalArgData
{
    RemoteAddress     argHome;  // enregistered variable home
    void             *argAddr;  // address if not enregistered
    CorElementType    argElementType;
    unsigned int      fullArgTypeNodeCount; // Pointer to LS (DebuggerIPCE_TypeArgData *) buffer holding full description of the argument type (if needed - only needed for struct types)
    void             *fullArgType; // Pointer to LS (DebuggerIPCE_TypeArgData *) buffer holding full description of the argument type (if needed - only needed for struct types)
    BYTE              argLiteralData[8]; // copy of generic value data
    bool              argIsLiteral; // true if value is in argLiteralData
    bool              argIsHandleValue; // true if argAddr is OBJECTHANDLE
};


//
// DebuggerIPCE_FuncEvalInfo holds info necessary to setup a func eval
// operation.
//
struct MSLAYOUT DebuggerIPCE_FuncEvalInfo
{
    VMPTR_Thread               vmThreadToken;
    DebuggerIPCE_FuncEvalType  funcEvalType;
    mdMethodDef                funcMetadataToken;
    mdTypeDef                  funcClassMetadataToken;
    VMPTR_DomainFile           vmDomainFile;
    RSPTR_CORDBEVAL            funcEvalKey;
    bool                       evalDuringException;

    unsigned int               argCount;
    unsigned int               genericArgsCount;
    unsigned int               genericArgsNodeCount;

    SIZE_T                     stringSize;

    SIZE_T                     arrayRank;
};


//
// Used in DebuggerIPCFirstChanceData. This tells the LS what action to take within the hijack
//
enum HijackAction
{
    HIJACK_ACTION_EXIT_UNHANDLED,
    HIJACK_ACTION_EXIT_HANDLED,
    HIJACK_ACTION_WAIT
};

//
// DebuggerIPCFirstChanceData holds info communicated from the LS to the RS when signaling that an exception does not
// belong to the runtime from a first chance hijack. This is used when Win32 debugging only.
//
struct MSLAYOUT DebuggerIPCFirstChanceData
{
    LSPTR_CONTEXT     pLeftSideContext;
    HijackAction      action;
    UINT              debugCounter;
};

//
// DebuggerIPCSecondChanceData holds info communicated from the RS
// to the LS when setting up a second chance exception hijack. This is
// used when Win32 debugging only.
//
struct MSLAYOUT DebuggerIPCSecondChanceData
{
    DT_CONTEXT       threadContext;
};



//-----------------------------------------------------------------------------
// This struct holds pointer from the LS and needs to copy to
// the RS. We have to free the memory on the RS.
// The transfer function is called when the RS first reads the event. At this point, 
// the LS is stopped while sending the event. Thus the LS pointers only need to be
// valid while the LS is in SendIPCEvent.
//
// Since this data is in an IPC/Marshallable block, it can't have any Ctors (holders)
// in it. 
//-----------------------------------------------------------------------------
struct MSLAYOUT Ls_Rs_BaseBuffer
{
#ifdef RIGHT_SIDE_COMPILE
protected:
    // copy data can happen on both LS and RS. In LS case,
    // ReadProcessMemory is really reading from its own process memory.
    //
    void CopyLSDataToRSWorker(ICorDebugDataTarget * pTargethProcess);
    
    // retrieve the RS data and own it
    BYTE *TransferRSDataWorker()
    {
        BYTE *pbRS = m_pbRS;
        m_pbRS = NULL;
        return pbRS;
    }
public:
    

    void CleanUp()
    {
        if (m_pbRS != NULL)
        {
            delete [] m_pbRS;
            m_pbRS = NULL;
        }
    }
#else
public:
    // Only LS can call this API
    void SetLsData(BYTE *pbLS, DWORD cbSize)
    {
        m_pbRS = NULL;
        m_pbLS = pbLS;
        m_cbSize = cbSize;
    }
#endif // RIGHT_SIDE_COMPILE

public:
    // Common APIs.
    DWORD  GetSize() { return m_cbSize; }



protected:
    // Size of data in bytes 
    DWORD  m_cbSize;

    // If this is non-null, pointer into LS for buffer.
    // LS can free this after the debug event is continued.
    BYTE  *m_pbLS; // @dbgtodo  cross-plat- for cross-platform purposes, this should be a TADDR

    // If this is non-null, pointer into RS for buffer. RS must then free this. 
    // This buffer was copied from the LS (via CopyLSDataToRSWorker).
    BYTE  *m_pbRS;
};

//-----------------------------------------------------------------------------
// Byte wrapper around the buffer.
//-----------------------------------------------------------------------------
struct MSLAYOUT Ls_Rs_ByteBuffer : public Ls_Rs_BaseBuffer
{
#ifdef RIGHT_SIDE_COMPILE
    BYTE *GetRSPointer() 
    { 
        return m_pbRS;
    }

    void CopyLSDataToRS(ICorDebugDataTarget * pTarget);
    BYTE *TransferRSData()
    {
        return TransferRSDataWorker();
    }
#endif    
};

//-----------------------------------------------------------------------------
// Wrapper around a Ls_rS_Buffer to get it as a string.
// This can also do some sanity checking.
//-----------------------------------------------------------------------------
struct MSLAYOUT Ls_Rs_StringBuffer : public Ls_Rs_BaseBuffer
{
#ifdef RIGHT_SIDE_COMPILE
    const WCHAR * GetString()
    {
        return reinterpret_cast<const WCHAR*> (m_pbRS);
    }

    // Copy over the string.
    void CopyLSDataToRS(ICorDebugDataTarget * pTarget);

    // Caller will pick up ownership.
    // Since caller will delete this data, we can't give back a constant pointer.
    WCHAR * TransferStringData()
    {
        return reinterpret_cast<WCHAR*> (TransferRSDataWorker());
    }
#endif  
};


// Data for an Managed Debug Assistant Probe (MDA).
struct MSLAYOUT DebuggerMDANotification
{
    Ls_Rs_StringBuffer szName;
    Ls_Rs_StringBuffer szDescription;
    Ls_Rs_StringBuffer szXml;
    DWORD        dwOSThreadId;
    CorDebugMDAFlags flags;
};


// The only remaining problem is that register number mappings are different for each platform. It turns out
// that the debugger only uses REGNUM_SP and REGNUM_AMBIENT_SP though, so we can just virtualize these two for
// the target platform.
// Keep this is sync with the definitions in inc/corinfo.h.
#if defined(DBG_TARGET_X86)
#define DBG_TARGET_REGNUM_SP 4
#define DBG_TARGET_REGNUM_AMBIENT_SP 9
#ifdef _TARGET_X86_
static_assert_no_msg(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
static_assert_no_msg(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
#endif // _TARGET_X86_
#elif defined(DBG_TARGET_AMD64)
#define DBG_TARGET_REGNUM_SP 4
#define DBG_TARGET_REGNUM_AMBIENT_SP 17
#ifdef _TARGET_AMD64_
static_assert_no_msg(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
static_assert_no_msg(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
#endif // _TARGET_AMD64_
#elif defined(DBG_TARGET_ARM)
#define DBG_TARGET_REGNUM_SP 13
#define DBG_TARGET_REGNUM_AMBIENT_SP 17
#ifdef _TARGET_ARM_
C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
#endif // _TARGET_ARM_
#elif defined(DBG_TARGET_ARM64)
#define DBG_TARGET_REGNUM_SP 31
#define DBG_TARGET_REGNUM_AMBIENT_SP 34
#ifdef _TARGET_ARM64_
C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
#endif // _TARGET_ARM64_
#else
#error Target registers are not defined for this platform
#endif


//
// Event structure that is passed between the Runtime Controller and the
// Debugger Interface. Some types of events are a fixed size and have
// entries in the main union, while others are variable length and have
// more specialized data structures that are attached to the end of this
// structure.
//
struct MSLAYOUT DebuggerIPCEvent
{
    DebuggerIPCEvent*       next;
    DebuggerIPCEventType    type;
    DWORD             processId;
    VMPTR_AppDomain   vmAppDomain;
    VMPTR_Thread      vmThread;

    HRESULT           hr;
    bool              replyRequired;
    bool              asyncSend;

    union MSLAYOUT
    {
        struct MSLAYOUT
        {
            // Pointer to a BOOL in the target.
            CORDB_ADDRESS pfBeingDebugged;
        } LeftSideStartupData;

        struct MSLAYOUT
        {
            // Module whos metadata is being updated
            // This tells the RS that the metadata for that module has become invalid.
            VMPTR_DomainFile vmDomainFile;
          
        } MetadataUpdateData;

        struct MSLAYOUT
        {
            // Handle to CLR's internal appdomain object.
            VMPTR_AppDomain vmAppDomain;
        } AppDomainData;

        struct MSLAYOUT
        {
            VMPTR_DomainAssembly vmDomainAssembly;
        } AssemblyData;

#ifdef TEST_DATA_CONSISTENCY
        // information necessary for testing whether the LS holds a lock on data
        // the RS needs to inspect. See code:DataTest::TestDataSafety and 
        // code:IDacDbiInterface::TestCrst for more information
        struct MSLAYOUT
        {
            // the lock to be tested
            VMPTR_Crst vmCrst;
            // indicates whether the LS holds the lock 
            bool       fOkToTake;
        } TestCrstData;

        // information necessary for testing whether the LS holds a lock on data
        // the RS needs to inspect. See code:DataTest::TestDataSafety and 
        // code:IDacDbiInterface::TestCrst for more information
        struct MSLAYOUT
        {
            // the lock to be tested
            VMPTR_SimpleRWLock vmRWLock;
            // indicates whether the LS holds the lock  
            bool               fOkToTake;
        } TestRWLockData;
#endif // TEST_DATA_CONSISTENCY

        // Debug event that a module has been loaded
        struct MSLAYOUT
        {
            // Module that was just loaded.
            VMPTR_DomainFile vmDomainFile;
        }LoadModuleData;

        
        struct MSLAYOUT
        {
            VMPTR_DomainFile vmDomainFile;
            LSPTR_ASSEMBLY debuggerAssemblyToken;
        } UnloadModuleData;

        
        // The given module's pdb has been updated. 
        // Queury PDB from OOP
        struct MSLAYOUT
        {   
            VMPTR_DomainFile vmDomainFile;
        } UpdateModuleSymsData;

        DebuggerMDANotification MDANotification;

        struct MSLAYOUT
        {
            LSPTR_BREAKPOINT breakpointToken;
            mdMethodDef  funcMetadataToken;
            VMPTR_DomainFile vmDomainFile;
            bool         isIL;
            SIZE_T       offset;
            SIZE_T       encVersion;
            LSPTR_METHODDESC  nativeCodeMethodDescToken; // points to the MethodDesc if !isIL
        } BreakpointData;

        struct MSLAYOUT
        {
            LSPTR_BREAKPOINT breakpointToken;
        } BreakpointSetErrorData;

        struct MSLAYOUT
        {
            LSPTR_STEPPER        stepperToken;
            VMPTR_Thread         vmThreadToken;
            FramePointer         frameToken;
            bool                 stepIn;
            bool                 rangeIL;
            bool                 IsJMCStop;
            unsigned int         totalRangeCount;
            CorDebugStepReason   reason;
            CorDebugUnmappedStop rgfMappingStop;
            CorDebugIntercept    rgfInterceptStop;
            unsigned int         rangeCount;
            COR_DEBUG_STEP_RANGE range; //note that this is an array
        } StepData;

        struct MSLAYOUT
        {
            // An unvalidated GC-handle
            VMPTR_OBJECTHANDLE GCHandle;
        } GetGCHandleInfo;

        struct MSLAYOUT
        {
            // An unvalidated GC-handle for which we're returning the results
            LSPTR_OBJECTHANDLE GCHandle;

            // The following are initialized by the LS in response to our query:
            VMPTR_AppDomain vmAppDomain; // AD that handle is in (only applicable if fValid).
            bool            fValid; // Did the LS determine the GC handle to be valid?
        } GetGCHandleInfoResult;

        // Allocate memory on the left-side
        struct MSLAYOUT
        {
            ULONG      bufSize;             // number of bytes to allocate
        } GetBuffer;

        // Memory allocated on the left-side
        struct MSLAYOUT
        {
            void        *pBuffer;           // LS pointer to the buffer allocated
            HRESULT     hr;                 // success / failure
        } GetBufferResult;

        // Free a buffer allocated on the left-side with GetBuffer
        struct MSLAYOUT
        {
            void        *pBuffer;           // Pointer previously returned in GetBufferResult
        } ReleaseBuffer;

        struct MSLAYOUT
        {
            HRESULT     hr;
        } ReleaseBufferResult;

        // Apply an EnC edit
        struct MSLAYOUT
        {            
            VMPTR_DomainFile vmDomainFile;      // Module to edit
            DWORD cbDeltaMetadata;              // size of blob pointed to by pDeltaMetadata
            CORDB_ADDRESS pDeltaMetadata;       // pointer to delta metadata in debuggee
                                                // it's the RS's responsibility to allocate and free
                                                // this (and pDeltaIL) using GetBuffer / ReleaseBuffer
            CORDB_ADDRESS pDeltaIL;             // pointer to delta IL in debugee
            DWORD cbDeltaIL;                    // size of blob pointed to by pDeltaIL
        } ApplyChanges;

        struct MSLAYOUT
        {
            HRESULT hr;
        } ApplyChangesResult;

        struct MSLAYOUT
        {
            mdTypeDef   classMetadataToken;
            VMPTR_DomainFile vmDomainFile;
            LSPTR_ASSEMBLY classDebuggerAssemblyToken;
        } LoadClass;

        struct MSLAYOUT
        {
            mdTypeDef   classMetadataToken;
            VMPTR_DomainFile vmDomainFile;
            LSPTR_ASSEMBLY classDebuggerAssemblyToken;
        } UnloadClass;

        struct MSLAYOUT
        {            
            VMPTR_DomainFile vmDomainFile;
            bool  flag;
        } SetClassLoad;

        struct MSLAYOUT
        {
            VMPTR_OBJECTHANDLE vmExceptionHandle;
            bool        firstChance;
            bool        continuable;
        } Exception;

        struct MSLAYOUT
        {
            VMPTR_Thread   vmThreadToken;
        } ClearException;

        struct MSLAYOUT
        {
            void        *address;
        } IsTransitionStub;

        struct MSLAYOUT
        {
            bool        isStub;
        } IsTransitionStubResult;

        struct MSLAYOUT
        {
            CORDB_ADDRESS    startAddress;
            bool             fCanSetIPOnly;
            VMPTR_Thread     vmThreadToken;
            VMPTR_DomainFile vmDomainFile;
            mdMethodDef      mdMethod;
            VMPTR_MethodDesc vmMethodDesc;
            SIZE_T           offset;
            bool             fIsIL;
            void *           firstExceptionHandler;
        } SetIP; // this is also used for CanSetIP

        struct MSLAYOUT
        {
            int iLevel;

            EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szCategory;
            Ls_Rs_StringBuffer szContent;
        } FirstLogMessage;

        struct MSLAYOUT
        {
            int iLevel;
            int iReason;

            EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szSwitchName;
            EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szParentSwitchName;
        } LogSwitchSettingMessage;

        // information needed to send to the RS as part of a custom notification from the target
        struct MSLAYOUT
        {
            // Domain file for the domain in which the notification occurred
            VMPTR_DomainFile vmDomainFile;

            // metadata token for the type of the CustomNotification object's type
            mdTypeDef    classToken;
        } CustomNotification;

        struct MSLAYOUT
        {
            VMPTR_Thread vmThreadToken;
            CorDebugThreadState debugState;
        } SetAllDebugState;

        DebuggerIPCE_FuncEvalInfo FuncEval;

        struct MSLAYOUT
        {
            CORDB_ADDRESS argDataArea;
            LSPTR_DEBUGGEREVAL debuggerEvalKey;
        } FuncEvalSetupComplete;

        struct MSLAYOUT
        {
            RSPTR_CORDBEVAL funcEvalKey;
            bool            successful;
            bool            aborted;
            void           *resultAddr;

            // AppDomain that the result is in.
            VMPTR_AppDomain vmAppDomain;

            VMPTR_OBJECTHANDLE vmObjectHandle;
            DebuggerIPCE_ExpandedTypeData resultType;
        } FuncEvalComplete;

        struct MSLAYOUT
        {
            LSPTR_DEBUGGEREVAL debuggerEvalKey;
        } FuncEvalAbort;

        struct MSLAYOUT
        {
            LSPTR_DEBUGGEREVAL debuggerEvalKey;
        } FuncEvalRudeAbort;

        struct MSLAYOUT
        {
            LSPTR_DEBUGGEREVAL debuggerEvalKey;
        } FuncEvalCleanup;

        struct MSLAYOUT
        {
            void           *objectRefAddress;
            VMPTR_OBJECTHANDLE vmObjectHandle;
            void           *newReference;
        } SetReference;

        struct MSLAYOUT
        {
            NameChangeType  eventType;
            VMPTR_AppDomain vmAppDomain;
            VMPTR_Thread    vmThread;
        } NameChange;

        struct MSLAYOUT
        {
            VMPTR_DomainFile vmDomainFile;
            BOOL             fAllowJitOpts;
            BOOL             fEnableEnC;
        } JitDebugInfo;

        // EnC Remap opportunity
        struct MSLAYOUT
        {
            VMPTR_DomainFile vmDomainFile;
            mdMethodDef funcMetadataToken ;        // methodDef of function with remap opportunity
            SIZE_T          currentVersionNumber;  // version currently executing
            SIZE_T          resumeVersionNumber;   // latest version
            SIZE_T          currentILOffset;       // the IL offset of the current IP
            SIZE_T          *resumeILOffset;       // pointer into left-side where an offset to resume
                                                   // to should be written if remap is desired.
        } EnCRemap;

        // EnC Remap has taken place
        struct MSLAYOUT
        {
            VMPTR_DomainFile vmDomainFile;
            mdMethodDef funcMetadataToken;         // methodDef of function that was remapped
        } EnCRemapComplete;

        // Notification that the LS is about to update a CLR data structure to account for a
        // specific edit made by EnC (function add/update or field add).
        struct MSLAYOUT
        {
            VMPTR_DomainFile vmDomainFile;
            mdToken         memberMetadataToken;   // Either a methodDef token indicating the function that
                                                   // was updated/added, or a fieldDef token indicating the
                                                   // field which was added.
            mdTypeDef       classMetadataToken;    // TypeDef token of the class in which the update was made
            SIZE_T          newVersionNumber;      // The new function/module version
        } EnCUpdate;

        struct MSLAYOUT
        {
            void      *oldData;
            void      *newData;
            DebuggerIPCE_BasicTypeData type;
        } SetValueClass;


        // Event used to tell LS if a single function is user or non-user code.
        // Same structure used to get function status.
        // @todo - Perhaps we can bundle these up so we can set multiple funcs w/ 1 event?
        struct MSLAYOUT
        {
            VMPTR_DomainFile vmDomainFile;
            mdMethodDef     funcMetadataToken;
            DWORD           dwStatus;
        } SetJMCFunctionStatus;

        struct MSLAYOUT
        {
            TASKID      taskid;
        } GetThreadForTaskId;

        struct MSLAYOUT
        {
            VMPTR_Thread vmThreadToken;
        } GetThreadForTaskIdResult;

        struct MSLAYOUT
        {
            CONNID     connectionId;
        } ConnectionChange;

        struct MSLAYOUT
        {
            CONNID     connectionId;
            EmbeddedIPCString<MAX_LONGPATH> wzConnectionName;
        } CreateConnection;

        struct MSLAYOUT
        {
            void            *objectToken;
            BOOL          fStrong;
        } CreateHandle;

        struct MSLAYOUT
        {
            VMPTR_OBJECTHANDLE vmObjectHandle;
        } CreateHandleResult;

        // used in DB_IPCE_DISPOSE_HANDLE event
        struct MSLAYOUT
        {
            VMPTR_OBJECTHANDLE vmObjectHandle;
            BOOL            fStrong;
        } DisposeHandle;

        struct MSLAYOUT
        {
            FramePointer                  framePointer;
            SIZE_T                        nOffset;
            CorDebugExceptionCallbackType eventType;
            DWORD                         dwFlags;
            VMPTR_OBJECTHANDLE            vmExceptionHandle;
        } ExceptionCallback2;

        struct MSLAYOUT
        {
            CorDebugExceptionUnwindCallbackType eventType;
            DWORD                               dwFlags;
        } ExceptionUnwind;

        struct MSLAYOUT
        {
            VMPTR_Thread vmThreadToken;
            FramePointer frameToken;
        } InterceptException;

        struct MSLAYOUT
        {
            VMPTR_Module vmModule;
            void * pMetadataStart;
            ULONG nMetadataSize;
        } MetadataUpdateRequest;

    };
};


// When using a network transport rather than shared memory buffers CorDBIPC_BUFFER_SIZE is the upper bound
// for a single DebuggerIPCEvent structure. This now relates to the maximal size of a network message and is
// orthogonal to the host's page size. Round the buffer size up to a multiple of 8 since MSVC seems more
// aggressive in this regard than gcc.
#define CorDBIPC_TRANSPORT_BUFFER_SIZE (((sizeof(DebuggerIPCEvent) + 7) / 8) * 8)

// A DebuggerIPCEvent must fit in the send & receive buffers, which are CorDBIPC_BUFFER_SIZE bytes.
static_assert_no_msg(sizeof(DebuggerIPCEvent) <= CorDBIPC_BUFFER_SIZE);
static_assert_no_msg(CorDBIPC_TRANSPORT_BUFFER_SIZE <= CorDBIPC_BUFFER_SIZE);

// 2*sizeof(WCHAR) for the two string terminating characters in the FirstLogMessage
#define LOG_MSG_PADDING         4

#endif /* _DbgIPCEvents_h_ */