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