summaryrefslogtreecommitdiff
path: root/src/inc/dacprivate.h
blob: cf786eec61015f2eec8d05c6f19bb0599594a78d (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
// 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.
//*****************************************************************************
//
// Internal data access functionality.
//
//*****************************************************************************

#ifndef _DACPRIVATE_H_
#define _DACPRIVATE_H_

#include <cor.h>
#include <clrdata.h>
#include <xclrdata.h>
#include <sospriv.h>

#ifndef FEATURE_PAL
// It is unfortunate having to include this header just to get the definition of GenericModeBlock
#include <msodw.h>
#endif // FEATURE_PAL

//----------------------------------------------------------------------------
//
// Utility class to allow for zero initialization of our Dacp- structs.
//
//----------------------------------------------------------------------------

template <class T>
struct ZeroInit
{
    ZeroInit()
    { memset(static_cast<T*>(this), 0, sizeof(T)); }
};

    
#include <livedatatarget.h>

//----------------------------------------------------------------------------
//
// Internal CLRData requests.
//
//----------------------------------------------------------------------------


// Private requests for DataModules
enum
{
    DACDATAMODULEPRIV_REQUEST_GET_MODULEPTR = 0xf0000000
};


// Private requests for stack walkers.
enum
{
    DACSTACKPRIV_REQUEST_FRAME_DATA = 0xf0000000
};

enum DacpObjectType { OBJ_STRING=0,OBJ_FREE,OBJ_OBJECT,OBJ_ARRAY,OBJ_OTHER };
struct DacpObjectData : ZeroInit<DacpObjectData>
{
    CLRDATA_ADDRESS MethodTable;
    DacpObjectType ObjectType;
    ULONG64 Size;
    CLRDATA_ADDRESS ElementTypeHandle;
    CorElementType ElementType;
    DWORD dwRank;
    ULONG64 dwNumComponents;
    ULONG64 dwComponentSize;
    CLRDATA_ADDRESS ArrayDataPtr;
    CLRDATA_ADDRESS ArrayBoundsPtr;
    CLRDATA_ADDRESS ArrayLowerBoundsPtr;

    CLRDATA_ADDRESS RCW;
    CLRDATA_ADDRESS CCW;
    
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetObjectData(addr, this);
    }
};

struct DacpExceptionObjectData : ZeroInit<DacpExceptionObjectData>
{
    CLRDATA_ADDRESS   Message;
    CLRDATA_ADDRESS   InnerException;
    CLRDATA_ADDRESS   StackTrace;
    CLRDATA_ADDRESS   WatsonBuckets;
    CLRDATA_ADDRESS   StackTraceString;
    CLRDATA_ADDRESS   RemoteStackTraceString;
    INT32             HResult;
    INT32             XCode;

    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        HRESULT hr;
        ISOSDacInterface2 *psos2 = NULL;
        if (SUCCEEDED(hr = sos->QueryInterface(__uuidof(ISOSDacInterface2), (void**) &psos2)))
        {
            hr = psos2->GetObjectExceptionData(addr, this);
            psos2->Release();
        }
        return hr;
    }
};

struct DacpUsefulGlobalsData : ZeroInit<DacpUsefulGlobalsData>
{
    CLRDATA_ADDRESS ArrayMethodTable;
    CLRDATA_ADDRESS StringMethodTable;
    CLRDATA_ADDRESS ObjectMethodTable;
    CLRDATA_ADDRESS ExceptionMethodTable;
    CLRDATA_ADDRESS FreeMethodTable;
};

struct DacpFieldDescData : ZeroInit<DacpFieldDescData>
{
    CorElementType Type;
    CorElementType sigType;     // ELEMENT_TYPE_XXX from signature. We need this to disply pretty name for String in minidump's case
    CLRDATA_ADDRESS MTOfType; // NULL if Type is not loaded
    
    CLRDATA_ADDRESS ModuleOfType;
    mdTypeDef TokenOfType;
    
    mdFieldDef mb;
    CLRDATA_ADDRESS MTOfEnclosingClass;
    DWORD dwOffset;
    BOOL bIsThreadLocal;
    BOOL bIsContextLocal;
    BOOL bIsStatic;
    CLRDATA_ADDRESS NextField;

    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetFieldDescData(addr, this);
    }
};

struct DacpMethodTableFieldData : ZeroInit<DacpMethodTableFieldData>
{
    WORD wNumInstanceFields;
    WORD wNumStaticFields;
    WORD wNumThreadStaticFields;

    CLRDATA_ADDRESS FirstField; // If non-null, you can retrieve more
    
    WORD wContextStaticOffset;
    WORD wContextStaticsSize;
    
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetMethodTableFieldData(addr, this);
    }
};

struct DacpMethodTableTransparencyData : ZeroInit<DacpMethodTableTransparencyData>
{
    BOOL bHasCriticalTransparentInfo;
    BOOL bIsCritical;
    BOOL bIsTreatAsSafe;

    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetMethodTableTransparencyData(addr, this);
    }
};

struct DacpDomainLocalModuleData : ZeroInit<DacpDomainLocalModuleData>
{
    // These two parameters are used as input params when calling the
    // no-argument form of Request below.
    CLRDATA_ADDRESS appDomainAddr;
    ULONG64  ModuleID;
    
    CLRDATA_ADDRESS pClassData;   
    CLRDATA_ADDRESS pDynamicClassTable;   
    CLRDATA_ADDRESS pGCStaticDataStart;
    CLRDATA_ADDRESS pNonGCStaticDataStart; 

    // Called when you have a pointer to the DomainLocalModule
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetDomainLocalModuleData(addr, this);
    }
};


struct DacpThreadLocalModuleData : ZeroInit<DacpThreadLocalModuleData>
{
    // These two parameters are used as input params when calling the
    // no-argument form of Request below.
    CLRDATA_ADDRESS threadAddr;
    ULONG64 ModuleIndex;
    
    CLRDATA_ADDRESS pClassData;   
    CLRDATA_ADDRESS pDynamicClassTable;   
    CLRDATA_ADDRESS pGCStaticDataStart;
    CLRDATA_ADDRESS pNonGCStaticDataStart;
};


struct DacpModuleData : ZeroInit<DacpModuleData>
{
    CLRDATA_ADDRESS Address;
    CLRDATA_ADDRESS File; // A PEFile addr
    CLRDATA_ADDRESS  ilBase;
    CLRDATA_ADDRESS metadataStart;
    ULONG64 metadataSize;
    CLRDATA_ADDRESS Assembly; // Assembly pointer
    BOOL bIsReflection;
    BOOL bIsPEFile;
    ULONG64 dwBaseClassIndex;
    ULONG64 dwModuleID;

    DWORD dwTransientFlags;
    
    CLRDATA_ADDRESS TypeDefToMethodTableMap;
    CLRDATA_ADDRESS TypeRefToMethodTableMap;
    CLRDATA_ADDRESS MethodDefToDescMap;
    CLRDATA_ADDRESS FieldDefToDescMap;
    CLRDATA_ADDRESS MemberRefToDescMap;
    CLRDATA_ADDRESS FileReferencesMap;
    CLRDATA_ADDRESS ManifestModuleReferencesMap;

    CLRDATA_ADDRESS pLookupTableHeap;
    CLRDATA_ADDRESS pThunkHeap;

    ULONG64 dwModuleIndex;

    DacpModuleData()
    {
    }
    
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetModuleData(addr, this);
    }

private:
    // Ensure that this data structure is not copied.
    DacpModuleData(const DacpModuleData&);
    void operator=(const DacpModuleData&);
};

struct DacpMethodTableData : ZeroInit<DacpMethodTableData>
{
    BOOL bIsFree; // everything else is NULL if this is true.
    CLRDATA_ADDRESS Module;
    CLRDATA_ADDRESS Class;
    CLRDATA_ADDRESS ParentMethodTable;
    WORD wNumInterfaces;
    WORD wNumMethods;
    WORD wNumVtableSlots;
    WORD wNumVirtuals;
    DWORD BaseSize;
    DWORD ComponentSize;
    mdTypeDef cl; // Metadata token    
    DWORD dwAttrClass; // cached metadata
    BOOL bIsShared; // flags & enum_flag_DomainNeutral
    BOOL bIsDynamic;
    BOOL bContainsPointers;
    
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetMethodTableData(addr, this);
    }
};


// Copied from util.hpp, for DacpThreadStoreData.fHostConfig below.
#define CLRMEMORYHOSTED                             0x1
#define CLRTASKHOSTED                               0x2
#define CLRSYNCHOSTED                               0x4
#define CLRTHREADPOOLHOSTED                         0x8
#define CLRIOCOMPLETIONHOSTED                       0x10
#define CLRASSEMBLYHOSTED                           0x20
#define CLRGCHOSTED                                 0x40
#define CLRSECURITYHOSTED                           0x80
#define CLRHOSTED           0x80000000

struct DacpThreadStoreData : ZeroInit<DacpThreadStoreData>
{
    LONG threadCount;
    LONG unstartedThreadCount;
    LONG backgroundThreadCount;
    LONG pendingThreadCount;
    LONG deadThreadCount;
    CLRDATA_ADDRESS firstThread;
    CLRDATA_ADDRESS finalizerThread;
    CLRDATA_ADDRESS gcThread;
    DWORD fHostConfig;          // Uses hosting flags defined above
	
    HRESULT Request(ISOSDacInterface *sos)
    {
        return sos->GetThreadStoreData(this);
    }
};

struct DacpAppDomainStoreData : ZeroInit<DacpAppDomainStoreData>
{
    CLRDATA_ADDRESS sharedDomain;
    CLRDATA_ADDRESS systemDomain;
    LONG DomainCount;

    HRESULT Request(ISOSDacInterface *sos)
    {
        return sos->GetAppDomainStoreData(this);
    }
};

struct DacpCOMInterfacePointerData : ZeroInit<DacpCOMInterfacePointerData>
{
    CLRDATA_ADDRESS methodTable;
    CLRDATA_ADDRESS interfacePtr;
    CLRDATA_ADDRESS comContext;
};

struct DacpRCWData : ZeroInit<DacpRCWData>
{
    CLRDATA_ADDRESS identityPointer;
    CLRDATA_ADDRESS unknownPointer;
    CLRDATA_ADDRESS managedObject;
    CLRDATA_ADDRESS jupiterObject;
    CLRDATA_ADDRESS vtablePtr;
    CLRDATA_ADDRESS creatorThread;
    CLRDATA_ADDRESS ctxCookie;
    
    LONG refCount;
    LONG interfaceCount;

    BOOL isJupiterObject;
    BOOL supportsIInspectable;
    BOOL isAggregated;
    BOOL isContained;
    BOOL isFreeThreaded;
    BOOL isDisconnected;
    
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS rcw)
    {
        return sos->GetRCWData(rcw, this);
    }

    HRESULT IsDCOMProxy(ISOSDacInterface *sos, CLRDATA_ADDRESS rcw, BOOL* isDCOMProxy)
    {
        ISOSDacInterface2 *pSOS2 = nullptr;
        HRESULT hr = sos->QueryInterface(__uuidof(ISOSDacInterface2), reinterpret_cast<LPVOID*>(&pSOS2));
        if (SUCCEEDED(hr))
        {
            hr = pSOS2->IsRCWDCOMProxy(rcw, isDCOMProxy);
            pSOS2->Release();
        }

        return hr;
    }
};

struct DacpCCWData : ZeroInit<DacpCCWData>
{
    CLRDATA_ADDRESS outerIUnknown;
    CLRDATA_ADDRESS managedObject;
    CLRDATA_ADDRESS handle;
    CLRDATA_ADDRESS ccwAddress;

    LONG refCount;
    LONG interfaceCount;
    BOOL isNeutered;

    LONG jupiterRefCount;
    BOOL isPegged;
    BOOL isGlobalPegged;
    BOOL hasStrongRef;
    BOOL isExtendsCOMObject;
    BOOL isAggregated;
    
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS ccw)
    {
        return sos->GetCCWData(ccw, this);
    }
};

enum DacpAppDomainDataStage {
    STAGE_CREATING,
    STAGE_READYFORMANAGEDCODE,
    STAGE_ACTIVE,
    STAGE_OPEN,
    STAGE_UNLOAD_REQUESTED,
    STAGE_EXITING,
    STAGE_EXITED,
    STAGE_FINALIZING,
    STAGE_FINALIZED,
    STAGE_HANDLETABLE_NOACCESS,
    STAGE_CLEARED,
    STAGE_COLLECTED,
    STAGE_CLOSED
};

// Information about a BaseDomain (AppDomain, SharedDomain or SystemDomain).
// For types other than AppDomain, some fields (like dwID, DomainLocalBlock, etc.) will be 0/null. 
struct DacpAppDomainData : ZeroInit<DacpAppDomainData>
{
    // The pointer to the BaseDomain (not necessarily an AppDomain).  
    // It's useful to keep this around in the structure
    CLRDATA_ADDRESS AppDomainPtr; 
    CLRDATA_ADDRESS AppSecDesc;
    CLRDATA_ADDRESS pLowFrequencyHeap;
    CLRDATA_ADDRESS pHighFrequencyHeap;
    CLRDATA_ADDRESS pStubHeap;
    CLRDATA_ADDRESS DomainLocalBlock;
    CLRDATA_ADDRESS pDomainLocalModules;    
    // The creation sequence number of this app domain (starting from 1)
    DWORD dwId;
    LONG AssemblyCount;
    LONG FailedAssemblyCount;
    DacpAppDomainDataStage appDomainStage; 
    
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetAppDomainData(addr, this);
    }
};

struct DacpAssemblyData : ZeroInit<DacpAssemblyData>
{
    CLRDATA_ADDRESS AssemblyPtr; //useful to have
    CLRDATA_ADDRESS ClassLoader;
    CLRDATA_ADDRESS ParentDomain;
    CLRDATA_ADDRESS BaseDomainPtr;
    CLRDATA_ADDRESS AssemblySecDesc;
    BOOL isDynamic;
    UINT ModuleCount;
    UINT LoadContext;
    BOOL isDomainNeutral;
    DWORD dwLocationFlags;

    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr, CLRDATA_ADDRESS baseDomainPtr)
    {
        return sos->GetAssemblyData(baseDomainPtr, addr, this);
    }

    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return Request(sos, addr, NULL);
    }
};


struct DacpThreadData : ZeroInit<DacpThreadData>
{
    DWORD corThreadId;
    DWORD osThreadId;
    int state;
    ULONG preemptiveGCDisabled;
    CLRDATA_ADDRESS allocContextPtr;
    CLRDATA_ADDRESS allocContextLimit;
    CLRDATA_ADDRESS context;
    CLRDATA_ADDRESS domain;
    CLRDATA_ADDRESS pFrame;
    DWORD lockCount;
    CLRDATA_ADDRESS firstNestedException; // Pass this pointer to DacpNestedExceptionInfo
    CLRDATA_ADDRESS teb;
    CLRDATA_ADDRESS fiberData;
    CLRDATA_ADDRESS lastThrownObjectHandle;
    CLRDATA_ADDRESS nextThread;

    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetThreadData(addr, this);
    }
};


struct DacpReJitData : ZeroInit<DacpReJitData>
{
    enum Flags
    {
        kUnknown,
        kRequested,
        kActive,
        kReverted,
    };

    CLRDATA_ADDRESS                 rejitID;
    Flags                           flags;
    CLRDATA_ADDRESS                 NativeCodeAddr;
};
    
struct DacpMethodDescData : ZeroInit<DacpMethodDescData>
{
    BOOL            bHasNativeCode;
    BOOL            bIsDynamic;
    WORD            wSlotNumber;
    CLRDATA_ADDRESS NativeCodeAddr;
    // Useful for breaking when a method is jitted.
    CLRDATA_ADDRESS AddressOfNativeCodeSlot;
    
    CLRDATA_ADDRESS MethodDescPtr;
    CLRDATA_ADDRESS MethodTablePtr;
    CLRDATA_ADDRESS ModulePtr;
    
    mdToken                  MDToken;
    CLRDATA_ADDRESS GCInfo;
    CLRDATA_ADDRESS GCStressCodeCopy;

    // This is only valid if bIsDynamic is true
    CLRDATA_ADDRESS managedDynamicMethodObject;

    CLRDATA_ADDRESS requestedIP;

    // Gives info for the single currently active version of a method
    DacpReJitData       rejitDataCurrent;

    // Gives info corresponding to requestedIP (for !ip2md)
    DacpReJitData       rejitDataRequested;
    
    // Total number of rejit versions that have been jitted
    ULONG               cJittedRejitVersions;

    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetMethodDescData(
            addr, 
            NULL,   // IP address
            this,
            0,      // cRejitData
            NULL,   // rejitData[]
            NULL    // pcNeededRejitData
            );
    }
};

struct DacpMethodDescTransparencyData : ZeroInit<DacpMethodDescTransparencyData>
{
    BOOL            bHasCriticalTransparentInfo;
    BOOL            bIsCritical;
    BOOL            bIsTreatAsSafe;

    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetMethodDescTransparencyData(addr, this);
    }
};

// for JITType
enum JITTypes {TYPE_UNKNOWN=0,TYPE_JIT,TYPE_PJIT};

struct DacpCodeHeaderData : ZeroInit<DacpCodeHeaderData>
{        
    CLRDATA_ADDRESS GCInfo;
    JITTypes                   JITType;
    CLRDATA_ADDRESS MethodDescPtr;
    CLRDATA_ADDRESS MethodStart;
    DWORD                    MethodSize;
    CLRDATA_ADDRESS ColdRegionStart;
    DWORD           ColdRegionSize;
    DWORD           HotRegionSize;
    
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS IPAddr)
    {
        return sos->GetCodeHeaderData(IPAddr, this);
    }
};

struct DacpWorkRequestData : ZeroInit<DacpWorkRequestData>
{
    CLRDATA_ADDRESS Function;
    CLRDATA_ADDRESS Context;
    CLRDATA_ADDRESS NextWorkRequest;
        
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetWorkRequestData(addr, this);
    }
};

struct DacpHillClimbingLogEntry : ZeroInit<DacpHillClimbingLogEntry>
{
    DWORD TickCount;
    int Transition;
    int NewControlSetting;
    int LastHistoryCount;
    double LastHistoryMean;
    
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS entry)
    {
        return sos->GetHillClimbingLogEntry(entry, this);   
    }
};


// Used for CLR versions >= 4.0
struct DacpThreadpoolData : ZeroInit<DacpThreadpoolData>
{
    LONG cpuUtilization;    
    int NumIdleWorkerThreads;
    int NumWorkingWorkerThreads;
    int NumRetiredWorkerThreads;
    LONG MinLimitTotalWorkerThreads;
    LONG MaxLimitTotalWorkerThreads;

    CLRDATA_ADDRESS FirstUnmanagedWorkRequest;

    CLRDATA_ADDRESS HillClimbingLog;
    int HillClimbingLogFirstIndex;
    int HillClimbingLogSize;

    DWORD NumTimers;
    // TODO: Add support to enumerate timers too.

    LONG   NumCPThreads;
    LONG   NumFreeCPThreads;
    LONG   MaxFreeCPThreads; 
    LONG   NumRetiredCPThreads;
    LONG   MaxLimitTotalCPThreads;
    LONG   CurrentLimitTotalCPThreads;
    LONG   MinLimitTotalCPThreads;

    CLRDATA_ADDRESS AsyncTimerCallbackCompletionFPtr;
    
    HRESULT Request(ISOSDacInterface *sos)
    {
        return sos->GetThreadpoolData(this);
    }
};

struct DacpGenerationData : ZeroInit<DacpGenerationData>
{    
    CLRDATA_ADDRESS start_segment;
    CLRDATA_ADDRESS allocation_start;

    // These are examined only for generation 0, otherwise NULL
    CLRDATA_ADDRESS allocContextPtr;
    CLRDATA_ADDRESS allocContextLimit;
};

#define DAC_NUMBERGENERATIONS 4


struct DacpAllocData : ZeroInit<DacpAllocData>
{
    CLRDATA_ADDRESS allocBytes;
    CLRDATA_ADDRESS allocBytesLoh;
};

struct DacpGenerationAllocData : ZeroInit<DacpGenerationAllocData>
{
    DacpAllocData allocData[DAC_NUMBERGENERATIONS]; 
};

struct DacpGcHeapDetails : ZeroInit<DacpGcHeapDetails>
{
    CLRDATA_ADDRESS heapAddr; // Only filled in in server mode, otherwise NULL
    CLRDATA_ADDRESS alloc_allocated;

    CLRDATA_ADDRESS mark_array;
    CLRDATA_ADDRESS current_c_gc_state;
    CLRDATA_ADDRESS next_sweep_obj;
    CLRDATA_ADDRESS saved_sweep_ephemeral_seg;
    CLRDATA_ADDRESS saved_sweep_ephemeral_start;
    CLRDATA_ADDRESS background_saved_lowest_address;
    CLRDATA_ADDRESS background_saved_highest_address;

    DacpGenerationData generation_table [DAC_NUMBERGENERATIONS]; 
    CLRDATA_ADDRESS ephemeral_heap_segment;        
    CLRDATA_ADDRESS finalization_fill_pointers [DAC_NUMBERGENERATIONS + 3];
    CLRDATA_ADDRESS lowest_address;
    CLRDATA_ADDRESS highest_address;
    CLRDATA_ADDRESS card_table;

    // Use this for workstation mode (DacpGcHeapDat.bServerMode==FALSE).
    HRESULT Request(ISOSDacInterface *sos)
    {
        return sos->GetGCHeapStaticData(this);
    }

    // Use this for Server mode, as there are multiple heaps,
    // and you need to pass a heap address in addr.
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetGCHeapDetails(addr, this);
    }
};

struct DacpGcHeapData
    : ZeroInit<DacpGcHeapData>
{
    BOOL bServerMode;
    BOOL bGcStructuresValid;
    UINT HeapCount;
    UINT g_max_generation;
    
    HRESULT Request(ISOSDacInterface *sos)
    {
        return sos->GetGCHeapData(this);
    }
};

struct DacpHeapSegmentData
    : ZeroInit<DacpHeapSegmentData>
{
    CLRDATA_ADDRESS segmentAddr;
    CLRDATA_ADDRESS allocated;
    CLRDATA_ADDRESS committed;
    CLRDATA_ADDRESS reserved;
    CLRDATA_ADDRESS used;
    CLRDATA_ADDRESS mem;
    // pass this to request if non-null to get the next segments.
    CLRDATA_ADDRESS next;
    CLRDATA_ADDRESS gc_heap; // only filled in in server mode, otherwise NULL
    // computed field: if this is the ephemeral segment highMark includes the ephemeral generation
    CLRDATA_ADDRESS highAllocMark;

    size_t flags;
    CLRDATA_ADDRESS background_allocated;

    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr, const DacpGcHeapDetails& heap)
    {
        HRESULT hr = sos->GetHeapSegmentData(addr, this);

        // if this is the start segment, set highAllocMark too.
        if (SUCCEEDED(hr))
        {
            // TODO:  This needs to be put on the Dac side.
            if (this->segmentAddr == heap.generation_table[0].start_segment)
                highAllocMark = heap.alloc_allocated;
            else
                highAllocMark = allocated;
        }    
        return hr;
    }
};

struct DacpOomData : ZeroInit<DacpOomData>
{
    int reason;
    ULONG64 alloc_size;
    ULONG64 available_pagefile_mb;
    ULONG64 gc_index;
    int fgm;
    ULONG64 size;
    BOOL loh_p;

    HRESULT Request(ISOSDacInterface *sos)
    {
        return sos->GetOOMStaticData(this);
    }

    // Use this for Server mode, as there are multiple heaps,
    // and you need to pass a heap address in addr.
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetOOMData(addr, this);
    }
};

// This is the value of max_idp_count in ndp\clr\src\vm\gcpriv.h
#define NUM_GC_DATA_POINTS 9
// These are from ndp\clr\src\vm\gcrecord.h
#define MAX_COMPACT_REASONS_COUNT 11
#define MAX_EXPAND_MECHANISMS_COUNT 6
#define MAX_GC_MECHANISM_BITS_COUNT 2
// This is from ndp\clr\src\vm\common.h
#define MAX_GLOBAL_GC_MECHANISMS_COUNT 6
struct DacpGCInterestingInfoData : ZeroInit<DacpGCInterestingInfoData>
{
    size_t interestingDataPoints[NUM_GC_DATA_POINTS];
    size_t compactReasons[MAX_COMPACT_REASONS_COUNT];
    size_t expandMechanisms[MAX_EXPAND_MECHANISMS_COUNT];
    size_t bitMechanisms[MAX_GC_MECHANISM_BITS_COUNT];
    size_t globalMechanisms[MAX_GLOBAL_GC_MECHANISMS_COUNT];

    HRESULT RequestGlobal(ISOSDacInterface *sos)
    {
        HRESULT hr;
        ISOSDacInterface3 *psos3 = NULL;
        if (SUCCEEDED(hr = sos->QueryInterface(__uuidof(ISOSDacInterface3), (void**) &psos3)))
        {
            hr = psos3->GetGCGlobalMechanisms(globalMechanisms);
            psos3->Release();
        }
        return hr;
    }

    HRESULT Request(ISOSDacInterface *sos)
    {
        HRESULT hr;
        ISOSDacInterface3 *psos3 = NULL;
        if (SUCCEEDED(hr = sos->QueryInterface(__uuidof(ISOSDacInterface3), (void**) &psos3)))
        {
            hr = psos3->GetGCInterestingInfoStaticData(this);
            psos3->Release();
        }
        return hr;
    }

    // Use this for Server mode, as there are multiple heaps,
    // and you need to pass a heap address in addr.
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        HRESULT hr;
        ISOSDacInterface3 *psos3 = NULL;
        if (SUCCEEDED(hr = sos->QueryInterface(__uuidof(ISOSDacInterface3), (void**) &psos3)))
        {
            hr = psos3->GetGCInterestingInfoData(addr, this);
            psos3->Release();
        }
        return hr;
    }
};

struct DacpGcHeapAnalyzeData
    : ZeroInit<DacpGcHeapAnalyzeData>
{
    CLRDATA_ADDRESS heapAddr; // Only filled in in server mode, otherwise NULL

    CLRDATA_ADDRESS internal_root_array;
    ULONG64         internal_root_array_index;
    BOOL            heap_analyze_success;

    // Use this for workstation mode (DacpGcHeapDat.bServerMode==FALSE).
    HRESULT Request(ISOSDacInterface *sos)
    {
        return sos->GetHeapAnalyzeStaticData(this);   
    }

    // Use this for Server mode, as there are multiple heaps,
    // and you need to pass a heap address in addr.
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS addr)
    {
        return sos->GetHeapAnalyzeData(addr, this);
    }
};


#define SYNCBLOCKDATA_COMFLAGS_CCW 1
#define SYNCBLOCKDATA_COMFLAGS_RCW 2
#define SYNCBLOCKDATA_COMFLAGS_CF 4

struct DacpSyncBlockData : ZeroInit<DacpSyncBlockData>
{        
    CLRDATA_ADDRESS Object;
    BOOL            bFree; // if set, no other fields are useful
    
    // fields below provide data from this, so it's just for display
    CLRDATA_ADDRESS SyncBlockPointer;
    DWORD           COMFlags;
    UINT            MonitorHeld;
    UINT            Recursion;
    CLRDATA_ADDRESS HoldingThread;
    UINT            AdditionalThreadCount;
    CLRDATA_ADDRESS appDomainPtr;
    
    // SyncBlockCount will always be filled in with the number of SyncBlocks.
    // SyncBlocks may be requested from [1,SyncBlockCount]
    UINT            SyncBlockCount;

    // SyncBlockNumber must be from [1,SyncBlockCount]    
    // If there are no SyncBlocks, a call to Request with SyncBlockCount = 1
    // will return E_FAIL.
    HRESULT Request(ISOSDacInterface *sos, UINT SyncBlockNumber)
    {
        return sos->GetSyncBlockData(SyncBlockNumber, this);
    }
};

struct DacpSyncBlockCleanupData : ZeroInit<DacpSyncBlockCleanupData>
{
    CLRDATA_ADDRESS SyncBlockPointer;
    
    CLRDATA_ADDRESS nextSyncBlock;
    CLRDATA_ADDRESS blockRCW;
    CLRDATA_ADDRESS blockClassFactory;
    CLRDATA_ADDRESS blockCCW;
    
    // Pass NULL on the first request to start a traversal.
    HRESULT Request(ISOSDacInterface *sos, CLRDATA_ADDRESS psyncBlock)
    {
        return sos->GetSyncBlockCleanupData(psyncBlock, this);
    }
};

///////////////////////////////////////////////////////////////////////////

enum EHClauseType {EHFault, EHFinally, EHFilter, EHTyped, EHUnknown};
                
struct DACEHInfo : ZeroInit<DACEHInfo>
{
    EHClauseType clauseType;
    CLRDATA_ADDRESS tryStartOffset;
    CLRDATA_ADDRESS tryEndOffset;
    CLRDATA_ADDRESS handlerStartOffset;
    CLRDATA_ADDRESS handlerEndOffset;
    BOOL isDuplicateClause;
    CLRDATA_ADDRESS filterOffset;   // valid when clauseType is EHFilter
    BOOL isCatchAllHandler;             // valid when clauseType is EHTyped
    CLRDATA_ADDRESS moduleAddr;    // when == 0 mtCatch contains a MethodTable, when != 0 tokCatch contains a type token
    CLRDATA_ADDRESS mtCatch;   // the method table of the TYPED clause type
    mdToken tokCatch;          // the type token of the TYPED clause type
};

struct DacpGetModuleAddress : ZeroInit<DacpGetModuleAddress>
{
    CLRDATA_ADDRESS ModulePtr;
    HRESULT Request(IXCLRDataModule* pDataModule)
    {
        return pDataModule->Request(DACDATAMODULEPRIV_REQUEST_GET_MODULEPTR,
                                0, NULL,
                                sizeof(*this), (PBYTE) this);
    }
};

struct DacpFrameData : ZeroInit<DacpFrameData>
{
    CLRDATA_ADDRESS frameAddr;

    // Could also be implemented for IXCLRDataFrame if desired.
    HRESULT Request(IXCLRDataStackWalk* dac)
    {
        return dac->Request(DACSTACKPRIV_REQUEST_FRAME_DATA,
                            0, NULL,
                            sizeof(*this), (PBYTE)this);
    }
};

struct DacpJitManagerInfo : ZeroInit<DacpJitManagerInfo>
{
    CLRDATA_ADDRESS managerAddr;
    DWORD codeType; // for union below
    CLRDATA_ADDRESS ptrHeapList;    // A HeapList * if IsMiIL(codeType)
};

enum CodeHeapType {CODEHEAP_LOADER=0,CODEHEAP_HOST,CODEHEAP_UNKNOWN};

struct DacpJitCodeHeapInfo : ZeroInit<DacpJitCodeHeapInfo>
{
    DWORD codeHeapType; // for union below

    union
    {
        CLRDATA_ADDRESS LoaderHeap;    // if CODEHEAP_LOADER
        struct
        {
            CLRDATA_ADDRESS baseAddr; // if CODEHEAP_HOST
            CLRDATA_ADDRESS currentAddr;
        } HostData;
    };
};

#include "static_assert.h"

/* DAC datastructures are frozen as of dev11 shipping.  Do NOT add fields, remove fields, or change the fields of
 * these structs in any way.  The correct way to get new data out of the runtime is to create a new struct and
 * add a new function to the latest Dac<-->SOS interface to produce this data.
 */
static_assert(sizeof(DacpAllocData) == 0x10, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpGenerationAllocData) == 0x40, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpSyncBlockCleanupData) == 0x28, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpThreadStoreData) == 0x38, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpAppDomainStoreData) == 0x18, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpAppDomainData) == 0x48, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpAssemblyData) == 0x40, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpThreadData) == 0x68, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpMethodDescData) == 0x98, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpCodeHeaderData) == 0x38, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpThreadpoolData) == 0x58, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpObjectData) == 0x60, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpMethodTableData) == 0x48, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpWorkRequestData) == 0x18, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpFieldDescData) == 0x40, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpModuleData) == 0xa0, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpGcHeapData) == 0x10, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpJitManagerInfo) == 0x18, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpHeapSegmentData) == 0x58, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpDomainLocalModuleData) == 0x30, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpUsefulGlobalsData) == 0x28, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DACEHInfo) == 0x58, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpRCWData) == 0x58, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpCCWData) == 0x48, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpMethodTableFieldData) == 0x18, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpMethodTableTransparencyData) == 0xc, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpThreadLocalModuleData) == 0x30, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpCOMInterfacePointerData) == 0x18, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpMethodDescTransparencyData) == 0xc, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpHillClimbingLogEntry) == 0x18, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpGenerationData) == 0x20, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpGcHeapDetails) == 0x120, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpOomData) == 0x38, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpGcHeapAnalyzeData) == 0x20, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpSyncBlockData) == 0x48, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpGetModuleAddress) == 0x8, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpFrameData) == 0x8, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpJitCodeHeapInfo) == 0x18, "Dacp structs cannot be modified due to backwards compatibility.");
static_assert(sizeof(DacpExceptionObjectData) == 0x38, "Dacp structs cannot be modified due to backwards compatibility.");

#endif  // _DACPRIVATE_H_