[Tizen] Add RelativeStubPrecode for arm64, which replaces StubPrecode in FNV images
[platform/upstream/coreclr.git] / src / debug / daccess / daccess.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
5 // File: daccess.cpp
6 //
7
8 //
9 // ClrDataAccess implementation.
10 //
11 //*****************************************************************************
12
13 #include "stdafx.h"
14 #include <clrdata.h>
15 #include "typestring.h"
16 #include "holder.h"
17 #include "debuginfostore.h"
18 #include "peimagelayout.inl"
19 #include "datatargetadapter.h"
20 #include "readonlydatatargetfacade.h"
21 #include "metadataexports.h"
22 #include "excep.h"
23 #include "debugger.h"
24 #include "dwreport.h"
25 #include "primitives.h"
26 #include "dbgutil.h"
27 #ifdef FEATURE_PAL
28 #include <dactablerva.h>
29 #endif
30
31 #include "dwbucketmanager.hpp"
32 #include "gcinterface.dac.h"
33
34 // To include definiton of IsThrowableThreadAbortException
35 // #include <exstatecommon.h>
36
37 CRITICAL_SECTION g_dacCritSec;
38 ClrDataAccess* g_dacImpl;
39 HINSTANCE g_thisModule;
40
41 extern VOID STDMETHODCALLTYPE TLS_FreeMasterSlotIndex();
42
43 EXTERN_C
44 #ifdef FEATURE_PAL
45 DLLEXPORT // For Win32 PAL LoadLibrary emulation
46 #endif
47 BOOL WINAPI DllMain(HANDLE instance, DWORD reason, LPVOID reserved)
48 {
49     static bool g_procInitialized = false;
50
51     switch(reason)
52     {
53     case DLL_PROCESS_ATTACH:
54     {
55         if (g_procInitialized)
56         {
57 #ifdef FEATURE_PAL
58             // Double initialization can happen on Unix
59             // in case of manual load of DAC shared lib and calling DllMain
60             // not a big deal, we just ignore it.
61             return TRUE;
62 #else
63             return FALSE;
64 #endif
65         }
66
67 #ifdef FEATURE_PAL
68         int err = PAL_InitializeDLL();
69         if(err != 0)
70         {
71             return FALSE;
72         }
73 #endif
74         InitializeCriticalSection(&g_dacCritSec);
75
76         // Save the module handle.
77         g_thisModule = (HINSTANCE)instance;
78
79         g_procInitialized = true;
80         break;
81     }
82
83     case DLL_PROCESS_DETACH:
84         // It's possible for this to be called without ATTACH completing (eg. if it failed)
85         if (g_procInitialized)
86         {
87             DeleteCriticalSection(&g_dacCritSec);
88         }
89 #ifndef FEATURE_PAL
90         TLS_FreeMasterSlotIndex();
91 #endif
92         g_procInitialized = false;
93         break;
94     }
95
96     return TRUE;
97 }
98
99 HINSTANCE
100 GetModuleInst(void)
101 {
102     return g_thisModule;
103 }
104
105 HRESULT
106 ConvertUtf8(__in LPCUTF8 utf8,
107             ULONG32 bufLen,
108             ULONG32* nameLen,
109             __out_ecount_part_opt(bufLen, *nameLen) PWSTR buffer)
110 {
111     if (nameLen)
112     {
113         *nameLen = WszMultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
114         if (!*nameLen)
115         {
116             return HRESULT_FROM_GetLastError();
117         }
118     }
119
120     if (buffer && bufLen)
121     {
122         if (!WszMultiByteToWideChar(CP_UTF8, 0, utf8, -1, buffer, bufLen))
123         {
124             return HRESULT_FROM_GetLastError();
125         }
126     }
127
128     return S_OK;
129 }
130
131 HRESULT
132 AllocUtf8(__in_opt LPCWSTR wstr,
133           ULONG32 srcChars,
134           __deref_out LPUTF8* utf8)
135 {
136     ULONG32 chars = WszWideCharToMultiByte(CP_UTF8, 0, wstr, srcChars,
137                                            NULL, 0, NULL, NULL);
138     if (!chars)
139     {
140         return HRESULT_FROM_GetLastError();
141     }
142
143     // Make sure the converted string is always terminated.
144     if (srcChars != (ULONG32)-1)
145     {
146         if (!ClrSafeInt<ULONG32>::addition(chars, 1, chars))
147         {
148             return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
149         }
150     }
151
152     char* mem = new (nothrow) char[chars];
153     if (!mem)
154     {
155         return E_OUTOFMEMORY;
156     }
157
158     if (!WszWideCharToMultiByte(CP_UTF8, 0, wstr, srcChars,
159                                 mem, chars, NULL, NULL))
160     {
161         HRESULT hr = HRESULT_FROM_GetLastError();
162         delete [] mem;
163         return hr;
164     }
165
166     if (srcChars != (ULONG32)-1)
167     {
168         mem[chars - 1] = 0;
169     }
170
171     *utf8 = mem;
172     return S_OK;
173 }
174
175 HRESULT
176 GetFullClassNameFromMetadata(IMDInternalImport* mdImport,
177                              mdTypeDef classToken,
178                              ULONG32 bufferChars,
179                              __inout_ecount(bufferChars) LPUTF8 buffer)
180 {
181     HRESULT hr;
182     LPCUTF8 baseName, namespaceName;
183
184     IfFailRet(mdImport->GetNameOfTypeDef(classToken, &baseName, &namespaceName));
185     return ns::MakePath(buffer, bufferChars, namespaceName, baseName) ?
186         S_OK : E_OUTOFMEMORY;
187 }
188
189 HRESULT
190 GetFullMethodNameFromMetadata(IMDInternalImport* mdImport,
191                               mdMethodDef methodToken,
192                               ULONG32 bufferChars,
193                               __inout_ecount(bufferChars) LPUTF8 buffer)
194 {
195     HRESULT status;
196     HRESULT hr;
197     mdTypeDef classToken;
198     size_t len;
199
200     if (mdImport->GetParentToken(methodToken, &classToken) == S_OK)
201     {
202         if ((status =
203              GetFullClassNameFromMetadata(mdImport, classToken,
204                                           bufferChars, buffer)) != S_OK)
205         {
206             return status;
207         }
208
209         len = strlen(buffer);
210         buffer += len;
211         bufferChars -= static_cast<ULONG32>(len) + 1;
212
213         if (!bufferChars)
214         {
215             return E_OUTOFMEMORY;
216         }
217
218         *buffer++ = NAMESPACE_SEPARATOR_CHAR;
219     }
220
221     LPCUTF8 methodName;
222     IfFailRet(mdImport->GetNameOfMethodDef(methodToken, &methodName));
223 // Review conversion of size_t to ULONG32.
224 #ifdef _MSC_VER
225 #pragma warning(push)
226 #pragma warning(disable:4267)
227 #endif
228     len = strlen(methodName);
229 #ifdef _MSC_VER
230 #pragma warning(pop)
231 #endif
232     if (len >= bufferChars)
233     {
234         return E_OUTOFMEMORY;
235     }
236
237     strcpy_s(buffer, bufferChars, methodName);
238     return S_OK;
239 }
240
241 HRESULT
242 SplitFullName(__in_z __in PCWSTR fullName,
243               SplitSyntax syntax,
244               ULONG32 memberDots,
245               __deref_out_opt LPUTF8* namespaceName,
246               __deref_out_opt LPUTF8* typeName,
247               __deref_out_opt LPUTF8* memberName,
248               __deref_out_opt LPUTF8* params)
249 {
250     HRESULT status;
251     PCWSTR paramsStart, memberStart, memberEnd, typeStart;
252
253     if (!*fullName)
254     {
255         return E_INVALIDARG;
256     }
257
258     //
259     // Split off parameters.
260     //
261
262     paramsStart = wcschr(fullName, W('('));
263     if (paramsStart)
264     {
265         if (syntax != SPLIT_METHOD ||
266             paramsStart == fullName)
267         {
268             return E_INVALIDARG;
269         }
270
271         if ((status = AllocUtf8(paramsStart, (ULONG32)-1, params)) != S_OK)
272         {
273             return status;
274         }
275
276         memberEnd = paramsStart - 1;
277     }
278     else
279     {
280         *params = NULL;
281         memberEnd = fullName + (wcslen(fullName) - 1);
282     }
283
284     if (syntax != SPLIT_TYPE)
285     {
286         //
287         // Split off member name.
288         //
289
290         memberStart = memberEnd;
291
292         for (;;)
293         {
294             while (memberStart >= fullName &&
295                    *memberStart != W('.'))
296             {
297                 memberStart--;
298             }
299
300             // Some member names (e.g. .ctor and .dtor) have
301             // dots, so go back to the first dot.
302             while (memberStart > fullName &&
303                    memberStart[-1] == W('.'))
304             {
305                 memberStart--;
306             }
307
308             if (memberStart <= fullName)
309             {
310                 if (memberDots > 0)
311                 {
312                     // Caller expected dots in the
313                     // member name and they weren't found.
314                     status = E_INVALIDARG;
315                     goto DelParams;
316                 }
317
318                 break;
319             }
320             else if (memberDots == 0)
321             {
322                 break;
323             }
324
325             memberStart--;
326             memberDots--;
327         }
328
329         memberStart++;
330         if (memberStart > memberEnd)
331         {
332             status = E_INVALIDARG;
333             goto DelParams;
334         }
335
336         if ((status = AllocUtf8(memberStart, (ULONG32)
337                                 (memberEnd - memberStart) + 1,
338                                 memberName)) != S_OK)
339         {
340             goto DelParams;
341         }
342     }
343     else
344     {
345         *memberName = NULL;
346         memberStart = memberEnd + 2;
347     }
348
349     //
350     // Split off type name.
351     //
352
353     if (memberStart > fullName)
354     {
355         // Must have at least one character for the type
356         // name.  If there was a member name, there must
357         // also be a separator.
358         if (memberStart < fullName + 2)
359         {
360             status = E_INVALIDARG;
361             goto DelMember;
362         }
363
364         typeStart = memberStart - 2;
365         while (typeStart >= fullName &&
366                *typeStart != W('.'))
367         {
368             typeStart--;
369         }
370         typeStart++;
371
372         if ((status = AllocUtf8(typeStart, (ULONG32)
373                                 (memberStart - typeStart) - 1,
374                                 typeName)) != S_OK)
375         {
376             goto DelMember;
377         }
378     }
379     else
380     {
381         *typeName = NULL;
382         typeStart = fullName;
383     }
384
385     //
386     // Namespace must be the rest.
387     //
388
389     if (typeStart > fullName)
390     {
391         if ((status = AllocUtf8(fullName, (ULONG32)
392                                 (typeStart - fullName) - 1,
393                                 namespaceName)) != S_OK)
394         {
395             goto DelType;
396         }
397     }
398     else
399     {
400         *namespaceName = NULL;
401     }
402
403     return S_OK;
404
405  DelType:
406     delete [] (*typeName);
407  DelMember:
408     delete [] (*memberName);
409  DelParams:
410     delete [] (*params);
411     return status;
412 }
413
414 int
415 CompareUtf8(__in LPCUTF8 str1, __in LPCUTF8 str2, __in ULONG32 nameFlags)
416 {
417     if (nameFlags & CLRDATA_BYNAME_CASE_INSENSITIVE)
418     {
419         // XXX Microsoft - Convert to Unicode?
420         return SString::_stricmp(str1, str2);
421     }
422
423     return strcmp(str1, str2);
424 }
425
426 //----------------------------------------------------------------------------
427 //
428 // MetaEnum.
429 //
430 //----------------------------------------------------------------------------
431
432 HRESULT
433 MetaEnum::Start(IMDInternalImport* mdImport, ULONG32 kind,
434                 mdToken container)
435 {
436     HRESULT status;
437
438     switch(kind)
439     {
440     case mdtTypeDef:
441         status = mdImport->EnumTypeDefInit(&m_enum);
442         break;
443     case mdtMethodDef:
444     case mdtFieldDef:
445         status = mdImport->EnumInit(kind, container, &m_enum);
446         break;
447     default:
448         return E_INVALIDARG;
449     }
450     if (status != S_OK)
451     {
452         return status;
453     }
454
455     m_mdImport = mdImport;
456     m_kind = kind;
457
458     return S_OK;
459 }
460
461 void
462 MetaEnum::End(void)
463 {
464     if (!m_mdImport)
465     {
466         return;
467     }
468
469     switch(m_kind)
470     {
471     case mdtTypeDef:
472         m_mdImport->EnumTypeDefClose(&m_enum);
473         break;
474     case mdtMethodDef:
475     case mdtFieldDef:
476         m_mdImport->EnumClose(&m_enum);
477         break;
478     }
479
480     Clear();
481 }
482
483 HRESULT
484 MetaEnum::NextToken(mdToken* token,
485                     __deref_opt_out_opt LPCUTF8* namespaceName,
486                     __deref_opt_out_opt LPCUTF8* name)
487 {
488     HRESULT hr;
489     if (!m_mdImport)
490     {
491         return E_INVALIDARG;
492     }
493
494     switch(m_kind)
495     {
496     case mdtTypeDef:
497         if (!m_mdImport->EnumTypeDefNext(&m_enum, token))
498         {
499             return S_FALSE;
500         }
501         m_lastToken = *token;
502         if (namespaceName || name)
503         {
504             LPCSTR _name, _namespaceName;
505
506             IfFailRet(m_mdImport->GetNameOfTypeDef(*token, &_name, &_namespaceName));
507             if (namespaceName)
508             {
509                 *namespaceName = _namespaceName;
510             }
511             if (name)
512             {
513                 *name = _name;
514             }
515         }
516         return S_OK;
517
518     case mdtMethodDef:
519         if (!m_mdImport->EnumNext(&m_enum, token))
520         {
521             return S_FALSE;
522         }
523         m_lastToken = *token;
524         if (namespaceName)
525         {
526             *namespaceName = NULL;
527         }
528         if (name != NULL)
529         {
530             IfFailRet(m_mdImport->GetNameOfMethodDef(*token, name));
531         }
532         return S_OK;
533
534     case mdtFieldDef:
535         if (!m_mdImport->EnumNext(&m_enum, token))
536         {
537             return S_FALSE;
538         }
539         m_lastToken = *token;
540         if (namespaceName)
541         {
542             *namespaceName = NULL;
543         }
544         if (name != NULL)
545         {
546             IfFailRet(m_mdImport->GetNameOfFieldDef(*token, name));
547         }
548         return S_OK;
549
550     default:
551         return E_INVALIDARG;
552     }
553 }
554
555 HRESULT
556 MetaEnum::NextDomainToken(AppDomain** appDomain,
557                           mdToken* token)
558 {
559     HRESULT status;
560
561     if (m_appDomain)
562     {
563         // Use only the caller-provided app domain.
564         *appDomain = m_appDomain;
565         return NextToken(token, NULL, NULL);
566     }
567
568     //
569     // Splay tokens across all app domains.
570     //
571
572     for (;;)
573     {
574         if (m_lastToken == mdTokenNil)
575         {
576             // Need to fetch a token.
577             if ((status = NextToken(token, NULL, NULL)) != S_OK)
578             {
579                 return status;
580             }
581
582             m_domainIter.Init();
583         }
584
585         if (m_domainIter.Next())
586         {
587             break;
588         }
589
590         m_lastToken = mdTokenNil;
591     }
592
593     *appDomain = m_domainIter.GetDomain();
594     *token = m_lastToken;
595
596     return S_OK;
597 }
598
599 HRESULT
600 MetaEnum::NextTokenByName(__in_opt LPCUTF8 namespaceName,
601                           __in_opt LPCUTF8 name,
602                           ULONG32 nameFlags,
603                           mdToken* token)
604 {
605     HRESULT status;
606     LPCUTF8 tokNamespace, tokName;
607
608     for (;;)
609     {
610         if ((status = NextToken(token, &tokNamespace, &tokName)) != S_OK)
611         {
612             return status;
613         }
614
615         if (namespaceName &&
616             (!tokNamespace ||
617              CompareUtf8(namespaceName, tokNamespace, nameFlags) != 0))
618         {
619             continue;
620         }
621         if (name &&
622             (!tokName ||
623              CompareUtf8(name, tokName, nameFlags) != 0))
624         {
625             continue;
626         }
627
628         return S_OK;
629     }
630 }
631
632 HRESULT
633 MetaEnum::NextDomainTokenByName(__in_opt LPCUTF8 namespaceName,
634                                 __in_opt LPCUTF8 name,
635                                 ULONG32 nameFlags,
636                                 AppDomain** appDomain, mdToken* token)
637 {
638     HRESULT status;
639
640     if (m_appDomain)
641     {
642         // Use only the caller-provided app domain.
643         *appDomain = m_appDomain;
644         return NextTokenByName(namespaceName, name, nameFlags, token);
645     }
646
647     //
648     // Splay tokens across all app domains.
649     //
650
651     for (;;)
652     {
653         if (m_lastToken == mdTokenNil)
654         {
655             // Need to fetch a token.
656             if ((status = NextTokenByName(namespaceName, name, nameFlags,
657                                           token)) != S_OK)
658             {
659                 return status;
660             }
661
662             m_domainIter.Init();
663         }
664
665         if (m_domainIter.Next())
666         {
667             break;
668         }
669
670         m_lastToken = mdTokenNil;
671     }
672
673     *appDomain = m_domainIter.GetDomain();
674     *token = m_lastToken;
675
676     return S_OK;
677 }
678
679 HRESULT
680 MetaEnum::New(Module* mod,
681               ULONG32 kind,
682               mdToken container,
683               IXCLRDataAppDomain* pubAppDomain,
684               MetaEnum** metaEnumRet,
685               CLRDATA_ENUM* handle)
686 {
687     HRESULT status;
688     MetaEnum* metaEnum;
689
690     if (handle)
691     {
692         *handle = TO_CDENUM(NULL);
693     }
694
695     if (!mod->GetFile()->HasMetadata())
696     {
697         return S_FALSE;
698     }
699
700     metaEnum = new (nothrow) MetaEnum;
701     if (!metaEnum)
702     {
703         return E_OUTOFMEMORY;
704     }
705
706     if ((status = metaEnum->
707          Start(mod->GetMDImport(), kind, container)) != S_OK)
708     {
709         delete metaEnum;
710         return status;
711     }
712
713     if (pubAppDomain)
714     {
715         metaEnum->m_appDomain =
716             ((ClrDataAppDomain*)pubAppDomain)->GetAppDomain();
717     }
718
719     if (metaEnumRet)
720     {
721         *metaEnumRet = metaEnum;
722     }
723     if (handle)
724     {
725         *handle = TO_CDENUM(metaEnum);
726     }
727     return S_OK;
728 }
729
730 //----------------------------------------------------------------------------
731 //
732 // SplitName
733 //
734 //----------------------------------------------------------------------------
735
736 SplitName::SplitName(SplitSyntax syntax, ULONG32 nameFlags,
737                      ULONG32 memberDots)
738 {
739     m_syntax = syntax;
740     m_nameFlags = nameFlags;
741     m_memberDots = memberDots;
742
743     Clear();
744 }
745
746 void
747 SplitName::Delete(void)
748 {
749     delete [] m_namespaceName;
750     m_namespaceName = NULL;
751     delete [] m_typeName;
752     m_typeName = NULL;
753     delete [] m_memberName;
754     m_memberName = NULL;
755     delete [] m_params;
756     m_params = NULL;
757 }
758
759 void
760 SplitName::Clear(void)
761 {
762     m_namespaceName = NULL;
763     m_typeName = NULL;
764     m_typeToken = mdTypeDefNil;
765     m_memberName = NULL;
766     m_memberToken = mdTokenNil;
767     m_params = NULL;
768
769     m_tlsThread = NULL;
770     m_metaEnum.m_appDomain = NULL;
771     m_module = NULL;
772     m_lastField = NULL;
773 }
774
775 HRESULT
776 SplitName::SplitString(__in_opt PCWSTR fullName)
777 {
778     if (m_syntax == SPLIT_NO_NAME)
779     {
780         if (fullName)
781         {
782             return E_INVALIDARG;
783         }
784
785         return S_OK;
786     }
787     else if (!fullName)
788     {
789         return E_INVALIDARG;
790     }
791
792     return SplitFullName(fullName,
793                          m_syntax,
794                          m_memberDots,
795                          &m_namespaceName,
796                          &m_typeName,
797                          &m_memberName,
798                          &m_params);
799 }
800
801 FORCEINLINE
802 WCHAR* wcrscan(LPCWSTR beg, LPCWSTR end, WCHAR ch)
803 {
804     //_ASSERTE(beg <= end);
805     WCHAR *p;
806     for (p = (WCHAR*)end; p >= beg; --p)
807     {
808         if (*p == ch)
809             break;
810     }
811     return p;
812 }
813
814 // This functions allocates a new UTF8 string that contains the classname
815 // lying between the current sepName and the previous sepName.  E.g. for a
816 // class name of "Outer+middler+inner" when sepName points to the NULL
817 // terminator this function will return "inner" in pResult and will update
818 // sepName to point to the second '+' character in the string.  When sepName
819 // points to the first '+' character this function will return "Outer" in
820 // pResult and sepName will point one WCHAR before fullName.
821 HRESULT NextEnclosingClasName(LPCWSTR fullName, __deref_inout LPWSTR& sepName, __deref_out LPUTF8 *pResult)
822 {
823     if (sepName < fullName)
824     {
825         return E_FAIL;
826     }
827     //_ASSERTE(*sepName == W('\0') || *sepName == W('+') || *sepName == W('/'));
828
829     LPWSTR origInnerName = sepName-1;
830     if ((sepName = wcrscan(fullName, origInnerName, W('+'))) < fullName)
831     {
832         sepName = wcrscan(fullName, origInnerName, W('/'));
833     }
834
835     return AllocUtf8(sepName+1, static_cast<ULONG32>(origInnerName-sepName), pResult);
836 }
837
838 bool
839 SplitName::FindType(IMDInternalImport* mdInternal)
840 {
841     if (m_typeToken != mdTypeDefNil)
842     {
843         return true;
844     }
845
846     if (!m_typeName)
847     {
848         return false;
849     }
850
851     if ((m_namespaceName == NULL || m_namespaceName[0] == '\0')
852         && (CompareUtf8(COR_MODULE_CLASS, m_typeName, m_nameFlags)==0))
853     {
854         m_typeToken = TokenFromRid(1, mdtTypeDef);  // <Module> class always has a RID of 1.
855         return true;
856     }
857
858     MetaEnum metaEnum;
859
860     if (metaEnum.Start(mdInternal, mdtTypeDef, mdTypeDefNil) != S_OK)
861     {
862         return false;
863     }
864
865     LPUTF8 curClassName;
866
867     ULONG32 length;
868     WCHAR   wszName[MAX_CLASS_NAME];
869     ConvertUtf8(m_typeName, MAX_CLASS_NAME, &length, wszName);
870
871     WCHAR *pHead;
872
873 Retry:
874
875     pHead = wszName + length;
876
877     if (FAILED(NextEnclosingClasName(wszName, pHead, &curClassName)))
878     {
879         return false;
880     }
881
882     // an inner class has an empty namespace associated with it
883     HRESULT hr = metaEnum.NextTokenByName((pHead < wszName) ? m_namespaceName : "",
884                                     curClassName,
885                                     m_nameFlags,
886                                     &m_typeToken);
887     delete[] curClassName;
888
889     if (hr != S_OK)
890     {
891         // if we didn't find a token with the given name
892         return false;
893     }
894     else if (pHead < wszName)
895     {
896         // if we did find a token, *and* the class name given
897         // does not specify any enclosing class, that's it
898         return true;
899     }
900     else
901     {
902         // restart with innermost class
903         pHead = wszName + length;
904         mdTypeDef tkInner = m_typeToken;
905         mdTypeDef tkOuter;
906         BOOL bRetry = FALSE;
907         LPUTF8 utf8Name;
908
909         while (
910             !bRetry
911             && SUCCEEDED(NextEnclosingClasName(wszName, pHead, &utf8Name))
912         )
913         {
914             if (mdInternal->GetNestedClassProps(tkInner, &tkOuter) != S_OK)
915                 tkOuter = mdTypeDefNil;
916
917             LPCSTR szName, szNS;
918             if (FAILED(mdInternal->GetNameOfTypeDef(tkInner, &szName, &szNS)))
919             {
920                 return false;
921             }
922             bRetry = (CompareUtf8(utf8Name, szName, m_nameFlags) != 0);
923             if (!bRetry)
924             {
925                 // if this is outermost class we need to compare namespaces too
926                 if (tkOuter == mdTypeDefNil)
927                 {
928                     // is this the outermost in the class name, too?
929                     if (pHead < wszName
930                         && CompareUtf8(m_namespaceName ? m_namespaceName : "", szNS, m_nameFlags) == 0)
931                     {
932                         delete[] utf8Name;
933                         return true;
934                     }
935                     else
936                     {
937                         bRetry = TRUE;
938                     }
939                 }
940             }
941             delete[] utf8Name;
942             tkInner = tkOuter;
943         }
944
945         goto Retry;
946     }
947
948 }
949
950 bool
951 SplitName::FindMethod(IMDInternalImport* mdInternal)
952 {
953     if (m_memberToken != mdTokenNil)
954     {
955         return true;
956     }
957
958     if (m_typeToken == mdTypeDefNil ||
959         !m_memberName)
960     {
961         return false;
962     }
963
964     ULONG32 EmptySig = 0;
965
966     // XXX Microsoft - Compare using signature when available.
967     if (mdInternal->FindMethodDefUsingCompare(m_typeToken,
968                                               m_memberName,
969                                               (PCCOR_SIGNATURE)&EmptySig,
970                                               sizeof(EmptySig),
971                                               NULL,
972                                               NULL,
973                                               &m_memberToken) != S_OK)
974     {
975         m_memberToken = mdTokenNil;
976         return false;
977     }
978
979     return true;
980 }
981
982 bool
983 SplitName::FindField(IMDInternalImport* mdInternal)
984 {
985     if (m_memberToken != mdTokenNil)
986     {
987         return true;
988     }
989
990     if (m_typeToken == mdTypeDefNil ||
991         !m_memberName ||
992         m_params)
993     {
994         // Can't have params with a field.
995         return false;
996     }
997
998     MetaEnum metaEnum;
999
1000     if (metaEnum.Start(mdInternal, mdtFieldDef, m_typeToken) != S_OK)
1001     {
1002         return false;
1003     }
1004
1005     return metaEnum.NextTokenByName(NULL,
1006                                     m_memberName,
1007                                     m_nameFlags,
1008                                     &m_memberToken) == S_OK;
1009 }
1010
1011 HRESULT
1012 SplitName::AllocAndSplitString(__in_opt PCWSTR fullName,
1013                                SplitSyntax syntax,
1014                                ULONG32 nameFlags,
1015                                ULONG32 memberDots,
1016                                SplitName** split)
1017 {
1018     HRESULT status;
1019
1020     if (nameFlags & ~(CLRDATA_BYNAME_CASE_SENSITIVE |
1021                       CLRDATA_BYNAME_CASE_INSENSITIVE))
1022     {
1023         return E_INVALIDARG;
1024     }
1025
1026     *split = new (nothrow) SplitName(syntax, nameFlags, memberDots);
1027     if (!*split)
1028     {
1029         return E_OUTOFMEMORY;
1030     }
1031
1032     if ((status = (*split)->SplitString(fullName)) != S_OK)
1033     {
1034         delete (*split);
1035         return status;
1036     }
1037
1038     return S_OK;
1039 }
1040
1041 HRESULT
1042 SplitName::CdStartMethod(__in_opt PCWSTR fullName,
1043                          ULONG32 nameFlags,
1044                          Module* mod,
1045                          mdTypeDef typeToken,
1046                          AppDomain* appDomain,
1047                          IXCLRDataAppDomain* pubAppDomain,
1048                          SplitName** splitRet,
1049                          CLRDATA_ENUM* handle)
1050 {
1051     HRESULT status;
1052     SplitName* split;
1053     ULONG methDots = 0;
1054
1055     *handle = TO_CDENUM(NULL);
1056
1057  Retry:
1058     if ((status = SplitName::
1059          AllocAndSplitString(fullName, SPLIT_METHOD, nameFlags,
1060                              methDots, &split)) != S_OK)
1061     {
1062         return status;
1063     }
1064
1065     if (typeToken == mdTypeDefNil)
1066     {
1067         if (!split->FindType(mod->GetMDImport()))
1068         {
1069             bool hasNamespace = split->m_namespaceName != NULL;
1070
1071             delete split;
1072
1073             //
1074             // We may have a case where there's an
1075             // explicitly implemented method which
1076             // has dots in the name.  If it's possible
1077             // to move the method name dot split
1078             // back, go ahead and retry that way.
1079             //
1080
1081             if (hasNamespace)
1082             {
1083                 methDots++;
1084                 goto Retry;
1085             }
1086
1087             return E_INVALIDARG;
1088         }
1089
1090         typeToken = split->m_typeToken;
1091     }
1092     else
1093     {
1094         if (split->m_namespaceName || split->m_typeName)
1095         {
1096             delete split;
1097             return E_INVALIDARG;
1098         }
1099     }
1100
1101     if ((status = split->m_metaEnum.
1102          Start(mod->GetMDImport(), mdtMethodDef, typeToken)) != S_OK)
1103     {
1104         delete split;
1105         return status;
1106     }
1107
1108     split->m_metaEnum.m_appDomain = appDomain;
1109     if (pubAppDomain)
1110     {
1111         split->m_metaEnum.m_appDomain =
1112             ((ClrDataAppDomain*)pubAppDomain)->GetAppDomain();
1113     }
1114     split->m_module = mod;
1115
1116     *handle = TO_CDENUM(split);
1117     if (splitRet)
1118     {
1119         *splitRet = split;
1120     }
1121     return S_OK;
1122 }
1123
1124 HRESULT
1125 SplitName::CdNextMethod(CLRDATA_ENUM* handle,
1126                         mdMethodDef* token)
1127 {
1128     SplitName* split = FROM_CDENUM(SplitName, *handle);
1129     if (!split)
1130     {
1131         return E_INVALIDARG;
1132     }
1133
1134     return split->m_metaEnum.
1135         NextTokenByName(NULL, split->m_memberName, split->m_nameFlags,
1136                         token);
1137 }
1138
1139 HRESULT
1140 SplitName::CdNextDomainMethod(CLRDATA_ENUM* handle,
1141                               AppDomain** appDomain,
1142                               mdMethodDef* token)
1143 {
1144     SplitName* split = FROM_CDENUM(SplitName, *handle);
1145     if (!split)
1146     {
1147         return E_INVALIDARG;
1148     }
1149
1150     return split->m_metaEnum.
1151         NextDomainTokenByName(NULL, split->m_memberName, split->m_nameFlags,
1152                               appDomain, token);
1153 }
1154
1155 HRESULT
1156 SplitName::CdStartField(__in_opt PCWSTR fullName,
1157                         ULONG32 nameFlags,
1158                         ULONG32 fieldFlags,
1159                         IXCLRDataTypeInstance* fromTypeInst,
1160                         TypeHandle typeHandle,
1161                         Module* mod,
1162                         mdTypeDef typeToken,
1163                         ULONG64 objBase,
1164                         Thread* tlsThread,
1165                         IXCLRDataTask* pubTlsThread,
1166                         AppDomain* appDomain,
1167                         IXCLRDataAppDomain* pubAppDomain,
1168                         SplitName** splitRet,
1169                         CLRDATA_ENUM* handle)
1170 {
1171     HRESULT status;
1172     SplitName* split;
1173
1174     *handle = TO_CDENUM(NULL);
1175
1176     if ((status = SplitName::
1177          AllocAndSplitString(fullName,
1178                              fullName ? SPLIT_FIELD : SPLIT_NO_NAME,
1179                              nameFlags, 0,
1180                              &split)) != S_OK)
1181     {
1182         return status;
1183     }
1184
1185     if (typeHandle.IsNull())
1186     {
1187         if (typeToken == mdTypeDefNil)
1188         {
1189             if (!split->FindType(mod->GetMDImport()))
1190             {
1191                 status = E_INVALIDARG;
1192                 goto Fail;
1193             }
1194
1195             typeToken = split->m_typeToken;
1196         }
1197         else
1198         {
1199             if (split->m_namespaceName || split->m_typeName)
1200             {
1201                 status = E_INVALIDARG;
1202                 goto Fail;
1203             }
1204         }
1205
1206         // With phased class loading, this may return a partially-loaded type
1207         // @todo : does this matter?
1208         typeHandle = mod->LookupTypeDef(split->m_typeToken);
1209         if (typeHandle.IsNull())
1210         {
1211             status = E_UNEXPECTED;
1212             goto Fail;
1213         }
1214     }
1215
1216     if ((status = InitFieldIter(&split->m_fieldEnum,
1217                                 typeHandle,
1218                                 true,
1219                                 fieldFlags,
1220                                 fromTypeInst)) != S_OK)
1221     {
1222         goto Fail;
1223     }
1224
1225     split->m_objBase = objBase;
1226     split->m_tlsThread = tlsThread;
1227     if (pubTlsThread)
1228     {
1229         split->m_tlsThread = ((ClrDataTask*)pubTlsThread)->GetThread();
1230     }
1231     split->m_metaEnum.m_appDomain = appDomain;
1232     if (pubAppDomain)
1233     {
1234         split->m_metaEnum.m_appDomain =
1235             ((ClrDataAppDomain*)pubAppDomain)->GetAppDomain();
1236     }
1237     split->m_module = mod;
1238
1239     *handle = TO_CDENUM(split);
1240     if (splitRet)
1241     {
1242         *splitRet = split;
1243     }
1244     return S_OK;
1245
1246  Fail:
1247     delete split;
1248     return status;
1249 }
1250
1251 HRESULT
1252 SplitName::CdNextField(ClrDataAccess* dac,
1253                        CLRDATA_ENUM* handle,
1254                        IXCLRDataTypeDefinition** fieldType,
1255                        ULONG32* fieldFlags,
1256                        IXCLRDataValue** value,
1257                        ULONG32 nameBufRetLen,
1258                        ULONG32* nameLenRet,
1259                        __out_ecount_part_opt(nameBufRetLen, *nameLenRet) WCHAR nameBufRet[  ],
1260                        IXCLRDataModule** tokenScopeRet,
1261                        mdFieldDef* tokenRet)
1262 {
1263     HRESULT status;
1264
1265     SplitName* split = FROM_CDENUM(SplitName, *handle);
1266     if (!split)
1267     {
1268         return E_INVALIDARG;
1269     }
1270
1271     FieldDesc* fieldDesc;
1272
1273     while ((fieldDesc = split->m_fieldEnum.Next()))
1274     {
1275         if (split->m_syntax != SPLIT_NO_NAME)
1276         {
1277             LPCUTF8 fieldName;
1278             if (FAILED(fieldDesc->GetName_NoThrow(&fieldName)) ||
1279                 (split->Compare(split->m_memberName, fieldName) != 0))
1280             {
1281                 continue;
1282             }
1283         }
1284
1285         split->m_lastField = fieldDesc;
1286
1287         if (fieldFlags != NULL)
1288         {
1289             *fieldFlags =
1290                 GetTypeFieldValueFlags(fieldDesc->GetFieldTypeHandleThrowing(),
1291                                        fieldDesc,
1292                                        split->m_fieldEnum.
1293                                        IsFieldFromParentClass() ?
1294                                        CLRDATA_FIELD_IS_INHERITED : 0,
1295                                        false);
1296         }
1297
1298         if ((nameBufRetLen != 0) || (nameLenRet != NULL))
1299         {
1300             LPCUTF8 szFieldName;
1301             status = fieldDesc->GetName_NoThrow(&szFieldName);
1302             if (status != S_OK)
1303             {
1304                 return status;
1305             }
1306
1307             status = ConvertUtf8(
1308                 szFieldName,
1309                 nameBufRetLen,
1310                 nameLenRet,
1311                 nameBufRet);
1312             if (status != S_OK)
1313             {
1314                 return status;
1315             }
1316         }
1317
1318         if (tokenScopeRet && !value)
1319         {
1320             *tokenScopeRet = new (nothrow)
1321                 ClrDataModule(dac, fieldDesc->GetModule());
1322             if (!*tokenScopeRet)
1323             {
1324                 return E_OUTOFMEMORY;
1325             }
1326         }
1327
1328         if (tokenRet)
1329         {
1330             *tokenRet = fieldDesc->GetMemberDef();
1331         }
1332
1333         if (fieldType)
1334         {
1335             TypeHandle fieldTypeHandle = fieldDesc->GetFieldTypeHandleThrowing();
1336             *fieldType = new (nothrow)
1337                 ClrDataTypeDefinition(dac,
1338                                       fieldTypeHandle.GetModule(),
1339                                       fieldTypeHandle.GetMethodTable()->GetCl(),
1340                                       fieldTypeHandle);
1341             if (!*fieldType && tokenScopeRet)
1342             {
1343                 delete (ClrDataModule*)*tokenScopeRet;
1344             }
1345             return *fieldType ? S_OK : E_OUTOFMEMORY;
1346         }
1347
1348         if (value)
1349         {
1350             return ClrDataValue::
1351                 NewFromFieldDesc(dac,
1352                                  split->m_metaEnum.m_appDomain,
1353                                  split->m_fieldEnum.IsFieldFromParentClass() ?
1354                                  CLRDATA_VALUE_IS_INHERITED : 0,
1355                                  fieldDesc,
1356                                  split->m_objBase,
1357                                  split->m_tlsThread,
1358                                  NULL,
1359                                  value,
1360                                  nameBufRetLen,
1361                                  nameLenRet,
1362                                  nameBufRet,
1363                                  tokenScopeRet,
1364                                  tokenRet);
1365         }
1366
1367         return S_OK;
1368     }
1369
1370     return S_FALSE;
1371 }
1372
1373 HRESULT
1374 SplitName::CdNextDomainField(ClrDataAccess* dac,
1375                              CLRDATA_ENUM* handle,
1376                              IXCLRDataValue** value)
1377 {
1378     HRESULT status;
1379
1380     SplitName* split = FROM_CDENUM(SplitName, *handle);
1381     if (!split)
1382     {
1383         return E_INVALIDARG;
1384     }
1385
1386     if (split->m_metaEnum.m_appDomain)
1387     {
1388         // Use only the caller-provided app domain.
1389         return CdNextField(dac, handle, NULL, NULL, value,
1390                            0, NULL, NULL, NULL, NULL);
1391     }
1392
1393     //
1394     // Splay fields across all app domains.
1395     //
1396
1397     for (;;)
1398     {
1399         if (!split->m_lastField)
1400         {
1401             // Need to fetch a field.
1402             if ((status = CdNextField(dac, handle, NULL, NULL, NULL,
1403                                       0, NULL, NULL, NULL, NULL)) != S_OK)
1404             {
1405                 return status;
1406             }
1407
1408             split->m_metaEnum.m_domainIter.Init();
1409         }
1410
1411         if (split->m_metaEnum.m_domainIter.Next())
1412         {
1413             break;
1414         }
1415
1416         split->m_lastField = NULL;
1417     }
1418
1419     return ClrDataValue::
1420         NewFromFieldDesc(dac,
1421                          split->m_metaEnum.m_domainIter.GetDomain(),
1422                          split->m_fieldEnum.IsFieldFromParentClass() ?
1423                          CLRDATA_VALUE_IS_INHERITED : 0,
1424                          split->m_lastField,
1425                          split->m_objBase,
1426                          split->m_tlsThread,
1427                          NULL,
1428                          value,
1429                          0,
1430                          NULL,
1431                          NULL,
1432                          NULL,
1433                          NULL);
1434 }
1435
1436 HRESULT
1437 SplitName::CdStartType(__in_opt PCWSTR fullName,
1438                        ULONG32 nameFlags,
1439                        Module* mod,
1440                        AppDomain* appDomain,
1441                        IXCLRDataAppDomain* pubAppDomain,
1442                        SplitName** splitRet,
1443                        CLRDATA_ENUM* handle)
1444 {
1445     HRESULT status;
1446     SplitName* split;
1447
1448     *handle = TO_CDENUM(NULL);
1449
1450     if ((status = SplitName::
1451          AllocAndSplitString(fullName, SPLIT_TYPE, nameFlags, 0,
1452                              &split)) != S_OK)
1453     {
1454         return status;
1455     }
1456
1457     if ((status = split->m_metaEnum.
1458          Start(mod->GetMDImport(), mdtTypeDef, mdTokenNil)) != S_OK)
1459     {
1460         delete split;
1461         return status;
1462     }
1463
1464     split->m_metaEnum.m_appDomain = appDomain;
1465     if (pubAppDomain)
1466     {
1467         split->m_metaEnum.m_appDomain =
1468             ((ClrDataAppDomain*)pubAppDomain)->GetAppDomain();
1469     }
1470     split->m_module = mod;
1471
1472     *handle = TO_CDENUM(split);
1473     if (splitRet)
1474     {
1475         *splitRet = split;
1476     }
1477     return S_OK;
1478 }
1479
1480 HRESULT
1481 SplitName::CdNextType(CLRDATA_ENUM* handle,
1482                       mdTypeDef* token)
1483 {
1484     SplitName* split = FROM_CDENUM(SplitName, *handle);
1485     if (!split)
1486     {
1487         return E_INVALIDARG;
1488     }
1489
1490     return split->m_metaEnum.
1491         NextTokenByName(split->m_namespaceName, split->m_typeName,
1492                         split->m_nameFlags, token);
1493 }
1494
1495 HRESULT
1496 SplitName::CdNextDomainType(CLRDATA_ENUM* handle,
1497                             AppDomain** appDomain,
1498                             mdTypeDef* token)
1499 {
1500     SplitName* split = FROM_CDENUM(SplitName, *handle);
1501     if (!split)
1502     {
1503         return E_INVALIDARG;
1504     }
1505
1506     return split->m_metaEnum.
1507         NextDomainTokenByName(split->m_namespaceName, split->m_typeName,
1508                               split->m_nameFlags, appDomain, token);
1509 }
1510
1511 //----------------------------------------------------------------------------
1512 //
1513 // DacInstanceManager.
1514 //
1515 // Data retrieved from the target process is cached for two reasons:
1516 //
1517 // 1. It may be necessary to map from the host address back to the target
1518 //    address.  For example, if any code uses a 'this' pointer or
1519 //    takes the address of a field the address has to be translated from
1520 //    host to target.  This requires instances to be held as long as
1521 //    they may be referenced.
1522 //
1523 // 2. Data is often referenced multiple times so caching is an important
1524 //    performance advantage.
1525 //
1526 // Ideally we'd like to implement a simple page cache but this is
1527 // complicated by the fact that user minidump memory can have
1528 // arbitrary granularity and also that the member operator (->)
1529 // needs to return a pointer to an object.  That means that all of
1530 // the data for an object must be sequential and cannot be split
1531 // at page boundaries.
1532 //
1533 // Data can also be accessed with different sizes.  For example,
1534 // a base struct can be accessed, then cast to a derived struct and
1535 // accessed again with the larger derived size.  The cache must
1536 // be able to replace data to maintain the largest amount of data
1537 // touched.
1538 //
1539 // We keep track of each access and the recovered memory for it.
1540 // A hash on target address allows quick access to instance data
1541 // by target address.  The data for each access has a header on it
1542 // for bookkeeping purposes, so host address to target address translation
1543 // is just a matter of backing up to the header and pulling the target
1544 // address from it.  Keeping each access separately allows easy
1545 // replacement by larger accesses.
1546 //
1547 //----------------------------------------------------------------------------
1548
1549 DacInstanceManager::DacInstanceManager(void)
1550     : m_unusedBlock(NULL)
1551 {
1552     InitEmpty();
1553 }
1554
1555 DacInstanceManager::~DacInstanceManager(void)
1556 {
1557     // We are stopping debugging in this case, so don't save any block of memory.
1558     // Otherwise, there will be a memory leak.
1559     Flush(false);
1560 }
1561
1562 #if defined(DAC_HASHTABLE)
1563 DAC_INSTANCE*
1564 DacInstanceManager::Add(DAC_INSTANCE* inst)
1565 {
1566     // Assert that we don't add NULL instances. This allows us to assert that found instances
1567     // are not NULL in DacInstanceManager::Find
1568     _ASSERTE(inst != NULL);
1569
1570     DWORD nHash = DAC_INSTANCE_HASH(inst->addr);
1571     HashInstanceKeyBlock* block = m_hash[nHash];
1572
1573     if (!block || block->firstElement == 0)
1574     {
1575
1576         HashInstanceKeyBlock* newBlock;
1577         if (block)
1578         {
1579             newBlock = (HashInstanceKeyBlock*) new (nothrow) BYTE[HASH_INSTANCE_BLOCK_ALLOC_SIZE];
1580         }
1581         else
1582         {
1583             // We allocate one big memory chunk that has a block for every index of the hash table to
1584             // improve data locality and reduce the number of allocs. In most cases, a hash bucket will
1585             // use only one block, so improving data locality across blocks (i.e. keeping the buckets of the
1586             // hash table together) should help.
1587             newBlock = (HashInstanceKeyBlock*)
1588                 ClrVirtualAlloc(NULL, HASH_INSTANCE_BLOCK_ALLOC_SIZE*NumItems(m_hash), MEM_COMMIT, PAGE_READWRITE);
1589         }
1590         if (!newBlock)
1591         {
1592             return NULL;
1593         }
1594         if (block)
1595         {
1596             // We add the newest block to the start of the list assuming that most accesses are for
1597             // recently added elements.
1598             newBlock->next = block;
1599             m_hash[nHash] = newBlock; // The previously allocated block
1600             newBlock->firstElement = HASH_INSTANCE_BLOCK_NUM_ELEMENTS;
1601             block = newBlock;
1602         }
1603         else
1604         {
1605             for (DWORD j = 0; j < NumItems(m_hash); j++)
1606             {
1607                 m_hash[j] = newBlock;
1608                 newBlock->next = NULL; // The previously allocated block
1609                 newBlock->firstElement = HASH_INSTANCE_BLOCK_NUM_ELEMENTS;
1610                 newBlock = (HashInstanceKeyBlock*) (((BYTE*) newBlock) + HASH_INSTANCE_BLOCK_ALLOC_SIZE);
1611             }
1612             block = m_hash[nHash];
1613         }
1614     }
1615     _ASSERTE(block->firstElement > 0);
1616     block->firstElement--;
1617     block->instanceKeys[block->firstElement].addr = inst->addr;
1618     block->instanceKeys[block->firstElement].instance = inst;
1619
1620     inst->next = NULL;
1621     return inst;
1622 }
1623 #else //DAC_HASHTABLE
1624 DAC_INSTANCE*
1625 DacInstanceManager::Add(DAC_INSTANCE* inst)
1626 {
1627     _ASSERTE(inst != NULL);
1628 #ifdef _DEBUG
1629     bool isInserted = (m_hash.find(inst->addr) == m_hash.end());
1630 #endif //_DEBUG
1631     DAC_INSTANCE *(&target) = m_hash[inst->addr];
1632     _ASSERTE(!isInserted || target == NULL);
1633     if( target != NULL )
1634     {
1635         //This is necessary to preserve the semantics of Supersede, however, it
1636         //is more or less dead code.
1637         inst->next = target;
1638         target = inst;
1639
1640         //verify descending order
1641         _ASSERTE(inst->size >= target->size);
1642     }
1643     else
1644     {
1645         target = inst;
1646     }
1647
1648     return inst;
1649 }
1650
1651 #endif // #if defined(DAC_HASHTABLE)
1652
1653
1654 DAC_INSTANCE*
1655 DacInstanceManager::Alloc(TADDR addr, ULONG32 size, DAC_USAGE_TYPE usage)
1656 {
1657     SUPPORTS_DAC_HOST_ONLY;
1658     DAC_INSTANCE_BLOCK* block;
1659     DAC_INSTANCE* inst;
1660     ULONG32 fullSize;
1661
1662     static_assert_no_msg(sizeof(DAC_INSTANCE_BLOCK) <= DAC_INSTANCE_ALIGN);
1663     static_assert_no_msg((sizeof(DAC_INSTANCE) & (DAC_INSTANCE_ALIGN - 1)) == 0);
1664
1665     //
1666     // All allocated instances must be kept alive as long
1667     // as anybody may have a host pointer for one of them.
1668     // This means that we cannot delete an arbitrary instance
1669     // unless we are sure no pointers exist, which currently
1670     // is not possible to determine, thus we just hold everything
1671     // until a Flush.  This greatly simplifies instance allocation
1672     // as we can then just sweep through large blocks rather
1673     // than having to use a real allocator.  The only
1674     // complication is that we need to keep all instance
1675     // data aligned.  We have guaranteed that the header will
1676     // preserve alignment of the data following if the header
1677     // is aligned, so as long as we round up all allocations
1678     // to a multiple of the alignment size everything just works.
1679     //
1680
1681     fullSize = (size + DAC_INSTANCE_ALIGN - 1) & ~(DAC_INSTANCE_ALIGN - 1);
1682     _ASSERTE(fullSize && fullSize <= 0xffffffff - 2 * sizeof(*inst));
1683     fullSize += sizeof(*inst);
1684
1685     //
1686     // Check for an existing block with space.
1687     //
1688
1689     for (block = m_blocks; block; block = block->next)
1690     {
1691         if (fullSize <= block->bytesFree)
1692         {
1693             break;
1694         }
1695     }
1696
1697     if (!block)
1698     {
1699         //
1700         // No existing block has enough space, so allocate a new
1701         // one if necessary and link it in.  We know we're allocating large
1702         // blocks so directly VirtualAlloc.  We save one block through a
1703         // flush so that we spend less time allocating/deallocating.
1704         //
1705
1706         ULONG32 blockSize = fullSize + DAC_INSTANCE_ALIGN;
1707         if (blockSize < DAC_INSTANCE_BLOCK_ALLOCATION)
1708         {
1709             blockSize = DAC_INSTANCE_BLOCK_ALLOCATION;
1710         }
1711
1712         // If we have a saved block and it's large enough, use it.
1713         block = m_unusedBlock;
1714         if ((block != NULL) &&
1715             ((block->bytesUsed + block->bytesFree) >= blockSize))
1716         {
1717             m_unusedBlock = NULL;
1718
1719             // Right now, we're locked to DAC_INSTANCE_BLOCK_ALLOCATION but
1720             // that might change in the future if we decide to do something
1721             // else with the size guarantee in code:DacInstanceManager::FreeAllBlocks
1722             blockSize = block->bytesUsed + block->bytesFree;
1723         }
1724         else
1725         {
1726              block = (DAC_INSTANCE_BLOCK*)
1727                 ClrVirtualAlloc(NULL, blockSize, MEM_COMMIT, PAGE_READWRITE);
1728         }
1729
1730         if (!block)
1731         {
1732             return NULL;
1733         }
1734
1735         // Keep the first aligned unit for the block header.
1736         block->bytesUsed = DAC_INSTANCE_ALIGN;
1737         block->bytesFree = blockSize - DAC_INSTANCE_ALIGN;
1738
1739         block->next = m_blocks;
1740         m_blocks = block;
1741
1742         m_blockMemUsage += blockSize;
1743     }
1744
1745     inst = (DAC_INSTANCE*)((PBYTE)block + block->bytesUsed);
1746     block->bytesUsed += fullSize;
1747     _ASSERTE(block->bytesFree >= fullSize);
1748     block->bytesFree -= fullSize;
1749
1750     inst->next = NULL;
1751     inst->addr = addr;
1752     inst->size = size;
1753     inst->sig = DAC_INSTANCE_SIG;
1754     inst->usage = usage;
1755     inst->enumMem = 0;
1756     inst->MDEnumed = 0;
1757
1758     m_numInst++;
1759     m_instMemUsage += fullSize;
1760     return inst;
1761 }
1762
1763 void
1764 DacInstanceManager::ReturnAlloc(DAC_INSTANCE* inst)
1765 {
1766     SUPPORTS_DAC_HOST_ONLY;
1767     DAC_INSTANCE_BLOCK* block;
1768     DAC_INSTANCE_BLOCK * pPrevBlock;
1769     ULONG32 fullSize;
1770
1771     //
1772     // This special routine handles cleanup in
1773     // cases where an instances has been allocated
1774     // but must be returned due to a following error.
1775     // The given instance must be the last instance
1776     // in an existing block.
1777     //
1778
1779     fullSize =
1780         ((inst->size + DAC_INSTANCE_ALIGN - 1) & ~(DAC_INSTANCE_ALIGN - 1)) +
1781         sizeof(*inst);
1782
1783     pPrevBlock = NULL;
1784     for (block = m_blocks; block; pPrevBlock = block, block = block->next)
1785     {
1786         if ((PBYTE)inst == (PBYTE)block + (block->bytesUsed - fullSize))
1787         {
1788             break;
1789         }
1790     }
1791
1792     if (!block)
1793     {
1794         return;
1795     }
1796
1797     block->bytesUsed -= fullSize;
1798     block->bytesFree += fullSize;
1799     m_numInst--;
1800     m_instMemUsage -= fullSize;
1801
1802     // If the block is empty after returning the specified instance, that means this block was newly created
1803     // when this instance was allocated.  We have seen cases where we are asked to allocate a
1804     // large chunk of memory only to fail to read the memory from a dump later on, i.e. when both the target
1805     // address and the size are invalid.  If we keep the allocation, we'll grow the VM size unnecessarily.
1806     // Thus, release a block if it's empty and if it's not the default size (to avoid thrashing memory).
1807     // See Dev10 Dbug 812112 for more information.
1808     if ((block->bytesUsed == DAC_INSTANCE_ALIGN) &&
1809         ((block->bytesFree + block->bytesUsed) != DAC_INSTANCE_BLOCK_ALLOCATION))
1810     {
1811         // The empty block is at the beginning of the list.
1812         if (pPrevBlock == NULL)
1813         {
1814             m_blocks = block->next;
1815         }
1816         else
1817         {
1818             _ASSERTE(pPrevBlock->next == block);
1819             pPrevBlock->next = block->next;
1820         }
1821         ClrVirtualFree(block, 0, MEM_RELEASE);
1822     }
1823 }
1824
1825
1826 #if defined(DAC_HASHTABLE)
1827 DAC_INSTANCE*
1828 DacInstanceManager::Find(TADDR addr)
1829 {
1830
1831 #if defined(DAC_MEASURE_PERF)
1832     unsigned _int64 nStart, nEnd;
1833     g_nFindCalls++;
1834     nStart = GetCycleCount();
1835 #endif // #if defined(DAC_MEASURE_PERF)
1836
1837     HashInstanceKeyBlock* block = m_hash[DAC_INSTANCE_HASH(addr)];
1838
1839 #if defined(DAC_MEASURE_PERF)
1840     nEnd = GetCycleCount();
1841     g_nFindHashTotalTime += nEnd - nStart;
1842 #endif // #if defined(DAC_MEASURE_PERF)
1843
1844     while (block)
1845     {
1846         DWORD nIndex = block->firstElement;
1847         for (; nIndex < HASH_INSTANCE_BLOCK_NUM_ELEMENTS; nIndex++)
1848         {
1849             if (block->instanceKeys[nIndex].addr == addr)
1850             {
1851  #if defined(DAC_MEASURE_PERF)
1852                 nEnd = GetCycleCount();
1853                 g_nFindHits++;
1854                 g_nFindTotalTime += nEnd - nStart;
1855                 if (g_nStackWalk) g_nFindStackTotalTime += nEnd - nStart;
1856 #endif // #if defined(DAC_MEASURE_PERF)
1857
1858                 DAC_INSTANCE* inst = block->instanceKeys[nIndex].instance;
1859
1860                 // inst should not be NULL even if the address was superseded. We search
1861                 // the entries in the reverse order they were added. So we should have
1862                 // found the superseding entry before this one. (Of course, if a NULL instance
1863                 // has been added, this assert is meaningless. DacInstanceManager::Add
1864                 // asserts that NULL instances aren't added.)
1865
1866                 _ASSERTE(inst != NULL);
1867
1868                 return inst;
1869             }
1870         }
1871         block = block->next;
1872     }
1873
1874 #if defined(DAC_MEASURE_PERF)
1875     nEnd = GetCycleCount();
1876     g_nFindFails++;
1877     g_nFindTotalTime += nEnd - nStart;
1878     if (g_nStackWalk) g_nFindStackTotalTime += nEnd - nStart;
1879 #endif // #if defined(DAC_MEASURE_PERF)
1880
1881     return NULL;
1882 }
1883 #else //DAC_HASHTABLE
1884 DAC_INSTANCE*
1885 DacInstanceManager::Find(TADDR addr)
1886 {
1887     DacInstanceHashIterator iter = m_hash.find(addr);
1888     if( iter == m_hash.end() )
1889     {
1890         return NULL;
1891     }
1892     else
1893     {
1894         return iter->second;
1895     }
1896 }
1897 #endif // if defined(DAC_HASHTABLE)
1898
1899 HRESULT
1900 DacInstanceManager::Write(DAC_INSTANCE* inst, bool throwEx)
1901 {
1902     HRESULT status;
1903
1904     if (inst->usage == DAC_VPTR)
1905     {
1906         // Skip over the host-side vtable pointer when
1907         // writing back.
1908         status = DacWriteAll(inst->addr + sizeof(TADDR),
1909                              (PBYTE)(inst + 1) + sizeof(PVOID),
1910                              inst->size - sizeof(TADDR),
1911                              throwEx);
1912     }
1913     else
1914     {
1915         // Write the whole instance back.
1916         status = DacWriteAll(inst->addr, inst + 1, inst->size, throwEx);
1917     }
1918
1919     return status;
1920 }
1921
1922 #if defined(DAC_HASHTABLE)
1923 void
1924 DacInstanceManager::Supersede(DAC_INSTANCE* inst)
1925 {
1926     _ASSERTE(inst != NULL);
1927
1928     //
1929     // This instance has been superseded by a larger
1930     // one and so must be removed from the hash.  However,
1931     // code may be holding the instance pointer so it
1932     // can't just be deleted.  Put it on a list for
1933     // later cleanup.
1934     //
1935
1936     HashInstanceKeyBlock* block = m_hash[DAC_INSTANCE_HASH(inst->addr)];
1937     while (block)
1938     {
1939         DWORD nIndex = block->firstElement;
1940         for (; nIndex < HASH_INSTANCE_BLOCK_NUM_ELEMENTS; nIndex++)
1941         {
1942             if (block->instanceKeys[nIndex].instance == inst)
1943             {
1944                 block->instanceKeys[nIndex].instance = NULL;
1945                 break;
1946             }
1947         }
1948         if (nIndex < HASH_INSTANCE_BLOCK_NUM_ELEMENTS)
1949         {
1950             break;
1951         }
1952         block = block->next;
1953     }
1954
1955     AddSuperseded(inst);
1956 }
1957 #else //DAC_HASHTABLE
1958 void
1959 DacInstanceManager::Supersede(DAC_INSTANCE* inst)
1960 {
1961     _ASSERTE(inst != NULL);
1962
1963     //
1964     // This instance has been superseded by a larger
1965     // one and so must be removed from the hash.  However,
1966     // code may be holding the instance pointer so it
1967     // can't just be deleted.  Put it on a list for
1968     // later cleanup.
1969     //
1970
1971     DacInstanceHashIterator iter = m_hash.find(inst->addr);
1972     if( iter == m_hash.end() )
1973         return;
1974
1975     DAC_INSTANCE** bucket = &(iter->second);
1976     DAC_INSTANCE* cur = *bucket;
1977     DAC_INSTANCE* prev = NULL;
1978     //walk through the chain looking for this particular instance
1979     while (cur)
1980     {
1981         if (cur == inst)
1982         {
1983             if (!prev)
1984             {
1985                 *bucket = inst->next;
1986             }
1987             else
1988             {
1989                 prev->next = inst->next;
1990             }
1991             break;
1992         }
1993
1994         prev = cur;
1995         cur = cur->next;
1996     }
1997
1998     AddSuperseded(inst);
1999 }
2000 #endif // if defined(DAC_HASHTABLE)
2001
2002 // This is the default Flush() called when the DAC cache is invalidated,
2003 // e.g. when we continue the debuggee process.  In this case, we want to
2004 // save one block of memory to avoid thrashing.  See the usage of m_unusedBlock
2005 // for more information.
2006 void DacInstanceManager::Flush(void)
2007 {
2008     Flush(true);
2009 }
2010
2011 void DacInstanceManager::Flush(bool fSaveBlock)
2012 {
2013     SUPPORTS_DAC_HOST_ONLY;
2014
2015     //
2016     // All allocated memory is in the block
2017     // list, so just free the blocks and
2018     // forget all the internal pointers.
2019     //
2020
2021     for (;;)
2022     {
2023         FreeAllBlocks(fSaveBlock);
2024
2025         DAC_INSTANCE_PUSH* push = m_instPushed;
2026         if (!push)
2027         {
2028             break;
2029         }
2030
2031         m_instPushed = push->next;
2032         m_blocks = push->blocks;
2033         delete push;
2034     }
2035
2036     // If we are not saving any memory blocks, then clear the saved buffer block (if any) as well.
2037     if (!fSaveBlock)
2038     {
2039         if (m_unusedBlock != NULL)
2040         {
2041             ClrVirtualFree(m_unusedBlock, 0, MEM_RELEASE);
2042             m_unusedBlock = NULL;
2043         }
2044     }
2045
2046 #if defined(DAC_HASHTABLE)
2047     for (int i = NumItems(m_hash) - 1; i >= 0; i--)
2048     {
2049         HashInstanceKeyBlock* block = m_hash[i];
2050         HashInstanceKeyBlock* next;
2051         while (block)
2052         {
2053             next = block->next;
2054             if (next)
2055             {
2056                 delete [] block;
2057             }
2058             else if (i == 0)
2059             {
2060                 ClrVirtualFree(block, 0, MEM_RELEASE);
2061             }
2062             block = next;
2063         }
2064     }
2065 #else //DAC_HASHTABLE
2066     m_hash.clear();
2067 #endif //DAC_HASHTABLE
2068
2069     InitEmpty();
2070 }
2071
2072 #if defined(DAC_HASHTABLE)
2073 void
2074 DacInstanceManager::ClearEnumMemMarker(void)
2075 {
2076     ULONG i;
2077     DAC_INSTANCE* inst;
2078
2079     for (i = 0; i < NumItems(m_hash); i++)
2080     {
2081         HashInstanceKeyBlock* block = m_hash[i];
2082         while (block)
2083         {
2084             DWORD j;
2085             for (j = block->firstElement; j < HASH_INSTANCE_BLOCK_NUM_ELEMENTS; j++)
2086             {
2087                 inst = block->instanceKeys[j].instance;
2088                 if (inst != NULL)
2089                 {
2090                     inst->enumMem = 0;
2091                 }
2092             }
2093             block = block->next;
2094         }
2095     }
2096     for (inst = m_superseded; inst; inst = inst->next)
2097     {
2098         inst->enumMem = 0;
2099     }
2100 }
2101 #else //DAC_HASHTABLE
2102 void
2103 DacInstanceManager::ClearEnumMemMarker(void)
2104 {
2105     ULONG i;
2106     DAC_INSTANCE* inst;
2107
2108     DacInstanceHashIterator end = m_hash.end();
2109     /* REVISIT_TODO Fri 10/20/2006
2110      * This might have an issue, since it might miss chained entries off of
2111      * ->next.  However, ->next is going away, and for all intents and
2112      *  purposes, this never happens.
2113 */
2114     for( DacInstanceHashIterator cur = m_hash.begin(); cur != end; ++cur )
2115     {
2116         cur->second->enumMem = 0;
2117     }
2118
2119     for (inst = m_superseded; inst; inst = inst->next)
2120     {
2121         inst->enumMem = 0;
2122     }
2123 }
2124 #endif // if defined(DAC_HASHTABLE)
2125
2126
2127 #if defined(DAC_HASHTABLE)
2128 //
2129 //
2130 // Iterating through all of the hash entry and report the memory
2131 // instance to minidump
2132 //
2133 // This function returns the total number of bytes that it reported.
2134 //
2135 //
2136 UINT
2137 DacInstanceManager::DumpAllInstances(
2138     ICLRDataEnumMemoryRegionsCallback *pCallBack)       // memory report call back
2139 {
2140     ULONG           i;
2141     DAC_INSTANCE*   inst;
2142     UINT            cbTotal = 0;
2143
2144 #if defined(DAC_MEASURE_PERF)
2145    FILE* fp = fopen("c:\\dumpLog.txt", "a");
2146    int total = 0;
2147 #endif // #if defined(DAC_MEASURE_PERF)
2148
2149     for (i = 0; i < NumItems(m_hash); i++)
2150     {
2151
2152 #if defined(DAC_MEASURE_PERF)
2153       int numInBucket = 0;
2154 #endif // #if defined(DAC_MEASURE_PERF)
2155
2156         HashInstanceKeyBlock* block = m_hash[i];
2157         while (block)
2158         {
2159             DWORD j;
2160             for (j = block->firstElement; j < HASH_INSTANCE_BLOCK_NUM_ELEMENTS; j++)
2161             {
2162                 inst = block->instanceKeys[j].instance;
2163
2164                 // Only report those we intended to.
2165                 // So far, only metadata is excluded!
2166                 //
2167                 if (inst && inst->noReport == 0)
2168                 {
2169                     cbTotal += inst->size;
2170                     HRESULT hr = pCallBack->EnumMemoryRegion(TO_CDADDR(inst->addr), inst->size);
2171                     if (hr == COR_E_OPERATIONCANCELED)
2172                     {
2173                         ThrowHR(hr);
2174                     }
2175                 }
2176
2177 #if defined(DAC_MEASURE_PERF)
2178                 if (inst)
2179                 {
2180                     numInBucket++;
2181                 }
2182 #endif // #if defined(DAC_MEASURE_PERF)
2183             }
2184             block = block->next;
2185         }
2186
2187  #if defined(DAC_MEASURE_PERF)
2188       fprintf(fp, "%4d: %4d%s", i, numInBucket, (i+1)%5?  ";  " : "\n");
2189         total += numInBucket;
2190 #endif // #if defined(DAC_MEASURE_PERF)
2191
2192     }
2193
2194 #if defined(DAC_MEASURE_PERF)
2195     fprintf(fp, "\n\nTotal entries: %d\n\n", total);
2196     fclose(fp);
2197 #endif // #if defined(DAC_MEASURE_PERF)
2198
2199     return cbTotal;
2200
2201 }
2202 #else //DAC_HASHTABLE
2203 //
2204 //
2205 // Iterating through all of the hash entry and report the memory
2206 // instance to minidump
2207 //
2208 // This function returns the total number of bytes that it reported.
2209 //
2210 //
2211 UINT
2212 DacInstanceManager::DumpAllInstances(
2213     ICLRDataEnumMemoryRegionsCallback *pCallBack)       // memory report call back
2214 {
2215     SUPPORTS_DAC_HOST_ONLY;
2216
2217     DAC_INSTANCE*   inst;
2218     UINT            cbTotal = 0;
2219
2220 #if defined(DAC_MEASURE_PERF)
2221    FILE* fp = fopen("c:\\dumpLog.txt", "a");
2222 #endif // #if defined(DAC_MEASURE_PERF)
2223
2224 #if defined(DAC_MEASURE_PERF)
2225    int numInBucket = 0;
2226 #endif // #if defined(DAC_MEASURE_PERF)
2227
2228    DacInstanceHashIterator end = m_hash.end();
2229    for (DacInstanceHashIterator cur = m_hash.begin(); end != cur; ++cur)
2230    {
2231        inst = cur->second;
2232
2233        // Only report those we intended to.
2234        // So far, only metadata is excluded!
2235        //
2236        if (inst->noReport == 0)
2237        {
2238            cbTotal += inst->size;
2239            HRESULT hr = pCallBack->EnumMemoryRegion(TO_CDADDR(inst->addr), inst->size);
2240            if (hr == COR_E_OPERATIONCANCELED)
2241            {
2242                ThrowHR(hr);
2243            }
2244        }
2245
2246 #if defined(DAC_MEASURE_PERF)
2247        numInBucket++;
2248 #endif // #if defined(DAC_MEASURE_PERF)
2249    }
2250
2251 #if defined(DAC_MEASURE_PERF)
2252     fprintf(fp, "\n\nTotal entries: %d\n\n", numInBucket);
2253     fclose(fp);
2254 #endif // #if defined(DAC_MEASURE_PERF)
2255
2256     return cbTotal;
2257
2258 }
2259 #endif // if defined(DAC_HASHTABLE)
2260
2261 DAC_INSTANCE_BLOCK*
2262 DacInstanceManager::FindInstanceBlock(DAC_INSTANCE* inst)
2263 {
2264     for (DAC_INSTANCE_BLOCK* block = m_blocks; block; block = block->next)
2265     {
2266         if ((PBYTE)inst >= (PBYTE)block &&
2267             (PBYTE)inst < (PBYTE)block + block->bytesUsed)
2268         {
2269             return block;
2270         }
2271     }
2272
2273     return NULL;
2274 }
2275
2276 // If fSaveBlock is false, free all blocks of allocated memory.  Otherwise,
2277 // free all blocks except the one we save to avoid thrashing memory.
2278 // Callers very frequently flush repeatedly with little memory needed in DAC
2279 // so this avoids wasteful repeated allocations/deallocations.
2280 // There is a very unlikely case that we'll have allocated an extremely large
2281 // block; if this is the only block we will save none since this block will
2282 // remain allocated.
2283 void
2284 DacInstanceManager::FreeAllBlocks(bool fSaveBlock)
2285 {
2286     DAC_INSTANCE_BLOCK* block;
2287
2288     while ((block = m_blocks))
2289     {
2290         m_blocks = block->next;
2291
2292         // If we haven't saved our single block yet and this block is the default size
2293         // then we will save it instead of freeing it.  This avoids saving an unnecessarily large
2294         // memory block.
2295         // Do *NOT* trash the byte counts.  code:DacInstanceManager::Alloc
2296         // depends on them being correct when checking to see if a block is large enough.
2297         if (fSaveBlock &&
2298             (m_unusedBlock == NULL) &&
2299             ((block->bytesFree + block->bytesUsed) == DAC_INSTANCE_BLOCK_ALLOCATION))
2300         {
2301             // Just to avoid confusion, since we're keeping it around.
2302             block->next = NULL;
2303             m_unusedBlock = block;
2304         }
2305         else
2306         {
2307             ClrVirtualFree(block, 0, MEM_RELEASE);
2308         }
2309     }
2310 }
2311
2312 //----------------------------------------------------------------------------
2313 //
2314 // DacStreamManager.
2315 //
2316 //----------------------------------------------------------------------------
2317
2318 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
2319
2320 namespace serialization { namespace bin {
2321
2322     //========================================================================
2323     // Support functions for binary serialization of simple types to a buffer:
2324     //   - raw_size() returns the size in bytes of the binary representation
2325     //                of a value.
2326     //   - raw_serialize() copies the binary representation of a value into a
2327     //                buffer.
2328     //   - raw_deserialize() generates a value from its binary representation
2329     //                in a buffer.
2330     // Beyond simple types the APIs below support SString instances. SStrings
2331     // are stored as UTF8 strings.
2332     //========================================================================
2333
2334     static const size_t ErrOverflow = (size_t)(-1);
2335
2336 #ifndef FEATURE_PAL
2337
2338     // Template class is_blittable
2339     template <typename _Ty, typename Enable = void>
2340     struct is_blittable
2341         : std::false_type
2342     { // determines whether _Ty is blittable
2343     };
2344
2345     template <typename _Ty>
2346     struct is_blittable<_Ty, typename std::enable_if<std::is_arithmetic<_Ty>::value>::type>
2347         : std::true_type
2348     { // determines whether _Ty is blittable
2349     };
2350
2351     // allow types to declare themselves blittable by including a static bool
2352     // member "is_blittable".
2353     template <typename _Ty>
2354     struct is_blittable<_Ty, typename std::enable_if<_Ty::is_blittable>::type>
2355         : std::true_type
2356     { // determines whether _Ty is blittable
2357     };
2358
2359
2360     //========================================================================
2361     // serialization::bin::Traits<T> enables binary serialization and
2362     //   deserialization of instances of T.
2363     //========================================================================
2364
2365     //
2366     // General specialization for non-blittable types - must be overridden
2367     // for each specific non-blittable type.
2368     //
2369     template <typename T, typename Enable = void>
2370     class Traits
2371     {
2372     public:
2373         static FORCEINLINE size_t
2374         raw_size(const T & val)
2375         {
2376             static_assert(false, "Non-blittable types need explicit specializations");
2377         }
2378     };
2379
2380     //
2381     // General type trait supporting serialization/deserialization of blittable
2382     // type arguments (as defined by the is_blittable<> type traits above).
2383     //
2384     template <typename T>
2385     class Traits<T, typename std::enable_if<is_blittable<T>::value>::type>
2386     {
2387 #else // FEATURE_PAL
2388     template <typename T>
2389     class Traits
2390     {
2391 #endif // !FEATURE_PAL
2392     public:
2393         //
2394         // raw_size() returns the size in bytes of the binary representation of a
2395         //                value.
2396         //
2397         static FORCEINLINE size_t
2398         raw_size(const T & val)
2399         {
2400             return sizeof(T);
2401         }
2402
2403         //
2404         // raw_serialize() copies the binary representation of a value into a
2405         //     "dest" buffer that has "destSize" bytes available.
2406         // Returns raw_size(val), or ErrOverflow if the buffer does not have
2407         //     enough space to accommodate "val".
2408         //
2409         static FORCEINLINE size_t
2410         raw_serialize(BYTE* dest, size_t destSize, const T & val)
2411         {
2412             size_t cnt = raw_size(val);
2413
2414             if (destSize < cnt)
2415             {
2416                 return ErrOverflow;
2417             }
2418
2419             memcpy_s(dest, destSize, &val, cnt);
2420
2421             return cnt;
2422         }
2423
2424         //
2425         // raw_deserialize() generates a value "val" from its binary
2426         //     representation in a buffer "src".
2427         // Returns raw_size(val), or ErrOverflow if the buffer does not have
2428         //     enough space to accommodate "val".
2429         //
2430         static FORCEINLINE size_t
2431         raw_deserialize(T & val, const BYTE* src, size_t srcSize)
2432         {
2433             size_t cnt = raw_size(*(T*)src);
2434
2435             if (srcSize < cnt)
2436             {
2437                 return ErrOverflow;
2438             }
2439
2440             memcpy_s(&val, cnt, src, cnt);
2441
2442             return cnt;
2443         }
2444
2445     };
2446
2447     //
2448     // Specialization for UTF8 strings
2449     //
2450     template<>
2451     class Traits<LPCUTF8>
2452     {
2453     public:
2454         static FORCEINLINE size_t
2455         raw_size(const LPCUTF8 & val)
2456         {
2457             return strlen(val) + 1;
2458         }
2459
2460         static FORCEINLINE size_t
2461         raw_serialize(BYTE* dest, size_t destSize, const LPCUTF8 & val)
2462         {
2463             size_t cnt = raw_size(val);
2464
2465             if (destSize < cnt)
2466             {
2467                 return ErrOverflow;
2468             }
2469
2470             memcpy_s(dest, destSize, &val, cnt);
2471
2472             return cnt;
2473         }
2474
2475         static FORCEINLINE size_t
2476         raw_deserialize(LPCUTF8 & val, const BYTE* src, size_t srcSize)
2477         {
2478             size_t cnt = strnlen((LPCUTF8)src, srcSize) + 1;
2479
2480             // assert we found a NULL terminated string at "src"
2481             if (srcSize < cnt)
2482             {
2483                 return ErrOverflow;
2484             }
2485
2486             // we won't allocate another buffer for this string
2487             val = (LPCUTF8)src;
2488
2489             return cnt;
2490         }
2491
2492     };
2493
2494     //
2495     // Specialization for SString.
2496     // SString serialization/deserialization is performed to/from a UTF8
2497     // string.
2498     //
2499     template<>
2500     class Traits<SString>
2501     {
2502     public:
2503         static FORCEINLINE size_t
2504         raw_size(const SString & val)
2505         {
2506             StackSString s;
2507             val.ConvertToUTF8(s);
2508             // make sure to include the NULL terminator
2509             return s.GetCount() + 1;
2510         }
2511
2512         static FORCEINLINE size_t
2513         raw_serialize(BYTE* dest, size_t destSize, const SString & val)
2514         {
2515             // instead of calling raw_size() we inline it here, so we can reuse
2516             // the UTF8 string obtained below as an argument to memcpy.
2517
2518             StackSString s;
2519             val.ConvertToUTF8(s);
2520             // make sure to include the NULL terminator
2521             size_t cnt = s.GetCount() + 1;
2522
2523             if (destSize < cnt)
2524             {
2525                 return ErrOverflow;
2526             }
2527
2528             memcpy_s(dest, destSize, s.GetUTF8NoConvert(), cnt);
2529
2530             return cnt;
2531         }
2532
2533         static FORCEINLINE size_t
2534         raw_deserialize(SString & val, const BYTE* src, size_t srcSize)
2535         {
2536             size_t cnt = strnlen((LPCUTF8)src, srcSize) + 1;
2537
2538             // assert we found a NULL terminated string at "src"
2539             if (srcSize < cnt)
2540             {
2541                 return ErrOverflow;
2542             }
2543
2544             // a literal SString avoids a new allocation + copy
2545             SString sUtf8(SString::Utf8Literal, (LPCUTF8) src);
2546             sUtf8.ConvertToUnicode(val);
2547
2548             return cnt;
2549         }
2550
2551     };
2552
2553 #ifndef FEATURE_PAL
2554     //
2555     // Specialization for SString-derived classes (like SStrings)
2556     //
2557     template<typename T>
2558     class Traits<T, typename std::enable_if<std::is_base_of<SString, T>::value>::type>
2559         : public Traits<SString>
2560     {
2561     };
2562 #endif // !FEATURE_PAL
2563
2564     //
2565     // Convenience functions to allow argument type deduction
2566     //
2567     template <typename T> FORCEINLINE
2568     size_t raw_size(const T & val)
2569     { return Traits<T>::raw_size(val); }
2570
2571     template <typename T> FORCEINLINE
2572     size_t raw_serialize(BYTE* dest, size_t destSize, const T & val)
2573     { return Traits<T>::raw_serialize(dest, destSize, val); }
2574
2575     template <typename T> FORCEINLINE
2576     size_t raw_deserialize(T & val, const BYTE* src, size_t srcSize)
2577     { return Traits<T>::raw_deserialize(val, src, srcSize); }
2578
2579
2580     enum StreamBuffState
2581     {
2582         sbsOK,
2583         sbsUnrecoverable,
2584         sbsOOM = sbsUnrecoverable,
2585     };
2586
2587     //
2588     // OStreamBuff - Manages writing to an output buffer
2589     //
2590     class OStreamBuff
2591     {
2592     public:
2593         OStreamBuff(BYTE * _buff, size_t _buffsize)
2594             : buffsize(_buffsize)
2595             , buff(_buff)
2596             , crt(0)
2597             , sbs(sbsOK)
2598         { }
2599
2600         template <typename T>
2601         OStreamBuff& operator << (const T & val)
2602         {
2603             if (sbs >= sbsUnrecoverable)
2604                 return *this;
2605
2606             size_t cnt = raw_serialize(buff+crt, buffsize-crt, val);
2607             if (cnt == ErrOverflow)
2608             {
2609                 sbs = sbsOOM;
2610             }
2611             else
2612             {
2613                 crt += cnt;
2614             }
2615
2616             return *this;
2617         }
2618
2619         inline size_t GetPos() const
2620         {
2621             return crt;
2622         }
2623
2624         inline BOOL operator!() const
2625         {
2626             return sbs >= sbsUnrecoverable;
2627         }
2628
2629         inline StreamBuffState State() const
2630         {
2631             return sbs;
2632         }
2633
2634     private:
2635         size_t          buffsize; // size of buffer
2636         BYTE*           buff;     // buffer to stream to
2637         size_t          crt;      // current offset in buffer
2638         StreamBuffState sbs;      // current state
2639     };
2640
2641
2642     //
2643     // OStreamBuff - Manages reading from an input buffer
2644     //
2645     class IStreamBuff
2646     {
2647     public:
2648         IStreamBuff(const BYTE* _buff, size_t _buffsize)
2649             : buffsize(_buffsize)
2650             , buff(_buff)
2651             , crt(0)
2652             , sbs(sbsOK)
2653         { }
2654
2655         template <typename T>
2656         IStreamBuff& operator >> (T & val)
2657         {
2658             if (sbs >= sbsUnrecoverable)
2659                 return *this;
2660
2661             size_t cnt = raw_deserialize(val, buff+crt, buffsize-crt);
2662             if (cnt == ErrOverflow)
2663             {
2664                 sbs = sbsOOM;
2665             }
2666             else
2667             {
2668                 crt += cnt;
2669             }
2670
2671             return *this;
2672         }
2673
2674         inline size_t GetPos() const
2675         {
2676             return crt;
2677         }
2678
2679         inline BOOL operator!() const
2680         {
2681             return sbs >= sbsUnrecoverable;
2682         }
2683
2684         inline StreamBuffState State() const
2685         {
2686             return sbs;
2687         }
2688
2689     private:
2690         size_t          buffsize; // size of buffer
2691         const BYTE *    buff;     // buffer to read from
2692         size_t          crt;      // current offset in buffer
2693         StreamBuffState sbs;      // current state
2694     };
2695
2696 } }
2697
2698 using serialization::bin::StreamBuffState;
2699 using serialization::bin::IStreamBuff;
2700 using serialization::bin::OStreamBuff;
2701
2702
2703 // Callback function type used by DacStreamManager to coordinate
2704 // amount of available memory between multiple streamable data
2705 // structures (e.g. DacEENamesStreamable)
2706 typedef bool (*Reserve_Fnptr)(DWORD size, void * writeState);
2707
2708
2709 //
2710 // DacEENamesStreamable
2711 //   Stores EE struct* -> Name mappings and streams them to a
2712 //   streambuf when asked
2713 //
2714 class DacEENamesStreamable
2715 {
2716 private:
2717     // the hash map storing the interesting mappings of EE* -> Names
2718     MapSHash< TADDR, SString,
2719               NoRemoveSHashTraits <
2720                   NonDacAwareSHashTraits< MapSHashTraits <TADDR, SString> >
2721             > > m_hash;
2722
2723     Reserve_Fnptr  m_reserveFn;
2724     void          *m_writeState;
2725
2726 private:
2727     // signature value in the header in stream
2728     static const DWORD sig = 0x614e4545; // "EENa" - EE Name
2729
2730     // header in stream
2731     struct StreamHeader
2732     {
2733         DWORD sig;        // 0x614e4545 == "EENa"
2734         DWORD cnt;        // count of entries
2735
2736         static const bool is_blittable = true;
2737     };
2738
2739 public:
2740     DacEENamesStreamable()
2741         : m_reserveFn(NULL)
2742         , m_writeState(NULL)
2743     {}
2744
2745     // Ensures the instance is ready for caching data and later writing
2746     // its map entries to an OStreamBuff.
2747     bool PrepareStreamForWriting(Reserve_Fnptr pfn, void * writeState)
2748     {
2749         _ASSERTE(pfn != NULL && writeState != NULL);
2750         m_reserveFn = pfn;
2751         m_writeState = writeState;
2752
2753         DWORD size = (DWORD) sizeof(StreamHeader);
2754
2755         // notify owner to reserve space for a StreamHeader
2756         return m_reserveFn(size, m_writeState);
2757     }
2758
2759     // Adds a new mapping from an EE struct pointer (e.g. MethodDesc*) to
2760     // its name
2761     bool AddEEName(TADDR taEE, const SString & eeName)
2762     {
2763         _ASSERTE(m_reserveFn != NULL && m_writeState != NULL);
2764
2765         // as a micro-optimization convert to Utf8 here as both raw_size and
2766         // raw_serialize are optimized for Utf8...
2767         StackSString seeName;
2768         eeName.ConvertToUTF8(seeName);
2769
2770         DWORD size = (DWORD)(serialization::bin::raw_size(taEE) +
2771                              serialization::bin::raw_size(seeName));
2772
2773         // notify owner of the amount of space needed in the buffer
2774         if (m_reserveFn(size, m_writeState))
2775         {
2776             // if there's still space cache the entry in m_hash
2777             m_hash.AddOrReplace(KeyValuePair<TADDR, SString>(taEE, seeName));
2778             return true;
2779         }
2780         else
2781         {
2782             return false;
2783         }
2784     }
2785
2786     // Finds an EE name from a target address of an EE struct (e.g.
2787     // MethodDesc*)
2788     bool FindEEName(TADDR taEE, SString & eeName) const
2789     {
2790         return m_hash.Lookup(taEE, &eeName) == TRUE;
2791     }
2792
2793     void Clear()
2794     {
2795         m_hash.RemoveAll();
2796     }
2797
2798     // Writes a header and the hash entries to an OStreamBuff
2799     HRESULT StreamTo(OStreamBuff &out) const
2800     {
2801         StreamHeader hdr;
2802         hdr.sig = sig;
2803         hdr.cnt = (DWORD) m_hash.GetCount();
2804
2805         out << hdr;
2806
2807         auto end = m_hash.End();
2808         for (auto cur = m_hash.Begin(); end != cur; ++cur)
2809         {
2810             out << cur->Key() << cur->Value();
2811             if (!out)
2812                 return E_FAIL;
2813         }
2814
2815         return S_OK;
2816     }
2817
2818     // Reads a header and the hash entries from an IStreamBuff
2819     HRESULT StreamFrom(IStreamBuff &in)
2820     {
2821         StreamHeader hdr;
2822
2823         in >> hdr; // in >> hdr.sig >> hdr.cnt;
2824
2825         if (hdr.sig != sig)
2826             return E_FAIL;
2827
2828         for (size_t i = 0; i < hdr.cnt; ++i)
2829         {
2830             TADDR taEE;
2831             SString eeName;
2832             in >> taEE >> eeName;
2833
2834             if (!in)
2835                 return E_FAIL;
2836
2837             m_hash.AddOrReplace(KeyValuePair<TADDR, SString>(taEE, eeName));
2838         }
2839
2840         return S_OK;
2841     }
2842
2843 };
2844
2845 //================================================================================
2846 // This class enables two scenarios:
2847 //   1. When debugging a triage/mini-dump the class is initialized with a valid
2848 //      buffer in taMiniMetaDataBuff. Afterwards one can call MdCacheGetEEName to
2849 //      retrieve the name associated with a MethodDesc*.
2850 //   2. When generating a dump one must follow this sequence:
2851 //      a. Initialize the DacStreamManager passing a valid (if the current
2852 //         debugging target is a triage/mini-dump) or empty buffer (if the
2853 //         current target is a live processa full or a heap dump)
2854 //      b. Call PrepareStreamsForWriting() before starting enumerating any memory
2855 //      c. Call MdCacheAddEEName() anytime we enumerate an EE structure of interest
2856 //      d. Call EnumStreams() as the last action in the memory enumeration method.
2857 //
2858 class DacStreamManager
2859 {
2860 public:
2861     enum eReadOrWrite
2862     {
2863         eNone,    // the stream doesn't exist (target is a live process/full/heap dump)
2864         eRO,      // the stream exists and we've read it (target is triage/mini-dump)
2865         eWO,      // the stream doesn't exist but we're creating it
2866                   // (e.g. to save a minidump from the current debugging session)
2867         eRW       // the stream exists but we're generating another triage/mini-dump
2868     };
2869
2870     static const DWORD sig = 0x6d727473;        // 'strm'
2871
2872     struct StreamsHeader
2873     {
2874         DWORD dwSig;        // 0x6d727473 == "strm"
2875         DWORD dwTotalSize;  // total size in bytes
2876         DWORD dwCntStreams; // number of streams (currently 1)
2877
2878         static const bool is_blittable = true;
2879     };
2880
2881     DacStreamManager(TADDR miniMetaDataBuffAddress, DWORD miniMetaDataBuffSizeMax)
2882         : m_MiniMetaDataBuffAddress(miniMetaDataBuffAddress)
2883         , m_MiniMetaDataBuffSizeMax(miniMetaDataBuffSizeMax)
2884         , m_rawBuffer(NULL)
2885         , m_cbAvailBuff(0)
2886         , m_rw(eNone)
2887         , m_bStreamsRead(FALSE)
2888         , m_EENames()
2889     {
2890         Initialize();
2891     }
2892
2893     ~DacStreamManager()
2894     {
2895         if (m_rawBuffer != NULL)
2896         {
2897             delete [] m_rawBuffer;
2898         }
2899     }
2900
2901     bool PrepareStreamsForWriting()
2902     {
2903         if (m_rw == eNone)
2904             m_rw = eWO;
2905         else if (m_rw == eRO)
2906             m_rw = eRW;
2907         else if (m_rw == eRW)
2908             /* nothing */;
2909         else // m_rw == eWO
2910         {
2911             // this is a second invocation from a possibly live process
2912             // clean up the map since the callstacks/exceptions may be different
2913             m_EENames.Clear();
2914         }
2915
2916         // update available count based on the header and footer sizes
2917         if (m_MiniMetaDataBuffSizeMax < sizeof(StreamsHeader))
2918             return false;
2919
2920         m_cbAvailBuff = m_MiniMetaDataBuffSizeMax - sizeof(StreamsHeader);
2921
2922         // update available count based on each stream's initial needs
2923         if (!m_EENames.PrepareStreamForWriting(&ReserveInBuffer, this))
2924             return false;
2925
2926         return true;
2927     }
2928
2929     bool MdCacheAddEEName(TADDR taEEStruct, const SString& name)
2930     {
2931         // don't cache unless we enabled "W"riting from a target that does not
2932         // already have a stream yet
2933         if (m_rw != eWO)
2934             return false;
2935
2936         m_EENames.AddEEName(taEEStruct, name);
2937         return true;
2938     }
2939
2940     HRESULT EnumStreams(IN CLRDataEnumMemoryFlags flags)
2941     {
2942         _ASSERTE(flags == CLRDATA_ENUM_MEM_MINI || flags == CLRDATA_ENUM_MEM_TRIAGE);
2943         _ASSERTE(m_rw == eWO || m_rw == eRW);
2944
2945         DWORD cbWritten = 0;
2946
2947         if (m_rw == eWO)
2948         {
2949             // only dump the stream is it wasn't already present in the target
2950             DumpAllStreams(&cbWritten);
2951         }
2952         else
2953         {
2954             cbWritten = m_MiniMetaDataBuffSizeMax;
2955         }
2956
2957         DacEnumMemoryRegion(m_MiniMetaDataBuffAddress, cbWritten, false);
2958         DacUpdateMemoryRegion(m_MiniMetaDataBuffAddress, cbWritten, m_rawBuffer);
2959
2960         return S_OK;
2961     }
2962
2963     bool MdCacheGetEEName(TADDR taEEStruct, SString & eeName)
2964     {
2965         if (!m_bStreamsRead)
2966         {
2967             ReadAllStreams();
2968         }
2969
2970         if (m_rw == eNone || m_rw == eWO)
2971         {
2972             return false;
2973         }
2974
2975         return m_EENames.FindEEName(taEEStruct, eeName);
2976     }
2977
2978 private:
2979     HRESULT Initialize()
2980     {
2981         _ASSERTE(m_rw == eNone);
2982         _ASSERTE(m_rawBuffer == NULL);
2983
2984         HRESULT hr = S_OK;
2985
2986         StreamsHeader hdr;
2987         DacReadAll(dac_cast<TADDR>(m_MiniMetaDataBuffAddress),
2988                    &hdr, sizeof(hdr), true);
2989
2990         // when the DAC looks at a triage dump or minidump generated using
2991         // a "minimetadata" enabled DAC, buff will point to a serialized
2992         // representation of a methoddesc->method name hashmap.
2993         if (hdr.dwSig == sig)
2994         {
2995             m_rw = eRO;
2996             m_MiniMetaDataBuffSizeMax = hdr.dwTotalSize;
2997             hr = S_OK;
2998         }
2999         else
3000         // when the DAC initializes this for the case where the target is
3001         // (a) a live process, or (b) a full dump, buff will point to a
3002         // zero initialized memory region (allocated w/ VirtualAlloc)
3003         if (hdr.dwSig == 0 && hdr.dwTotalSize == 0 && hdr.dwCntStreams == 0)
3004         {
3005             hr = S_OK;
3006         }
3007         // otherwise we may have some memory corruption. treat this as
3008         // a liveprocess/full dump
3009         else
3010         {
3011             hr = S_FALSE;
3012         }
3013
3014         BYTE * buff = new BYTE[m_MiniMetaDataBuffSizeMax];
3015         DacReadAll(dac_cast<TADDR>(m_MiniMetaDataBuffAddress),
3016                    buff, m_MiniMetaDataBuffSizeMax, true);
3017
3018         m_rawBuffer = buff;
3019
3020         return hr;
3021     }
3022
3023     HRESULT DumpAllStreams(DWORD * pcbWritten)
3024     {
3025         _ASSERTE(m_rw == eWO);
3026
3027         HRESULT hr = S_OK;
3028
3029         OStreamBuff out(m_rawBuffer, m_MiniMetaDataBuffSizeMax);
3030
3031         // write header
3032         StreamsHeader hdr;
3033         hdr.dwSig = sig;
3034         hdr.dwTotalSize = m_MiniMetaDataBuffSizeMax-m_cbAvailBuff; // will update
3035         hdr.dwCntStreams = 1;
3036
3037         out << hdr;
3038
3039         // write MethodDesc->Method name map
3040         hr = m_EENames.StreamTo(out);
3041
3042         // wrap up the buffer whether we ecountered an error or not
3043         size_t cbWritten = out.GetPos();
3044         cbWritten = ALIGN_UP(cbWritten, sizeof(size_t));
3045
3046         // patch the dwTotalSize field blitted at the beginning of the buffer
3047         ((StreamsHeader*)m_rawBuffer)->dwTotalSize = (DWORD) cbWritten;
3048
3049         if (pcbWritten)
3050             *pcbWritten = (DWORD) cbWritten;
3051
3052         return hr;
3053     }
3054
3055     HRESULT ReadAllStreams()
3056     {
3057         _ASSERTE(!m_bStreamsRead);
3058
3059         if (m_rw == eNone || m_rw == eWO)
3060         {
3061             // no streams to read...
3062             m_bStreamsRead = TRUE;
3063             return S_FALSE;
3064         }
3065
3066         HRESULT hr = S_OK;
3067
3068         IStreamBuff in(m_rawBuffer, m_MiniMetaDataBuffSizeMax);
3069
3070         // read header
3071         StreamsHeader hdr;
3072         in >> hdr;
3073         _ASSERTE(hdr.dwSig == sig);
3074         _ASSERTE(hdr.dwCntStreams == 1);
3075
3076         // read EE struct pointer -> EE name map
3077         m_EENames.Clear();
3078         hr = m_EENames.StreamFrom(in);
3079
3080         m_bStreamsRead = TRUE;
3081
3082         return hr;
3083     }
3084
3085     static bool ReserveInBuffer(DWORD size, void * writeState)
3086     {
3087         DacStreamManager * pThis = reinterpret_cast<DacStreamManager*>(writeState);
3088         if (size > pThis->m_cbAvailBuff)
3089         {
3090             return false;
3091         }
3092         else
3093         {
3094             pThis->m_cbAvailBuff -= size;
3095             return true;
3096         }
3097     }
3098
3099 private:
3100     TADDR                 m_MiniMetaDataBuffAddress;    // TADDR of the buffer
3101     DWORD                 m_MiniMetaDataBuffSizeMax;    // max size of buffer
3102     BYTE                * m_rawBuffer;                  // inproc copy of buffer
3103     DWORD                 m_cbAvailBuff;                // available bytes in buffer
3104     eReadOrWrite          m_rw;
3105     BOOL                  m_bStreamsRead;
3106     DacEENamesStreamable  m_EENames;
3107 };
3108
3109 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
3110
3111 //----------------------------------------------------------------------------
3112 //
3113 // ClrDataAccess.
3114 //
3115 //----------------------------------------------------------------------------
3116
3117 LONG ClrDataAccess::s_procInit;
3118
3119 ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLegacyTarget/*=0*/)
3120 {
3121     SUPPORTS_DAC_HOST_ONLY;     // ctor does no marshalling - don't check with DacCop
3122
3123     /*
3124      *  Stash the various forms of the new ICorDebugDataTarget interface
3125      */
3126     m_pTarget = pTarget;
3127     m_pTarget->AddRef();
3128
3129     HRESULT hr;
3130
3131     hr = m_pTarget->QueryInterface(__uuidof(ICorDebugMutableDataTarget),
3132                                 (void**)&m_pMutableTarget);
3133
3134     if (hr != S_OK)
3135     {
3136         // Create a target which always fails the write requests with CORDBG_E_TARGET_READONLY
3137         m_pMutableTarget = new ReadOnlyDataTargetFacade();
3138         m_pMutableTarget->AddRef();
3139     }
3140
3141     /*
3142      * If we have a legacy target, it means we're providing compatibility for code that used
3143      * the old ICLRDataTarget interfaces.  There are still a few things (like metadata location,
3144      * GetImageBase, and VirtualAlloc) that the implementation may use which we haven't superseded
3145      * in ICorDebugDataTarget, so we still need access to the old target interfaces.
3146      * Any functionality that does exist in ICorDebugDataTarget is accessed from that interface
3147      * using the DataTargetAdapter on top of the legacy interface (to unify the calling code).
3148      * Eventually we may expose all functionality we need using ICorDebug (possibly a private
3149      * interface for things like VirtualAlloc), at which point we can stop using the legacy interfaces
3150      * completely (except in the DataTargetAdapter).
3151      */
3152     m_pLegacyTarget = NULL;
3153     m_pLegacyTarget2 = NULL;
3154     m_pLegacyTarget3 = NULL;
3155     m_legacyMetaDataLocator = NULL;
3156     m_target3 = NULL;
3157     if (pLegacyTarget != NULL)
3158     {
3159         m_pLegacyTarget = pLegacyTarget;
3160
3161         m_pLegacyTarget->AddRef();
3162
3163         m_pLegacyTarget->QueryInterface(__uuidof(ICLRDataTarget2), (void**)&m_pLegacyTarget2);
3164
3165         m_pLegacyTarget->QueryInterface(__uuidof(ICLRDataTarget3), (void**)&m_pLegacyTarget3);
3166
3167         if (pLegacyTarget->QueryInterface(__uuidof(ICLRMetadataLocator),
3168                                  (void**)&m_legacyMetaDataLocator) != S_OK)
3169         {
3170             // The debugger doesn't implement IMetadataLocator. Use
3171             // IXCLRDataTarget3 if that exists.  Otherwise we don't need it.
3172             pLegacyTarget->QueryInterface(__uuidof(IXCLRDataTarget3),
3173                                          (void**)&m_target3);
3174         }
3175     }
3176
3177     m_globalBase = 0;
3178     m_refs = 1;
3179     m_instanceAge = 0;
3180     m_debugMode = GetEnvironmentVariableA("MSCORDACWKS_DEBUG", NULL, 0) != 0;
3181
3182     m_enumMemCb = NULL;
3183     m_updateMemCb = NULL;
3184     m_enumMemFlags = (CLRDataEnumMemoryFlags)-1;    // invalid
3185     m_jitNotificationTable = NULL;
3186     m_gcNotificationTable  = NULL;
3187
3188 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
3189     m_streams = NULL;
3190 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
3191
3192     // Target consistency checks are disabled by default.
3193     // See code:ClrDataAccess::SetTargetConsistencyChecks for details.
3194     m_fEnableTargetConsistencyAsserts = false;
3195
3196 #ifdef _DEBUG
3197     if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgDACEnableAssert))
3198     {
3199         m_fEnableTargetConsistencyAsserts = true;
3200     }
3201
3202     // Verification asserts are disabled by default because some debuggers (cdb/windbg) probe likely locations
3203     // for DAC and having this assert pop up all the time can be annoying.  We let derived classes enable
3204     // this if they want.  It can also be overridden at run-time with COMPlus_DbgDACAssertOnMismatch,
3205     // see ClrDataAccess::VerifyDlls for details.
3206     m_fEnableDllVerificationAsserts = false;
3207 #endif
3208
3209 }
3210
3211 ClrDataAccess::~ClrDataAccess(void)
3212 {
3213     SUPPORTS_DAC_HOST_ONLY;
3214
3215 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
3216     if (m_streams)
3217     {
3218         delete m_streams;
3219     }
3220 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
3221
3222     delete [] m_jitNotificationTable;
3223     if (m_pLegacyTarget)
3224     {
3225         m_pLegacyTarget->Release();
3226     }
3227     if (m_pLegacyTarget2)
3228     {
3229         m_pLegacyTarget2->Release();
3230     }
3231     if (m_pLegacyTarget3)
3232     {
3233         m_pLegacyTarget3->Release();
3234     }
3235     if (m_legacyMetaDataLocator)
3236     {
3237         m_legacyMetaDataLocator->Release();
3238     }
3239     if (m_target3)
3240     {
3241         m_target3->Release();
3242     }
3243     m_pTarget->Release();
3244     m_pMutableTarget->Release();
3245 }
3246
3247 STDMETHODIMP
3248 ClrDataAccess::QueryInterface(THIS_
3249                               IN REFIID interfaceId,
3250                               OUT PVOID* iface)
3251 {
3252     void* ifaceRet;
3253
3254     if (IsEqualIID(interfaceId, IID_IUnknown) ||
3255         IsEqualIID(interfaceId, __uuidof(IXCLRDataProcess)) ||
3256         IsEqualIID(interfaceId, __uuidof(IXCLRDataProcess2)))
3257     {
3258         ifaceRet = static_cast<IXCLRDataProcess2*>(this);
3259     }
3260     else if (IsEqualIID(interfaceId, __uuidof(ICLRDataEnumMemoryRegions)))
3261     {
3262         ifaceRet = static_cast<ICLRDataEnumMemoryRegions*>(this);
3263     }
3264     else if (IsEqualIID(interfaceId, __uuidof(ISOSDacInterface)))
3265     {
3266         ifaceRet = static_cast<ISOSDacInterface*>(this);
3267     }
3268     else if (IsEqualIID(interfaceId, __uuidof(ISOSDacInterface2)))
3269     {
3270         ifaceRet = static_cast<ISOSDacInterface2*>(this);
3271     }
3272     else if (IsEqualIID(interfaceId, __uuidof(ISOSDacInterface3)))
3273     {
3274         ifaceRet = static_cast<ISOSDacInterface3*>(this);
3275     }
3276     else if (IsEqualIID(interfaceId, __uuidof(ISOSDacInterface4)))
3277     {
3278         ifaceRet = static_cast<ISOSDacInterface4*>(this);
3279     }
3280     else if (IsEqualIID(interfaceId, __uuidof(ISOSDacInterface5)))
3281     {
3282         ifaceRet = static_cast<ISOSDacInterface5*>(this);
3283     }
3284     else if (IsEqualIID(interfaceId, __uuidof(ISOSDacInterface6)))
3285     {
3286         ifaceRet = static_cast<ISOSDacInterface6*>(this);
3287     }
3288     else
3289     {
3290         *iface = NULL;
3291         return E_NOINTERFACE;
3292     }
3293
3294     AddRef();
3295     *iface = ifaceRet;
3296     return S_OK;
3297 }
3298
3299 STDMETHODIMP_(ULONG)
3300 ClrDataAccess::AddRef(THIS)
3301 {
3302     return InterlockedIncrement(&m_refs);
3303 }
3304
3305 STDMETHODIMP_(ULONG)
3306 ClrDataAccess::Release(THIS)
3307 {
3308     SUPPORTS_DAC_HOST_ONLY;
3309     LONG newRefs = InterlockedDecrement(&m_refs);
3310     if (newRefs == 0)
3311     {
3312         delete this;
3313     }
3314     return newRefs;
3315 }
3316
3317 HRESULT STDMETHODCALLTYPE
3318 ClrDataAccess::Flush(void)
3319 {
3320     SUPPORTS_DAC_HOST_ONLY;
3321
3322     //
3323     // Free MD import objects.
3324     //
3325     m_mdImports.Flush();
3326
3327     // Free instance memory.
3328     m_instances.Flush();
3329
3330     // When the host instance cache is flushed we
3331     // update the instance age count so that
3332     // all child objects automatically become
3333     // invalid.  This prevents them from using
3334     // any pointers they've kept to host instances
3335     // which are now gone.
3336     m_instanceAge++;
3337
3338     return S_OK;
3339 }
3340
3341 HRESULT STDMETHODCALLTYPE
3342 ClrDataAccess::StartEnumTasks(
3343     /* [out] */ CLRDATA_ENUM* handle)
3344 {
3345     HRESULT status;
3346
3347     DAC_ENTER();
3348
3349     EX_TRY
3350     {
3351         if (ThreadStore::s_pThreadStore)
3352         {
3353             Thread* thread = ThreadStore::GetAllThreadList(NULL, 0, 0);
3354             *handle = TO_CDENUM(thread);
3355             status = *handle ? S_OK : S_FALSE;
3356         }
3357         else
3358         {
3359             status = S_FALSE;
3360         }
3361     }
3362     EX_CATCH
3363     {
3364         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3365         {
3366             EX_RETHROW;
3367         }
3368     }
3369     EX_END_CATCH(SwallowAllExceptions)
3370
3371     DAC_LEAVE();
3372     return status;
3373 }
3374
3375 HRESULT STDMETHODCALLTYPE
3376 ClrDataAccess::EnumTask(
3377     /* [in, out] */ CLRDATA_ENUM* handle,
3378     /* [out] */ IXCLRDataTask **task)
3379 {
3380     HRESULT status;
3381
3382     DAC_ENTER();
3383
3384     EX_TRY
3385     {
3386         if (*handle)
3387         {
3388             Thread* thread = FROM_CDENUM(Thread, *handle);
3389             *task = new (nothrow) ClrDataTask(this, thread);
3390             if (*task)
3391             {
3392                 thread = ThreadStore::GetAllThreadList(thread, 0, 0);
3393                 *handle = TO_CDENUM(thread);
3394                 status = S_OK;
3395             }
3396             else
3397             {
3398                 status = E_OUTOFMEMORY;
3399             }
3400         }
3401         else
3402         {
3403             status = S_FALSE;
3404         }
3405     }
3406     EX_CATCH
3407     {
3408         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3409         {
3410             EX_RETHROW;
3411         }
3412     }
3413     EX_END_CATCH(SwallowAllExceptions)
3414
3415     DAC_LEAVE();
3416     return status;
3417 }
3418
3419 HRESULT STDMETHODCALLTYPE
3420 ClrDataAccess::EndEnumTasks(
3421     /* [in] */ CLRDATA_ENUM handle)
3422 {
3423     HRESULT status;
3424
3425     DAC_ENTER();
3426
3427     EX_TRY
3428     {
3429         // Enumerator holds no resources.
3430         status = S_OK;
3431     }
3432     EX_CATCH
3433     {
3434         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3435         {
3436             EX_RETHROW;
3437         }
3438     }
3439     EX_END_CATCH(SwallowAllExceptions)
3440
3441     DAC_LEAVE();
3442     return status;
3443 }
3444
3445 HRESULT STDMETHODCALLTYPE
3446 ClrDataAccess::GetTaskByOSThreadID(
3447     /* [in] */ ULONG32 osThreadID,
3448     /* [out] */ IXCLRDataTask **task)
3449 {
3450     HRESULT status;
3451
3452     DAC_ENTER();
3453
3454     EX_TRY
3455     {
3456         status = E_INVALIDARG;
3457         Thread* thread = DacGetThread(osThreadID);
3458         if (thread != NULL)
3459         {
3460             *task = new (nothrow) ClrDataTask(this, thread);
3461             status = *task ? S_OK : E_OUTOFMEMORY;
3462         }
3463     }
3464     EX_CATCH
3465     {
3466         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3467         {
3468             EX_RETHROW;
3469         }
3470     }
3471     EX_END_CATCH(SwallowAllExceptions)
3472
3473     DAC_LEAVE();
3474     return status;
3475 }
3476
3477 HRESULT STDMETHODCALLTYPE
3478 ClrDataAccess::GetTaskByUniqueID(
3479     /* [in] */ ULONG64 uniqueID,
3480     /* [out] */ IXCLRDataTask **task)
3481 {
3482     HRESULT status;
3483
3484     DAC_ENTER();
3485
3486     EX_TRY
3487     {
3488         Thread* thread = FindClrThreadByTaskId(uniqueID);
3489         if (thread)
3490         {
3491             *task = new (nothrow) ClrDataTask(this, thread);
3492             status = *task ? S_OK : E_OUTOFMEMORY;
3493         }
3494         else
3495         {
3496             status = E_INVALIDARG;
3497         }
3498     }
3499     EX_CATCH
3500     {
3501         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3502         {
3503             EX_RETHROW;
3504         }
3505     }
3506     EX_END_CATCH(SwallowAllExceptions)
3507
3508     DAC_LEAVE();
3509     return status;
3510 }
3511
3512 HRESULT STDMETHODCALLTYPE
3513 ClrDataAccess::GetFlags(
3514     /* [out] */ ULONG32 *flags)
3515 {
3516     HRESULT status;
3517
3518     DAC_ENTER();
3519
3520     EX_TRY
3521     {
3522         // XXX Microsoft - GC check.
3523         *flags = CLRDATA_PROCESS_DEFAULT;
3524         status = S_OK;
3525     }
3526     EX_CATCH
3527     {
3528         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3529         {
3530             EX_RETHROW;
3531         }
3532     }
3533     EX_END_CATCH(SwallowAllExceptions)
3534
3535     DAC_LEAVE();
3536     return status;
3537 }
3538
3539 HRESULT STDMETHODCALLTYPE
3540 ClrDataAccess::IsSameObject(
3541     /* [in] */ IXCLRDataProcess* process)
3542 {
3543     HRESULT status;
3544
3545     DAC_ENTER();
3546
3547     EX_TRY
3548     {
3549         status = m_pTarget == ((ClrDataAccess*)process)->m_pTarget ?
3550             S_OK : S_FALSE;
3551     }
3552     EX_CATCH
3553     {
3554         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3555         {
3556             EX_RETHROW;
3557         }
3558     }
3559     EX_END_CATCH(SwallowAllExceptions)
3560
3561     DAC_LEAVE();
3562     return status;
3563 }
3564
3565 HRESULT STDMETHODCALLTYPE
3566 ClrDataAccess::GetManagedObject(
3567     /* [out] */ IXCLRDataValue **value)
3568 {
3569     HRESULT status;
3570
3571     DAC_ENTER();
3572
3573     EX_TRY
3574     {
3575         // XXX Microsoft.
3576         status = E_NOTIMPL;
3577     }
3578     EX_CATCH
3579     {
3580         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3581         {
3582             EX_RETHROW;
3583         }
3584     }
3585     EX_END_CATCH(SwallowAllExceptions)
3586
3587     DAC_LEAVE();
3588     return status;
3589 }
3590
3591 HRESULT STDMETHODCALLTYPE
3592 ClrDataAccess::GetDesiredExecutionState(
3593     /* [out] */ ULONG32 *state)
3594 {
3595     HRESULT status;
3596
3597     DAC_ENTER();
3598
3599     EX_TRY
3600     {
3601         // XXX Microsoft.
3602         status = E_NOTIMPL;
3603     }
3604     EX_CATCH
3605     {
3606         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3607         {
3608             EX_RETHROW;
3609         }
3610     }
3611     EX_END_CATCH(SwallowAllExceptions)
3612
3613     DAC_LEAVE();
3614     return status;
3615 }
3616
3617 HRESULT STDMETHODCALLTYPE
3618 ClrDataAccess::SetDesiredExecutionState(
3619     /* [in] */ ULONG32 state)
3620 {
3621     HRESULT status;
3622
3623     DAC_ENTER();
3624
3625     EX_TRY
3626     {
3627         // XXX Microsoft.
3628         status = E_NOTIMPL;
3629     }
3630     EX_CATCH
3631     {
3632         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3633         {
3634             EX_RETHROW;
3635         }
3636     }
3637     EX_END_CATCH(SwallowAllExceptions)
3638
3639     DAC_LEAVE();
3640     return status;
3641 }
3642
3643 HRESULT STDMETHODCALLTYPE
3644 ClrDataAccess::GetAddressType(
3645     /* [in] */ CLRDATA_ADDRESS address,
3646     /* [out] */ CLRDataAddressType* type)
3647 {
3648     HRESULT status;
3649
3650     DAC_ENTER();
3651
3652     EX_TRY
3653     {
3654         // The only thing that constitutes a failure is some
3655         // dac failure while checking things.
3656         status = S_OK;
3657         TADDR taAddr = CLRDATA_ADDRESS_TO_TADDR(address);
3658         if (IsPossibleCodeAddress(taAddr) == S_OK)
3659         {
3660             if (ExecutionManager::IsManagedCode(taAddr))
3661             {
3662                 *type = CLRDATA_ADDRESS_MANAGED_METHOD;
3663                 goto Exit;
3664             }
3665
3666             if (StubManager::IsStub(taAddr))
3667             {
3668                 *type = CLRDATA_ADDRESS_RUNTIME_UNMANAGED_STUB;
3669                 goto Exit;
3670             }
3671         }
3672
3673         *type = CLRDATA_ADDRESS_UNRECOGNIZED;
3674
3675     Exit: ;
3676     }
3677     EX_CATCH
3678     {
3679         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3680         {
3681             EX_RETHROW;
3682         }
3683     }
3684     EX_END_CATCH(SwallowAllExceptions)
3685
3686     DAC_LEAVE();
3687     return status;
3688 }
3689
3690 HRESULT STDMETHODCALLTYPE
3691 ClrDataAccess::GetRuntimeNameByAddress(
3692     /* [in] */ CLRDATA_ADDRESS address,
3693     /* [in] */ ULONG32 flags,
3694     /* [in] */ ULONG32 bufLen,
3695     /* [out] */ ULONG32 *symbolLen,
3696     /* [size_is][out] */ __out_ecount_opt(bufLen) WCHAR symbolBuf[  ],
3697     /* [out] */ CLRDATA_ADDRESS* displacement)
3698 {
3699     HRESULT status;
3700
3701     DAC_ENTER();
3702
3703     EX_TRY
3704     {
3705 #ifdef _TARGET_ARM_
3706         address &= ~THUMB_CODE; //workaround for windbg passing in addresses with the THUMB mode bit set
3707 #endif
3708         status = RawGetMethodName(address, flags, bufLen, symbolLen, symbolBuf,
3709                                   displacement);
3710     }
3711     EX_CATCH
3712     {
3713         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3714         {
3715             EX_RETHROW;
3716         }
3717     }
3718     EX_END_CATCH(SwallowAllExceptions)
3719
3720     DAC_LEAVE();
3721     return status;
3722 }
3723
3724 HRESULT STDMETHODCALLTYPE
3725 ClrDataAccess::StartEnumAppDomains(
3726     /* [out] */ CLRDATA_ENUM* handle)
3727 {
3728     HRESULT status;
3729
3730     DAC_ENTER();
3731
3732     EX_TRY
3733     {
3734         AppDomainIterator* iter = new (nothrow) AppDomainIterator(FALSE);
3735         if (iter)
3736         {
3737             *handle = TO_CDENUM(iter);
3738             status = S_OK;
3739         }
3740         else
3741         {
3742             status = E_OUTOFMEMORY;
3743         }
3744     }
3745     EX_CATCH
3746     {
3747         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3748         {
3749             EX_RETHROW;
3750         }
3751     }
3752     EX_END_CATCH(SwallowAllExceptions)
3753
3754     DAC_LEAVE();
3755     return status;
3756 }
3757
3758 HRESULT STDMETHODCALLTYPE
3759 ClrDataAccess::EnumAppDomain(
3760     /* [in, out] */ CLRDATA_ENUM* handle,
3761     /* [out] */ IXCLRDataAppDomain **appDomain)
3762 {
3763     HRESULT status;
3764
3765     DAC_ENTER();
3766
3767     EX_TRY
3768     {
3769         AppDomainIterator* iter = FROM_CDENUM(AppDomainIterator, *handle);
3770         if (iter->Next())
3771         {
3772             *appDomain = new (nothrow)
3773                 ClrDataAppDomain(this, iter->GetDomain());
3774             status = *appDomain ? S_OK : E_OUTOFMEMORY;
3775         }
3776         else
3777         {
3778             status = S_FALSE;
3779         }
3780     }
3781     EX_CATCH
3782     {
3783         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3784         {
3785             EX_RETHROW;
3786         }
3787     }
3788     EX_END_CATCH(SwallowAllExceptions)
3789
3790     DAC_LEAVE();
3791     return status;
3792 }
3793
3794 HRESULT STDMETHODCALLTYPE
3795 ClrDataAccess::EndEnumAppDomains(
3796     /* [in] */ CLRDATA_ENUM handle)
3797 {
3798     HRESULT status;
3799
3800     DAC_ENTER();
3801
3802     EX_TRY
3803     {
3804         AppDomainIterator* iter = FROM_CDENUM(AppDomainIterator, handle);
3805         delete iter;
3806         status = S_OK;
3807     }
3808     EX_CATCH
3809     {
3810         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3811         {
3812             EX_RETHROW;
3813         }
3814     }
3815     EX_END_CATCH(SwallowAllExceptions)
3816
3817     DAC_LEAVE();
3818     return status;
3819 }
3820
3821 HRESULT STDMETHODCALLTYPE
3822 ClrDataAccess::GetAppDomainByUniqueID(
3823     /* [in] */ ULONG64 uniqueID,
3824     /* [out] */ IXCLRDataAppDomain **appDomain)
3825 {
3826     HRESULT status;
3827
3828     DAC_ENTER();
3829
3830     EX_TRY
3831     {
3832         if (uniqueID != DefaultADID)
3833         {
3834             status = E_INVALIDARG;
3835         }
3836         else
3837         {
3838             *appDomain = new (nothrow)
3839                 ClrDataAppDomain(this, AppDomain::GetCurrentDomain());
3840             status = *appDomain ? S_OK : E_OUTOFMEMORY;
3841         }
3842     }
3843     EX_CATCH
3844     {
3845         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3846         {
3847             EX_RETHROW;
3848         }
3849     }
3850     EX_END_CATCH(SwallowAllExceptions)
3851
3852     DAC_LEAVE();
3853     return status;
3854 }
3855
3856 HRESULT STDMETHODCALLTYPE
3857 ClrDataAccess::StartEnumAssemblies(
3858     /* [out] */ CLRDATA_ENUM* handle)
3859 {
3860     HRESULT status;
3861
3862     DAC_ENTER();
3863
3864     EX_TRY
3865     {
3866         ProcessModIter* iter = new (nothrow) ProcessModIter;
3867         if (iter)
3868         {
3869             *handle = TO_CDENUM(iter);
3870             status = S_OK;
3871         }
3872         else
3873         {
3874             status = E_OUTOFMEMORY;
3875         }
3876     }
3877     EX_CATCH
3878     {
3879         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3880         {
3881             EX_RETHROW;
3882         }
3883     }
3884     EX_END_CATCH(SwallowAllExceptions)
3885
3886     DAC_LEAVE();
3887     return status;
3888 }
3889
3890 HRESULT STDMETHODCALLTYPE
3891 ClrDataAccess::EnumAssembly(
3892     /* [in, out] */ CLRDATA_ENUM* handle,
3893     /* [out] */ IXCLRDataAssembly **assembly)
3894 {
3895     HRESULT status;
3896
3897     DAC_ENTER();
3898
3899     EX_TRY
3900     {
3901         ProcessModIter* iter = FROM_CDENUM(ProcessModIter, *handle);
3902         Assembly* assem;
3903
3904         if ((assem = iter->NextAssem()))
3905         {
3906             *assembly = new (nothrow)
3907                 ClrDataAssembly(this, assem);
3908             status = *assembly ? S_OK : E_OUTOFMEMORY;
3909         }
3910         else
3911         {
3912             status = S_FALSE;
3913         }
3914     }
3915     EX_CATCH
3916     {
3917         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3918         {
3919             EX_RETHROW;
3920         }
3921     }
3922     EX_END_CATCH(SwallowAllExceptions)
3923
3924     DAC_LEAVE();
3925     return status;
3926 }
3927
3928 HRESULT STDMETHODCALLTYPE
3929 ClrDataAccess::EndEnumAssemblies(
3930     /* [in] */ CLRDATA_ENUM handle)
3931 {
3932     HRESULT status;
3933
3934     DAC_ENTER();
3935
3936     EX_TRY
3937     {
3938         ProcessModIter* iter = FROM_CDENUM(ProcessModIter, handle);
3939         delete iter;
3940         status = S_OK;
3941     }
3942     EX_CATCH
3943     {
3944         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3945         {
3946             EX_RETHROW;
3947         }
3948     }
3949     EX_END_CATCH(SwallowAllExceptions)
3950
3951     DAC_LEAVE();
3952     return status;
3953 }
3954
3955 HRESULT STDMETHODCALLTYPE
3956 ClrDataAccess::StartEnumModules(
3957     /* [out] */ CLRDATA_ENUM* handle)
3958 {
3959     HRESULT status;
3960
3961     DAC_ENTER();
3962
3963     EX_TRY
3964     {
3965         ProcessModIter* iter = new (nothrow) ProcessModIter;
3966         if (iter)
3967         {
3968             *handle = TO_CDENUM(iter);
3969             status = S_OK;
3970         }
3971         else
3972         {
3973             status = E_OUTOFMEMORY;
3974         }
3975     }
3976     EX_CATCH
3977     {
3978         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
3979         {
3980             EX_RETHROW;
3981         }
3982     }
3983     EX_END_CATCH(SwallowAllExceptions)
3984
3985     DAC_LEAVE();
3986     return status;
3987 }
3988
3989 HRESULT STDMETHODCALLTYPE
3990 ClrDataAccess::EnumModule(
3991     /* [in, out] */ CLRDATA_ENUM* handle,
3992     /* [out] */ IXCLRDataModule **mod)
3993 {
3994     HRESULT status;
3995
3996     DAC_ENTER();
3997
3998     EX_TRY
3999     {
4000         ProcessModIter* iter = FROM_CDENUM(ProcessModIter, *handle);
4001         Module* curMod;
4002
4003         if ((curMod = iter->NextModule()))
4004         {
4005             *mod = new (nothrow)
4006                 ClrDataModule(this, curMod);
4007             status = *mod ? S_OK : E_OUTOFMEMORY;
4008         }
4009         else
4010         {
4011             status = S_FALSE;
4012         }
4013     }
4014     EX_CATCH
4015     {
4016         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4017         {
4018             EX_RETHROW;
4019         }
4020     }
4021     EX_END_CATCH(SwallowAllExceptions)
4022
4023     DAC_LEAVE();
4024     return status;
4025 }
4026
4027 HRESULT STDMETHODCALLTYPE
4028 ClrDataAccess::EndEnumModules(
4029     /* [in] */ CLRDATA_ENUM handle)
4030 {
4031     HRESULT status;
4032
4033     DAC_ENTER();
4034
4035     EX_TRY
4036     {
4037         ProcessModIter* iter = FROM_CDENUM(ProcessModIter, handle);
4038         delete iter;
4039         status = S_OK;
4040     }
4041     EX_CATCH
4042     {
4043         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4044         {
4045             EX_RETHROW;
4046         }
4047     }
4048     EX_END_CATCH(SwallowAllExceptions)
4049
4050     DAC_LEAVE();
4051     return status;
4052 }
4053
4054 HRESULT STDMETHODCALLTYPE
4055 ClrDataAccess::GetModuleByAddress(
4056     /* [in] */ CLRDATA_ADDRESS address,
4057     /* [out] */ IXCLRDataModule** mod)
4058 {
4059     HRESULT status;
4060
4061     DAC_ENTER();
4062
4063     EX_TRY
4064     {
4065         ProcessModIter modIter;
4066         Module* modDef;
4067
4068         while ((modDef = modIter.NextModule()))
4069         {
4070             TADDR base;
4071             ULONG32 length;
4072             PEFile* file = modDef->GetFile();
4073
4074             if ((base = PTR_TO_TADDR(file->GetLoadedImageContents(&length))))
4075             {
4076                 if (TO_CDADDR(base) <= address &&
4077                     TO_CDADDR(base + length) > address)
4078                 {
4079                     break;
4080                 }
4081             }
4082             if (file->HasNativeImage())
4083             {
4084                 base = PTR_TO_TADDR(file->GetLoadedNative()->GetBase());
4085                 length = file->GetLoadedNative()->GetVirtualSize();
4086                 if (TO_CDADDR(base) <= address &&
4087                     TO_CDADDR(base + length) > address)
4088                 {
4089                     break;
4090                 }
4091             }
4092         }
4093
4094         if (modDef)
4095         {
4096             *mod = new (nothrow)
4097                 ClrDataModule(this, modDef);
4098             status = *mod ? S_OK : E_OUTOFMEMORY;
4099         }
4100         else
4101         {
4102             status = S_FALSE;
4103         }
4104     }
4105     EX_CATCH
4106     {
4107         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4108         {
4109             EX_RETHROW;
4110         }
4111     }
4112     EX_END_CATCH(SwallowAllExceptions)
4113
4114     DAC_LEAVE();
4115     return status;
4116 }
4117
4118 HRESULT STDMETHODCALLTYPE
4119 ClrDataAccess::StartEnumMethodDefinitionsByAddress(
4120     /* [in] */ CLRDATA_ADDRESS address,
4121     /* [out] */ CLRDATA_ENUM *handle)
4122 {
4123     HRESULT status;
4124
4125     DAC_ENTER();
4126
4127     EX_TRY
4128     {
4129         ProcessModIter modIter;
4130         Module* modDef;
4131
4132         while ((modDef = modIter.NextModule()))
4133         {
4134             TADDR base;
4135             ULONG32 length;
4136             PEFile* file = modDef->GetFile();
4137
4138             if ((base = PTR_TO_TADDR(file->GetLoadedImageContents(&length))))
4139             {
4140                 if (TO_CDADDR(base) <= address &&
4141                     TO_CDADDR(base + length) > address)
4142                 {
4143                     break;
4144                 }
4145             }
4146         }
4147
4148         status = EnumMethodDefinitions::
4149             CdStart(modDef, true, address, handle);
4150     }
4151     EX_CATCH
4152     {
4153         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4154         {
4155             EX_RETHROW;
4156         }
4157     }
4158     EX_END_CATCH(SwallowAllExceptions)
4159
4160     DAC_LEAVE();
4161     return status;
4162 }
4163
4164 HRESULT STDMETHODCALLTYPE
4165 ClrDataAccess::EnumMethodDefinitionByAddress(
4166     /* [out][in] */ CLRDATA_ENUM* handle,
4167     /* [out] */ IXCLRDataMethodDefinition **method)
4168 {
4169     HRESULT status;
4170
4171     DAC_ENTER();
4172
4173     EX_TRY
4174     {
4175         status = EnumMethodDefinitions::CdNext(this, handle, method);
4176     }
4177     EX_CATCH
4178     {
4179         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4180         {
4181             EX_RETHROW;
4182         }
4183     }
4184     EX_END_CATCH(SwallowAllExceptions)
4185
4186     DAC_LEAVE();
4187     return status;
4188 }
4189
4190 HRESULT STDMETHODCALLTYPE
4191 ClrDataAccess::EndEnumMethodDefinitionsByAddress(
4192     /* [in] */ CLRDATA_ENUM handle)
4193 {
4194     HRESULT status;
4195
4196     DAC_ENTER();
4197
4198     EX_TRY
4199     {
4200         status = EnumMethodDefinitions::CdEnd(handle);
4201     }
4202     EX_CATCH
4203     {
4204         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4205         {
4206             EX_RETHROW;
4207         }
4208     }
4209     EX_END_CATCH(SwallowAllExceptions)
4210
4211     DAC_LEAVE();
4212     return status;
4213 }
4214
4215 HRESULT STDMETHODCALLTYPE
4216 ClrDataAccess::StartEnumMethodInstancesByAddress(
4217     /* [in] */ CLRDATA_ADDRESS address,
4218     /* [in] */ IXCLRDataAppDomain* appDomain,
4219     /* [out] */ CLRDATA_ENUM *handle)
4220 {
4221     HRESULT status;
4222
4223     DAC_ENTER();
4224
4225     EX_TRY
4226     {
4227         MethodDesc* methodDesc;
4228
4229         *handle = 0;
4230         status = S_FALSE;
4231         TADDR taddr;
4232         if( (status = TRY_CLRDATA_ADDRESS_TO_TADDR(address, &taddr)) != S_OK )
4233         {
4234             goto Exit;
4235         }
4236
4237         if (IsPossibleCodeAddress(taddr) != S_OK)
4238         {
4239             goto Exit;
4240         }
4241
4242         methodDesc = ExecutionManager::GetCodeMethodDesc(taddr);
4243         if (!methodDesc)
4244         {
4245             goto Exit;
4246         }
4247
4248         status = EnumMethodInstances::CdStart(methodDesc, appDomain,
4249                                               handle);
4250
4251     Exit: ;
4252     }
4253     EX_CATCH
4254     {
4255         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4256         {
4257             EX_RETHROW;
4258         }
4259     }
4260     EX_END_CATCH(SwallowAllExceptions)
4261
4262     DAC_LEAVE();
4263     return status;
4264 }
4265
4266 HRESULT STDMETHODCALLTYPE
4267 ClrDataAccess::EnumMethodInstanceByAddress(
4268     /* [out][in] */ CLRDATA_ENUM* handle,
4269     /* [out] */ IXCLRDataMethodInstance **method)
4270 {
4271     HRESULT status;
4272
4273     DAC_ENTER();
4274
4275     EX_TRY
4276     {
4277         status = EnumMethodInstances::CdNext(this, handle, method);
4278     }
4279     EX_CATCH
4280     {
4281         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4282         {
4283             EX_RETHROW;
4284         }
4285     }
4286     EX_END_CATCH(SwallowAllExceptions)
4287
4288     DAC_LEAVE();
4289     return status;
4290 }
4291
4292 HRESULT STDMETHODCALLTYPE
4293 ClrDataAccess::EndEnumMethodInstancesByAddress(
4294     /* [in] */ CLRDATA_ENUM handle)
4295 {
4296     HRESULT status;
4297
4298     DAC_ENTER();
4299
4300     EX_TRY
4301     {
4302         status = EnumMethodInstances::CdEnd(handle);
4303     }
4304     EX_CATCH
4305     {
4306         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4307         {
4308             EX_RETHROW;
4309         }
4310     }
4311     EX_END_CATCH(SwallowAllExceptions)
4312
4313     DAC_LEAVE();
4314     return status;
4315 }
4316
4317 HRESULT STDMETHODCALLTYPE
4318 ClrDataAccess::GetDataByAddress(
4319     /* [in] */ CLRDATA_ADDRESS address,
4320     /* [in] */ ULONG32 flags,
4321     /* [in] */ IXCLRDataAppDomain* appDomain,
4322     /* [in] */ IXCLRDataTask* tlsTask,
4323     /* [in] */ ULONG32 bufLen,
4324     /* [out] */ ULONG32 *nameLen,
4325     /* [size_is][out] */ __out_ecount_part_opt(bufLen, *nameLen) WCHAR nameBuf[  ],
4326     /* [out] */ IXCLRDataValue **value,
4327     /* [out] */ CLRDATA_ADDRESS *displacement)
4328 {
4329     HRESULT status;
4330
4331     if (flags != 0)
4332     {
4333         return E_INVALIDARG;
4334     }
4335
4336     DAC_ENTER();
4337
4338     EX_TRY
4339     {
4340         // XXX Microsoft.
4341         status = E_NOTIMPL;
4342     }
4343     EX_CATCH
4344     {
4345         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4346         {
4347             EX_RETHROW;
4348         }
4349     }
4350     EX_END_CATCH(SwallowAllExceptions)
4351
4352     DAC_LEAVE();
4353     return status;
4354 }
4355
4356 HRESULT STDMETHODCALLTYPE
4357 ClrDataAccess::GetExceptionStateByExceptionRecord(
4358     /* [in] */ EXCEPTION_RECORD64 *record,
4359     /* [out] */ IXCLRDataExceptionState **exception)
4360 {
4361     HRESULT status;
4362
4363     DAC_ENTER();
4364
4365     EX_TRY
4366     {
4367         // XXX Microsoft.
4368         status = E_NOTIMPL;
4369     }
4370     EX_CATCH
4371     {
4372         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4373         {
4374             EX_RETHROW;
4375         }
4376     }
4377     EX_END_CATCH(SwallowAllExceptions)
4378
4379     DAC_LEAVE();
4380     return status;
4381 }
4382
4383 HRESULT STDMETHODCALLTYPE
4384 ClrDataAccess::TranslateExceptionRecordToNotification(
4385     /* [in] */ EXCEPTION_RECORD64 *record,
4386     /* [in] */ IXCLRDataExceptionNotification *notify)
4387 {
4388     HRESULT status = E_FAIL;
4389     ClrDataModule* pubModule = NULL;
4390     ClrDataMethodInstance* pubMethodInst = NULL;
4391     ClrDataExceptionState* pubExState = NULL;
4392     GcEvtArgs pubGcEvtArgs;
4393     ULONG32 notifyType = 0;
4394     DWORD catcherNativeOffset = 0;
4395     TADDR nativeCodeLocation = NULL;
4396
4397     DAC_ENTER();
4398
4399     EX_TRY
4400     {
4401         //
4402         // We cannot hold the dac lock while calling
4403         // out as the external code can do arbitrary things.
4404         // Instead we make a pass over the exception
4405         // information and create all necessary objects.
4406         // We then leave the lock and make the callbac.
4407         //
4408
4409         TADDR exInfo[EXCEPTION_MAXIMUM_PARAMETERS];
4410         for (UINT i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
4411         {
4412             exInfo[i] = TO_TADDR(record->ExceptionInformation[i]);
4413         }
4414
4415         notifyType = DACNotify::GetType(exInfo);
4416         switch(notifyType)
4417         {
4418         case DACNotify::MODULE_LOAD_NOTIFICATION:
4419         {
4420             TADDR modulePtr;
4421
4422             if (DACNotify::ParseModuleLoadNotification(exInfo, modulePtr))
4423             {
4424                 Module* clrModule = PTR_Module(modulePtr);
4425                 pubModule = new (nothrow) ClrDataModule(this, clrModule);
4426                 if (pubModule == NULL)
4427                 {
4428                     status = E_OUTOFMEMORY;
4429                 }
4430                 else
4431                 {
4432                     status = S_OK;
4433                 }
4434             }
4435             break;
4436         }
4437
4438         case DACNotify::MODULE_UNLOAD_NOTIFICATION:
4439         {
4440             TADDR modulePtr;
4441
4442             if (DACNotify::ParseModuleUnloadNotification(exInfo, modulePtr))
4443             {
4444                 Module* clrModule = PTR_Module(modulePtr);
4445                 pubModule = new (nothrow) ClrDataModule(this, clrModule);
4446                 if (pubModule == NULL)
4447                 {
4448                     status = E_OUTOFMEMORY;
4449                 }
4450                 else
4451                 {
4452                     status = S_OK;
4453                 }
4454             }
4455             break;
4456         }
4457
4458         case DACNotify::JIT_NOTIFICATION2:
4459         {
4460             TADDR methodDescPtr;
4461
4462             if(DACNotify::ParseJITNotification(exInfo, methodDescPtr, nativeCodeLocation))
4463             {
4464                 // Try and find the right appdomain
4465                 MethodDesc* methodDesc = PTR_MethodDesc(methodDescPtr);
4466                 BaseDomain* baseDomain = methodDesc->GetDomain();
4467                 AppDomain* appDomain = NULL;
4468
4469                 if (baseDomain->IsAppDomain())
4470                 {
4471                     appDomain = PTR_AppDomain(PTR_HOST_TO_TADDR(baseDomain));
4472                 }
4473                 else
4474                 {
4475                     // Find a likely domain, because it's the shared domain.
4476                     AppDomainIterator adi(FALSE);
4477                     appDomain = adi.GetDomain();
4478                 }
4479
4480                 pubMethodInst =
4481                     new (nothrow) ClrDataMethodInstance(this,
4482                                                         appDomain,
4483                                                         methodDesc);
4484                 if (pubMethodInst == NULL)
4485                 {
4486                     status = E_OUTOFMEMORY;
4487                 }
4488                 else
4489                 {
4490                     status = S_OK;
4491                 }
4492             }
4493             break;
4494         }
4495
4496         case DACNotify::EXCEPTION_NOTIFICATION:
4497         {
4498             TADDR threadPtr;
4499
4500             if (DACNotify::ParseExceptionNotification(exInfo, threadPtr))
4501             {
4502                 // Translation can only occur at the time of
4503                 // receipt of the notify exception, so we assume
4504                 // that the Thread's current exception state
4505                 // is the state we want.
4506                 status = ClrDataExceptionState::
4507                     NewFromThread(this,
4508                                   PTR_Thread(threadPtr),
4509                                   &pubExState,
4510                                   NULL);
4511             }
4512             break;
4513         }
4514
4515         case DACNotify::GC_NOTIFICATION:
4516         {
4517             if (DACNotify::ParseGCNotification(exInfo, pubGcEvtArgs))
4518             {
4519                 status = S_OK;
4520             }
4521             break;
4522         }
4523
4524         case DACNotify::CATCH_ENTER_NOTIFICATION:
4525         {
4526             TADDR methodDescPtr;
4527             if (DACNotify::ParseExceptionCatcherEnterNotification(exInfo, methodDescPtr, catcherNativeOffset))
4528             {
4529                 // Try and find the right appdomain
4530                 MethodDesc* methodDesc = PTR_MethodDesc(methodDescPtr);
4531                 BaseDomain* baseDomain = methodDesc->GetDomain();
4532                 AppDomain* appDomain = NULL;
4533
4534                 if (baseDomain->IsAppDomain())
4535                 {
4536                     appDomain = PTR_AppDomain(PTR_HOST_TO_TADDR(baseDomain));
4537                 }
4538                 else
4539                 {
4540                     // Find a likely domain, because it's the shared domain.
4541                     AppDomainIterator adi(FALSE);
4542                     appDomain = adi.GetDomain();
4543                 }
4544
4545                 pubMethodInst =
4546                     new (nothrow) ClrDataMethodInstance(this,
4547                                                         appDomain,
4548                                                         methodDesc);
4549                 if (pubMethodInst == NULL)
4550                 {
4551                     status = E_OUTOFMEMORY;
4552                 }
4553                 else
4554                 {
4555                     status = S_OK;
4556                 }
4557             }
4558             break;
4559         }
4560
4561         default:
4562             status = E_INVALIDARG;
4563             break;
4564         }
4565     }
4566     EX_CATCH
4567     {
4568         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4569         {
4570             EX_RETHROW;
4571         }
4572     }
4573     EX_END_CATCH(SwallowAllExceptions)
4574
4575     DAC_LEAVE();
4576
4577     if (status == S_OK)
4578     {
4579         IXCLRDataExceptionNotification2* notify2;
4580
4581         if (notify->QueryInterface(__uuidof(IXCLRDataExceptionNotification2),
4582                                    (void**)&notify2) != S_OK)
4583         {
4584             notify2 = NULL;
4585         }
4586
4587         IXCLRDataExceptionNotification3* notify3;
4588         if (notify->QueryInterface(__uuidof(IXCLRDataExceptionNotification3),
4589                                    (void**)&notify3) != S_OK)
4590         {
4591             notify3 = NULL;
4592         }
4593
4594         IXCLRDataExceptionNotification4* notify4;
4595         if (notify->QueryInterface(__uuidof(IXCLRDataExceptionNotification4),
4596                                    (void**)&notify4) != S_OK)
4597         {
4598             notify4 = NULL;
4599         }
4600
4601         IXCLRDataExceptionNotification5* notify5;
4602         if (notify->QueryInterface(__uuidof(IXCLRDataExceptionNotification5),
4603                                    (void**)&notify5) != S_OK)
4604         {
4605             notify5 = NULL;
4606         }
4607
4608         switch(notifyType)
4609         {
4610         case DACNotify::MODULE_LOAD_NOTIFICATION:
4611             notify->OnModuleLoaded(pubModule);
4612             break;
4613
4614         case DACNotify::MODULE_UNLOAD_NOTIFICATION:
4615             notify->OnModuleUnloaded(pubModule);
4616             break;
4617
4618         case DACNotify::JIT_NOTIFICATION2:
4619             notify->OnCodeGenerated(pubMethodInst);
4620
4621             if (notify5)
4622             {
4623                 notify5->OnCodeGenerated2(pubMethodInst, TO_CDADDR(nativeCodeLocation));
4624             }
4625             break;
4626
4627         case DACNotify::EXCEPTION_NOTIFICATION:
4628             if (notify2)
4629             {
4630                 notify2->OnException(pubExState);
4631             }
4632             else
4633             {
4634                 status = E_INVALIDARG;
4635             }
4636             break;
4637
4638         case DACNotify::GC_NOTIFICATION:
4639             if (notify3)
4640             {
4641                 notify3->OnGcEvent(pubGcEvtArgs);
4642             }
4643             break;
4644
4645         case DACNotify::CATCH_ENTER_NOTIFICATION:
4646             if (notify4)
4647             {
4648                 notify4->ExceptionCatcherEnter(pubMethodInst, catcherNativeOffset);
4649             }
4650             break;
4651
4652         default:
4653             // notifyType has already been validated.
4654             _ASSERTE(FALSE);
4655             break;
4656         }
4657
4658         if (notify2)
4659         {
4660             notify2->Release();
4661         }
4662         if (notify3)
4663         {
4664             notify3->Release();
4665         }
4666         if (notify4)
4667         {
4668             notify4->Release();
4669         }
4670         if (notify5)
4671         {
4672             notify5->Release();
4673         }
4674     }
4675
4676     if (pubModule)
4677     {
4678         pubModule->Release();
4679     }
4680     if (pubMethodInst)
4681     {
4682         pubMethodInst->Release();
4683     }
4684     if (pubExState)
4685     {
4686         pubExState->Release();
4687     }
4688
4689     return status;
4690 }
4691
4692 HRESULT STDMETHODCALLTYPE
4693 ClrDataAccess::CreateMemoryValue(
4694     /* [in] */ IXCLRDataAppDomain* appDomain,
4695     /* [in] */ IXCLRDataTask* tlsTask,
4696     /* [in] */ IXCLRDataTypeInstance* type,
4697     /* [in] */ CLRDATA_ADDRESS addr,
4698     /* [out] */ IXCLRDataValue** value)
4699 {
4700     HRESULT status;
4701
4702     DAC_ENTER();
4703
4704     EX_TRY
4705     {
4706         AppDomain* dacDomain;
4707         Thread* dacThread;
4708         TypeHandle dacType;
4709         ULONG32 flags;
4710         NativeVarLocation loc;
4711
4712         dacDomain = ((ClrDataAppDomain*)appDomain)->GetAppDomain();
4713         if (tlsTask)
4714         {
4715             dacThread = ((ClrDataTask*)tlsTask)->GetThread();
4716         }
4717         else
4718         {
4719             dacThread = NULL;
4720         }
4721         dacType = ((ClrDataTypeInstance*)type)->GetTypeHandle();
4722
4723         flags = GetTypeFieldValueFlags(dacType, NULL, 0, false);
4724
4725         loc.addr = addr;
4726         loc.size = dacType.GetSize();
4727         loc.contextReg = false;
4728
4729         *value = new (nothrow)
4730             ClrDataValue(this, dacDomain, dacThread, flags,
4731                          dacType, addr, 1, &loc);
4732         status = *value ? S_OK : E_OUTOFMEMORY;
4733     }
4734     EX_CATCH
4735     {
4736         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4737         {
4738             EX_RETHROW;
4739         }
4740     }
4741     EX_END_CATCH(SwallowAllExceptions)
4742
4743     DAC_LEAVE();
4744     return status;
4745 }
4746
4747 HRESULT STDMETHODCALLTYPE
4748 ClrDataAccess::SetAllTypeNotifications(
4749     /* [in] */ IXCLRDataModule* mod,
4750     /* [in] */ ULONG32 flags)
4751 {
4752     HRESULT status;
4753
4754     DAC_ENTER();
4755
4756     EX_TRY
4757     {
4758         // XXX Microsoft.
4759         status = E_NOTIMPL;
4760     }
4761     EX_CATCH
4762     {
4763         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4764         {
4765             EX_RETHROW;
4766         }
4767     }
4768     EX_END_CATCH(SwallowAllExceptions)
4769
4770     DAC_LEAVE();
4771     return status;
4772 }
4773
4774 HRESULT STDMETHODCALLTYPE
4775 ClrDataAccess::SetAllCodeNotifications(
4776     /* [in] */ IXCLRDataModule* mod,
4777     /* [in] */ ULONG32 flags)
4778 {
4779     HRESULT status;
4780
4781     DAC_ENTER();
4782
4783     EX_TRY
4784     {
4785         status = E_FAIL;
4786
4787         if (!IsValidMethodCodeNotification(flags))
4788         {
4789             status = E_INVALIDARG;
4790         }
4791         else
4792         {
4793             JITNotifications jn(GetHostJitNotificationTable());
4794             if (!jn.IsActive())
4795             {
4796                 status = E_OUTOFMEMORY;
4797             }
4798             else
4799             {
4800                 BOOL changedTable;
4801                 TADDR modulePtr = mod ?
4802                     PTR_HOST_TO_TADDR(((ClrDataModule*)mod)->GetModule()) :
4803                     NULL;
4804
4805                 if (jn.SetAllNotifications(modulePtr, flags, &changedTable))
4806                 {
4807                     if (!changedTable ||
4808                         (changedTable && jn.UpdateOutOfProcTable()))
4809                     {
4810                         status = S_OK;
4811                     }
4812                 }
4813             }
4814         }
4815     }
4816     EX_CATCH
4817     {
4818         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4819         {
4820             EX_RETHROW;
4821         }
4822     }
4823     EX_END_CATCH(SwallowAllExceptions)
4824
4825     DAC_LEAVE();
4826     return status;
4827 }
4828
4829 HRESULT STDMETHODCALLTYPE
4830 ClrDataAccess::GetTypeNotifications(
4831     /* [in] */ ULONG32 numTokens,
4832     /* [in, size_is(numTokens)] */ IXCLRDataModule* mods[],
4833     /* [in] */ IXCLRDataModule* singleMod,
4834     /* [in, size_is(numTokens)] */ mdTypeDef tokens[],
4835     /* [out, size_is(numTokens)] */ ULONG32 flags[])
4836 {
4837     HRESULT status;
4838
4839     DAC_ENTER();
4840
4841     EX_TRY
4842     {
4843         // XXX Microsoft.
4844         status = E_NOTIMPL;
4845     }
4846     EX_CATCH
4847     {
4848         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4849         {
4850             EX_RETHROW;
4851         }
4852     }
4853     EX_END_CATCH(SwallowAllExceptions)
4854
4855     DAC_LEAVE();
4856     return status;
4857 }
4858
4859 HRESULT STDMETHODCALLTYPE
4860 ClrDataAccess::SetTypeNotifications(
4861     /* [in] */ ULONG32 numTokens,
4862     /* [in, size_is(numTokens)] */ IXCLRDataModule* mods[],
4863     /* [in] */ IXCLRDataModule* singleMod,
4864     /* [in, size_is(numTokens)] */ mdTypeDef tokens[],
4865     /* [in, size_is(numTokens)] */ ULONG32 flags[],
4866     /* [in] */ ULONG32 singleFlags)
4867 {
4868     HRESULT status;
4869
4870     DAC_ENTER();
4871
4872     EX_TRY
4873     {
4874         // XXX Microsoft.
4875         status = E_NOTIMPL;
4876     }
4877     EX_CATCH
4878     {
4879         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4880         {
4881             EX_RETHROW;
4882         }
4883     }
4884     EX_END_CATCH(SwallowAllExceptions)
4885
4886     DAC_LEAVE();
4887     return status;
4888 }
4889
4890 HRESULT STDMETHODCALLTYPE
4891 ClrDataAccess::GetCodeNotifications(
4892     /* [in] */ ULONG32 numTokens,
4893     /* [in, size_is(numTokens)] */ IXCLRDataModule* mods[],
4894     /* [in] */ IXCLRDataModule* singleMod,
4895     /* [in, size_is(numTokens)] */ mdMethodDef tokens[],
4896     /* [out, size_is(numTokens)] */ ULONG32 flags[])
4897 {
4898     HRESULT status;
4899
4900     DAC_ENTER();
4901
4902     EX_TRY
4903     {
4904         if ((flags == NULL || tokens == NULL) ||
4905             (mods == NULL && singleMod == NULL) ||
4906             (mods != NULL && singleMod != NULL))
4907         {
4908             status = E_INVALIDARG;
4909         }
4910         else
4911         {
4912             JITNotifications jn(GetHostJitNotificationTable());
4913             if (!jn.IsActive())
4914             {
4915                 status = E_OUTOFMEMORY;
4916             }
4917             else
4918             {
4919                 TADDR modulePtr = NULL;
4920                 if (singleMod)
4921                 {
4922                     modulePtr = PTR_HOST_TO_TADDR(((ClrDataModule*)singleMod)->
4923                                                   GetModule());
4924                 }
4925
4926                 for (ULONG32 i = 0; i < numTokens; i++)
4927                 {
4928                     if (singleMod == NULL)
4929                     {
4930                         modulePtr =
4931                             PTR_HOST_TO_TADDR(((ClrDataModule*)mods[i])->
4932                                               GetModule());
4933                     }
4934                     USHORT jt = jn.Requested(modulePtr, tokens[i]);
4935                     flags[i] = jt;
4936                 }
4937
4938                 status = S_OK;
4939             }
4940         }
4941     }
4942     EX_CATCH
4943     {
4944         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
4945         {
4946             EX_RETHROW;
4947         }
4948     }
4949     EX_END_CATCH(SwallowAllExceptions)
4950
4951     DAC_LEAVE();
4952     return status;
4953 }
4954
4955 HRESULT STDMETHODCALLTYPE
4956 ClrDataAccess::SetCodeNotifications(
4957     /* [in] */ ULONG32 numTokens,
4958     /* [in, size_is(numTokens)] */ IXCLRDataModule* mods[],
4959     /* [in] */ IXCLRDataModule* singleMod,
4960     /* [in, size_is(numTokens)] */ mdMethodDef tokens[],
4961     /* [in, size_is(numTokens)] */ ULONG32 flags[],
4962     /* [in] */ ULONG32 singleFlags)
4963 {
4964     HRESULT status = E_UNEXPECTED;
4965
4966     DAC_ENTER();
4967
4968     EX_TRY
4969     {
4970         if ((tokens == NULL) ||
4971             (mods == NULL && singleMod == NULL) ||
4972             (mods != NULL && singleMod != NULL))
4973         {
4974             status = E_INVALIDARG;
4975         }
4976         else
4977         {
4978             JITNotifications jn(GetHostJitNotificationTable());
4979             if (!jn.IsActive() || numTokens > jn.GetTableSize())
4980             {
4981                 status = E_OUTOFMEMORY;
4982             }
4983             else
4984             {
4985                 BOOL changedTable = FALSE;
4986
4987                 // Are flags valid?
4988                 if (flags)
4989                 {
4990                     for (ULONG32 check = 0; check < numTokens; check++)
4991                     {
4992                         if (!IsValidMethodCodeNotification(flags[check]))
4993                         {
4994                             status = E_INVALIDARG;
4995                             goto Exit;
4996                         }
4997                     }
4998                 }
4999                 else if (!IsValidMethodCodeNotification(singleFlags))
5000                 {
5001                     status = E_INVALIDARG;
5002                     goto Exit;
5003                 }
5004
5005                 TADDR modulePtr = NULL;
5006                 if (singleMod)
5007                 {
5008                     modulePtr =
5009                         PTR_HOST_TO_TADDR(((ClrDataModule*)singleMod)->
5010                                           GetModule());
5011                 }
5012
5013                 for (ULONG32 i = 0; i < numTokens; i++)
5014                 {
5015                     if (singleMod == NULL)
5016                     {
5017                         modulePtr =
5018                             PTR_HOST_TO_TADDR(((ClrDataModule*)mods[i])->
5019                                               GetModule());
5020                     }
5021
5022                     USHORT curFlags = jn.Requested(modulePtr, tokens[i]);
5023                     USHORT setFlags = (USHORT)(flags ? flags[i] : singleFlags);
5024
5025                     if (curFlags != setFlags)
5026                     {
5027                         if (!jn.SetNotification(modulePtr, tokens[i],
5028                                                 setFlags))
5029                         {
5030                             status = E_FAIL;
5031                             goto Exit;
5032                         }
5033
5034                         changedTable = TRUE;
5035                     }
5036                 }
5037
5038                 if (!changedTable ||
5039                     (changedTable && jn.UpdateOutOfProcTable()))
5040                 {
5041                     status = S_OK;
5042                 }
5043             }
5044         }
5045
5046 Exit: ;
5047     }
5048     EX_CATCH
5049     {
5050         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
5051         {
5052             EX_RETHROW;
5053         }
5054     }
5055     EX_END_CATCH(SwallowAllExceptions)
5056
5057     DAC_LEAVE();
5058     return status;
5059 }
5060
5061 HRESULT
5062 ClrDataAccess::GetOtherNotificationFlags(
5063     /* [out] */ ULONG32* flags)
5064 {
5065     HRESULT status;
5066
5067     DAC_ENTER();
5068
5069     EX_TRY
5070     {
5071         *flags = g_dacNotificationFlags;
5072         status = S_OK;
5073     }
5074     EX_CATCH
5075     {
5076         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
5077         {
5078             EX_RETHROW;
5079         }
5080     }
5081     EX_END_CATCH(SwallowAllExceptions)
5082
5083     DAC_LEAVE();
5084     return status;
5085 }
5086
5087 HRESULT
5088 ClrDataAccess::SetOtherNotificationFlags(
5089     /* [in] */ ULONG32 flags)
5090 {
5091     HRESULT status;
5092
5093     if ((flags & ~(CLRDATA_NOTIFY_ON_MODULE_LOAD |
5094                    CLRDATA_NOTIFY_ON_MODULE_UNLOAD |
5095                    CLRDATA_NOTIFY_ON_EXCEPTION |
5096                    CLRDATA_NOTIFY_ON_EXCEPTION_CATCH_ENTER)) != 0)
5097     {
5098         return E_INVALIDARG;
5099     }
5100
5101     DAC_ENTER();
5102
5103     EX_TRY
5104     {
5105         g_dacNotificationFlags = flags;
5106         status = S_OK;
5107     }
5108     EX_CATCH
5109     {
5110         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
5111         {
5112             EX_RETHROW;
5113         }
5114     }
5115     EX_END_CATCH(SwallowAllExceptions)
5116
5117     DAC_LEAVE();
5118     return status;
5119 }
5120
5121 enum
5122 {
5123     STUB_BUF_FLAGS_START,
5124
5125     STUB_BUF_METHOD_JITTED,
5126     STUB_BUF_FRAME_PUSHED,
5127     STUB_BUF_STUB_MANAGER_PUSHED,
5128
5129     STUB_BUF_FLAGS_END,
5130 };
5131
5132 union STUB_BUF
5133 {
5134     CLRDATA_FOLLOW_STUB_BUFFER apiBuf;
5135     struct
5136     {
5137         ULONG64 flags;
5138         ULONG64 addr;
5139         ULONG64 arg1;
5140     } u;
5141 };
5142
5143 HRESULT
5144 ClrDataAccess::FollowStubStep(
5145     /* [in] */ Thread* thread,
5146     /* [in] */ ULONG32 inFlags,
5147     /* [in] */ TADDR inAddr,
5148     /* [in] */ union STUB_BUF* inBuffer,
5149     /* [out] */ TADDR* outAddr,
5150     /* [out] */ union STUB_BUF* outBuffer,
5151     /* [out] */ ULONG32* outFlags)
5152 {
5153     TraceDestination trace;
5154     bool traceDone = false;
5155     BYTE* retAddr;
5156     T_CONTEXT localContext;
5157     REGDISPLAY regDisp;
5158     MethodDesc* methodDesc;
5159
5160     ZeroMemory(outBuffer, sizeof(*outBuffer));
5161
5162     if (inBuffer)
5163     {
5164         switch(inBuffer->u.flags)
5165         {
5166         case STUB_BUF_METHOD_JITTED:
5167             if (inAddr != GFN_TADDR(DACNotifyCompilationFinished))
5168             {
5169                 return E_INVALIDARG;
5170             }
5171
5172             // It's possible that this notification is
5173             // for a different method, so double-check
5174             // and recycle the notification if necessary.
5175             methodDesc = PTR_MethodDesc(CORDB_ADDRESS_TO_TADDR(inBuffer->u.addr));
5176             if (methodDesc->HasNativeCode())
5177             {
5178                 *outAddr = methodDesc->GetNativeCode();
5179                 *outFlags = CLRDATA_FOLLOW_STUB_EXIT;
5180                 return S_OK;
5181             }
5182
5183             // We didn't end up with native code so try again.
5184             trace.InitForUnjittedMethod(methodDesc);
5185             traceDone = true;
5186             break;
5187
5188         case STUB_BUF_FRAME_PUSHED:
5189             if (!thread ||
5190                 inAddr != inBuffer->u.addr)
5191             {
5192                 return E_INVALIDARG;
5193             }
5194
5195             trace.InitForFramePush(CORDB_ADDRESS_TO_TADDR(inBuffer->u.addr));
5196             DacGetThreadContext(thread, &localContext);
5197             thread->FillRegDisplay(&regDisp, &localContext);
5198             if (!thread->GetFrame()->
5199                 TraceFrame(thread,
5200                            TRUE,
5201                            &trace,
5202                            &regDisp))
5203             {
5204                 return E_FAIL;
5205             }
5206
5207             traceDone = true;
5208             break;
5209
5210         case STUB_BUF_STUB_MANAGER_PUSHED:
5211             if (!thread ||
5212                 inAddr != inBuffer->u.addr ||
5213                 !inBuffer->u.arg1)
5214             {
5215                 return E_INVALIDARG;
5216             }
5217
5218             trace.InitForManagerPush(CORDB_ADDRESS_TO_TADDR(inBuffer->u.addr),
5219                                      PTR_StubManager(CORDB_ADDRESS_TO_TADDR(inBuffer->u.arg1)));
5220             DacGetThreadContext(thread, &localContext);
5221             if (!trace.GetStubManager()->
5222                 TraceManager(thread,
5223                              &trace,
5224                              &localContext,
5225                              &retAddr))
5226             {
5227                 return E_FAIL;
5228             }
5229
5230             traceDone = true;
5231             break;
5232
5233         default:
5234             return E_INVALIDARG;
5235         }
5236     }
5237
5238     if ((!traceDone &&
5239          !StubManager::TraceStub(inAddr, &trace)) ||
5240         !StubManager::FollowTrace(&trace))
5241     {
5242         return E_NOINTERFACE;
5243     }
5244
5245     switch(trace.GetTraceType())
5246     {
5247     case TRACE_UNMANAGED:
5248     case TRACE_MANAGED:
5249         // We've hit non-stub code so we're done.
5250         *outAddr = trace.GetAddress();
5251         *outFlags = CLRDATA_FOLLOW_STUB_EXIT;
5252         break;
5253
5254     case TRACE_UNJITTED_METHOD:
5255         // The stub causes jitting, so return
5256         // the address of the jit-complete routine
5257         // so that the real native address can
5258         // be picked up once the JIT is done.
5259
5260         // One special case is ngen'ed code that
5261         // needs the prestub run.  This results in
5262         // an unjitted trace but no jitting will actually
5263         // occur since the code is ngen'ed.  Detect
5264         // this and redirect to the actual code.
5265         methodDesc = trace.GetMethodDesc();
5266         if (methodDesc->IsPreImplemented() &&
5267             !methodDesc->IsPointingToStableNativeCode() &&
5268             !methodDesc->IsGenericMethodDefinition() &&
5269             methodDesc->HasNativeCode())
5270         {
5271             *outAddr = methodDesc->GetNativeCode();
5272             *outFlags = CLRDATA_FOLLOW_STUB_EXIT;
5273             break;
5274         }
5275
5276         *outAddr = GFN_TADDR(DACNotifyCompilationFinished);
5277         outBuffer->u.flags = STUB_BUF_METHOD_JITTED;
5278         outBuffer->u.addr = PTR_HOST_TO_TADDR(methodDesc);
5279         *outFlags = CLRDATA_FOLLOW_STUB_INTERMEDIATE;
5280         break;
5281
5282     case TRACE_FRAME_PUSH:
5283         if (!thread)
5284         {
5285             return E_INVALIDARG;
5286         }
5287
5288         *outAddr = trace.GetAddress();
5289         outBuffer->u.flags = STUB_BUF_FRAME_PUSHED;
5290         outBuffer->u.addr = trace.GetAddress();
5291         *outFlags = CLRDATA_FOLLOW_STUB_INTERMEDIATE;
5292         break;
5293
5294     case TRACE_MGR_PUSH:
5295         if (!thread)
5296         {
5297             return E_INVALIDARG;
5298         }
5299
5300         *outAddr = trace.GetAddress();
5301         outBuffer->u.flags = STUB_BUF_STUB_MANAGER_PUSHED;
5302         outBuffer->u.addr = trace.GetAddress();
5303         outBuffer->u.arg1 = PTR_HOST_TO_TADDR(trace.GetStubManager());
5304         *outFlags = CLRDATA_FOLLOW_STUB_INTERMEDIATE;
5305         break;
5306
5307     default:
5308         return E_INVALIDARG;
5309     }
5310
5311     return S_OK;
5312 }
5313
5314 HRESULT STDMETHODCALLTYPE
5315 ClrDataAccess::FollowStub(
5316     /* [in] */ ULONG32 inFlags,
5317     /* [in] */ CLRDATA_ADDRESS inAddr,
5318     /* [in] */ CLRDATA_FOLLOW_STUB_BUFFER* _inBuffer,
5319     /* [out] */ CLRDATA_ADDRESS* outAddr,
5320     /* [out] */ CLRDATA_FOLLOW_STUB_BUFFER* _outBuffer,
5321     /* [out] */ ULONG32* outFlags)
5322 {
5323     return FollowStub2(NULL, inFlags, inAddr, _inBuffer,
5324                        outAddr, _outBuffer, outFlags);
5325 }
5326
5327 HRESULT STDMETHODCALLTYPE
5328 ClrDataAccess::FollowStub2(
5329     /* [in] */ IXCLRDataTask* task,
5330     /* [in] */ ULONG32 inFlags,
5331     /* [in] */ CLRDATA_ADDRESS _inAddr,
5332     /* [in] */ CLRDATA_FOLLOW_STUB_BUFFER* _inBuffer,
5333     /* [out] */ CLRDATA_ADDRESS* _outAddr,
5334     /* [out] */ CLRDATA_FOLLOW_STUB_BUFFER* _outBuffer,
5335     /* [out] */ ULONG32* outFlags)
5336 {
5337     HRESULT status;
5338
5339     if ((inFlags & ~(CLRDATA_FOLLOW_STUB_DEFAULT)) != 0)
5340     {
5341         return E_INVALIDARG;
5342     }
5343
5344     STUB_BUF* inBuffer = (STUB_BUF*)_inBuffer;
5345     STUB_BUF* outBuffer = (STUB_BUF*)_outBuffer;
5346
5347     if (inBuffer &&
5348         (inBuffer->u.flags <= STUB_BUF_FLAGS_START ||
5349          inBuffer->u.flags >= STUB_BUF_FLAGS_END))
5350     {
5351         return E_INVALIDARG;
5352     }
5353
5354     DAC_ENTER();
5355
5356     EX_TRY
5357     {
5358         STUB_BUF cycleBuf;
5359         TADDR inAddr = TO_TADDR(_inAddr);
5360         TADDR outAddr;
5361         Thread* thread = task ? ((ClrDataTask*)task)->GetThread() : NULL;
5362         ULONG32 loops = 4;
5363
5364         for (;;)
5365         {
5366             if ((status = FollowStubStep(thread,
5367                                          inFlags,
5368                                          inAddr,
5369                                          inBuffer,
5370                                          &outAddr,
5371                                          outBuffer,
5372                                          outFlags)) != S_OK)
5373             {
5374                 break;
5375             }
5376
5377             // Some stub tracing just requests further iterations
5378             // of processing, so detect that case and loop.
5379             if (outAddr != inAddr)
5380             {
5381                 // We can make forward progress, we're done.
5382                 *_outAddr = TO_CDADDR(outAddr);
5383                 break;
5384             }
5385
5386             // We need more processing.  As a protection
5387             // against infinite loops in corrupted or buggy
5388             // situations, we only allow this to happen a
5389             // small number of times.
5390             if (--loops == 0)
5391             {
5392                 ZeroMemory(outBuffer, sizeof(*outBuffer));
5393                 status = E_FAIL;
5394                 break;
5395             }
5396
5397             cycleBuf = *outBuffer;
5398             inBuffer = &cycleBuf;
5399         }
5400     }
5401     EX_CATCH
5402     {
5403         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
5404         {
5405             EX_RETHROW;
5406         }
5407     }
5408     EX_END_CATCH(SwallowAllExceptions)
5409
5410     DAC_LEAVE();
5411     return status;
5412 }
5413
5414 #ifdef _MSC_VER
5415 #pragma warning(push)
5416 #pragma warning(disable:4297)
5417 #endif // _MSC_VER
5418 STDMETHODIMP
5419 ClrDataAccess::GetGcNotification(GcEvtArgs* gcEvtArgs)
5420 {
5421     HRESULT status;
5422
5423     DAC_ENTER();
5424
5425     EX_TRY
5426     {
5427         if (gcEvtArgs->typ >= GC_EVENT_TYPE_MAX)
5428         {
5429             status = E_INVALIDARG;
5430         }
5431         else
5432         {
5433             GcNotifications gn(GetHostGcNotificationTable());
5434             if (!gn.IsActive())
5435             {
5436                 status = E_OUTOFMEMORY;
5437             }
5438             else
5439             {
5440                 GcEvtArgs *res = gn.GetNotification(*gcEvtArgs);
5441                 if (res != NULL)
5442                 {
5443                     *gcEvtArgs = *res;
5444                     status = S_OK;
5445                 }
5446                 else
5447                 {
5448                     status = E_FAIL;
5449                 }
5450             }
5451         }
5452     }
5453     EX_CATCH
5454     {
5455         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
5456         {
5457             EX_RETHROW;
5458         }
5459     }
5460     EX_END_CATCH(SwallowAllExceptions)
5461
5462     DAC_LEAVE();
5463     return status;
5464 }
5465
5466 STDMETHODIMP
5467 ClrDataAccess::SetGcNotification(IN GcEvtArgs gcEvtArgs)
5468 {
5469     HRESULT status;
5470
5471     DAC_ENTER();
5472
5473     EX_TRY
5474     {
5475         if (gcEvtArgs.typ >= GC_EVENT_TYPE_MAX)
5476         {
5477             status = E_INVALIDARG;
5478         }
5479         else
5480         {
5481             GcNotifications gn(GetHostGcNotificationTable());
5482             if (!gn.IsActive())
5483             {
5484                 status = E_OUTOFMEMORY;
5485             }
5486             else
5487             {
5488                 if (gn.SetNotification(gcEvtArgs) && gn.UpdateOutOfProcTable())
5489                 {
5490                     status = S_OK;
5491                 }
5492                 else
5493                 {
5494                     status = E_FAIL;
5495                 }
5496             }
5497         }
5498     }
5499     EX_CATCH
5500     {
5501         if (!DacExceptionFilter(GET_EXCEPTION(), this, &status))
5502         {
5503             EX_RETHROW;
5504         }
5505     }
5506     EX_END_CATCH(SwallowAllExceptions)
5507
5508     DAC_LEAVE();
5509     return status;
5510 }
5511
5512 #ifdef _MSC_VER
5513 #pragma warning(pop)
5514 #endif // _MSC_VER
5515
5516 HRESULT
5517 ClrDataAccess::Initialize(void)
5518 {
5519     HRESULT hr;
5520     CLRDATA_ADDRESS base;
5521
5522     //
5523     // We do not currently support cross-platform
5524     // debugging.  Verify that cross-platform is not
5525     // being attempted.
5526     //
5527
5528     // Determine our platform based on the pre-processor macros set when we were built
5529
5530 #ifdef FEATURE_PAL
5531     #if defined(DBG_TARGET_X86)
5532         CorDebugPlatform hostPlatform = CORDB_PLATFORM_POSIX_X86;
5533     #elif defined(DBG_TARGET_AMD64)
5534         CorDebugPlatform hostPlatform = CORDB_PLATFORM_POSIX_AMD64;
5535     #elif defined(DBG_TARGET_ARM)
5536         CorDebugPlatform hostPlatform = CORDB_PLATFORM_POSIX_ARM;
5537     #elif defined(DBG_TARGET_ARM64)
5538         CorDebugPlatform hostPlatform = CORDB_PLATFORM_POSIX_ARM64;
5539     #else
5540         #error Unknown Processor.
5541     #endif
5542 #else
5543     #if defined(DBG_TARGET_X86)
5544         CorDebugPlatform hostPlatform = CORDB_PLATFORM_WINDOWS_X86;
5545     #elif defined(DBG_TARGET_AMD64)
5546         CorDebugPlatform hostPlatform = CORDB_PLATFORM_WINDOWS_AMD64;
5547     #elif defined(DBG_TARGET_ARM)
5548         CorDebugPlatform hostPlatform = CORDB_PLATFORM_WINDOWS_ARM;
5549     #elif defined(DBG_TARGET_ARM64)
5550         CorDebugPlatform hostPlatform = CORDB_PLATFORM_WINDOWS_ARM64;
5551     #else
5552         #error Unknown Processor.
5553     #endif
5554 #endif
5555
5556     CorDebugPlatform targetPlatform;
5557     IfFailRet(m_pTarget->GetPlatform(&targetPlatform));
5558
5559     if (targetPlatform != hostPlatform)
5560     {
5561         // DAC fatal error: Platform mismatch - the platform reported by the data target
5562         // is not what this version of mscordacwks.dll was built for.
5563         return CORDBG_E_UNCOMPATIBLE_PLATFORMS;
5564     }
5565
5566     //
5567     // Get the current DLL base for mscorwks globals.
5568     // In case of multiple-CLRs, there may be multiple dlls named "mscorwks".
5569     // code:OpenVirtualProcess can take the base address (clrInstanceId) to select exactly
5570     // which CLR to is being target. If so, m_globalBase will already be set.
5571     //
5572
5573     if (m_globalBase == 0)
5574     {
5575         // Caller didn't specify which CLR to debug.  This supports Whidbey SOS cases, so we should
5576         // be using a legacy data target.
5577         if (m_pLegacyTarget == NULL)
5578         {
5579             DacError(E_INVALIDARG);
5580             UNREACHABLE();
5581         }
5582
5583         // Since this is Whidbey, assume there's only 1 CLR named "mscorwks.dll" and pick that.
5584         IfFailRet(m_pLegacyTarget->GetImageBase(MAIN_CLR_DLL_NAME_W, &base));
5585
5586         m_globalBase = TO_TADDR(base);
5587     }
5588
5589     // We don't need to try too hard to prevent
5590     // multiple initializations as each one will
5591     // copy the same data into the globals and so
5592     // cannot interfere with each other.
5593     if (!s_procInit)
5594     {
5595         IfFailRet(GetDacGlobals());
5596         IfFailRet(DacGetHostVtPtrs());
5597         s_procInit = true;
5598     }
5599
5600     //
5601     // DAC is now setup and ready to use
5602     //
5603
5604     // Do some validation
5605     IfFailRet(VerifyDlls());
5606
5607     // To support EH SxS, utilcode requires the base address of the runtime
5608     // as part of its initialization so that functions like "WasThrownByUs" work correctly since
5609     // they use the CLR base address to check if an exception was raised by a given instance of the runtime
5610     // or not.
5611     //
5612     // Thus, when DAC is initialized, initialize utilcode with the base address of the runtime loaded in the
5613     // target process. This is similar to work done in CorDB::SetTargetCLR for mscordbi.
5614
5615     // Initialize UtilCode for SxS scenarios
5616     CoreClrCallbacks cccallbacks;
5617     cccallbacks.m_hmodCoreCLR               = (HINSTANCE)m_globalBase; // Base address of the runtime in the target process
5618     cccallbacks.m_pfnIEE                    = NULL;
5619     cccallbacks.m_pfnGetCORSystemDirectory  = NULL;
5620     InitUtilcode(cccallbacks);
5621
5622     return S_OK;
5623 }
5624
5625 Thread*
5626 ClrDataAccess::FindClrThreadByTaskId(ULONG64 taskId)
5627 {
5628     Thread* thread = NULL;
5629
5630     if (!ThreadStore::s_pThreadStore)
5631     {
5632         return NULL;
5633     }
5634
5635     while ((thread = ThreadStore::GetAllThreadList(thread, 0, 0)))
5636     {
5637         if (thread->GetThreadId() == (DWORD)taskId)
5638         {
5639             return thread;
5640         }
5641     }
5642
5643     return NULL;
5644 }
5645
5646 HRESULT
5647 ClrDataAccess::IsPossibleCodeAddress(IN TADDR address)
5648 {
5649     SUPPORTS_DAC;
5650     BYTE testRead;
5651     ULONG32 testDone;
5652
5653     // First do a trivial check on the readability of the
5654     // address.  This makes for quick rejection of bogus
5655     // addresses that the debugger sends in when searching
5656     // stacks for return addresses.
5657     // XXX Microsoft - Will this cause problems in minidumps
5658     // where it's possible the stub is identifiable but
5659     // the stub code isn't present?  Yes, but the lack
5660     // of that code could confuse the walker on its own
5661     // if it does code analysis.
5662     if ((m_pTarget->ReadVirtual(address, &testRead, sizeof(testRead),
5663                                &testDone) != S_OK) ||
5664         !testDone)
5665     {
5666         return E_INVALIDARG;
5667     }
5668
5669     return S_OK;
5670 }
5671
5672 HRESULT
5673 ClrDataAccess::GetFullMethodName(
5674     IN MethodDesc* methodDesc,
5675     IN ULONG32 symbolChars,
5676     OUT ULONG32* symbolLen,
5677     __out_ecount_part_opt(symbolChars, *symbolLen) LPWSTR symbol
5678     )
5679 {
5680     StackSString s;
5681 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
5682     PAL_CPP_TRY
5683     {
5684 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
5685
5686         TypeString::AppendMethodInternal(s, methodDesc, TypeString::FormatSignature|TypeString::FormatNamespace|TypeString::FormatFullInst);
5687
5688 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
5689     }
5690     PAL_CPP_CATCH_ALL
5691     {
5692         if (!MdCacheGetEEName(dac_cast<TADDR>(methodDesc), s))
5693         {
5694             PAL_CPP_RETHROW;
5695         }
5696     }
5697     PAL_CPP_ENDTRY
5698 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
5699
5700     if (symbol)
5701     {
5702         // Copy as much as we can and truncate the rest.
5703         wcsncpy_s(symbol, symbolChars, s.GetUnicode(), _TRUNCATE);
5704     }
5705
5706     if (symbolLen)
5707         *symbolLen = s.GetCount() + 1;
5708
5709     if (symbol != NULL && symbolChars < (s.GetCount() + 1))
5710         return S_FALSE;
5711     else
5712         return S_OK;
5713 }
5714
5715 PCSTR
5716 ClrDataAccess::GetJitHelperName(
5717     IN TADDR address,
5718     IN bool dynamicHelpersOnly /*=false*/
5719     )
5720 {
5721     const static PCSTR s_rgHelperNames[] = {
5722 #define JITHELPER(code,fn,sig) #code,
5723 #include <jithelpers.h>
5724     };
5725     static_assert_no_msg(COUNTOF(s_rgHelperNames) == CORINFO_HELP_COUNT);
5726
5727 #ifdef FEATURE_PAL
5728     if (!dynamicHelpersOnly)
5729 #else
5730     if (!dynamicHelpersOnly && g_runtimeLoadedBaseAddress <= address &&
5731             address < g_runtimeLoadedBaseAddress + g_runtimeVirtualSize)
5732 #endif // FEATURE_PAL
5733     {
5734         // Read the whole table from the target in one shot for better performance
5735         VMHELPDEF * pTable = static_cast<VMHELPDEF *>(
5736             PTR_READ(dac_cast<TADDR>(&hlpFuncTable), CORINFO_HELP_COUNT * sizeof(VMHELPDEF)));
5737
5738         for (int i = 0; i < CORINFO_HELP_COUNT; i++)
5739         {
5740             if (address == (TADDR)(pTable[i].pfnHelper))
5741                 return s_rgHelperNames[i];
5742         }
5743     }
5744
5745     // Check if its a dynamically generated JIT helper
5746     const static CorInfoHelpFunc s_rgDynamicHCallIds[] = {
5747 #define DYNAMICJITHELPER(code, fn, sig) code,
5748 #define JITHELPER(code, fn,sig)
5749 #include <jithelpers.h>
5750     };
5751
5752     // Read the whole table from the target in one shot for better performance
5753     VMHELPDEF * pDynamicTable = static_cast<VMHELPDEF *>(
5754         PTR_READ(dac_cast<TADDR>(&hlpDynamicFuncTable), DYNAMIC_CORINFO_HELP_COUNT * sizeof(VMHELPDEF)));
5755     for (unsigned d = 0; d < DYNAMIC_CORINFO_HELP_COUNT; d++)
5756     {
5757         if (address == (TADDR)(pDynamicTable[d].pfnHelper))
5758         {
5759             return s_rgHelperNames[s_rgDynamicHCallIds[d]];
5760         }
5761     }
5762
5763     return NULL;
5764 }
5765
5766 HRESULT
5767 ClrDataAccess::RawGetMethodName(
5768     /* [in] */ CLRDATA_ADDRESS address,
5769     /* [in] */ ULONG32 flags,
5770     /* [in] */ ULONG32 bufLen,
5771     /* [out] */ ULONG32 *symbolLen,
5772     /* [size_is][out] */ __out_ecount_opt(bufLen) WCHAR symbolBuf[  ],
5773     /* [out] */ CLRDATA_ADDRESS* displacement)
5774 {
5775 #ifdef _TARGET_ARM_
5776     _ASSERTE((address & THUMB_CODE) == 0);
5777     address &= ~THUMB_CODE;
5778 #endif
5779
5780     const UINT k_cch64BitHexFormat = COUNTOF("1234567812345678");
5781     HRESULT status;
5782
5783     if (flags != 0)
5784     {
5785         return E_INVALIDARG;
5786     }
5787
5788     TADDR taddr;
5789     if( (status = TRY_CLRDATA_ADDRESS_TO_TADDR(address, &taddr)) != S_OK )
5790     {
5791         return status;
5792     }
5793
5794     if ((status = IsPossibleCodeAddress(taddr)) != S_OK)
5795     {
5796         return status;
5797     }
5798
5799     PTR_StubManager pStubManager;
5800     MethodDesc* methodDesc = NULL;
5801
5802     {
5803         EECodeInfo codeInfo(TO_TADDR(address));
5804         if (codeInfo.IsValid())
5805         {
5806             if (displacement)
5807             {
5808                 *displacement = codeInfo.GetRelOffset();
5809             }
5810
5811             methodDesc = codeInfo.GetMethodDesc();
5812             goto NameFromMethodDesc;
5813         }
5814     }
5815
5816     pStubManager = StubManager::FindStubManager(TO_TADDR(address));
5817     if (pStubManager != NULL)
5818     {
5819         if (displacement)
5820         {
5821             *displacement = 0;
5822         }
5823
5824         //
5825         // Special-cased stub managers
5826         //
5827 #ifdef FEATURE_PREJIT
5828         if (pStubManager == RangeSectionStubManager::g_pManager)
5829         {
5830             switch (RangeSectionStubManager::GetStubKind(TO_TADDR(address)))
5831             {
5832             case STUB_CODE_BLOCK_PRECODE:
5833                 goto PrecodeStub;
5834
5835             case STUB_CODE_BLOCK_JUMPSTUB:
5836                 goto JumpStub;
5837
5838             default:
5839                 break;
5840             }
5841         }
5842         else
5843 #endif
5844         if (pStubManager == PrecodeStubManager::g_pManager)
5845         {
5846 #ifdef FEATURE_PREJIT
5847         PrecodeStub:
5848 #endif
5849             PCODE alignedAddress = AlignDown(TO_TADDR(address), PRECODE_ALIGNMENT);
5850
5851 #ifdef _TARGET_ARM_
5852             alignedAddress += THUMB_CODE;
5853 #endif
5854
5855             SIZE_T maxPrecodeSize = sizeof(StubPrecode);
5856
5857 #ifdef HAS_RELATIVE_STUB_PRECODE
5858             maxPrecodeSize = max(maxPrecodeSize, sizeof(RelativeStubPrecode));
5859 #endif
5860
5861 #ifdef HAS_RELATIVE_FIXUP_PRECODE
5862             maxPrecodeSize = max(maxPrecodeSize, sizeof(RelativeFixupPrecode));
5863 #endif
5864
5865 #ifdef HAS_THISPTR_RETBUF_PRECODE
5866             maxPrecodeSize = max(maxPrecodeSize, sizeof(ThisPtrRetBufPrecode));
5867 #endif
5868
5869             for (SIZE_T i = 0; i < maxPrecodeSize / PRECODE_ALIGNMENT; i++)
5870             {
5871                 EX_TRY
5872                 {
5873                     // Try to find matching precode entrypoint
5874                     Precode* pPrecode = Precode::GetPrecodeFromEntryPoint(alignedAddress, TRUE);
5875                     if (pPrecode != NULL)
5876                     {
5877                         methodDesc = pPrecode->GetMethodDesc();
5878                         if (methodDesc != NULL)
5879                         {
5880                             if (DacValidateMD(methodDesc))
5881                             {
5882                                 if (displacement)
5883                                 {
5884                                     *displacement = TO_TADDR(address) - PCODEToPINSTR(alignedAddress);
5885                                 }
5886                                 goto NameFromMethodDesc;
5887                             }
5888                         }
5889                     }
5890                     alignedAddress -= PRECODE_ALIGNMENT;
5891                 }
5892                 EX_CATCH
5893                 {
5894                 }
5895                 EX_END_CATCH(SwallowAllExceptions)
5896             }
5897         }
5898         else
5899         if (pStubManager == JumpStubStubManager::g_pManager)
5900         {
5901 #ifdef FEATURE_PREJIT
5902         JumpStub:
5903 #endif
5904             PCODE pTarget = decodeBackToBackJump(TO_TADDR(address));
5905
5906             HRESULT hr = GetRuntimeNameByAddress(pTarget, flags, bufLen, symbolLen, symbolBuf, NULL);
5907             if (SUCCEEDED(hr))
5908             {
5909                 return hr;
5910             }
5911
5912             PCSTR pHelperName = GetJitHelperName(pTarget);
5913             if (pHelperName != NULL)
5914             {
5915                 hr = ConvertUtf8(pHelperName, bufLen, symbolLen, symbolBuf);
5916                 if (FAILED(hr))
5917                     return S_FALSE;
5918
5919                 return hr;
5920             }
5921         }
5922
5923         static WCHAR s_wszFormatNameWithStubManager[] = W("CLRStub[%s]@%I64x");
5924
5925         LPCWSTR wszStubManagerName = pStubManager->GetStubManagerName(TO_TADDR(address));
5926         _ASSERTE(wszStubManagerName != NULL);
5927
5928         int result = _snwprintf_s(
5929             symbolBuf,
5930             bufLen,
5931             _TRUNCATE,
5932             s_wszFormatNameWithStubManager,
5933             wszStubManagerName,                                         // Arg 1 = stub name
5934             TO_TADDR(address));                                         // Arg 2 = stub hex address
5935
5936         if (result != -1)
5937         {
5938             // Printf succeeded, so we have an exact char count to return
5939             if (symbolLen)
5940             {
5941                 size_t cchSymbol = wcslen(symbolBuf) + 1;
5942                 if (!FitsIn<ULONG32>(cchSymbol))
5943                     return COR_E_OVERFLOW;
5944
5945                 *symbolLen = (ULONG32) cchSymbol;
5946             }
5947             return S_OK;
5948         }
5949
5950         // Printf failed.  Estimate a size that will be at least big enough to hold the name
5951         if (symbolLen)
5952         {
5953             size_t cchSymbol = COUNTOF(s_wszFormatNameWithStubManager) +
5954                 wcslen(wszStubManagerName) +
5955                 k_cch64BitHexFormat +
5956                 1;
5957
5958             if (!FitsIn<ULONG32>(cchSymbol))
5959                 return COR_E_OVERFLOW;
5960
5961             *symbolLen = (ULONG32) cchSymbol;
5962         }
5963         return S_FALSE;
5964     }
5965
5966     // Do not waste time looking up name for static helper. Debugger can get the actual name from .pdb.
5967     PCSTR pHelperName;
5968     pHelperName = GetJitHelperName(TO_TADDR(address), true /* dynamicHelpersOnly */);
5969     if (pHelperName != NULL)
5970     {
5971         if (displacement)
5972         {
5973             *displacement = 0;
5974         }
5975
5976         HRESULT hr = ConvertUtf8(pHelperName, bufLen, symbolLen, symbolBuf);
5977         if (FAILED(hr))
5978             return S_FALSE;
5979
5980         return S_OK;
5981     }
5982
5983     return E_NOINTERFACE;
5984
5985 NameFromMethodDesc:
5986     if (methodDesc->GetClassification() == mcDynamic &&
5987         !methodDesc->GetSig())
5988     {
5989         // XXX Microsoft - Should this case have a more specific name?
5990         static WCHAR s_wszFormatNameAddressOnly[] = W("CLRStub@%I64x");
5991
5992         int result = _snwprintf_s(
5993             symbolBuf,
5994             bufLen,
5995             _TRUNCATE,
5996             s_wszFormatNameAddressOnly,
5997             TO_TADDR(address));
5998
5999         if (result != -1)
6000         {
6001             // Printf succeeded, so we have an exact char count to return
6002             if (symbolLen)
6003             {
6004                 size_t cchSymbol = wcslen(symbolBuf) + 1;
6005                 if (!FitsIn<ULONG32>(cchSymbol))
6006                     return COR_E_OVERFLOW;
6007
6008                 *symbolLen = (ULONG32) cchSymbol;
6009             }
6010             return S_OK;
6011         }
6012
6013         // Printf failed.  Estimate a size that will be at least big enough to hold the name
6014         if (symbolLen)
6015         {
6016             size_t cchSymbol = COUNTOF(s_wszFormatNameAddressOnly) +
6017                 k_cch64BitHexFormat +
6018                 1;
6019
6020             if (!FitsIn<ULONG32>(cchSymbol))
6021                 return COR_E_OVERFLOW;
6022
6023             *symbolLen = (ULONG32) cchSymbol;
6024         }
6025
6026         return S_FALSE;
6027     }
6028
6029     return GetFullMethodName(methodDesc, bufLen, symbolLen, symbolBuf);
6030 }
6031
6032 HRESULT
6033 ClrDataAccess::GetMethodExtents(MethodDesc* methodDesc,
6034                                 METH_EXTENTS** extents)
6035 {
6036     CLRDATA_ADDRESS_RANGE* curExtent;
6037
6038     {
6039         //
6040         // Get the information from the methoddesc.
6041         // We'll go through the CodeManager + JitManagers, so this should work
6042         // for all types of managed code.
6043         //
6044
6045         PCODE methodStart = methodDesc->GetNativeCode();
6046         if (!methodStart)
6047         {
6048             return E_NOINTERFACE;
6049         }
6050
6051         EECodeInfo codeInfo(methodStart);
6052         _ASSERTE(codeInfo.IsValid());
6053
6054         TADDR codeSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfoToken());
6055
6056         *extents = new (nothrow) METH_EXTENTS;
6057         if (!*extents)
6058         {
6059             return E_OUTOFMEMORY;
6060         }
6061
6062         (*extents)->numExtents = 1;
6063         curExtent = (*extents)->extents;
6064         curExtent->startAddress = TO_CDADDR(methodStart);
6065         curExtent->endAddress =
6066             curExtent->startAddress + codeSize;
6067         curExtent++;
6068     }
6069
6070     (*extents)->curExtent = 0;
6071
6072     return S_OK;
6073 }
6074
6075 // Allocator to pass to the debug-info-stores...
6076 BYTE* DebugInfoStoreNew(void * pData, size_t cBytes)
6077 {
6078     return new (nothrow) BYTE[cBytes];
6079 }
6080
6081 HRESULT
6082 ClrDataAccess::GetMethodVarInfo(MethodDesc* methodDesc,
6083                                 TADDR address,
6084                                 ULONG32* numVarInfo,
6085                                 ICorDebugInfo::NativeVarInfo** varInfo,
6086                                 ULONG32* codeOffset)
6087 {
6088     SUPPORTS_DAC;
6089     COUNT_T countNativeVarInfo;
6090     NewHolder<ICorDebugInfo::NativeVarInfo> nativeVars(NULL);
6091
6092     DebugInfoRequest request;
6093     TADDR  nativeCodeStartAddr = PCODEToPINSTR(methodDesc->GetNativeCode());
6094     request.InitFromStartingAddr(methodDesc, nativeCodeStartAddr);
6095
6096     BOOL success = DebugInfoManager::GetBoundariesAndVars(
6097         request,
6098         DebugInfoStoreNew, NULL, // allocator
6099         NULL, NULL,
6100         &countNativeVarInfo, &nativeVars);
6101
6102
6103     if (!success)
6104     {
6105         return E_FAIL;
6106     }
6107
6108     if (!nativeVars || !countNativeVarInfo)
6109     {
6110         return E_NOINTERFACE;
6111     }
6112
6113     *numVarInfo = countNativeVarInfo;
6114     *varInfo = nativeVars;
6115     nativeVars.SuppressRelease(); // To prevent NewHolder from releasing the memory
6116
6117     if (codeOffset)
6118     {
6119         *codeOffset = (ULONG32)
6120             (address - nativeCodeStartAddr);
6121     }
6122     return S_OK;
6123 }
6124
6125 HRESULT
6126 ClrDataAccess::GetMethodNativeMap(MethodDesc* methodDesc,
6127                                   TADDR address,
6128                                   ULONG32* numMap,
6129                                   DebuggerILToNativeMap** map,
6130                                   bool* mapAllocated,
6131                                   CLRDATA_ADDRESS* codeStart,
6132                                   ULONG32* codeOffset)
6133 {
6134     _ASSERTE((codeOffset == NULL) || (address != NULL));
6135
6136     // Use the DebugInfoStore to get IL->Native maps.
6137     // It doesn't matter whether we're jitted, ngenned etc.
6138
6139     DebugInfoRequest request;
6140     TADDR  nativeCodeStartAddr = PCODEToPINSTR(methodDesc->GetNativeCode());
6141     request.InitFromStartingAddr(methodDesc, nativeCodeStartAddr);
6142
6143
6144     // Bounds info.
6145     ULONG32 countMapCopy;
6146     NewHolder<ICorDebugInfo::OffsetMapping> mapCopy(NULL);
6147
6148     BOOL success = DebugInfoManager::GetBoundariesAndVars(
6149         request,
6150         DebugInfoStoreNew, NULL, // allocator
6151         &countMapCopy, &mapCopy,
6152         NULL, NULL);
6153
6154     if (!success)
6155     {
6156         return E_FAIL;
6157     }
6158
6159
6160     // Need to convert map formats.
6161     *numMap = countMapCopy;
6162
6163     *map = new (nothrow) DebuggerILToNativeMap[countMapCopy];
6164     if (!*map)
6165     {
6166         return E_OUTOFMEMORY;
6167     }
6168
6169     ULONG32 i;
6170     for (i = 0; i < *numMap; i++)
6171     {
6172         (*map)[i].ilOffset = mapCopy[i].ilOffset;
6173         (*map)[i].nativeStartOffset = mapCopy[i].nativeOffset;
6174         if (i > 0)
6175         {
6176             (*map)[i - 1].nativeEndOffset = (*map)[i].nativeStartOffset;
6177         }
6178         (*map)[i].source = mapCopy[i].source;
6179     }
6180     if (*numMap >= 1)
6181     {
6182         (*map)[i - 1].nativeEndOffset = 0;
6183     }
6184
6185
6186     // Update varion out params.
6187     if (codeStart)
6188     {
6189         *codeStart = TO_CDADDR(nativeCodeStartAddr);
6190     }
6191     if (codeOffset)
6192     {
6193         *codeOffset = (ULONG32)
6194             (address - nativeCodeStartAddr);
6195     }
6196
6197     *mapAllocated = true;
6198     return S_OK;
6199 }
6200
6201 // Get the MethodDesc for a function
6202 // Arguments:
6203 //    Input:
6204 //       pModule   - pointer to the module for the function
6205 //       memberRef - metadata token for the function
6206 // Return Value:
6207 //       MethodDesc for the function
6208 MethodDesc * ClrDataAccess::FindLoadedMethodRefOrDef(Module* pModule,
6209     mdToken memberRef)
6210 {
6211     CONTRACT(MethodDesc *)
6212     {
6213         GC_NOTRIGGER;
6214         PRECONDITION(CheckPointer(pModule));
6215         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6216     }
6217     CONTRACT_END;
6218
6219     // Must have a MemberRef or a MethodDef
6220     mdToken tkType = TypeFromToken(memberRef);
6221     _ASSERTE((tkType == mdtMemberRef) || (tkType == mdtMethodDef));
6222
6223     if (tkType == mdtMemberRef)
6224     {
6225         RETURN pModule->LookupMemberRefAsMethod(memberRef);
6226     }
6227
6228     RETURN pModule->LookupMethodDef(memberRef);
6229 } // FindLoadedMethodRefOrDef
6230
6231 //
6232 // ReportMem - report a region of memory for dump gathering
6233 //
6234 // If you specify that you expect success, any failure will cause ReportMem to
6235 // return false.  If you do not expect success, true is always returned.
6236 // This function only throws when all dump collection should be cancelled.
6237 //
6238 // Arguments:
6239 //     addr - the starting target address for the memory to report
6240 //     size - the length (in bytes) to report
6241 //     fExpectSuccess - if true (the default), then we expect that this region of memory
6242 //                      should be fully readable.  Any read errors indicate a corrupt target.
6243 //
6244 bool ClrDataAccess::ReportMem(TADDR addr, TSIZE_T size, bool fExpectSuccess /*= true*/)
6245 {
6246     SUPPORTS_DAC_HOST_ONLY;
6247
6248     // This block of code is to help debugging blocks that we report
6249     // to minidump/heapdump. You can set break point here to view the static
6250     // variable to figure out the size of blocks that we are reporting.
6251     // Most useful is set conditional break point to catch large chuck of
6252     // memory. We will leave it here for all builds.
6253     //
6254     static TADDR debugAddr;
6255     static TSIZE_T debugSize;
6256     debugAddr = addr;
6257     debugSize = size;
6258
6259     HRESULT status;
6260     if (!addr || addr == (TADDR)-1 || !size)
6261     {
6262         if (fExpectSuccess)
6263             return false;
6264         else
6265             return true;
6266     }
6267
6268     //
6269     // Try and sanity-check the reported region of memory
6270     //
6271 #ifdef _DEBUG
6272     // in debug builds, sanity-check all reports
6273     const TSIZE_T k_minSizeToCheck = 1;
6274 #else
6275     // in retail builds, only sanity-check larger chunks which have the potential to waste a
6276     // lot of time and/or space.  This avoids the overhead of checking for the majority of
6277     // memory regions (which are small).
6278     const TSIZE_T k_minSizeToCheck = 1024;
6279 #endif
6280     if (size >= k_minSizeToCheck)
6281     {
6282         if (!IsFullyReadable(addr, size))
6283         {
6284             if (!fExpectSuccess)
6285             {
6286                 // We know the read might fail (eg. we're trying to find mapped pages in
6287                 // a module image), so just skip this block silently.
6288                 // Note that the EnumMemoryRegion callback won't necessarily do anything if any part of
6289                 // the region is unreadable, and so there is no point in calling it.  For cases where we expect
6290                 // the read might fail, but we want to report any partial blocks, we have to break up the region
6291                 // into pages and try reporting each page anyway
6292                 return true;
6293             }
6294
6295             // We're reporting bogus memory, so the target must be corrupt (or there is a issue). We should abort
6296             // reporting and continue with the next data structure (where the exception is caught),
6297             // just like we would for a DAC read error (otherwise we might do something stupid
6298             // like get into an infinite loop, or otherwise waste time with corrupt data).
6299
6300             TARGET_CONSISTENCY_CHECK(false, "Found unreadable memory while reporting memory regions for dump gathering");
6301             return false;
6302         }
6303     }
6304
6305     // Minidumps should never contain data structures that are anywhere near 4MB.  If we see this, it's
6306     // probably due to memory corruption.  To keep the dump small, we'll truncate the block.  Note that
6307     // the size to which the block is truncated is pretty unique, so should be good evidence in a dump
6308     // that this has happened.
6309     // Note that it's hard to say what a good value would be here, or whether we should dump any of the
6310     // data structure at all.  Hopefully experience will help guide this going forward.
6311     // @dbgtodo : Extend dump-gathering API to allow a dump-log to be included.
6312     const TSIZE_T kMaxMiniDumpRegion = 4*1024*1024 - 3;    // 4MB-3
6313     if( size > kMaxMiniDumpRegion
6314         && (m_enumMemFlags == CLRDATA_ENUM_MEM_MINI
6315           || m_enumMemFlags == CLRDATA_ENUM_MEM_TRIAGE))
6316     {
6317         TARGET_CONSISTENCY_CHECK( false, "Dump target consistency failure - truncating minidump data structure");
6318         size = kMaxMiniDumpRegion;
6319     }
6320
6321     // track the total memory reported.
6322     m_cbMemoryReported += size;
6323
6324     // ICLRData APIs take only 32-bit sizes.  In practice this will almost always be sufficient, but
6325     // in theory we might have some >4GB ranges on large 64-bit processes doing a heap dump
6326     // (for example, the code:LoaderHeap).  If necessary, break up the reporting into maximum 4GB
6327     // chunks so we can use the existing API.
6328     // @dbgtodo : ICorDebugDataTarget should probably use 64-bit sizes
6329     while (size)
6330     {
6331         ULONG32 enumSize;
6332         if (size > ULONG_MAX)
6333         {
6334             enumSize = ULONG_MAX;
6335         }
6336         else
6337         {
6338             enumSize = (ULONG32)size;
6339         }
6340
6341         // Actually perform the memory reporting callback
6342         status = m_enumMemCb->EnumMemoryRegion(TO_CDADDR(addr), enumSize);
6343         if (status != S_OK)
6344         {
6345             // If dump generation was cancelled, allow us to throw upstack so we'll actually quit.
6346             if ((fExpectSuccess) && (status != COR_E_OPERATIONCANCELED))
6347                 return false;
6348         }
6349
6350         // If the return value of EnumMemoryRegion is COR_E_OPERATIONCANCELED,
6351         // it means that user has requested that the minidump gathering be canceled.
6352         // To do this we throw an exception which is caught in EnumMemoryRegionsWrapper.
6353         if (status == COR_E_OPERATIONCANCELED)
6354         {
6355             ThrowHR(status);
6356         }
6357
6358         // Move onto the next chunk (if any)
6359         size -= enumSize;
6360         addr += enumSize;
6361     }
6362
6363     return true;
6364 }
6365
6366
6367 //
6368 // DacUpdateMemoryRegion - updates/poisons a region of memory of generated dump
6369 //
6370 // Parameters:
6371 //   addr           - target address of the beginning of the memory region
6372 //   bufferSize     - number of bytes to update/poison
6373 //   buffer         - data to be written at given target address
6374 //
6375 bool ClrDataAccess::DacUpdateMemoryRegion(TADDR addr, TSIZE_T bufferSize, BYTE* buffer)
6376 {
6377     SUPPORTS_DAC_HOST_ONLY;
6378
6379     HRESULT status;
6380     if (!addr || addr == (TADDR)-1 || !bufferSize)
6381     {
6382         return false;
6383     }
6384
6385     // track the total memory reported.
6386     m_cbMemoryReported += bufferSize;
6387
6388     if (m_updateMemCb == NULL)
6389     {
6390         return false;
6391     }
6392
6393     // Actually perform the memory updating callback
6394     status = m_updateMemCb->UpdateMemoryRegion(TO_CDADDR(addr), (ULONG32)bufferSize, buffer);
6395     if (status != S_OK)
6396     {
6397         return false;
6398     }
6399
6400     return true;
6401 }
6402
6403 //
6404 // Check whether a region of target memory is fully readable.
6405 //
6406 // Arguments:
6407 //     addr    The base target address of the region
6408 //     size    The size of the region to analyze
6409 //
6410 // Return value:
6411 //     True if the entire regions appears to be readable, false otherwise.
6412 //
6413 // Notes:
6414 //     The motivation here is that reporting large regions of unmapped address space to dbgeng can result in
6415 //     it taking a long time trying to identify a valid subrange.  This can happen when the target
6416 //     memory is corrupt, and we enumerate a data structure with a dynamic size.  Ideally we would just spec
6417 //     the ICLRDataEnumMemoryRegionsCallback API to require the client to fail if it detects an unmapped
6418 //     memory address in the region.  However, we can't change the existing dbgeng code, so for now we'll
6419 //     rely on this heuristic here.
6420 //     @dbgtodo : Try and get the dbg team to change their EnumMemoryRegion behavior.  See DevDiv Bugs 6265
6421 //
6422 bool ClrDataAccess::IsFullyReadable(TADDR taBase, TSIZE_T dwSize)
6423 {
6424     // The only way we have to verify that a memory region is readable is to try reading it in it's
6425     // entirety.  This is potentially expensive, so we'll rely on a heuristic that spot-checks various
6426     // points in the region.
6427
6428     // Ensure we've got something to check
6429     if( dwSize == 0 )
6430         return true;
6431
6432     // Check for overflow
6433     TADDR taEnd = DacTAddrOffset(taBase, dwSize, 1);
6434
6435     // Loop through using expontential growth, being sure to check both the first and last byte
6436     TADDR taCurr = taBase;
6437     TSIZE_T dwInc = 4096;
6438     bool bDone = false;
6439     while (!bDone)
6440     {
6441         // Try and read a byte from the target.  Note that we don't use PTR_BYTE here because we don't want
6442         // the overhead of inserting entries into the DAC instance cache.
6443         BYTE b;
6444         ULONG32 dwBytesRead;
6445         HRESULT hr = m_pTarget->ReadVirtual(taCurr, &b, 1, &dwBytesRead);
6446         if( hr != S_OK || dwBytesRead < 1 )
6447         {
6448             return false;
6449         }
6450
6451         if (taEnd - taCurr <= 1)
6452         {
6453             // We just read the last byte so we're done
6454             _ASSERTE( taCurr = taEnd - 1 );
6455             bDone = true;
6456         }
6457         else if (dwInc == 0 || dwInc >= taEnd - taCurr)
6458         {
6459             // we've reached the end of the exponential series, check the last byte
6460             taCurr = taEnd - 1;
6461         }
6462         else
6463         {
6464             // advance current pointer (subtraction above ensures this won't overflow)
6465             taCurr += dwInc;
6466
6467             // double the increment for next time (or set to 0 if it's already the max)
6468             dwInc <<= 1;
6469         }
6470     }
6471     return true;
6472 }
6473
6474 JITNotification*
6475 ClrDataAccess::GetHostJitNotificationTable()
6476 {
6477     if (m_jitNotificationTable == NULL)
6478     {
6479         m_jitNotificationTable =
6480             JITNotifications::InitializeNotificationTable(1000);
6481     }
6482
6483     return m_jitNotificationTable;
6484 }
6485
6486 GcNotification*
6487 ClrDataAccess::GetHostGcNotificationTable()
6488 {
6489     if (m_gcNotificationTable == NULL)
6490     {
6491         m_gcNotificationTable =
6492             GcNotifications::InitializeNotificationTable(128);
6493     }
6494
6495     return m_gcNotificationTable;
6496 }
6497
6498 /* static */ bool
6499 ClrDataAccess::GetMetaDataFileInfoFromPEFile(PEFile *pPEFile,
6500                                              DWORD &dwTimeStamp,
6501                                              DWORD &dwSize,
6502                                              DWORD &dwDataSize,
6503                                              DWORD &dwRvaHint,
6504                                              bool  &isNGEN,
6505                                              __out_ecount(cchFilePath) LPWSTR wszFilePath,
6506                                              const DWORD cchFilePath)
6507 {
6508     SUPPORTS_DAC_HOST_ONLY;
6509     PEImage *mdImage = NULL;
6510     PEImageLayout   *layout;
6511     IMAGE_DATA_DIRECTORY *pDir = NULL;
6512     COUNT_T uniPathChars = 0;
6513
6514     isNGEN = false;
6515
6516     if (pPEFile->HasNativeImage())
6517     {
6518         mdImage = pPEFile->GetNativeImage();
6519         _ASSERTE(mdImage != NULL);
6520         layout = mdImage->GetLoadedLayout();
6521         pDir = &(layout->GetCorHeader()->MetaData);
6522         // For ngen image, the IL metadata is stored for private use. So we need to pass
6523         // the RVA hint to find it to debuggers.
6524         //
6525         if (pDir->Size != 0)
6526         {
6527             isNGEN = true;
6528             dwRvaHint = pDir->VirtualAddress;
6529             dwDataSize = pDir->Size;
6530         }
6531
6532     }
6533     if (pDir == NULL || pDir->Size == 0)
6534     {
6535         mdImage = pPEFile->GetILimage();
6536         if (mdImage != NULL)
6537         {
6538             layout = mdImage->GetLoadedLayout();
6539             pDir = &layout->GetCorHeader()->MetaData;
6540
6541             // In IL image case, we do not have any hint to IL metadata since it is stored
6542             // in the corheader.
6543             //
6544             dwRvaHint = 0;
6545             dwDataSize = pDir->Size;
6546         }
6547         else
6548         {
6549             return false;
6550         }
6551     }
6552
6553     // Do not fail if path can not be read. Triage dumps don't have paths and we want to fallback
6554     // on searching metadata from IL image.
6555     mdImage->GetPath().DacGetUnicode(cchFilePath, wszFilePath, &uniPathChars);
6556
6557     if (!mdImage->HasNTHeaders() ||
6558         !mdImage->HasCorHeader() ||
6559         !mdImage->HasLoadedLayout() ||
6560         (uniPathChars > cchFilePath))
6561     {
6562         return false;
6563     }
6564
6565     // It is possible that the module is in-memory. That is the wszFilePath here is empty.
6566     // We will try to use the module name instead in this case for hosting debugger
6567     // to find match.
6568     if (wcslen(wszFilePath) == 0)
6569     {
6570         mdImage->GetModuleFileNameHintForDAC().DacGetUnicode(cchFilePath, wszFilePath, &uniPathChars);
6571         if (uniPathChars > cchFilePath)
6572         {
6573             return false;
6574         }
6575     }
6576
6577     dwTimeStamp = layout->GetTimeDateStamp();
6578     dwSize = (ULONG32)layout->GetVirtualSize();
6579
6580     return true;
6581 }
6582
6583 /* static */
6584 bool ClrDataAccess::GetILImageInfoFromNgenPEFile(PEFile *peFile,
6585                                                  DWORD &dwTimeStamp,
6586                                                  DWORD &dwSize,
6587                                                  __out_ecount(cchFilePath) LPWSTR wszFilePath,
6588                                                  const DWORD cchFilePath)
6589 {
6590     SUPPORTS_DAC_HOST_ONLY;
6591     DWORD dwWritten = 0;
6592
6593     // use the IL File name
6594     if (!peFile->GetPath().DacGetUnicode(cchFilePath, wszFilePath, (COUNT_T *)(&dwWritten)))
6595     {
6596         // Use DAC hint to retrieve the IL name.
6597         peFile->GetModuleFileNameHint().DacGetUnicode(cchFilePath, wszFilePath, (COUNT_T *)(&dwWritten));
6598     }
6599 #ifdef FEATURE_PREJIT
6600     // Need to get IL image information from cached info in the ngen image.
6601     dwTimeStamp = peFile->GetLoaded()->GetNativeVersionInfo()->sourceAssembly.timeStamp;
6602     dwSize = peFile->GetLoaded()->GetNativeVersionInfo()->sourceAssembly.ilImageSize;
6603 #else
6604     dwTimeStamp = 0;
6605     dwSize = 0;
6606 #endif //  FEATURE_PREJIT
6607
6608     return true;
6609 }
6610
6611 #if defined(FEATURE_CORESYSTEM)
6612 /* static */
6613 // We extract "ni.dll or .ni.winmd" from the NGEM image name to obtain the IL image name.
6614 // In the end we add given ilExtension.
6615 // This dependecy is based on Apollo installer behavior.
6616 bool ClrDataAccess::GetILImageNameFromNgenImage( LPCWSTR ilExtension,
6617                                                  __out_ecount(cchFilePath) LPWSTR wszFilePath,
6618                                                  const DWORD cchFilePath)
6619 {
6620     if (wszFilePath == NULL || cchFilePath == 0)
6621     {
6622         return false;
6623     }
6624
6625     _wcslwr_s(wszFilePath, cchFilePath);
6626     // Find the "ni.dll" or "ni.winmd" extension (check for PEFile isWinRT something to know when is winmd or not.
6627     // If none exists use NGEN image name.
6628     //
6629     const WCHAR* ngenExtension[] = {W("ni.dll"), W("ni.winmd")};
6630
6631     for (unsigned i = 0; i < COUNTOF(ngenExtension); ++i)
6632     {
6633         if (wcslen(ilExtension) > wcslen(ngenExtension[i]))
6634         {
6635             // We should not have IL image name bigger than NGEN image.
6636             // It will not fit inside wszFilePath.
6637             continue;
6638         }
6639         LPWSTR  wszFileExtension = wcsstr(wszFilePath, ngenExtension[i]);
6640         if (wszFileExtension != 0)
6641         {
6642             LPWSTR  wszNextFileExtension = wszFileExtension;
6643             // Find last occurence
6644             do
6645             {
6646                 wszFileExtension = wszNextFileExtension;
6647                 wszNextFileExtension = wcsstr(wszFileExtension + 1, ngenExtension[i]);
6648             } while (wszNextFileExtension != 0);
6649
6650             // Overwrite ni.dll or ni.winmd with ilExtension(.dll, .winmd)
6651             if (!memcpy_s(wszFileExtension,
6652                            wcslen(ngenExtension[i])*sizeof(WCHAR),
6653                            ilExtension,
6654                            wcslen(ilExtension)*sizeof(WCHAR)))
6655             {
6656                 wszFileExtension[wcslen(ilExtension)] = '\0';
6657                 return true;
6658             }
6659         }
6660     }
6661
6662     //Use ngen filename if there is no ".ni"
6663     if (wcsstr(wszFilePath, W(".ni")) == 0)
6664     {
6665         return true;
6666     }
6667
6668     return false;
6669 }
6670 #endif // FEATURE_CORESYSTEM
6671
6672 void *
6673 ClrDataAccess::GetMetaDataFromHost(PEFile* peFile,
6674                                    bool* isAlternate)
6675 {
6676     DWORD imageTimestamp, imageSize, dataSize;
6677     void* buffer = NULL;
6678     WCHAR uniPath[MAX_LONGPATH] = {0};
6679     bool isAlt = false;
6680     bool isNGEN = false;
6681     DAC_INSTANCE* inst = NULL;
6682     HRESULT  hr = S_OK;
6683     DWORD ulRvaHint;
6684     //
6685     // We always ask for the IL image metadata,
6686     // as we expect that to be more
6687     // available than others.  The drawback is that
6688     // there may be differences between the IL image
6689     // metadata and native image metadata, so we
6690     // have to mark such alternate metadata so that
6691     // we can fail unsupported usage of it.
6692     //
6693
6694     // Microsoft - above comment seems to be an unimplemented thing.
6695     // The DAC_MD_IMPORT.isAlternate field gets ultimately set, but
6696     // on the searching I did, I cannot find any usage of it
6697     // other than in the ctor.  Should we be doing something, or should
6698     // we remove this comment and the isAlternate field?
6699     // It's possible that test will want us to track whether we have
6700     // an IL image's metadata loaded against an NGEN'ed image
6701     // so the field remains for now.
6702
6703     if (!ClrDataAccess::GetMetaDataFileInfoFromPEFile(
6704             peFile,
6705             imageTimestamp,
6706             imageSize,
6707             dataSize,
6708             ulRvaHint,
6709             isNGEN,
6710             uniPath,
6711             NumItems(uniPath)))
6712     {
6713         return NULL;
6714     }
6715
6716     // try direct match for the image that is loaded into the managed process
6717     peFile->GetLoadedMetadata((COUNT_T *)(&dataSize));
6718
6719     DWORD allocSize = 0;
6720     if (!ClrSafeInt<DWORD>::addition(dataSize, sizeof(DAC_INSTANCE), allocSize))
6721     {
6722         DacError(HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW));
6723     }
6724
6725     inst = m_instances.Alloc(0, allocSize, DAC_DPTR);
6726     if (!inst)
6727     {
6728         DacError(E_OUTOFMEMORY);
6729         return NULL;
6730     }
6731
6732     buffer = (void*)(inst + 1);
6733
6734     // APIs implemented by hosting debugger.  It can use the path/filename, timestamp, and
6735     // file size to find an exact match for the image.  If that fails for an ngen'ed image,
6736     // we can request the IL image which it came from.
6737     if (m_legacyMetaDataLocator)
6738     {
6739         // Legacy API implemented by hosting debugger.
6740         hr = m_legacyMetaDataLocator->GetMetadata(
6741             uniPath,
6742             imageTimestamp,
6743             imageSize,
6744             NULL,           // MVID - not used yet
6745             ulRvaHint,
6746             0,              // flags - reserved for future.
6747             dataSize,
6748             (BYTE*)buffer,
6749             NULL);
6750     }
6751     else
6752     {
6753         hr = m_target3->GetMetaData(
6754             uniPath,
6755             imageTimestamp,
6756             imageSize,
6757             NULL,           // MVID - not used yet
6758             ulRvaHint,
6759             0,              // flags - reserved for future.
6760             dataSize,
6761             (BYTE*)buffer,
6762             NULL);
6763     }
6764     if (FAILED(hr) && isNGEN)
6765     {
6766         // We failed to locate the ngen'ed image. We should try to
6767         // find the matching IL image
6768         //
6769         isAlt = true;
6770         if (!ClrDataAccess::GetILImageInfoFromNgenPEFile(
6771                 peFile,
6772                 imageTimestamp,
6773                 imageSize,
6774                 uniPath,
6775                 NumItems(uniPath)))
6776         {
6777             goto ErrExit;
6778         }
6779
6780 #if defined(FEATURE_CORESYSTEM)
6781         const WCHAR* ilExtension[] = {W("dll"), W("winmd")};
6782         WCHAR ngenImageName[MAX_LONGPATH] = {0};
6783         if (wcscpy_s(ngenImageName, NumItems(ngenImageName), uniPath) != 0)
6784         {
6785             goto ErrExit;
6786         }
6787         for (unsigned i = 0; i < COUNTOF(ilExtension); i++)
6788         {
6789             if (wcscpy_s(uniPath, NumItems(uniPath), ngenImageName) != 0)
6790             {
6791                 goto ErrExit;
6792             }
6793             // Transform NGEN image name into IL Image name
6794             if (!GetILImageNameFromNgenImage(ilExtension[i], uniPath, NumItems(uniPath)))
6795             {
6796                 goto ErrExit;
6797             }
6798 #endif//FEATURE_CORESYSTEM
6799
6800             // RVA size in ngen image and IL image is the same. Because the only
6801             // different is in RVA. That is 4 bytes column fixed.
6802             //
6803
6804             // try again
6805             if (m_legacyMetaDataLocator)
6806             {
6807                 hr = m_legacyMetaDataLocator->GetMetadata(
6808                     uniPath,
6809                     imageTimestamp,
6810                     imageSize,
6811                     NULL,           // MVID - not used yet
6812                     0,              // pass zero hint here... important
6813                     0,              // flags - reserved for future.
6814                     dataSize,
6815                     (BYTE*)buffer,
6816                     NULL);
6817             }
6818             else
6819             {
6820                 hr = m_target3->GetMetaData(
6821                     uniPath,
6822                     imageTimestamp,
6823                     imageSize,
6824                     NULL,           // MVID - not used yet
6825                     0,              // pass zero hint here... important
6826                     0,              // flags - reserved for future.
6827                     dataSize,
6828                     (BYTE*)buffer,
6829                     NULL);
6830             }
6831 #if defined(FEATURE_CORESYSTEM)
6832             if (SUCCEEDED(hr))
6833             {
6834                 break;
6835             }
6836         }
6837 #endif // FEATURE_CORESYSTEM
6838     }
6839
6840     if (FAILED(hr))
6841     {
6842         goto ErrExit;
6843     }
6844
6845     *isAlternate = isAlt;
6846     m_instances.AddSuperseded(inst);
6847     return buffer;
6848
6849 ErrExit:
6850     if (inst != NULL)
6851     {
6852         m_instances.ReturnAlloc(inst);
6853     }
6854     return NULL;
6855 }
6856
6857
6858 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6859 //
6860 // Given a PEFile or a ReflectionModule try to find the corresponding metadata
6861 // We will first ask debugger to locate it. If fail, we will try
6862 // to get it from the target process
6863 //
6864 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6865 IMDInternalImport*
6866 ClrDataAccess::GetMDImport(const PEFile* peFile, const ReflectionModule* reflectionModule, bool throwEx)
6867 {
6868     HRESULT     status;
6869     PTR_CVOID mdBaseTarget = NULL;
6870     COUNT_T     mdSize;
6871     IMDInternalImport* mdImport = NULL;
6872     PVOID       mdBaseHost = NULL;
6873     bool        isAlternate = false;
6874
6875     _ASSERTE((peFile == NULL && reflectionModule != NULL) || (peFile != NULL && reflectionModule == NULL));
6876     TADDR       peFileAddr = (peFile != NULL) ? dac_cast<TADDR>(peFile) : dac_cast<TADDR>(reflectionModule);
6877
6878     //
6879     // Look for one we've already created.
6880     //
6881     mdImport = m_mdImports.Get(peFileAddr);
6882     if (mdImport != NULL)
6883     {
6884         return mdImport;
6885     }
6886
6887     if (peFile != NULL)
6888     {
6889         // Get the metadata size
6890         mdBaseTarget = ((PEFile*)peFile)->GetLoadedMetadata(&mdSize);
6891     }
6892     else if (reflectionModule != NULL)
6893     {
6894         // Get the metadata
6895         PTR_SBuffer metadataBuffer = reflectionModule->GetDynamicMetadataBuffer();
6896         if (metadataBuffer != PTR_NULL)
6897         {
6898             mdBaseTarget = dac_cast<PTR_CVOID>((metadataBuffer->DacGetRawBuffer()).StartAddress());
6899             mdSize = metadataBuffer->GetSize();
6900         }
6901         else
6902         {
6903             if (throwEx)
6904             {
6905                 DacError(E_FAIL);
6906             }
6907             return NULL;
6908         }
6909     }
6910     else
6911     {
6912         if (throwEx)
6913         {
6914             DacError(E_FAIL);
6915         }
6916         return NULL;
6917     }
6918
6919     if (mdBaseTarget == PTR_NULL)
6920     {
6921         mdBaseHost = NULL;
6922     }
6923     else
6924     {
6925
6926         //
6927         // Maybe the target process has the metadata
6928         // Find out where the metadata for the image is
6929         // in the target's memory.
6930         //
6931         //
6932         // Read the metadata into the host process. Make sure pass in false in the last
6933         // parameter. This is only matters when producing skinny mini-dump. This will
6934         // prevent metadata gets reported into mini-dump.
6935         //
6936         mdBaseHost = DacInstantiateTypeByAddressNoReport(dac_cast<TADDR>(mdBaseTarget), mdSize,
6937                                                  false);
6938     }
6939
6940     // Try to see if debugger can locate it
6941     if (peFile != NULL && mdBaseHost == NULL && (m_target3 || m_legacyMetaDataLocator))
6942     {
6943         // We couldn't read the metadata from memory.  Ask
6944         // the target for metadata as it may be able to
6945         // provide it from some alternate means.
6946         mdBaseHost = GetMetaDataFromHost(const_cast<PEFile *>(peFile), &isAlternate);
6947     }
6948
6949     if (mdBaseHost == NULL)
6950     {
6951         // cannot locate metadata anywhere
6952         if (throwEx)
6953         {
6954             DacError(E_INVALIDARG);
6955         }
6956         return NULL;
6957     }
6958
6959     //
6960     // Open the MD interface on the host copy of the metadata.
6961     //
6962
6963     status = GetMDInternalInterface(mdBaseHost, mdSize, ofRead,
6964                                     IID_IMDInternalImport,
6965                                     (void**)&mdImport);
6966     if (status != S_OK)
6967     {
6968         if (throwEx)
6969         {
6970             DacError(status);
6971         }
6972         return NULL;
6973     }
6974
6975     //
6976     // Remember the object for this module for
6977     // possible later use.
6978     // The m_mdImports list does get cleaned up by calls to ClrDataAccess::Flush,
6979     // i.e. every time the process changes state.
6980
6981     if (m_mdImports.Add(peFileAddr, mdImport, isAlternate) == NULL)
6982     {
6983         mdImport->Release();
6984         DacError(E_OUTOFMEMORY);
6985     }
6986
6987     return mdImport;
6988 }
6989
6990
6991 //
6992 // Set whether inconsistencies in the target should raise asserts.
6993 // This overrides the default initial setting.
6994 //
6995 // Arguments:
6996 //     fEnableAsserts - whether ASSERTs in dacized code should be enabled
6997 //
6998
6999 void ClrDataAccess::SetTargetConsistencyChecks(bool fEnableAsserts)
7000 {
7001     LIMITED_METHOD_DAC_CONTRACT;
7002     m_fEnableTargetConsistencyAsserts = fEnableAsserts;
7003 }
7004
7005 //
7006 // Get whether inconsistencies in the target should raise asserts.
7007 //
7008 // Return value:
7009 //     whether ASSERTs in dacized code should be enabled
7010 //
7011 // Notes:
7012 //     The implementation of ASSERT accesses this via code:DacTargetConsistencyAssertsEnabled
7013 //
7014 //     By default, this is disabled, unless COMPlus_DbgDACEnableAssert is set (see code:ClrDataAccess::ClrDataAccess).
7015 //     This is necessary for compatibility.  For example, SOS expects to be able to scan for
7016 //     valid MethodTables etc. (which may cause ASSERTs), and also doesn't want ASSERTs when working
7017 //     with targets with corrupted memory.
7018 //
7019 //     Calling code:ClrDataAccess::SetTargetConsistencyChecks overrides the default setting.
7020 //
7021 bool ClrDataAccess::TargetConsistencyAssertsEnabled()
7022 {
7023     LIMITED_METHOD_DAC_CONTRACT;
7024     return m_fEnableTargetConsistencyAsserts;
7025 }
7026
7027 #ifdef FEATURE_CORESYSTEM
7028 #define ctime_s _ctime32_s
7029 #define time_t __time32_t
7030 #endif
7031
7032 //
7033 // VerifyDlls - Validate that the mscorwks in the target matches this version of mscordacwks
7034 // Only done on Windows and Mac builds at the moment.
7035 // See code:CordbProcess::CordbProcess#DBIVersionChecking for more information regarding version checking.
7036 //
7037 HRESULT ClrDataAccess::VerifyDlls()
7038 {
7039 #ifndef FEATURE_PAL
7040     // Provide a knob for disabling this check if we really want to try and proceed anyway with a
7041     // DAC mismatch.  DAC behavior may be arbitrarily bad - globals probably won't be at the same
7042     // address, data structures may be laid out differently, etc.
7043     if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgDACSkipVerifyDlls))
7044     {
7045         return S_OK;
7046     }
7047
7048     // Read the debug directory timestamp from the target mscorwks image using DAC
7049     // Note that we don't use the PE timestamp because the PE file might be changed in ways
7050     // that don't effect the PDB (and therefore don't effect DAC).  Specifically, we rebase
7051     // our DLLs at the end of a build, that changes the PE file, but not the PDB.
7052     // Note that if we wanted to be extra careful, we could read the CV contents (which includes
7053     // the GUID signature) and verify it matches.  Using the timestamp is useful for helpful error
7054     // messages, and should be sufficient in any real scenario.
7055     DWORD timestamp = 0;
7056     HRESULT hr = S_OK;
7057     DAC_ENTER();
7058     EX_TRY
7059     {
7060         // Note that we don't need to worry about ensuring the image memory read by this code
7061         // is saved in a minidump.  Managed minidump debugging already requires that you have
7062         // the full mscorwks.dll available at debug time (eg. windbg won't even load DAC without it).
7063         PEDecoder pedecoder(dac_cast<PTR_VOID>(m_globalBase));
7064
7065         // We use the first codeview debug directory entry since this should always refer to the single
7066         // PDB for mscorwks.dll.
7067         const UINT k_maxDebugEntries = 32;  // a reasonable upper limit in case of corruption
7068         for( UINT i = 0; i < k_maxDebugEntries; i++)
7069         {
7070             PTR_IMAGE_DEBUG_DIRECTORY pDebugEntry = pedecoder.GetDebugDirectoryEntry(i);
7071
7072             // If there are no more entries, then stop
7073             if (pDebugEntry == NULL)
7074                 break;
7075
7076             // Ignore non-codeview entries.  Some scenarios (eg. optimized builds), there may be extra
7077             // debug directory entries at the end of some other type.
7078             if (pDebugEntry->Type == IMAGE_DEBUG_TYPE_CODEVIEW)
7079             {
7080                 // Found a codeview entry - use it's timestamp for comparison
7081                 timestamp = pDebugEntry->TimeDateStamp;
7082                 break;
7083             }
7084         }
7085         char szMsgBuf[1024];
7086         _snprintf_s(szMsgBuf, sizeof(szMsgBuf), _TRUNCATE,
7087             "Failed to find any valid codeview debug directory entry in %s image",
7088             MAIN_CLR_MODULE_NAME_A);
7089         _ASSERTE_MSG(timestamp != 0, szMsgBuf);
7090     }
7091     EX_CATCH
7092     {
7093         if (!DacExceptionFilter(GET_EXCEPTION(), this, &hr))
7094         {
7095             EX_RETHROW;
7096         }
7097     }
7098     EX_END_CATCH(SwallowAllExceptions)
7099     DAC_LEAVE();
7100     if (FAILED(hr))
7101     {
7102         return hr;
7103     }
7104
7105     // Validate that we got a timestamp and it matches what the DAC table told us to expect
7106     if (timestamp == 0 || timestamp != g_dacTableInfo.dwID0)
7107     {
7108         // Timestamp mismatch.  This means mscordacwks is being used with a version of
7109         // mscorwks other than the one it was built for.  This will not work reliably.
7110
7111 #ifdef _DEBUG
7112         // Check if verbose asserts are enabled.  The default is up to the specific instantiation of
7113         // ClrDataAccess, but can be overridden (in either direction) by a COMPlus_ knob.
7114         // Note that we check this knob every time because it may be handy to turn it on in
7115         // the environment mid-flight.
7116         DWORD dwAssertDefault = m_fEnableDllVerificationAsserts ? 1 : 0;
7117         if (REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_DbgDACAssertOnMismatch, dwAssertDefault))
7118         {
7119             // Output a nice error message that contains the timestamps in string format.
7120             time_t actualTime = timestamp;
7121             char szActualTime[30];
7122             ctime_s(szActualTime, sizeof(szActualTime), &actualTime);
7123
7124             time_t expectedTime = g_dacTableInfo.dwID0;
7125             char szExpectedTime[30];
7126             ctime_s(szExpectedTime, sizeof(szExpectedTime), &expectedTime);
7127
7128             // Create a nice detailed message for the assert dialog.
7129             // Note that the strings returned by ctime_s have terminating newline characters.
7130             // This is technically a TARGET_CONSISTENCY_CHECK because a corrupt target could,
7131             // in-theory, have a corrupt mscrowks PE header and cause this check to fail
7132             // unnecessarily.  However, this check occurs during startup, before we know
7133             // whether target consistency checks should be enabled, so it's always enabled
7134             // at the moment.
7135
7136             char szMsgBuf[1024];
7137             _snprintf_s(szMsgBuf, sizeof(szMsgBuf), _TRUNCATE,
7138                 "DAC fatal error: %s/mscordacwks.dll version mismatch\n\n"\
7139                 "The debug directory timestamp of the loaded %s does not match the\n"\
7140                 "version mscordacwks.dll was built for.\n"\
7141                 "Expected %s timestamp: %s"\
7142                 "Actual %s timestamp: %s\n"\
7143                 "DAC will now fail to initialize with a CORDBG_E_MISMATCHED_CORWKS_AND_DACWKS_DLLS\n"\
7144                 "error.  If you really want to try and use the mimatched DLLs, you can disable this\n"\
7145                 "check by setting COMPlus_DbgDACSkipVerifyDlls=1.  However, using a mismatched DAC\n"\
7146                 "DLL will usually result in arbitrary debugger failures.\n",
7147                 MAIN_CLR_DLL_NAME_A,
7148                 MAIN_CLR_DLL_NAME_A,
7149                 MAIN_CLR_DLL_NAME_A,
7150                 szExpectedTime,
7151                 MAIN_CLR_DLL_NAME_A,
7152                 szActualTime);
7153             _ASSERTE_MSG(false, szMsgBuf);
7154         }
7155 #endif
7156
7157         // Return a specific hresult indicating this problem
7158         return CORDBG_E_MISMATCHED_CORWKS_AND_DACWKS_DLLS;
7159     }
7160 #endif // FEATURE_PAL
7161
7162     return S_OK;
7163 }
7164
7165 #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
7166
7167 void ClrDataAccess::InitStreamsForWriting(IN CLRDataEnumMemoryFlags flags)
7168 {
7169     // enforce this should only be called when generating triage and mini-dumps
7170     if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
7171         return;
7172
7173     EX_TRY
7174     {
7175         if (m_streams == NULL)
7176             m_streams = new DacStreamManager(g_MiniMetaDataBuffAddress, g_MiniMetaDataBuffMaxSize);
7177
7178         if (!m_streams->PrepareStreamsForWriting())
7179         {
7180             delete m_streams;
7181             m_streams = NULL;
7182         }
7183     }
7184     EX_CATCH
7185     {
7186         if (m_streams != NULL)
7187         {
7188             delete m_streams;
7189             m_streams = NULL;
7190         }
7191     }
7192     EX_END_CATCH(SwallowAllExceptions)
7193 }
7194
7195 bool ClrDataAccess::MdCacheAddEEName(TADDR taEEStruct, const SString& name)
7196 {
7197     bool result = false;
7198     EX_TRY
7199     {
7200         if (m_streams != NULL)
7201             result = m_streams->MdCacheAddEEName(taEEStruct, name);
7202     }
7203     EX_CATCH
7204     {
7205         result = false;
7206     }
7207     EX_END_CATCH(SwallowAllExceptions)
7208
7209     return result;
7210 }
7211
7212 void ClrDataAccess::EnumStreams(IN CLRDataEnumMemoryFlags flags)
7213 {
7214     // enforce this should only be called when generating triage and mini-dumps
7215     if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
7216         return;
7217
7218     EX_TRY
7219     {
7220         if (m_streams != NULL)
7221             m_streams->EnumStreams(flags);
7222     }
7223     EX_CATCH
7224     {
7225     }
7226     EX_END_CATCH(SwallowAllExceptions)
7227 }
7228
7229 bool ClrDataAccess::MdCacheGetEEName(TADDR taEEStruct, SString & eeName)
7230 {
7231     bool result = false;
7232     EX_TRY
7233     {
7234         if (m_streams == NULL)
7235             m_streams = new DacStreamManager(g_MiniMetaDataBuffAddress, g_MiniMetaDataBuffMaxSize);
7236
7237         result = m_streams->MdCacheGetEEName(taEEStruct, eeName);
7238     }
7239     EX_CATCH
7240     {
7241         result = false;
7242     }
7243     EX_END_CATCH(SwallowAllExceptions)
7244
7245     return result;
7246 }
7247
7248 #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
7249
7250 // Needed for RT_RCDATA.
7251 #define MAKEINTRESOURCE(v) MAKEINTRESOURCEW(v)
7252
7253 // this funny looking double macro forces x to be macro expanded before L is prepended
7254 #define _WIDE(x) _WIDE2(x)
7255 #define _WIDE2(x) W(x)
7256
7257 HRESULT
7258 ClrDataAccess::GetDacGlobals()
7259 {
7260 #ifdef FEATURE_PAL
7261 #ifdef DAC_TABLE_SIZE
7262     if (DAC_TABLE_SIZE != sizeof(g_dacGlobals))
7263     {
7264         return E_INVALIDARG;
7265     }
7266 #endif
7267     ULONG64 dacTableAddress = m_globalBase + DAC_TABLE_RVA;
7268     if (FAILED(ReadFromDataTarget(m_pTarget, dacTableAddress, (BYTE*)&g_dacGlobals, sizeof(g_dacGlobals))))
7269     {
7270         return CORDBG_E_MISSING_DEBUGGER_EXPORTS;
7271     }
7272     if (g_dacGlobals.ThreadStore__s_pThreadStore == NULL)
7273     {
7274         return CORDBG_E_UNSUPPORTED;
7275     }
7276     return S_OK;
7277 #else
7278     HRESULT status = E_FAIL;
7279     DWORD rsrcRVA = 0;
7280     LPVOID rsrcData = NULL;
7281     DWORD rsrcSize = 0;
7282
7283     DWORD resourceSectionRVA = 0;
7284
7285     if (FAILED(status = GetMachineAndResourceSectionRVA(m_pTarget, m_globalBase, NULL, &resourceSectionRVA)))
7286     {
7287         _ASSERTE_MSG(false, "DAC fatal error: can't locate resource section in " MAIN_CLR_DLL_NAME_A);
7288         return CORDBG_E_MISSING_DEBUGGER_EXPORTS;
7289     }
7290
7291     if (FAILED(status = GetResourceRvaFromResourceSectionRvaByName(m_pTarget, m_globalBase,
7292         resourceSectionRVA, (DWORD)RT_RCDATA, _WIDE(DACCESS_TABLE_RESOURCE), 0,
7293         &rsrcRVA, &rsrcSize)))
7294     {
7295         _ASSERTE_MSG(false, "DAC fatal error: can't locate DAC table resource in " MAIN_CLR_DLL_NAME_A);
7296         return CORDBG_E_MISSING_DEBUGGER_EXPORTS;
7297     }
7298
7299     rsrcData = new (nothrow) BYTE[rsrcSize];
7300     if (rsrcData == NULL)
7301         return E_OUTOFMEMORY;
7302
7303     if (FAILED(status = ReadFromDataTarget(m_pTarget, m_globalBase + rsrcRVA, (BYTE*)rsrcData, rsrcSize)))
7304     {
7305         _ASSERTE_MSG(false, "DAC fatal error: can't load DAC table resource from " MAIN_CLR_DLL_NAME_A);
7306         return CORDBG_E_MISSING_DEBUGGER_EXPORTS;
7307     }
7308
7309
7310     PBYTE rawData = (PBYTE)rsrcData;
7311     DWORD bytesLeft = rsrcSize;
7312
7313     // Read the header
7314     struct DacTableHeader header;
7315
7316     // We currently expect the header to be 2 32-bit values and 1 16-byte value,
7317     // make sure there is no packing going on or anything.
7318     static_assert_no_msg(sizeof(DacTableHeader) == 2 * 4 + 16);
7319
7320     if (bytesLeft < sizeof(DacTableHeader))
7321     {
7322         _ASSERTE_MSG(false, "DAC fatal error: DAC table too small for header.");
7323         goto Exit;
7324     }
7325     memcpy(&header, rawData, sizeof(DacTableHeader));
7326     rawData += sizeof(DacTableHeader);
7327     bytesLeft -= sizeof(DacTableHeader);
7328
7329     // Save the table info for later use
7330     g_dacTableInfo = header.info;
7331
7332     // Sanity check that the DAC table is the size we expect.
7333     // This could fail if a different version of dacvars.h or vptr_list.h was used when building
7334     // mscordacwks.dll than when running DacTableGen.
7335
7336     if (offsetof(DacGlobals, Thread__vtAddr) != header.numGlobals * sizeof(ULONG))
7337     {
7338 #ifdef _DEBUG
7339         char szMsgBuf[1024];
7340         _snprintf_s(szMsgBuf, sizeof(szMsgBuf), _TRUNCATE,
7341             "DAC fatal error: mismatch in number of globals in DAC table. Read from file: %d, expected: %d.",
7342             header.numGlobals,
7343             offsetof(DacGlobals, Thread__vtAddr) / sizeof(ULONG));
7344         _ASSERTE_MSG(false, szMsgBuf);
7345 #endif // _DEBUG
7346
7347         status = E_INVALIDARG;
7348         goto Exit;
7349     }
7350
7351     if (sizeof(DacGlobals) != (header.numGlobals + header.numVptrs) * sizeof(ULONG))
7352     {
7353 #ifdef _DEBUG
7354         char szMsgBuf[1024];
7355         _snprintf_s(szMsgBuf, sizeof(szMsgBuf), _TRUNCATE,
7356             "DAC fatal error: mismatch in number of vptrs in DAC table. Read from file: %d, expected: %d.",
7357             header.numVptrs,
7358             (sizeof(DacGlobals) - offsetof(DacGlobals, Thread__vtAddr)) / sizeof(ULONG));
7359         _ASSERTE_MSG(false, szMsgBuf);
7360 #endif // _DEBUG
7361
7362         status = E_INVALIDARG;
7363         goto Exit;
7364     }
7365
7366     // Copy the DAC table into g_dacGlobals
7367     if (bytesLeft < sizeof(DacGlobals))
7368     {
7369         _ASSERTE_MSG(false, "DAC fatal error: DAC table resource too small for DacGlobals.");
7370         status = E_UNEXPECTED;
7371         goto Exit;
7372     }
7373     memcpy(&g_dacGlobals, rawData, sizeof(DacGlobals));
7374     rawData += sizeof(DacGlobals);
7375     bytesLeft -= sizeof(DacGlobals);
7376
7377     status = S_OK;
7378
7379 Exit:
7380
7381     return status;
7382 #endif
7383 }
7384
7385 #undef MAKEINTRESOURCE
7386
7387 //----------------------------------------------------------------------------
7388 //
7389 // IsExceptionFromManagedCode - report if pExceptionRecord points to an exception belonging to the current runtime
7390 //
7391 // Arguments:
7392 //    pExceptionRecord - the exception record
7393 //
7394 // Return Value:
7395 //    TRUE if it is
7396 //    Otherwise, FALSE
7397 //
7398 //----------------------------------------------------------------------------
7399 BOOL ClrDataAccess::IsExceptionFromManagedCode(EXCEPTION_RECORD* pExceptionRecord)
7400 {
7401     DAC_ENTER();
7402
7403     BOOL flag = FALSE;
7404
7405     if (::IsExceptionFromManagedCode(pExceptionRecord))
7406     {
7407         flag = TRUE;
7408     }
7409
7410     DAC_LEAVE();
7411
7412     return flag;
7413 }
7414
7415 #ifndef FEATURE_PAL
7416
7417 //----------------------------------------------------------------------------
7418 //
7419 // GetWatsonBuckets - retrieve Watson buckets from the specified thread
7420 //
7421 // Arguments:
7422 //    dwThreadId - the thread ID
7423 //    pGM - pointer to the space to store retrieved Watson buckets
7424 //
7425 // Return Value:
7426 //    S_OK if the operation is successful.
7427 //    or S_FALSE if Watson buckets cannot be found
7428 //    else detailed error code.
7429 //
7430 //----------------------------------------------------------------------------
7431 HRESULT ClrDataAccess::GetWatsonBuckets(DWORD dwThreadId, GenericModeBlock * pGM)
7432 {
7433     _ASSERTE((dwThreadId != 0) && (pGM != NULL));
7434     if ((dwThreadId == 0) || (pGM == NULL))
7435     {
7436         return E_INVALIDARG;
7437     }
7438
7439     DAC_ENTER();
7440
7441     Thread * pThread = DacGetThread(dwThreadId);
7442     _ASSERTE(pThread != NULL);
7443
7444     HRESULT hr = E_UNEXPECTED;
7445
7446     if (pThread != NULL)
7447     {
7448         hr = GetClrWatsonBucketsWorker(pThread, pGM);
7449     }
7450
7451     DAC_LEAVE();
7452     return hr;
7453 }
7454
7455 #endif // FEATURE_PAL
7456
7457 //----------------------------------------------------------------------------
7458 //
7459 // CLRDataAccessCreateInstance - create and initialize a ClrDataAccess object
7460 //
7461 // Arguments:
7462 //    pLegacyTarget - data target object
7463 //    pClrDataAccess - ClrDataAccess object
7464 //
7465 // Return Value:
7466 //    S_OK on success, else detailed error code.
7467 //
7468 //----------------------------------------------------------------------------
7469 STDAPI CLRDataAccessCreateInstance(ICLRDataTarget * pLegacyTarget,
7470                                    ClrDataAccess ** pClrDataAccess)
7471 {
7472     if ((pLegacyTarget == NULL) || (pClrDataAccess == NULL))
7473     {
7474         return E_INVALIDARG;
7475     }
7476
7477     *pClrDataAccess = NULL;
7478
7479     // Create an adapter which implements the new ICorDebugDataTarget interfaces using
7480     // a legacy implementation of ICLRDataTarget
7481     // ClrDataAccess will take a take a ref on this and delete it when it's released.
7482     DataTargetAdapter * pDtAdapter = new (nothrow) DataTargetAdapter(pLegacyTarget);
7483     if (!pDtAdapter)
7484     {
7485         return E_OUTOFMEMORY;
7486     }
7487
7488     ClrDataAccess* dacClass = new (nothrow) ClrDataAccess(pDtAdapter, pLegacyTarget);
7489     if (!dacClass)
7490     {
7491         delete pDtAdapter;
7492         return E_OUTOFMEMORY;
7493     }
7494
7495     HRESULT hr = dacClass->Initialize();
7496     if (FAILED(hr))
7497     {
7498         dacClass->Release();
7499         return hr;
7500     }
7501
7502     *pClrDataAccess = dacClass;
7503     return S_OK;
7504 }
7505
7506
7507 //----------------------------------------------------------------------------
7508 //
7509 // CLRDataCreateInstance.
7510 // Creates the IXClrData object
7511 // This is the legacy entrypoint to DAC, used by dbgeng/dbghelp (windbg, SOS, watson, etc).
7512 //
7513 //----------------------------------------------------------------------------
7514 STDAPI
7515 DLLEXPORT
7516 CLRDataCreateInstance(REFIID iid,
7517                       ICLRDataTarget * pLegacyTarget,
7518                       void ** iface)
7519 {
7520     if ((pLegacyTarget == NULL) || (iface == NULL))
7521     {
7522         return E_INVALIDARG;
7523     }
7524
7525     *iface = NULL;
7526     ClrDataAccess * pClrDataAccess;
7527     HRESULT hr = CLRDataAccessCreateInstance(pLegacyTarget, &pClrDataAccess);
7528     if (hr != S_OK)
7529     {
7530         return hr;
7531     }
7532
7533     hr = pClrDataAccess->QueryInterface(iid, iface);
7534
7535     pClrDataAccess->Release();
7536     return hr;
7537 }
7538
7539
7540 //----------------------------------------------------------------------------
7541 //
7542 // OutOfProcessExceptionEventGetProcessIdAndThreadId - get ProcessID and ThreadID
7543 //
7544 // Arguments:
7545 //    hProcess - process handle
7546 //    hThread - thread handle
7547 //    pPId - pointer to DWORD to store ProcessID
7548 //    pThreadId - pointer to DWORD to store ThreadID
7549 //
7550 // Return Value:
7551 //    TRUE if the operation is successful.
7552 //    FALSE if it fails
7553 //
7554 //----------------------------------------------------------------------------
7555 BOOL OutOfProcessExceptionEventGetProcessIdAndThreadId(HANDLE hProcess, HANDLE hThread, DWORD * pPId, DWORD * pThreadId)
7556 {
7557     _ASSERTE((pPId != NULL) && (pThreadId != NULL));
7558
7559 #ifdef FEATURE_PAL
7560     // UNIXTODO: mikem 1/13/15 Need appropriate PAL functions for getting ids
7561     *pPId = (DWORD)(SIZE_T)hProcess;
7562     *pThreadId = (DWORD)(SIZE_T)hThread;
7563 #else
7564 #if !defined(FEATURE_CORESYSTEM)
7565     HMODULE hKernel32 = WszGetModuleHandle(W("kernel32.dll"));
7566 #else
7567         HMODULE hKernel32 = WszGetModuleHandle(W("api-ms-win-core-processthreads-l1-1-1.dll"));
7568 #endif
7569     if (hKernel32 == NULL)
7570     {
7571         return FALSE;
7572     }
7573
7574     typedef WINBASEAPI DWORD (WINAPI GET_PROCESSID_OF_THREAD)(HANDLE);
7575     GET_PROCESSID_OF_THREAD * pGetProcessIdOfThread;
7576
7577     typedef WINBASEAPI DWORD (WINAPI GET_THREADID)(HANDLE);
7578     GET_THREADID * pGetThreadId;
7579
7580     pGetProcessIdOfThread = (GET_PROCESSID_OF_THREAD *)GetProcAddress(hKernel32, "GetProcessIdOfThread");
7581     pGetThreadId = (GET_THREADID *)GetProcAddress(hKernel32, "GetThreadId");
7582
7583     // OOP callbacks are used on Win7 or later.   We should have having below two APIs available.
7584     _ASSERTE((pGetProcessIdOfThread != NULL) && (pGetThreadId != NULL));
7585     if ((pGetProcessIdOfThread == NULL) || (pGetThreadId == NULL))
7586     {
7587         return FALSE;
7588     }
7589
7590     *pPId = (*pGetProcessIdOfThread)(hThread);
7591     *pThreadId = (*pGetThreadId)(hThread);
7592 #endif // FEATURE_PAL
7593     return TRUE;
7594 }
7595
7596 // WER_RUNTIME_EXCEPTION_INFORMATION will be available from Win7 SDK once Win7 SDK is released.
7597 #if !defined(WER_RUNTIME_EXCEPTION_INFORMATION)
7598 typedef struct _WER_RUNTIME_EXCEPTION_INFORMATION
7599 {
7600     DWORD dwSize;
7601     HANDLE hProcess;
7602     HANDLE hThread;
7603     EXCEPTION_RECORD exceptionRecord;
7604     CONTEXT context;
7605 } WER_RUNTIME_EXCEPTION_INFORMATION, * PWER_RUNTIME_EXCEPTION_INFORMATION;
7606 #endif // !defined(WER_RUNTIME_EXCEPTION_INFORMATION)
7607
7608
7609 #ifndef FEATURE_PAL
7610
7611 //----------------------------------------------------------------------------
7612 //
7613 // OutOfProcessExceptionEventGetWatsonBucket - retrieve Watson buckets if it is a managed exception
7614 //
7615 // Arguments:
7616 //    pContext - the context passed at helper module registration
7617 //    pExceptionInformation - structure that contains information about the crash
7618 //    pGM - pointer to the space to store retrieved Watson buckets
7619 //
7620 // Return Value:
7621 //    S_OK if the operation is successful.
7622 //    or S_FALSE if it is not a managed exception or Watson buckets cannot be found
7623 //    else detailed error code.
7624 //
7625 //----------------------------------------------------------------------------
7626 STDAPI OutOfProcessExceptionEventGetWatsonBucket(__in PDWORD pContext,
7627                                                  __in const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation,
7628                                                  __out GenericModeBlock * pGMB)
7629 {
7630     HANDLE hProcess = pExceptionInformation->hProcess;
7631     HANDLE hThread  = pExceptionInformation->hThread;
7632     DWORD PId, ThreadId;
7633
7634     if (!OutOfProcessExceptionEventGetProcessIdAndThreadId(hProcess, hThread, &PId, &ThreadId))
7635     {
7636         return E_FAIL;
7637     }
7638
7639     CLRDATA_ADDRESS baseAddressOfRuntime = (CLRDATA_ADDRESS)pContext;
7640     NewHolder<LiveProcDataTarget> dataTarget(NULL);
7641
7642     dataTarget = new (nothrow) LiveProcDataTarget(hProcess, PId, baseAddressOfRuntime);
7643     if (dataTarget == NULL)
7644     {
7645         return E_OUTOFMEMORY;
7646     }
7647
7648     NewHolder<ClrDataAccess> pClrDataAccess(NULL);
7649
7650     HRESULT hr = CLRDataAccessCreateInstance(dataTarget, &pClrDataAccess);
7651     if (hr != S_OK)
7652     {
7653         if (hr == S_FALSE)
7654         {
7655             return E_FAIL;
7656         }
7657         else
7658         {
7659             return hr;
7660         }
7661     }
7662
7663     if (!pClrDataAccess->IsExceptionFromManagedCode(&pExceptionInformation->exceptionRecord))
7664     {
7665         return S_FALSE;
7666     }
7667
7668     return pClrDataAccess->GetWatsonBuckets(ThreadId, pGMB);
7669 }
7670
7671 //----------------------------------------------------------------------------
7672 //
7673 // OutOfProcessExceptionEventCallback - claim the ownership of this event if current
7674 //                                      runtime threw the unhandled exception
7675 //
7676 // Arguments:
7677 //    pContext - the context passed at helper module registration
7678 //    pExceptionInformation - structure that contains information about the crash
7679 //    pbOwnershipClaimed - output parameter for claiming the ownership of this event
7680 //    pwszEventName - name of the event. If this is NULL, pchSize cannot be NULL.
7681 //                    This parameter is valid only if * pbOwnershipClaimed is TRUE.
7682 //    pchSize - the size of the buffer pointed by pwszEventName
7683 //    pdwSignatureCount - the count of signature parameters. Valid values range from
7684 //                        0 to 10. If the value returned is greater than 10, only the
7685 //                        1st 10 parameters are used for bucketing parameters. This
7686 //                        parameter is valid only if * pbOwnershipClaimed is TRUE.
7687 //
7688 // Return Value:
7689 //    S_OK on success, else detailed error code.
7690 //
7691 // Note:
7692 //    This is the 1st function that is called into by WER. This API through its out
7693 //    parameters, tells WER as to whether or not it is claiming the crash. If it does
7694 //    claim the crash, WER uses the event name specified in the string pointed to by
7695 //    pwszEventName for error reporting. WER then proceed to call the
7696 //    OutOfProcessExceptionEventSignatureCallback to get the bucketing parameters from
7697 //    the helper dll.
7698 //
7699 //    This function follows the multiple call paradigms. WER may call into this function
7700 //    with *pwszEventName pointer set to NULL. This is to indicate to the function, that
7701 //    WER wants to know the buffer size needed by the function to populate the string
7702 //    into the buffer. The function should return E_INSUFFICIENTBUFFER with the needed
7703 //    buffer size in *pchSize. WER shall then allocate a buffer of size *pchSize for
7704 //    pwszEventName and then call this function again at which point the function should
7705 //    populate the string and return S_OK.
7706 //
7707 //    Note that *pdOwnershipClaimed should be set to TRUE everytime this function is called
7708 //    for the helper dll to claim ownership of bucketing.
7709 //
7710 //    The Win7 WER spec is at
7711 //    http://windows/windows7/docs/COSD%20Documents/Fundamentals/Feedback%20Services%20and%20Platforms/WER-CLR%20Integration%20Dev%20Spec.docx
7712 //
7713 //    !!!READ THIS!!!
7714 //    Since this is called by external modules it's important that we don't let any exceptions leak out (see Win8 95224).
7715 //
7716 //----------------------------------------------------------------------------
7717 STDAPI OutOfProcessExceptionEventCallback(__in PDWORD pContext,
7718                                           __in const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation,
7719                                           __out BOOL * pbOwnershipClaimed,
7720                                           __out_ecount(*pchSize) PWSTR pwszEventName,
7721                                           __inout PDWORD pchSize,
7722                                           __out PDWORD pdwSignatureCount)
7723 {
7724     SUPPORTS_DAC_HOST_ONLY;
7725
7726     if ((pContext == NULL) ||
7727         (pExceptionInformation == NULL) ||
7728         (pExceptionInformation->dwSize < sizeof(WER_RUNTIME_EXCEPTION_INFORMATION)) ||
7729         (pbOwnershipClaimed == NULL) ||
7730         (pchSize == NULL) ||
7731         (pdwSignatureCount == NULL))
7732     {
7733         return E_INVALIDARG;
7734     }
7735
7736     *pbOwnershipClaimed = FALSE;
7737
7738     GenericModeBlock gmb;
7739     HRESULT hr = E_FAIL;
7740
7741     EX_TRY
7742     {
7743         // get Watson buckets if it is a managed exception
7744         hr = OutOfProcessExceptionEventGetWatsonBucket(pContext, pExceptionInformation, &gmb);
7745     }
7746     EX_CATCH_HRESULT(hr);
7747
7748     if (hr != S_OK)
7749     {
7750         // S_FALSE means either it is not a managed exception or we do not have Watson buckets.
7751         // Since we have set pbOwnershipClaimed to FALSE, we return S_OK to WER.
7752         if (hr == S_FALSE)
7753         {
7754             hr = S_OK;
7755         }
7756
7757         return hr;
7758     }
7759
7760     if ((pwszEventName == NULL) || (*pchSize <= wcslen(gmb.wzEventTypeName)))
7761     {
7762         *pchSize = static_cast<DWORD>(wcslen(gmb.wzEventTypeName)) + 1;
7763         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
7764     }
7765
7766     // copy custom event name
7767     wcscpy_s(pwszEventName, *pchSize, gmb.wzEventTypeName);
7768     *pdwSignatureCount = GetCountBucketParamsForEvent(gmb.wzEventTypeName);
7769     *pbOwnershipClaimed = TRUE;
7770
7771     return S_OK;
7772 }
7773
7774
7775 //----------------------------------------------------------------------------
7776 //
7777 // OutOfProcessExceptionEventCallback - provide custom Watson buckets
7778 //
7779 // Arguments:
7780 //    pContext - the context passed at helper module registration
7781 //    pExceptionInformation - structure that contains information about the crash
7782 //    dwIndex - the index of the bucketing parameter being requested. Valid values are
7783 //              from 0 to 9
7784 //    pwszName - pointer to the name of the bucketing parameter
7785 //    pchName - pointer to character count of the pwszName buffer. If pwszName points to
7786 //              null, *pchName represents the buffer size (represented in number of characters)
7787 //              needed to populate the name in pwszName.
7788 //    pwszValue - pointer to the value of the pwszName bucketing parameter
7789 //    pchValue - pointer to the character count of the pwszValue buffer. If pwszValue points
7790 //               to null, *pchValue represents the buffer size (represented in number of
7791 //               characters) needed to populate the value in pwszValue.
7792 //
7793 // Return Value:
7794 //    S_OK on success, else detailed error code.
7795 //
7796 // Note:
7797 //    This function is called by WER only if the call to OutOfProcessExceptionEventCallback()
7798 //    was successful and the value of *pbOwnershipClaimed was TRUE. This function is called
7799 //    pdwSignatureCount times to collect the bucketing parameters from the helper dll.
7800 //
7801 //    This function also follows the multiple call paradigm as described for the
7802 //    OutOfProcessExceptionEventCallback() function. The buffer sizes needed for
7803 //    this function are of the pwszName and pwszValue buffers.
7804 //
7805 //    !!!READ THIS!!!
7806 //    Since this is called by external modules it's important that we don't let any exceptions leak out (see Win8 95224).
7807 //
7808 //----------------------------------------------------------------------------
7809 STDAPI OutOfProcessExceptionEventSignatureCallback(__in PDWORD pContext,
7810                                                    __in const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation,
7811                                                    __in DWORD dwIndex,
7812                                                    __out_ecount(*pchName) PWSTR pwszName,
7813                                                    __inout PDWORD pchName,
7814                                                    __out_ecount(*pchValue) PWSTR pwszValue,
7815                                                    __inout PDWORD pchValue)
7816 {
7817     SUPPORTS_DAC_HOST_ONLY;
7818
7819     if ((pContext == NULL) ||
7820         (pExceptionInformation == NULL) ||
7821         (pExceptionInformation->dwSize < sizeof(WER_RUNTIME_EXCEPTION_INFORMATION)) ||
7822         (pchName == NULL) ||
7823         (pchValue == NULL))
7824     {
7825         return E_INVALIDARG;
7826     }
7827
7828     if ((pwszName == NULL) || (*pchName == 0))
7829     {
7830         *pchName = 1;
7831         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
7832     }
7833
7834     GenericModeBlock gmb;
7835     const PWSTR pwszBucketValues[] = {gmb.wzP1,
7836                                       gmb.wzP2,
7837                                       gmb.wzP3,
7838                                       gmb.wzP4,
7839                                       gmb.wzP5,
7840                                       gmb.wzP6,
7841                                       gmb.wzP7,
7842                                       gmb.wzP8,
7843                                       gmb.wzP9,
7844                                       gmb.wzP10};
7845
7846     HRESULT hr = E_FAIL;
7847
7848     EX_TRY
7849     {
7850         // get Watson buckets if it is a managed exception
7851         hr = OutOfProcessExceptionEventGetWatsonBucket(pContext, pExceptionInformation, &gmb);
7852     }
7853     EX_CATCH_HRESULT(hr);
7854
7855     // it's possible for the OS to kill
7856     // the faulting process before WER crash reporting has completed.
7857     _ASSERTE(hr == S_OK || hr == CORDBG_E_READVIRTUAL_FAILURE);
7858
7859     if (hr != S_OK)
7860     {
7861         // S_FALSE means either it is not a managed exception or we do not have Watson buckets.
7862         // Either case is a logic error becuase this function is called by WER only if the call
7863         // to OutOfProcessExceptionEventCallback() was successful and the value of
7864         // *pbOwnershipClaimed was TRUE.
7865         if (hr == S_FALSE)
7866         {
7867             hr = E_FAIL;
7868         }
7869
7870         return hr;
7871     }
7872
7873     DWORD paramCount = GetCountBucketParamsForEvent(gmb.wzEventTypeName);
7874
7875     if (dwIndex >= paramCount)
7876     {
7877         _ASSERTE(!"dwIndex is out of range");
7878         return E_INVALIDARG;
7879     }
7880
7881     // Return pwszName as an emptry string to let WER use localized version of "Parameter n"
7882     *pwszName = W('\0');
7883
7884     if ((pwszValue == NULL) || (*pchValue <= wcslen(pwszBucketValues[dwIndex])))
7885     {
7886         *pchValue = static_cast<DWORD>(wcslen(pwszBucketValues[dwIndex]))+ 1;
7887         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
7888     }
7889
7890     // copy custom Watson bucket value
7891     wcscpy_s(pwszValue, *pchValue, pwszBucketValues[dwIndex]);
7892
7893     return S_OK;
7894 }
7895
7896 #endif // FEATURE_PAL
7897
7898 //----------------------------------------------------------------------------
7899 //
7900 // OutOfProcessExceptionEventCallback - provide custom debugger launch string
7901 //
7902 // Arguments:
7903 //    pContext - the context passed at helper module registration
7904 //    pExceptionInformation - structure that contains information about the crash
7905 //    pbCustomDebuggerNeeded - pointer to a BOOL. If this BOOL is set to TRUE, then
7906 //                             a custom debugger launch option is needed by the
7907 //                             process. In that case, the subsequent parameters will
7908 //                             be meaningfully used. If this is FALSE, the subsequent
7909 //                             parameters will be ignored.
7910 //    pwszDebuggerLaunch - pointer to a string that will be used to launch the debugger,
7911 //                         if the debugger is launched. The value of this string overrides
7912 //                         the default debugger launch string used by WER.
7913 //    pchSize - pointer to the character count of the pwszDebuggerLaunch  buffer. If
7914 //              pwszDebuggerLaunch points to null, *pchSize represents the buffer size
7915 //              (represented in number of characters) needed to populate the debugger
7916 //              launch string in pwszDebuggerLaunch.
7917 //    pbAutoLaunchDebugger - pointer to a BOOL. If this BOOL is set to TRUE, WER will
7918 //                           directly launch the debugger. If set to FALSE, WER will show
7919 //                           the debug option to the user in the WER UI.
7920 //
7921 // Return Value:
7922 //    S_OK on success, else detailed error code.
7923 //
7924 // Note:
7925 //    This function is called into by WER only if the call to OutOfProcessExceptionEventCallback()
7926 //    was successful and the value of *pbOwnershipClaimed was TRUE. This function allows the helper
7927 //    dll to customize the debugger launch options including the launch string.
7928 //
7929 //    This function also follows the multiple call paradigm as described for the
7930 //    OutOfProcessExceptionEventCallback() function. The buffer sizes needed for
7931 //    this function are of the pwszName and pwszValue buffers.
7932 //
7933 //----------------------------------------------------------------------------
7934 STDAPI OutOfProcessExceptionEventDebuggerLaunchCallback(__in PDWORD pContext,
7935                                                         __in const PWER_RUNTIME_EXCEPTION_INFORMATION pExceptionInformation,
7936                                                         __out BOOL * pbCustomDebuggerNeeded,
7937                                                         __out_ecount_opt(*pchSize) PWSTR pwszDebuggerLaunch,
7938                                                         __inout PDWORD pchSize,
7939                                                         __out BOOL * pbAutoLaunchDebugger)
7940 {
7941     SUPPORTS_DAC_HOST_ONLY;
7942
7943     if ((pContext == NULL) ||
7944         (pExceptionInformation == NULL) ||
7945         (pExceptionInformation->dwSize < sizeof(WER_RUNTIME_EXCEPTION_INFORMATION)) ||
7946         (pbCustomDebuggerNeeded == NULL) ||
7947         (pwszDebuggerLaunch == NULL) ||
7948         (pchSize == NULL) ||
7949         (pbAutoLaunchDebugger == NULL))
7950     {
7951         return E_INVALIDARG;
7952     }
7953
7954     // Starting from CLRv4 managed debugger string and setting are unified with native debuggers.
7955     // There is no need to provide custom debugger string for WER.
7956     *pbCustomDebuggerNeeded = FALSE;
7957
7958     return S_OK;
7959 }
7960
7961 // DacHandleEnum
7962
7963 #include "comcallablewrapper.h"
7964
7965 DacHandleWalker::DacHandleWalker()
7966     : mDac(0),  m_instanceAge(0), mMap(0), mIndex(0),
7967       mTypeMask(0), mGenerationFilter(-1), mChunkIndex(0), mCurr(0),
7968       mIteratorIndex(0)
7969 {
7970     SUPPORTS_DAC;
7971 }
7972
7973 DacHandleWalker::~DacHandleWalker()
7974 {
7975     SUPPORTS_DAC;
7976
7977     HandleChunkHead *curr = mHead.Next;
7978
7979     while (curr)
7980     {
7981         HandleChunkHead *tmp = curr;
7982         curr = curr->Next;
7983         delete tmp;
7984     }
7985 }
7986
7987 HRESULT DacHandleWalker::Init(ClrDataAccess *dac, UINT types[], UINT typeCount)
7988 {
7989     SUPPORTS_DAC;
7990
7991     if (dac == NULL || types == NULL)
7992         return E_POINTER;
7993
7994     mDac = dac;
7995     m_instanceAge = dac->m_instanceAge;
7996
7997     return Init(BuildTypemask(types, typeCount));
7998 }
7999
8000 HRESULT DacHandleWalker::Init(ClrDataAccess *dac, UINT types[], UINT typeCount, int gen)
8001 {
8002     SUPPORTS_DAC;
8003
8004     if (gen < 0 || gen > (int)*g_gcDacGlobals->max_gen)
8005         return E_INVALIDARG;
8006
8007     mGenerationFilter = gen;
8008
8009     return Init(dac, types, typeCount);
8010 }
8011
8012 HRESULT DacHandleWalker::Init(UINT32 typemask)
8013 {
8014     SUPPORTS_DAC;
8015
8016     mMap = g_gcDacGlobals->handle_table_map;
8017     mTypeMask = typemask;
8018
8019     return S_OK;
8020 }
8021
8022 UINT32 DacHandleWalker::BuildTypemask(UINT types[], UINT typeCount)
8023 {
8024     SUPPORTS_DAC;
8025
8026     UINT32 mask = 0;
8027
8028     for (UINT i = 0; i < typeCount; ++i)
8029     {
8030         _ASSERTE(types[i] < 32);
8031         mask |= (1 << types[i]);
8032     }
8033
8034     return mask;
8035 }
8036
8037 HRESULT DacHandleWalker::Next(unsigned int celt,
8038              SOSHandleData handles[],
8039              unsigned int *pceltFetched)
8040 {
8041     SUPPORTS_DAC;
8042
8043     if (handles == NULL || pceltFetched == NULL)
8044         return E_POINTER;
8045
8046     SOSHelperEnter();
8047
8048     hr = DoHandleWalk<SOSHandleData, unsigned int, DacHandleWalker::EnumCallbackSOS>(celt, handles, pceltFetched);
8049
8050     SOSHelperLeave();
8051
8052     return hr;
8053 }
8054
8055 bool DacHandleWalker::FetchMoreHandles(HANDLESCANPROC callback)
8056 {
8057     SUPPORTS_DAC;
8058
8059     // The table slots are based on the number of GC heaps in the process.
8060     int max_slots = 1;
8061
8062 #ifdef FEATURE_SVR_GC
8063     if (GCHeapUtilities::IsServerHeap())
8064         max_slots = GCHeapCount();
8065 #endif // FEATURE_SVR_GC
8066
8067     // Reset the Count on all cached chunks.  We reuse chunks after allocating
8068     // them, and the count is the only thing which needs resetting.
8069     for (HandleChunkHead *curr = &mHead; curr; curr = curr->Next)
8070         curr->Count = 0;
8071
8072     DacHandleWalkerParam param(&mHead);
8073
8074     do
8075     {
8076         // Have we advanced past the end of the current bucket?
8077         if (mMap && mIndex >= INITIAL_HANDLE_TABLE_ARRAY_SIZE)
8078         {
8079             mIndex = 0;
8080             mMap = mMap->pNext;
8081         }
8082
8083         // Have we walked the entire handle table map?
8084         if (mMap == NULL)
8085         {
8086             mCurr = NULL;
8087             return false;
8088         }
8089
8090         if (mMap->pBuckets[mIndex] != NULL)
8091         {
8092             for (int i = 0; i < max_slots; ++i)
8093             {
8094                 DPTR(dac_handle_table) hTable = mMap->pBuckets[mIndex]->pTable[i];
8095                 if (hTable)
8096                 {
8097                     // Yikes!  The handle table callbacks don't produce the handle type or
8098                     // the AppDomain that we need, and it's too difficult to propogate out
8099                     // these things (especially the type) without worrying about performance
8100                     // implications for the GC.  Instead we'll have the callback walk each
8101                     // type individually.  There are only a few handle types, and the handle
8102                     // table has a fast-path for only walking a single type anyway.
8103                     UINT32 handleType = 0;
8104                     for (UINT32 mask = mTypeMask; mask; mask >>= 1, handleType++)
8105                     {
8106                         if (mask & 1)
8107                         {
8108                             dac_handle_table *pTable = hTable;
8109                             PTR_AppDomain pDomain = AppDomain::GetCurrentDomain();
8110                             param.AppDomain = TO_CDADDR(pDomain.GetAddr());
8111                             param.Type = handleType;
8112
8113                             // Either enumerate the handles regularly, or walk the handle
8114                             // table as the GC does if a generation filter was requested.
8115                             if (mGenerationFilter != -1)
8116                                 HndScanHandlesForGC(hTable, callback,
8117                                                     (LPARAM)&param, 0,
8118                                                      &handleType, 1,
8119                                                      mGenerationFilter, *g_gcDacGlobals->max_gen, 0);
8120                             else
8121                                 HndEnumHandles(hTable, &handleType, 1, callback, (LPARAM)&param, 0, FALSE);
8122                         }
8123                     }
8124                 }
8125             }
8126         }
8127
8128         // Stop looping as soon as we have found data.  We also stop if we have a failed HRESULT during
8129         // the callback (this should indicate OOM).
8130         mIndex++;
8131     } while (mHead.Count == 0 && SUCCEEDED(param.Result));
8132
8133     mCurr = mHead.Next;
8134     return true;
8135 }
8136
8137
8138 HRESULT DacHandleWalker::Skip(unsigned int celt)
8139 {
8140     return E_NOTIMPL;
8141 }
8142
8143 HRESULT DacHandleWalker::Reset()
8144 {
8145     return E_NOTIMPL;
8146 }
8147
8148 HRESULT DacHandleWalker::GetCount(unsigned int *pcelt)
8149 {
8150     return E_NOTIMPL;
8151 }
8152
8153
8154 void DacHandleWalker::GetRefCountedHandleInfo(
8155     OBJECTREF oref, unsigned int uType,
8156     unsigned int *pRefCount, unsigned int *pJupiterRefCount, BOOL *pIsPegged, BOOL *pIsStrong)
8157 {
8158     SUPPORTS_DAC;
8159
8160 #ifdef FEATURE_COMINTEROP
8161     if (uType == HNDTYPE_REFCOUNTED)
8162     {
8163         // get refcount from the CCW
8164         PTR_ComCallWrapper pWrap = ComCallWrapper::GetWrapperForObject(oref);
8165         if (pWrap != NULL)
8166         {
8167             if (pRefCount)
8168                 *pRefCount = (unsigned int)pWrap->GetRefCount();
8169
8170             if (pJupiterRefCount)
8171                 *pJupiterRefCount = (unsigned int)pWrap->GetJupiterRefCount();
8172
8173             if (pIsPegged)
8174                 *pIsPegged = pWrap->IsConsideredPegged();
8175
8176             if (pIsStrong)
8177                 *pIsStrong = pWrap->IsWrapperActive();
8178
8179             return;
8180         }
8181     }
8182 #endif // FEATURE_COMINTEROP
8183
8184     if (pRefCount)
8185         *pRefCount = 0;
8186
8187     if (pJupiterRefCount)
8188         *pJupiterRefCount = 0;
8189
8190     if (pIsPegged)
8191         *pIsPegged = FALSE;
8192
8193     if (pIsStrong)
8194         *pIsStrong = FALSE;
8195 }
8196
8197 void CALLBACK DacHandleWalker::EnumCallbackSOS(PTR_UNCHECKED_OBJECTREF handle, uintptr_t *pExtraInfo, uintptr_t param1, uintptr_t param2)
8198 {
8199     SUPPORTS_DAC;
8200
8201     DacHandleWalkerParam *param = (DacHandleWalkerParam *)param1;
8202     HandleChunkHead *curr = param->Curr;
8203
8204     // If we failed on a previous call (OOM) don't keep trying to allocate, it's not going to work.
8205     if (FAILED(param->Result))
8206         return;
8207
8208     // We've moved past the size of the current chunk.  We'll allocate a new chunk
8209     // and stuff the handles there.  These are cleaned up by the destructor
8210     if (curr->Count >= (curr->Size/sizeof(SOSHandleData)))
8211     {
8212         if (curr->Next == NULL)
8213         {
8214             HandleChunk *next = new (nothrow) HandleChunk;
8215             if (next != NULL)
8216             {
8217                 curr->Next = next;
8218             }
8219             else
8220             {
8221                 param->Result = E_OUTOFMEMORY;
8222                 return;
8223             }
8224         }
8225
8226         curr = param->Curr = param->Curr->Next;
8227     }
8228
8229     // Fill the current handle.
8230     SOSHandleData *dataArray = (SOSHandleData*)curr->pData;
8231     SOSHandleData &data = dataArray[curr->Count++];
8232
8233     data.Handle = TO_CDADDR(handle.GetAddr());
8234     data.Type = param->Type;
8235     if (param->Type == HNDTYPE_DEPENDENT)
8236         data.Secondary = GetDependentHandleSecondary(handle.GetAddr()).GetAddr();
8237 #ifdef FEATURE_COMINTEROP
8238     else if (param->Type == HNDTYPE_WEAK_WINRT)
8239         data.Secondary = HndGetHandleExtraInfo(handle.GetAddr());
8240 #endif // FEATURE_COMINTEROP
8241     else
8242         data.Secondary = 0;
8243     data.AppDomain = param->AppDomain;
8244     GetRefCountedHandleInfo((OBJECTREF)*handle, param->Type, &data.RefCount, &data.JupiterRefCount, &data.IsPegged, &data.StrongReference);
8245     data.StrongReference |= (BOOL)IsAlwaysStrongReference(param->Type);
8246 }
8247
8248 DacStackReferenceWalker::DacStackReferenceWalker(ClrDataAccess *dac, DWORD osThreadID)
8249     : mDac(dac), m_instanceAge(dac ? dac->m_instanceAge : 0), mThread(0), mErrors(0), mEnumerated(false),
8250       mChunkIndex(0), mCurr(0), mIteratorIndex(0)
8251 {
8252     Thread *curr = NULL;
8253
8254     for (curr = ThreadStore::GetThreadList(curr);
8255          curr;
8256          curr = ThreadStore::GetThreadList(curr))
8257      {
8258         if (curr->GetOSThreadId() == osThreadID)
8259         {
8260             mThread = curr;
8261             break;
8262         }
8263      }
8264 }
8265
8266 DacStackReferenceWalker::~DacStackReferenceWalker()
8267 {
8268     StackRefChunkHead *curr = mHead.next;
8269
8270     while (curr)
8271     {
8272         StackRefChunkHead *tmp = curr;
8273         curr = curr->next;
8274         delete tmp;
8275     }
8276 }
8277
8278 HRESULT DacStackReferenceWalker::Init()
8279 {
8280     if (!mThread)
8281         return E_INVALIDARG;
8282     return mHeap.Init();
8283 }
8284
8285 HRESULT STDMETHODCALLTYPE DacStackReferenceWalker::Skip(unsigned int count)
8286 {
8287     return E_NOTIMPL;
8288 }
8289
8290 HRESULT STDMETHODCALLTYPE DacStackReferenceWalker::Reset()
8291 {
8292     return E_NOTIMPL;
8293 }
8294
8295 HRESULT DacStackReferenceWalker::GetCount(unsigned int *pCount)
8296 {
8297     if (!pCount)
8298         return E_POINTER;
8299
8300     SOSHelperEnter();
8301
8302     if (!mEnumerated)
8303     {
8304         // Fill out our data structures.
8305         WalkStack<unsigned int, SOSStackRefData>(0, NULL, DacStackReferenceWalker::GCReportCallbackSOS, DacStackReferenceWalker::GCEnumCallbackSOS);
8306     }
8307
8308     unsigned int count = 0;
8309     for(StackRefChunkHead *curr = &mHead; curr; curr = curr->next)
8310         count += curr->count;
8311
8312     *pCount = count;
8313
8314     SOSHelperLeave();
8315     return hr;
8316 }
8317
8318 HRESULT DacStackReferenceWalker::Next(unsigned int count,
8319                                       SOSStackRefData stackRefs[],
8320                                       unsigned int *pFetched)
8321 {
8322     if (stackRefs == NULL || pFetched == NULL)
8323         return E_POINTER;
8324
8325     SOSHelperEnter();
8326
8327     hr = DoStackWalk<unsigned int, SOSStackRefData,
8328                      DacStackReferenceWalker::GCReportCallbackSOS,
8329                      DacStackReferenceWalker::GCEnumCallbackSOS>
8330                      (count, stackRefs, pFetched);
8331
8332     SOSHelperLeave();
8333
8334     return hr;
8335 }
8336
8337 HRESULT DacStackReferenceWalker::EnumerateErrors(ISOSStackRefErrorEnum **ppEnum)
8338 {
8339     if (!ppEnum)
8340         return E_POINTER;
8341
8342     SOSHelperEnter();
8343
8344     if (mThread)
8345     {
8346         // Fill out our data structures.
8347         WalkStack<unsigned int, SOSStackRefData>(0, NULL, DacStackReferenceWalker::GCReportCallbackSOS, DacStackReferenceWalker::GCEnumCallbackSOS);
8348     }
8349
8350     DacStackReferenceErrorEnum *pEnum = new DacStackReferenceErrorEnum(this, mErrors);
8351     hr = pEnum->QueryInterface(__uuidof(ISOSStackRefErrorEnum), (void**)ppEnum);
8352
8353     SOSHelperLeave();
8354     return hr;
8355 }
8356
8357 CLRDATA_ADDRESS DacStackReferenceWalker::ReadPointer(TADDR addr)
8358 {
8359     ULONG32 bytesRead = 0;
8360     TADDR result = 0;
8361     HRESULT hr = mDac->m_pTarget->ReadVirtual(addr, (BYTE*)&result, sizeof(TADDR), &bytesRead);
8362
8363     if (FAILED(hr) || (bytesRead != sizeof(TADDR)))
8364         return (CLRDATA_ADDRESS)~0;
8365
8366     return TO_CDADDR(result);
8367 }
8368
8369
8370 void DacStackReferenceWalker::GCEnumCallbackSOS(LPVOID hCallback, OBJECTREF *pObject, uint32_t flags, DacSlotLocation loc)
8371 {
8372     GCCONTEXT *gcctx = (GCCONTEXT *)hCallback;
8373     DacScanContext *dsc = (DacScanContext*)gcctx->sc;
8374
8375     // Yuck.  The GcInfoDecoder reports a local pointer for registers (as it's reading out of the REGDISPLAY
8376     // in the stack walk), and it reports a TADDR for stack locations.  This is architecturally difficulty
8377     // to fix, so we are leaving it for now.
8378     TADDR addr = 0;
8379     TADDR obj = 0;
8380
8381     if (loc.targetPtr)
8382     {
8383         addr = (TADDR)pObject;
8384         obj = TO_TADDR(dsc->pWalker->ReadPointer((CORDB_ADDRESS)addr));
8385     }
8386     else
8387     {
8388         obj = pObject->GetAddr();
8389     }
8390
8391     if (flags & GC_CALL_INTERIOR)
8392     {
8393         CORDB_ADDRESS fixed_obj = 0;
8394         HRESULT hr = dsc->pWalker->mHeap.ListNearObjects((CORDB_ADDRESS)obj, NULL, &fixed_obj, NULL);
8395
8396         // If we failed...oh well, SOS won't mind.  We'll just report the interior pointer as is.
8397         if (SUCCEEDED(hr))
8398             obj = TO_TADDR(fixed_obj);
8399     }
8400
8401     SOSStackRefData *data = dsc->pWalker->GetNextObject<SOSStackRefData>(dsc);
8402     if (data != NULL)
8403     {
8404         // Report where the object and where it was found.
8405         data->HasRegisterInformation = true;
8406         data->Register = loc.reg;
8407         data->Offset = loc.regOffset;
8408         data->Address = TO_CDADDR(addr);
8409         data->Object = TO_CDADDR(obj);
8410         data->Flags = flags;
8411
8412         // Report the frame that the data came from.
8413         data->StackPointer = TO_CDADDR(dsc->sp);
8414
8415         if (dsc->pFrame)
8416         {
8417             data->SourceType = SOS_StackSourceFrame;
8418             data->Source = dac_cast<PTR_Frame>(dsc->pFrame).GetAddr();
8419         }
8420         else
8421         {
8422             data->SourceType = SOS_StackSourceIP;
8423             data->Source = TO_CDADDR(dsc->pc);
8424         }
8425     }
8426 }
8427
8428
8429 void DacStackReferenceWalker::GCReportCallbackSOS(PTR_PTR_Object ppObj, ScanContext *sc, uint32_t flags)
8430 {
8431     DacScanContext *dsc = (DacScanContext*)sc;
8432     CLRDATA_ADDRESS obj = dsc->pWalker->ReadPointer(ppObj.GetAddr());
8433
8434     if (flags & GC_CALL_INTERIOR)
8435     {
8436         CORDB_ADDRESS fixed_addr = 0;
8437         HRESULT hr = dsc->pWalker->mHeap.ListNearObjects((CORDB_ADDRESS)obj, NULL, &fixed_addr, NULL);
8438
8439         // If we failed...oh well, SOS won't mind.  We'll just report the interior pointer as is.
8440         if (SUCCEEDED(hr))
8441             obj = TO_CDADDR(fixed_addr);
8442     }
8443
8444     SOSStackRefData *data = dsc->pWalker->GetNextObject<SOSStackRefData>(dsc);
8445     if (data != NULL)
8446     {
8447         data->HasRegisterInformation = false;
8448         data->Register = 0;
8449         data->Offset = 0;
8450         data->Address = ppObj.GetAddr();
8451         data->Object = obj;
8452         data->Flags = flags;
8453         data->StackPointer = TO_CDADDR(dsc->sp);
8454
8455         if (dsc->pFrame)
8456         {
8457             data->SourceType = SOS_StackSourceFrame;
8458             data->Source = dac_cast<PTR_Frame>(dsc->pFrame).GetAddr();
8459         }
8460         else
8461         {
8462             data->SourceType = SOS_StackSourceIP;
8463             data->Source = TO_CDADDR(dsc->pc);
8464         }
8465     }
8466 }
8467
8468 StackWalkAction DacStackReferenceWalker::Callback(CrawlFrame *pCF, VOID *pData)
8469 {
8470     //
8471     // KEEP IN SYNC WITH GcStackCrawlCallBack in vm\gcscan.cpp
8472     //
8473
8474     GCCONTEXT *gcctx = (GCCONTEXT*)pData;
8475     DacScanContext *dsc = (DacScanContext*)gcctx->sc;
8476
8477     MethodDesc *pMD = pCF->GetFunction();
8478     gcctx->sc->pMD = pMD;
8479
8480     PREGDISPLAY pRD = pCF->GetRegisterSet();
8481     dsc->sp = (TADDR)GetRegdisplaySP(pRD);;
8482     dsc->pc = PCODEToPINSTR(GetControlPC(pRD));
8483
8484     ResetPointerHolder<CrawlFrame*> rph(&gcctx->cf);
8485     gcctx->cf = pCF;
8486
8487     bool fReportGCReferences = true;
8488 #if defined(WIN64EXCEPTIONS)
8489     // On Win64 and ARM, we may have unwound this crawlFrame and thus, shouldn't report the invalid
8490     // references it may contain.
8491     // todo.
8492     fReportGCReferences = pCF->ShouldCrawlframeReportGCReferences();
8493 #endif // defined(WIN64EXCEPTIONS)
8494
8495     Frame *pFrame = ((DacScanContext*)gcctx->sc)->pFrame = pCF->GetFrame();
8496
8497     EX_TRY
8498     {
8499         if (fReportGCReferences)
8500         {
8501             if (pCF->IsFrameless())
8502             {
8503                 ICodeManager * pCM = pCF->GetCodeManager();
8504                 _ASSERTE(pCM != NULL);
8505
8506                 unsigned flags = pCF->GetCodeManagerFlags();
8507
8508                 pCM->EnumGcRefs(pCF->GetRegisterSet(),
8509                                 pCF->GetCodeInfo(),
8510                                 flags,
8511                                 dsc->pEnumFunc,
8512                                 pData);
8513             }
8514             else
8515             {
8516                 pFrame->GcScanRoots(gcctx->f, gcctx->sc);
8517             }
8518         }
8519     }
8520     EX_CATCH
8521     {
8522         SOSStackErrorList *err = new SOSStackErrorList;
8523         err->pNext = NULL;
8524
8525         if (pFrame)
8526         {
8527             err->error.SourceType = SOS_StackSourceFrame;
8528             err->error.Source = dac_cast<PTR_Frame>(pFrame).GetAddr();
8529         }
8530         else
8531         {
8532             err->error.SourceType = SOS_StackSourceIP;
8533             err->error.Source = TO_CDADDR(dsc->pc);
8534         }
8535
8536         if (dsc->pWalker->mErrors == NULL)
8537         {
8538             dsc->pWalker->mErrors = err;
8539         }
8540         else
8541         {
8542             // This exception case should be non-existent.  It only happens when there is either
8543             // a clr!Frame on the callstack which is not properly dac-ized, or when a call down
8544             // EnumGcRefs causes a data read exception.  Since this is so rare, we don't worry
8545             // about making this code very efficient.
8546             SOSStackErrorList *curr = dsc->pWalker->mErrors;
8547             while (curr->pNext)
8548                 curr = curr->pNext;
8549
8550             curr->pNext = err;
8551         }
8552     }
8553     EX_END_CATCH(SwallowAllExceptions)
8554
8555 #if 0
8556     // todo
8557
8558     // If we're executing a LCG dynamic method then we must promote the associated resolver to ensure it
8559     // doesn't get collected and yank the method code out from under us).
8560
8561     // Be careful to only promote the reference -- we can also be called to relocate the reference and
8562     // that can lead to all sorts of problems since we could be racing for the relocation with the long
8563     // weak handle we recover the reference from. Promoting the reference is enough, the handle in the
8564     // reference will be relocated properly as long as we keep it alive till the end of the collection
8565     // as long as the reference is actually maintained by the long weak handle.
8566     if (pMD)
8567     {
8568         BOOL fMaybeCollectibleMethod = TRUE;
8569
8570         // If this is a frameless method then the jitmanager can answer the question of whether
8571         // or not this is LCG simply by looking at the heap where the code lives, however there
8572         // is also the prestub case where we need to explicitly look at the MD for stuff that isn't
8573         // ngen'd
8574         if (pCF->IsFrameless() && pMD->IsLCGMethod())
8575         {
8576             fMaybeCollectibleMethod = ExecutionManager::IsCollectibleMethod(pCF->GetMethodToken());
8577         }
8578
8579         if (fMaybeCollectibleMethod && pMD->IsLCGMethod())
8580         {
8581             PTR_Object obj = OBJECTREFToObject(pMD->AsDynamicMethodDesc()->GetLCGMethodResolver()->GetManagedResolver());
8582             dsc->pWalker->ReportObject(obj);
8583         }
8584         else
8585         {
8586             if (fMaybeCollectibleMethod)
8587             {
8588                 PTR_Object obj = pMD->GetLoaderAllocator()->GetExposedObject();
8589                 dsc->pWalker->ReportObject(obj);
8590             }
8591
8592             if (fReportGCReferences)
8593             {
8594                 GenericParamContextType paramContextType = GENERIC_PARAM_CONTEXT_NONE;
8595
8596                 if (pCF->IsFrameless())
8597                 {
8598                     // We need to grab the Context Type here because there are cases where the MethodDesc
8599                     // is shared, and thus indicates there should be an instantion argument, but the JIT
8600                     // was still allowed to optimize it away and we won't grab it below because we're not
8601                     // reporting any references from this frame.
8602                     paramContextType = pCF->GetCodeManager()->GetParamContextType(pCF->GetRegisterSet(), pCF->GetCodeInfo());
8603                 }
8604                 else
8605                 {
8606                     if (pMD->RequiresInstMethodDescArg())
8607                         paramContextType = GENERIC_PARAM_CONTEXT_METHODDESC;
8608                     else if (pMD->RequiresInstMethodTableArg())
8609                         paramContextType = GENERIC_PARAM_CONTEXT_METHODTABLE;
8610                 }
8611
8612                 // Handle the case where the method is a static shared generic method and we need to keep the type of the generic parameters alive
8613                 if (paramContextType == GENERIC_PARAM_CONTEXT_METHODDESC)
8614                 {
8615                     MethodDesc *pMDReal = dac_cast<PTR_MethodDesc>(pCF->GetParamTypeArg());
8616                     _ASSERTE((pMDReal != NULL) || !pCF->IsFrameless());
8617                     if (pMDReal != NULL)
8618                     {
8619                         PTR_Object obj = pMDReal->GetLoaderAllocator()->GetExposedObject();
8620                         dsc->pWalker->ReportObject(obj);
8621                     }
8622                 }
8623                 else if (paramContextType == GENERIC_PARAM_CONTEXT_METHODTABLE)
8624                 {
8625                     MethodTable *pMTReal = dac_cast<PTR_MethodTable>(pCF->GetParamTypeArg());
8626                     _ASSERTE((pMTReal != NULL) || !pCF->IsFrameless());
8627                     if (pMTReal != NULL)
8628                     {
8629                         PTR_Object obj = pMTReal->GetLoaderAllocator()->GetExposedObject();
8630                         dsc->pWalker->ReportObject(obj);
8631                     }
8632                 }
8633             }
8634         }
8635     }
8636 #endif
8637
8638     return SWA_CONTINUE;
8639 }
8640
8641
8642 DacStackReferenceErrorEnum::DacStackReferenceErrorEnum(DacStackReferenceWalker *pEnum, SOSStackErrorList *pErrors)
8643     : mEnum(pEnum), mHead(pErrors), mCurr(pErrors)
8644 {
8645     _ASSERTE(mEnum);
8646
8647     if (mHead != NULL)
8648         mEnum->AddRef();
8649 }
8650
8651 DacStackReferenceErrorEnum::~DacStackReferenceErrorEnum()
8652 {
8653     if (mHead)
8654         mEnum->Release();
8655 }
8656
8657 HRESULT DacStackReferenceErrorEnum::Skip(unsigned int count)
8658 {
8659     unsigned int i = 0;
8660     for (i = 0; i < count && mCurr; ++i)
8661         mCurr = mCurr->pNext;
8662
8663     return i < count ? S_FALSE : S_OK;
8664 }
8665
8666 HRESULT DacStackReferenceErrorEnum::Reset()
8667 {
8668     mCurr = mHead;
8669
8670     return S_OK;
8671 }
8672
8673 HRESULT DacStackReferenceErrorEnum::GetCount(unsigned int *pCount)
8674 {
8675     SOSStackErrorList *curr = mHead;
8676     unsigned int count = 0;
8677
8678     while (curr)
8679     {
8680         curr = curr->pNext;
8681         count++;
8682     }
8683
8684     *pCount = count;
8685     return S_OK;
8686 }
8687
8688 HRESULT DacStackReferenceErrorEnum::Next(unsigned int count, SOSStackRefError ref[], unsigned int *pFetched)
8689 {
8690     if (pFetched == NULL || ref == NULL)
8691         return E_POINTER;
8692
8693     unsigned int i;
8694     for (i = 0; i < count && mCurr; ++i, mCurr = mCurr->pNext)
8695         ref[i] = mCurr->error;
8696
8697     *pFetched = i;
8698     return i < count ? S_FALSE : S_OK;
8699 }