Make dumpmd work with tiered jitting. Now displays previous code addresses (#13805)
[platform/upstream/coreclr.git] / src / ToolBox / SOS / Strike / util.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 // ==++==
6 // 
7
8 // 
9 // ==--==
10 #include "sos.h"
11 #include "disasm.h"
12 #include <dbghelp.h>
13
14 #include "corhdr.h"
15 #include "cor.h"
16 #include "dacprivate.h"
17 #include "sospriv.h"
18 #include "corerror.h"
19 #include "safemath.h"
20
21 #include <psapi.h>
22 #include <cordebug.h>
23 #include <xcordebug.h>
24 #include <metahost.h>
25 #include <mscoree.h>
26 #include <tchar.h>
27 #include "debugshim.h"
28
29 #ifdef FEATURE_PAL
30 #include "datatarget.h"
31 #endif // FEATURE_PAL
32 #include "gcinfo.h"
33
34 #ifndef STRESS_LOG
35 #define STRESS_LOG
36 #endif // STRESS_LOG
37 #define STRESS_LOG_READONLY
38 #include "stresslog.h"
39
40 #ifndef FEATURE_PAL
41 #define MAX_SYMBOL_LEN 4096
42 #define SYM_BUFFER_SIZE (sizeof(IMAGEHLP_SYMBOL) + MAX_SYMBOL_LEN)
43 char symBuffer[SYM_BUFFER_SIZE];
44 PIMAGEHLP_SYMBOL sym = (PIMAGEHLP_SYMBOL) symBuffer;
45 #else
46 #include <sys/stat.h>
47 #include <coreruncommon.h>
48 #include <dlfcn.h>
49 #endif // !FEATURE_PAL
50
51 #include <coreclrhost.h>
52 #include <set>
53
54 LoadSymbolsForModuleDelegate SymbolReader::loadSymbolsForModuleDelegate;
55 DisposeDelegate SymbolReader::disposeDelegate;
56 ResolveSequencePointDelegate SymbolReader::resolveSequencePointDelegate;
57 GetLocalVariableName SymbolReader::getLocalVariableNameDelegate;
58 GetLineByILOffsetDelegate SymbolReader::getLineByILOffsetDelegate;
59
60 const char * const CorElementTypeName[ELEMENT_TYPE_MAX]=
61 {
62 #define TYPEINFO(e,ns,c,s,g,ia,ip,if,im,gv)    c,
63 #include "cortypeinfo.h"
64 #undef TYPEINFO
65 };
66
67 const char * const CorElementTypeNamespace[ELEMENT_TYPE_MAX]=
68 {
69 #define TYPEINFO(e,ns,c,s,g,ia,ip,if,im,gv)    ns,
70 #include "cortypeinfo.h"
71 #undef TYPEINFO
72 };
73
74 IXCLRDataProcess *g_clrData = NULL;
75 ISOSDacInterface *g_sos = NULL;
76 ICorDebugProcess *g_pCorDebugProcess = NULL;
77
78 #ifndef IfFailRet
79 #define IfFailRet(EXPR) do { Status = (EXPR); if(FAILED(Status)) { return (Status); } } while (0)
80 #endif
81
82 #ifndef IfFailGoto
83 #define IfFailGoto(EXPR, label) do { Status = (EXPR); if(FAILED(Status)) { goto label; } } while (0)
84 #endif // IfFailGoto
85
86 #ifndef IfFailGo
87 #define IfFailGo(EXPR) IfFailGoto(EXPR, Error)
88 #endif // IfFailGo
89
90 // Max number of reverted rejit versions that !dumpmd and !ip2md will print
91 const UINT kcMaxRevertedRejitData   = 10;
92 const UINT kcMaxTieredVersions      = 10;
93 #ifndef FEATURE_PAL
94
95 // ensure we always allocate on the process heap
96 void* __cdecl operator new(size_t size) throw()
97 { return HeapAlloc(GetProcessHeap(), 0, size); }
98 void __cdecl operator delete(void* pObj) throw()
99 { HeapFree(GetProcessHeap(), 0, pObj); }
100
101 void* __cdecl operator new[](size_t size) throw()
102 { return HeapAlloc(GetProcessHeap(), 0, size); }
103 void __cdecl operator delete[](void* pObj) throw()
104 { HeapFree(GetProcessHeap(), 0, pObj); }
105
106 /**********************************************************************\
107 * Here we define types and functions that support custom COM           *
108 * activation rules, as defined by the CIOptions enum.                  *
109 *                                                                      *
110 \**********************************************************************/
111
112 typedef unsigned __int64 QWORD;
113
114 namespace com_activation
115 {
116     //
117     // Forward declarations for the implementation methods
118     //
119
120     HRESULT CreateInstanceCustomImpl(
121                             REFCLSID clsid,
122                             REFIID   iid,
123                             LPCWSTR  dllName,
124                             CIOptions cciOptions,
125                             void** ppItf);
126     HRESULT ClrCreateInstance(
127                             REFCLSID clsid, 
128                             REFIID iid, 
129                             LPCWSTR dllName,
130                             CIOptions cciOptions, 
131                             void** ppItf);
132     HRESULT CreateInstanceFromPath(
133                             REFCLSID clsid, 
134                             REFIID iid, 
135                             LPCWSTR path, 
136                             void** ppItf);
137     BOOL GetPathFromModule(
138                             HMODULE hModule, 
139                             __in_ecount(cFqPath) LPWSTR fqPath,
140                             DWORD  cFqPath);
141     HRESULT PickClrRuntimeInfo(
142                             ICLRMetaHost *pMetaHost,
143                             CIOptions cciOptions,
144                             ICLRRuntimeInfo** ppClr);
145     QWORD VerString2Qword(LPCWSTR vStr);
146     void CleanupClsidHmodMap();
147
148     // Helper structures for defining the CLSID -> HMODULE hash table we
149     // use for caching already activated objects
150     class hash_compareGUID
151     {
152     public:
153         static const size_t bucket_size = 4;
154         static const size_t min_buckets = 8;
155         hash_compareGUID()
156         { }
157
158         size_t operator( )(const GUID& _Key) const
159         {
160             DWORD *pdw = (DWORD*)&_Key;
161             return (size_t)(pdw[0] ^ pdw[1] ^ pdw[2] ^ pdw[3]);
162         }
163
164         bool operator( )(const GUID& _Key1, const GUID& _Key2) const
165         { return memcmp(&_Key1, &_Key2, sizeof(GUID)) == -1; }
166     };
167
168     static std::unordered_map<GUID, HMODULE, hash_compareGUID> *g_pClsidHmodMap = NULL;
169
170
171
172 /**********************************************************************\
173 * Routine Description:                                                 *
174 *                                                                      *
175 * CreateInstanceCustomImpl() provides a way to activate a COM object   *
176 * w/o triggering the FeatureOnDemand dialog. In order to do this we    *
177 * must avoid using  the CoCreateInstance() API, which, on a machine    *
178 * with v4+ installed and w/o v2, would trigger this.                   *
179 * CreateInstanceCustom() activates the requested COM object according  *
180 * to the specified passed in CIOptions, in the following order         *
181 * (skipping the steps not enabled in the CIOptions flags passed in):   *
182 *    1. Attempt to activate the COM object using a framework install:  *
183 *       a. If the debugger machine has a V4+ shell shim use the shim   *
184 *          to activate the object                                      *
185 *       b. Otherwise simply call CoCreateInstance                      *
186 *    2. If unsuccessful attempt to activate looking for the dllName in *
187 *       the same folder as the DAC was loaded from                     *
188 *    3. If unsuccessful attempt to activate the COM object looking in  *
189 *       every path specified in the debugger's .exepath and .sympath   *
190 \**********************************************************************/
191 HRESULT CreateInstanceCustomImpl(
192                         REFCLSID clsid,
193                         REFIID   iid,
194                         LPCWSTR  dllName,
195                         CIOptions cciOptions,
196                         void** ppItf)
197 {
198     _ASSERTE(ppItf != NULL);
199
200     if (ppItf == NULL)
201         return E_POINTER;
202
203     WCHAR wszClsid[64] = W("<CLSID>");
204
205     // Step 1: Attempt activation using an installed runtime
206     if ((cciOptions & cciFxMask) != 0)
207     {
208         CIOptions opt = cciOptions & cciFxMask;
209         if (SUCCEEDED(ClrCreateInstance(clsid, iid, dllName, opt, ppItf)))
210             return S_OK;
211
212         ExtDbgOut("Failed to instantiate {%ls} from installed .NET framework locations.\n", wszClsid);
213     }
214
215     if ((cciOptions & cciDbiColocated) != 0)
216     {
217         // if we institute a way to retrieve the module for the current DBI we
218         // can perform the same steps as for the DAC.
219     }
220
221     // Step 2: attempt activation using the folder the DAC was loaded from
222     if ((cciOptions & cciDacColocated) != 0)
223     {
224         _ASSERTE(dllName != NULL);
225         HMODULE hDac = NULL;
226         WCHAR path[MAX_LONGPATH];
227
228         if (SUCCEEDED(g_sos->GetDacModuleHandle(&hDac))
229             && GetPathFromModule(hDac, path, _countof(path)))
230         {
231             // build the fully qualified file name and attempt instantiation
232             if (wcscat_s(path, dllName) == 0
233                 && SUCCEEDED(CreateInstanceFromPath(clsid, iid, path, ppItf)))
234             {
235                 return S_OK;
236             }
237         }
238
239         ExtDbgOut("Failed to instantiate {%ls} from DAC location.\n", wszClsid);
240     }
241
242     // Step 3: attempt activation using the debugger's .exepath and .sympath
243     if ((cciOptions & cciDbgPath) != 0)
244     {
245         _ASSERTE(dllName != NULL);
246
247         ToRelease<IDebugSymbols3> spSym3(NULL);
248         HRESULT hr = g_ExtSymbols->QueryInterface(__uuidof(IDebugSymbols3), (void**)&spSym3);
249         if (FAILED(hr))
250         {
251             ExtDbgOut("Unable to query IDebugSymbol3 HRESULT=0x%x.\n", hr);
252             goto ErrDbgPath;
253         }
254
255         typedef HRESULT (__stdcall IDebugSymbols3::*GetPathFunc)(LPWSTR , ULONG, ULONG*);
256
257         {
258             // Handle both the image path and the symbol path
259             GetPathFunc rgGetPathFuncs[] = 
260                 { &IDebugSymbols3::GetImagePathWide, &IDebugSymbols3::GetSymbolPathWide };
261
262             for (int i = 0; i < _countof(rgGetPathFuncs); ++i)
263             {
264                 ULONG pathSize = 0;
265
266                 // get the path buffer size
267                 if ((spSym3.GetPtr()->*rgGetPathFuncs[i])(NULL, 0, &pathSize) != S_OK)
268                 {
269                     continue;
270                 }
271
272                 ArrayHolder<WCHAR> imgPath = new WCHAR[pathSize+MAX_LONGPATH+1];
273                 if (imgPath == NULL)
274                 {
275                     continue;
276                 }
277
278                 // actually get the path
279                 if ((spSym3.GetPtr()->*rgGetPathFuncs[i])(imgPath, pathSize, NULL) != S_OK)
280                 {
281                     continue;
282                 }
283
284                 LPWSTR ctx;
285                 LPCWSTR pathElem = wcstok_s(imgPath, W(";"), &ctx);
286                 while (pathElem != NULL)
287                 {
288                     WCHAR fullName[MAX_LONGPATH];
289                     wcscpy_s(fullName, _countof(fullName), pathElem);
290                     if (wcscat_s(fullName, W("\\")) == 0 && wcscat_s(fullName, dllName) == 0)
291                     {
292                         if (SUCCEEDED(CreateInstanceFromPath(clsid, iid, fullName, ppItf)))
293                         {
294                             return S_OK;
295                         }
296                     }
297
298                     pathElem = wcstok_s(NULL, W(";"), &ctx);
299                 }
300             }
301         }
302
303     ErrDbgPath:
304         ExtDbgOut("Failed to instantiate {%ls} from debugger's image path.\n", wszClsid);
305     }
306
307     return REGDB_E_CLASSNOTREG;
308 }
309
310
311 #ifdef _MSC_VER
312 // SOS is essentially single-threaded. ignore "construction of local static object is not thread-safe"
313 #pragma warning(push)
314 #pragma warning(disable:4640)
315 #endif // _MSC_VER
316
317
318 /**********************************************************************\
319 * Routine Description:                                                 *
320 *                                                                      *
321 * ClrCreateInstance() attempts to activate a COM object using an       *
322 * installed framework:                                                 *
323 *    a. If the debugger machine has a V4+ shell shim use the shim to   *
324 *        activate the object                                           *
325 *    b. Otherwise simply call CoCreateInstance                         *
326 \**********************************************************************/
327 HRESULT ClrCreateInstance(
328                         REFCLSID clsid, 
329                         REFIID iid,
330                         LPCWSTR dllName,
331                         CIOptions cciOptions, 
332                         void** ppItf)
333 {
334     _ASSERTE((cciOptions & ~cciFxMask) == 0 && (cciOptions & cciFxMask) != 0);
335     HRESULT Status = S_OK;
336
337     static CIOptions prevOpt = 0;
338     static HRESULT   prevHr = S_OK;
339
340     // if we already tried to use NetFx install and failed don't try it again
341     if (prevOpt == cciOptions && FAILED(prevHr))
342     {
343         return prevHr;
344     }
345
346     prevOpt = cciOptions;
347
348     // first try usig the metahost API:
349     HRESULT (__stdcall *pfnCLRCreateInstance)(REFCLSID  clsid, REFIID riid, LPVOID * ppInterface) = NULL;
350     HMODULE hMscoree = NULL;
351
352     // if there's a v4+ shim on the debugger machine
353     if (GetProcAddressT("CLRCreateInstance", W("mscoree.dll"), &pfnCLRCreateInstance, &hMscoree))
354     {
355         // attempt to create an ICLRMetaHost instance
356         ToRelease<ICLRMetaHost> spMH;
357         Status = pfnCLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (void**)&spMH);
358         if (Status == E_NOTIMPL)
359         {
360             // E_NOTIMPL means we have a v4 aware mscoree but no v4+ framework
361             IfFailGo( CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, ppItf) );
362         }
363         else
364         {
365             IfFailGo( Status );
366
367             // pick a runtime according to cciOptions
368             ToRelease<ICLRRuntimeInfo> spClr;
369             IfFailGo( PickClrRuntimeInfo(spMH, cciOptions, &spClr) );
370
371             // activate the COM object
372             Status = spClr->GetInterface(clsid, iid, ppItf);
373
374             if (FAILED(Status) && dllName)
375             {
376                 // if we have a v4+ runtime that does not have the fix to activate the requested CLSID
377                 // try activating with the path
378                 WCHAR clrDir[MAX_LONGPATH]; 
379                 DWORD cchClrDir = _countof(clrDir);
380                 IfFailGo( spClr->GetRuntimeDirectory(clrDir, &cchClrDir) );
381                 IfFailGo( wcscat_s(clrDir, dllName) == 0 ? S_OK : E_FAIL  );
382                 IfFailGo( CreateInstanceFromPath(clsid, iid, clrDir, ppItf) );
383             }
384         }
385     }
386     else
387     {
388         // otherwise fallback to regular COM activation
389         IfFailGo( CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, ppItf) );
390     }
391
392 Error:
393     if (hMscoree != NULL)
394     {
395         FreeLibrary(hMscoree);
396     }
397
398     // remember if we succeeded or failed
399     prevHr = Status;
400
401     return Status;
402 }
403
404 #ifdef _MSC_VER
405 #pragma warning(pop)
406 #endif // _MSC_VER
407
408
409 /**********************************************************************\
410 * Routine Description:                                                 *
411 *                                                                      *
412 * CreateInstanceFromPath() instantiates a COM object using a passed in *
413 * fully-qualified path and a CLSID.                                    *
414 *                                                                      *
415 * Note:                                                                *
416 *                                                                      *
417 * It uses a unordered_map to cache the mapping between a CLSID and the      *
418 * HMODULE that is successfully used to activate the CLSID from. When   *
419 * SOS is unloaded (in DebugExtensionUninitialize()) we call            *
420 * FreeLibrary() for all cached HMODULEs.                               *
421 \**********************************************************************/
422 HRESULT CreateInstanceFromPath(
423                         REFCLSID clsid, 
424                         REFIID iid, 
425                         LPCWSTR path, 
426                         void** ppItf)
427 {
428     HRESULT Status = S_OK;
429     HRESULT (__stdcall *pfnDllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID *ppv) = NULL;
430
431     HMODULE hmod = NULL;
432
433     if (g_pClsidHmodMap == NULL)
434     {
435         g_pClsidHmodMap = new std::unordered_map<GUID, HMODULE, hash_compareGUID>();
436         OnUnloadTask::Register(CleanupClsidHmodMap);
437     }
438
439     auto it = g_pClsidHmodMap->find(clsid);
440     if (it != g_pClsidHmodMap->end())
441         hmod = it->second;
442
443     if (!GetProcAddressT("DllGetClassObject", path, &pfnDllGetClassObject, &hmod))
444         return REGDB_E_CLASSNOTREG;
445
446     ToRelease<IClassFactory> pFactory;
447     IfFailGo(pfnDllGetClassObject(clsid, IID_IClassFactory, (void**)&pFactory));
448
449     IfFailGo(pFactory->CreateInstance(NULL, iid, ppItf));
450
451     // only cache the HMODULE if we successfully created the COM object
452     (*g_pClsidHmodMap)[clsid] = hmod;
453
454     return S_OK;
455
456 Error:
457     if (hmod != NULL)
458         FreeLibrary(hmod);
459
460     return Status;
461 }
462
463
464 /**********************************************************************\
465 * Routine Description:                                                 *
466 *                                                                      *
467 * CleanupClsidHmodMap() cleans up the CLSID -> HMODULE map used to     *
468 * cache successful activations from specific paths. This is registered *
469 * as an OnUnloadTask in CreateInstanceFromPath(), and executes when    *
470 * SOS is unloaded, in DebugExtensionUninitialize().                    *
471 \**********************************************************************/
472 void CleanupClsidHmodMap()
473 {
474     if (g_pClsidHmodMap != NULL)
475     {
476         for (auto it = g_pClsidHmodMap->begin(); it != g_pClsidHmodMap->end(); ++it)
477         {
478             _ASSERTE(it->second != NULL);
479             FreeLibrary(it->second);
480         }
481
482         delete g_pClsidHmodMap;
483         g_pClsidHmodMap = NULL;
484     }
485 }
486
487 /**********************************************************************\
488 * Routine Description:                                                 *
489 *                                                                      *
490 * PickClrRuntimeInfo() selects on CLR runtime from the ones installed  *
491 * on the debugger machine. If cciFxAny is specified in cciOptions it   *
492 * simply returns the first runtime enumerated by the metahost          *
493 * interface. If cciLatestFx is specified we pick the runtime with the  *
494 * highest version (parsing the string returned from                    *
495 * ICLRRuntimeInfo::GetVersionString().                                 *
496 \**********************************************************************/
497 HRESULT PickClrRuntimeInfo(
498                         ICLRMetaHost *pMetaHost,
499                         CIOptions cciOptions,
500                         ICLRRuntimeInfo** ppClr)
501 {
502     if (ppClr == NULL)
503         return E_POINTER;
504
505     // only support "Any framework" and "latest framework"
506     if (cciOptions != cciAnyFx && cciOptions != cciLatestFx)
507         return E_INVALIDARG;
508
509     HRESULT Status = S_OK;
510     *ppClr = NULL;
511
512     // get the CLRRuntime enumerator
513     ToRelease<IEnumUnknown> spClrsEnum;
514     IfFailRet(pMetaHost->EnumerateInstalledRuntimes(&spClrsEnum));
515
516     ToRelease<ICLRRuntimeInfo> spChosenClr;
517     QWORD verMax = 0;
518
519     int cntClr = 0;
520     while (1)
521     {
522         // retrieve the next ICLRRuntimeInfo
523         ULONG cnt;
524         ToRelease<IUnknown> spClrUnk;
525         if (spClrsEnum->Next(1, &spClrUnk, &cnt) != S_OK || cnt != 1)
526             break;
527
528         ToRelease<ICLRRuntimeInfo> spClr;
529         BOOL bLoadable = FALSE;
530         // ignore un-loadable runtimes
531         if (FAILED(spClrUnk->QueryInterface(IID_ICLRRuntimeInfo, (void**)&spClr))
532             || FAILED(spClr->IsLoadable(&bLoadable))
533             || !bLoadable)
534         {
535             continue;
536         }
537
538         WCHAR vStr[128];
539         DWORD cStr = _countof(vStr);
540         if (FAILED(spClr->GetVersionString(vStr, &cStr)))
541             continue;
542
543         ++cntClr;
544
545         if ((cciOptions & cciAnyFx) != 0)
546         {
547             spChosenClr = spClr.Detach();
548             break;
549         }
550
551         QWORD ver = VerString2Qword(vStr);
552         if ((cciOptions & cciLatestFx) != 0)
553         {
554             if (ver > verMax)
555             {
556                 verMax = ver;
557                 spChosenClr = spClr.Detach();
558             }
559         }
560     }
561
562     if (cntClr == 0 || spChosenClr == NULL)
563     {
564         *ppClr = NULL;
565         return E_NOINTERFACE;
566     }
567     else
568     {
569         *ppClr = spChosenClr.Detach();
570         return S_OK;
571     }
572 }
573
574
575 /**********************************************************************\
576 * Routine Description:                                                 *
577 *                                                                      *
578 * VerString2Qword() parses a string as returned from                   *
579 * ICLRRuntimeInfo::GetVersionString() into a QWORD, assuming every     *
580 * numeric element is a WORD portion in the QWORD.                      *
581 \**********************************************************************/
582 QWORD VerString2Qword(LPCWSTR vStr)
583 {
584     _ASSERTE(vStr[0] == L'v' || vStr[0] == L'V');
585     QWORD result = 0;
586
587     DWORD v1, v2, v3;
588     if (swscanf_s(vStr+1, W("%d.%d.%d"), &v1, &v2, &v3) == 3)
589     {
590         result = ((QWORD)v1 << 48) | ((QWORD)v2 << 32) | ((QWORD)v3 << 16);
591     }
592     else if (swscanf_s(vStr+1, W("%d.%d"), &v1, &v2) == 2)
593     {
594         result = ((QWORD)v1 << 48) | ((QWORD)v2 << 32);
595     }
596     else if (swscanf_s(vStr+1, W("%d"), &v1) == 1)
597     {
598         result = ((QWORD)v1 << 48);
599     }
600
601     return result;
602 }
603
604
605 /**********************************************************************\
606 * Routine Description:                                                 *
607 *                                                                      *
608 * GetPathFromModule() returns the name of the folder containing the    *
609 * file associated with hModule.                                        *
610  \**********************************************************************/
611 BOOL GetPathFromModule(
612                         HMODULE hModule, 
613                         __in_ecount(cFqPath) LPWSTR fqPath, 
614                         DWORD  cFqPath)
615 {
616     int len = GetModuleFileNameW(hModule, fqPath, cFqPath);
617     if (len == 0 || len == cFqPath)
618         return FALSE;
619
620     WCHAR *pLastSep = _wcsrchr(fqPath, DIRECTORY_SEPARATOR_CHAR_W);
621     if (pLastSep == NULL || pLastSep+1 >= fqPath+cFqPath)
622         return FALSE;
623
624     *(pLastSep+1) = L'\0';
625
626     return TRUE;
627 }
628
629 }
630
631 /**********************************************************************\
632 * Routine Description:                                                 *
633 *                                                                      *
634 * CreateInstanceCustom() provides a way to activate a COM object w/o   *
635 * triggering the FeatureOnDemand dialog. In order to do this we        *
636 * must avoid using  the CoCreateInstance() API, which, on a machine    *
637 * with v4+ installed and w/o v2, would trigger this.                   *
638 * CreateInstanceCustom() activates the requested COM object according  *
639 * to the specified passed in CIOptions, in the following order         *
640 * (skipping the steps not enabled in the CIOptions flags passed in):   *
641 *    1. Attempt to activate the COM object using a framework install:  *
642 *       a. If the debugger machine has a V4+ shell shim use the shim   *
643 *          to activate the object                                      *
644 *       b. Otherwise simply call CoCreateInstance                      *
645 *    2. If unsuccessful attempt to activate looking for the dllName in *
646 *       the same folder as the DAC was loaded from                     *
647 *    3. If unsuccessful attempt to activate the COM object looking in  *
648 *       every path specified in the debugger's .exepath and .sympath   *
649 \**********************************************************************/
650 HRESULT CreateInstanceCustom(
651                         REFCLSID clsid,
652                         REFIID   iid,
653                         LPCWSTR  dllName,
654                         CIOptions cciOptions,
655                         void** ppItf)
656 {
657     return com_activation::CreateInstanceCustomImpl(clsid, iid, dllName, cciOptions, ppItf);
658 }
659
660
661
662
663 /**********************************************************************\
664 * Routine Description:                                                 *
665 *                                                                      *
666 *    This function is called to get the memory address given a symbol  *  
667 *    name.  It handles difference in symbol name between ntsd and      *
668 *    windbg.                                                           *
669 *                                                                      *
670 \**********************************************************************/
671 DWORD_PTR GetValueFromExpression (___in __in_z const char *const instr)
672 {
673     ULONG64 dwAddr;
674     const char *str = instr;
675     char name[256];
676
677     dwAddr = 0;
678     HRESULT hr = g_ExtSymbols->GetOffsetByName (str, &dwAddr);
679     if (SUCCEEDED(hr))
680         return (DWORD_PTR)dwAddr;
681     else if (hr == S_FALSE && dwAddr)
682         return (DWORD_PTR)dwAddr;
683
684     strcpy_s (name, _countof(name), str);
685     char *ptr;
686     if ((ptr = strstr (name, "__")) != NULL)
687     {
688         ptr[0] = ':';
689         ptr[1] = ':';
690         ptr += 2;
691         while ((ptr = strstr(ptr, "__")) != NULL)
692         {
693             ptr[0] = ':';
694             ptr[1] = ':';
695             ptr += 2;
696         }
697         dwAddr = 0;
698         hr = g_ExtSymbols->GetOffsetByName (name, &dwAddr);
699         if (SUCCEEDED(hr))
700             return (DWORD_PTR)dwAddr;
701         else if (hr == S_FALSE && dwAddr)
702             return (DWORD_PTR)dwAddr;
703     }
704     else if ((ptr = strstr (name, "::")) != NULL)
705     {
706         ptr[0] = '_';
707         ptr[1] = '_';
708         ptr += 2;
709         while ((ptr = strstr(ptr, "::")) != NULL)
710         {
711             ptr[0] = '_';
712             ptr[1] = '_';
713             ptr += 2;
714         }
715         dwAddr = 0;
716         hr = g_ExtSymbols->GetOffsetByName (name, &dwAddr);
717         if (SUCCEEDED(hr))
718             return (DWORD_PTR)dwAddr;
719         else if (hr == S_FALSE && dwAddr)
720             return (DWORD_PTR)dwAddr;
721     }
722     return 0;
723 }
724
725 #endif // FEATURE_PAL
726
727 ModuleInfo moduleInfo[MSCOREND] = {{0,FALSE,0},{0,FALSE,0},{0,FALSE,0}};
728
729 void ReportOOM()
730 {
731     ExtOut("SOS Error: Out of memory\n");
732 }
733
734 HRESULT CheckEEDll()
735 {
736 #ifndef FEATURE_PAL
737     VS_FIXEDFILEINFO ee = {};
738
739     static VS_FIXEDFILEINFO sos = {};
740     static BOOL sosDataInit = FALSE;
741     
742     BOOL result = GetEEVersion(&ee);
743     if (result && !sosDataInit)
744     {
745         result = GetSOSVersion(&sos);
746         
747         if (result)
748             sosDataInit = TRUE;
749     }
750
751     // We will ignore errors because it's possible sos is being loaded before CLR.
752     if (result)
753     {
754         if ((ee.dwFileVersionMS != sos.dwFileVersionMS) || (ee.dwFileVersionLS != sos.dwFileVersionLS))
755         {
756             ExtOut("The version of SOS does not match the version of CLR you are debugging.  Please\n");
757             ExtOut("load the matching version of SOS for the version of CLR you are debugging.\n");
758             ExtOut("CLR Version: %u.%u.%u.%u\n",
759                    HIWORD(ee.dwFileVersionMS),
760                    LOWORD(ee.dwFileVersionMS),
761                    HIWORD(ee.dwFileVersionLS),
762                    LOWORD(ee.dwFileVersionLS));
763
764             ExtOut("SOS Version: %u.%u.%u.%u\n",
765                    HIWORD(sos.dwFileVersionMS),
766                    LOWORD(sos.dwFileVersionMS),
767                    HIWORD(sos.dwFileVersionLS),
768                    LOWORD(sos.dwFileVersionLS));
769         }
770     }
771
772     DEBUG_MODULE_PARAMETERS Params;
773             
774     // Do we have clr.dll
775     if (moduleInfo[MSCORWKS].baseAddr == 0)
776     {
777         g_ExtSymbols->GetModuleByModuleName (MAIN_CLR_MODULE_NAME_A,0,NULL,
778                                              &moduleInfo[MSCORWKS].baseAddr);
779         if (moduleInfo[MSCORWKS].baseAddr != 0 && moduleInfo[MSCORWKS].hasPdb == FALSE)
780         {
781             g_ExtSymbols->GetModuleParameters (1, &moduleInfo[MSCORWKS].baseAddr, 0, &Params);
782             if (Params.SymbolType == SymDeferred)
783             {
784                 g_ExtSymbols->Reload("/f " MAIN_CLR_DLL_NAME_A);
785                 g_ExtSymbols->GetModuleParameters (1, &moduleInfo[MSCORWKS].baseAddr, 0, &Params);
786             }
787
788             if (Params.SymbolType == SymPdb || Params.SymbolType == SymDia)
789             {
790                 moduleInfo[MSCORWKS].hasPdb = TRUE;
791             }
792
793             moduleInfo[MSCORWKS].size = Params.Size;
794         }
795         if (moduleInfo[MSCORWKS].baseAddr != 0 && moduleInfo[MSCORWKS].hasPdb == FALSE)
796             ExtOut("PDB symbol for clr.dll not loaded\n");
797     }
798     
799     return (moduleInfo[MSCORWKS].baseAddr != 0) ? S_OK : E_FAIL;
800 #else
801     return S_OK;
802 #endif // FEATURE_PAL
803 }
804
805 EEFLAVOR GetEEFlavor ()
806 {
807 #ifdef FEATURE_PAL
808     return MSCORWKS;
809 #else // FEATUER_PAL
810     EEFLAVOR flavor = UNKNOWNEE;    
811     
812     if (SUCCEEDED(g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A,0,NULL,NULL))) {
813         flavor = MSCORWKS;
814     }
815     return flavor;
816 #endif // FEATURE_PAL else
817 }
818
819 BOOL IsDumpFile ()
820 {
821     static int g_fDumpFile = -1;
822     if (g_fDumpFile == -1) {
823         ULONG Class;
824         ULONG Qualifier;
825         g_ExtControl->GetDebuggeeType(&Class,&Qualifier);
826         if (Qualifier >= DEBUG_DUMP_SMALL)
827             g_fDumpFile = 1;
828         else
829             g_fDumpFile = 0;
830     }
831     return g_fDumpFile != 0;
832 }
833
834 BOOL g_InMinidumpSafeMode = FALSE;
835
836 BOOL IsMiniDumpFileNODAC ()
837 {
838 #ifndef FEATURE_PAL
839     ULONG Class;
840     ULONG Qualifier;
841     g_ExtControl->GetDebuggeeType(&Class,&Qualifier);
842     if (Qualifier == DEBUG_DUMP_SMALL) 
843     {
844         g_ExtControl->GetDumpFormatFlags(&Qualifier);
845         if ((Qualifier & DEBUG_FORMAT_USER_SMALL_FULL_MEMORY) == 0)
846         {
847             return TRUE;
848         }
849     }
850     
851 #endif // FEATURE_PAL    
852     return FALSE;
853 }
854
855
856 // We use this predicate to mean the smallest, most restrictive kind of
857 // minidump file. There is no heap dump, only that set of information
858 // gathered to make !clrstack, !threads, !help, !eeversion and !pe work.
859 BOOL IsMiniDumpFile ()
860 {
861 #ifndef FEATURE_PAL
862     // It is okay for this to be static, because although the debugger may debug multiple
863     // managed processes at once, I don't believe multiple dumpfiles of different
864     // types is a scenario to worry about.
865     if (IsMiniDumpFileNODAC())
866     {
867         // Beyond recognizing the dump type above, all we can rely on for this
868         // is a flag set by the user indicating they want a safe mode minidump
869         // experience. This is primarily for testing.
870         return g_InMinidumpSafeMode;
871     }
872     
873 #endif // FEATURE_PAL
874     return FALSE;
875 }
876
877 ULONG DebuggeeType()
878 {
879     static ULONG Class = DEBUG_CLASS_UNINITIALIZED;
880     if (Class == DEBUG_CLASS_UNINITIALIZED) {
881         ULONG Qualifier;
882         g_ExtControl->GetDebuggeeType(&Class,&Qualifier);
883     }
884     return Class;
885 }
886
887 #ifndef FEATURE_PAL
888
889 // Check if a file exist
890 BOOL FileExist (const char *filename)
891 {
892     WIN32_FIND_DATA FindFileData;
893     HANDLE handle = FindFirstFile (filename, &FindFileData);
894     if (handle != INVALID_HANDLE_VALUE) {
895         FindClose (handle);
896         return TRUE;
897     }
898     else
899         return FALSE;
900 }
901
902
903 BOOL FileExist (const WCHAR *filename)
904 {
905     WIN32_FIND_DATAW FindFileData;
906     HANDLE handle = FindFirstFileW (filename, &FindFileData);
907     if (handle != INVALID_HANDLE_VALUE) {
908         FindClose (handle);
909         return TRUE;
910     }
911     else
912         return FALSE;
913 }
914
915 /**********************************************************************\
916 * Routine Description:                                                 *
917 *                                                                      *
918 *    This function is called to find out if a dll is bbt-ized          *  
919 *                                                                      *
920 \**********************************************************************/
921 BOOL IsRetailBuild (size_t base)
922 {
923     IMAGE_DOS_HEADER DosHeader;
924     if (g_ExtData->ReadVirtual(TO_CDADDR(base), &DosHeader, sizeof(DosHeader), NULL) != S_OK)
925         return FALSE;
926     IMAGE_NT_HEADERS32 Header32;
927     if (g_ExtData->ReadVirtual(TO_CDADDR(base + DosHeader.e_lfanew), &Header32, sizeof(Header32), NULL) != S_OK)
928         return FALSE;
929     // If there is no COMHeader, this can not be managed code.
930     if (Header32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress == 0)
931         return FALSE;
932
933     size_t debugDirAddr = base + Header32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
934     size_t nSize = Header32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
935     IMAGE_DEBUG_DIRECTORY debugDir;
936     size_t nbytes = 0;
937     while (nbytes < nSize) {
938         if (g_ExtData->ReadVirtual(TO_CDADDR(debugDirAddr+nbytes), &debugDir, sizeof(debugDir), NULL) != S_OK)
939             return FALSE;
940         if (debugDir.Type == 0xA) {
941             return TRUE;
942         }
943         nbytes += sizeof(debugDir);
944     }
945     return FALSE;
946 }
947
948 #endif // !FEATURE_PAL
949
950 /**********************************************************************\
951 * Routine Description:                                                 *
952 *                                                                      *
953 *    This function is called to read memory from the debugee's         *  
954 *    address space.  If the initial read fails, it attempts to read    *
955 *    only up to the edge of the page containing "offset".              *
956 *                                                                      *
957 \**********************************************************************/
958 BOOL SafeReadMemory (TADDR offset, PVOID lpBuffer, ULONG cb,
959                      PULONG lpcbBytesRead)
960 {
961     BOOL bRet = FALSE;
962
963     bRet = SUCCEEDED(g_ExtData->ReadVirtual(TO_CDADDR(offset), lpBuffer, cb,
964                                             lpcbBytesRead));
965     
966     if (!bRet)
967     {
968         cb   = (ULONG)(NextOSPageAddress(offset) - offset);
969         bRet = SUCCEEDED(g_ExtData->ReadVirtual(TO_CDADDR(offset), lpBuffer, cb,
970                                                 lpcbBytesRead));
971     }
972     return bRet;
973 }
974
975 ULONG OSPageSize ()
976 {
977     static ULONG pageSize = 0;
978     if (pageSize == 0)
979         g_ExtControl->GetPageSize(&pageSize);
980
981     return pageSize;
982 }
983
984 size_t NextOSPageAddress (size_t addr)
985 {
986     size_t pageSize = OSPageSize();
987     return (addr+pageSize)&(~(pageSize-1));
988 }
989
990
991 /**********************************************************************\
992 * Routine Description:                                                 *
993 *                                                                      *
994 *    This function is called to get the address of MethodDesc          *  
995 *    given an ip address                                               *
996 *                                                                      *
997 \**********************************************************************/
998 void IP2MethodDesc (DWORD_PTR IP, DWORD_PTR &methodDesc, JITTypes &jitType,
999                     DWORD_PTR &gcinfoAddr)
1000 {
1001
1002     CLRDATA_ADDRESS EIP = TO_CDADDR(IP);
1003     DacpCodeHeaderData codeHeaderData;
1004     
1005     methodDesc = NULL;
1006     gcinfoAddr = NULL;
1007     
1008     if (codeHeaderData.Request(g_sos, EIP) != S_OK)
1009     {        
1010         return;
1011     }
1012
1013     methodDesc = (DWORD_PTR) codeHeaderData.MethodDescPtr;
1014     jitType = (JITTypes) codeHeaderData.JITType;
1015     gcinfoAddr = (DWORD_PTR) codeHeaderData.GCInfo;    
1016 }
1017
1018 BOOL IsValueField (DacpFieldDescData *pFD)
1019 {
1020     return (pFD->Type == ELEMENT_TYPE_VALUETYPE);
1021 }
1022
1023 void DisplayDataMember (DacpFieldDescData* pFD, DWORD_PTR dwAddr, BOOL fAlign=TRUE)
1024 {
1025     if (dwAddr > 0)
1026     {
1027         // we must have called this function for a "real" (non-zero size) data type
1028         PREFIX_ASSUME(gElementTypeInfo[pFD->Type] != 0);
1029
1030         DWORD_PTR dwTmp = dwAddr;
1031         bool bVTStatic = (pFD->bIsStatic && pFD->Type == ELEMENT_TYPE_VALUETYPE);
1032         
1033         if (gElementTypeInfo[pFD->Type] != NO_SIZE || bVTStatic)
1034         {
1035             union Value
1036             {
1037                 char ch;
1038                 short Short;
1039                 DWORD_PTR ptr;
1040                 int Int;
1041                 unsigned int UInt;
1042                 __int64 Int64;
1043                 unsigned __int64 UInt64;
1044                 float Float;
1045                 double Double;
1046             } value;
1047
1048             ZeroMemory(&value, sizeof(value));
1049             if (bVTStatic)
1050             {
1051                 // static VTypes are boxed
1052                 moveBlock (value, dwTmp, gElementTypeInfo[ELEMENT_TYPE_CLASS]);
1053             }
1054             else
1055             {
1056                 moveBlock (value, dwTmp, gElementTypeInfo[pFD->Type]);
1057             }
1058
1059             switch (pFD->Type) 
1060             {
1061                 case ELEMENT_TYPE_I1:
1062                     // there's no ANSI conformant type specifier for 
1063                     // signed char, so use the next best thing, 
1064                     // signed short (sign extending)
1065                     if (fAlign)
1066                         ExtOut("%" POINTERSIZE "hd", (short)value.ch);
1067                     else
1068                         ExtOut("%d", value.ch);
1069                     break;
1070                 case ELEMENT_TYPE_I2:
1071                     if (fAlign)
1072                         ExtOut("%" POINTERSIZE "hd", value.Short);
1073                     else
1074                         ExtOut("%d", value.Short);
1075                     break;
1076                 case ELEMENT_TYPE_I4:
1077                     if (fAlign)
1078                         ExtOut("%" POINTERSIZE "d", value.Int);
1079                     else
1080                         ExtOut("%d", value.Int);
1081                     break;
1082                 case ELEMENT_TYPE_I8:
1083                     ExtOut("%I64d", value.Int64);
1084                     break;
1085                 case ELEMENT_TYPE_U1:
1086                 case ELEMENT_TYPE_BOOLEAN:
1087                     if (fAlign)
1088                     // there's no ANSI conformant type specifier for 
1089                     // unsigned char, so use the next best thing, 
1090                     // unsigned short, not extending the sign
1091                         ExtOut("%" POINTERSIZE "hu", (USHORT)value.Short);
1092                     else
1093                         ExtOut("%u", value.ch);
1094                     break;
1095                 case ELEMENT_TYPE_U2:
1096                     if (fAlign)
1097                         ExtOut("%" POINTERSIZE "hu", value.Short);
1098                     else
1099                         ExtOut("%u", value.Short);
1100                     break;
1101                 case ELEMENT_TYPE_U4:
1102                     if (fAlign)
1103                         ExtOut("%" POINTERSIZE "u", value.UInt);
1104                     else
1105                         ExtOut("%u", value.UInt);
1106                     break;
1107                 case ELEMENT_TYPE_U8:
1108                     ExtOut("%I64u", value.UInt64);
1109                     break;
1110                 case ELEMENT_TYPE_I:
1111                 case ELEMENT_TYPE_U:
1112                     if (fAlign)
1113                         ExtOut("%" POINTERSIZE "p", SOS_PTR(value.ptr));
1114                     else
1115                         ExtOut("%p", SOS_PTR(value.ptr));
1116                     break;
1117                 case ELEMENT_TYPE_R4:
1118                     ExtOut("%f", value.Float);
1119                     break;
1120                 case ELEMENT_TYPE_R8:
1121                     ExtOut("%f", value.Double);
1122                     break;
1123                 case ELEMENT_TYPE_CHAR:
1124                     if (fAlign)
1125                         ExtOut("%" POINTERSIZE "hx", value.Short);
1126                     else
1127                         ExtOut("%x", value.Short);
1128                     break;
1129                 case ELEMENT_TYPE_VALUETYPE:
1130                     if (value.ptr)
1131                         DMLOut(DMLValueClass(pFD->MTOfType, dwTmp));
1132                     else
1133                         ExtOut("%p", SOS_PTR(0));
1134                     break;
1135                 default:
1136                     if (value.ptr)
1137                         DMLOut(DMLObject(value.ptr));
1138                     else
1139                         ExtOut("%p", SOS_PTR(0));
1140                     break;
1141             }
1142         }
1143         else
1144         {
1145             if (pFD->Type == ELEMENT_TYPE_VALUETYPE)
1146                 DMLOut(DMLValueClass(pFD->MTOfType, dwTmp));
1147             else
1148                 ExtOut("%p", SOS_PTR(0));
1149         }
1150     }
1151     else
1152     {
1153         ExtOut("%" POINTERSIZE "s", " ");
1154     }
1155 }
1156
1157 void GetStaticFieldPTR(DWORD_PTR* pOutPtr, DacpDomainLocalModuleData* pDLMD, DacpMethodTableData* pMTD, DacpFieldDescData* pFDD, BYTE* pFlags = 0)
1158 {
1159     DWORD_PTR dwTmp;
1160
1161     if (pFDD->Type == ELEMENT_TYPE_VALUETYPE
1162             || pFDD->Type == ELEMENT_TYPE_CLASS)
1163     {
1164         dwTmp = (DWORD_PTR) pDLMD->pGCStaticDataStart + pFDD->dwOffset;
1165     }
1166     else
1167     {
1168         dwTmp = (DWORD_PTR) pDLMD->pNonGCStaticDataStart + pFDD->dwOffset;
1169     }
1170
1171     *pOutPtr = 0;
1172     
1173     if (pMTD->bIsDynamic)
1174     {
1175         ExtOut("dynamic statics NYI");
1176         return;
1177     }
1178     else
1179     {
1180         if (pFlags && pMTD->bIsShared)
1181         {
1182             BYTE flags;
1183             DWORD_PTR pTargetFlags = (DWORD_PTR) pDLMD->pClassData + RidFromToken(pMTD->cl) - 1;            
1184             move_xp (flags, pTargetFlags);
1185
1186             *pFlags = flags;
1187         }
1188                
1189         
1190         *pOutPtr = dwTmp;            
1191     }
1192     return;
1193 }
1194
1195 void GetDLMFlags(DacpDomainLocalModuleData* pDLMD, DacpMethodTableData* pMTD, BYTE* pFlags)
1196 {   
1197     if (pMTD->bIsDynamic)
1198     {
1199         ExtOut("dynamic statics NYI");
1200         return;
1201     }
1202     else
1203     {
1204         if (pFlags)
1205         {
1206             BYTE flags;
1207             DWORD_PTR pTargetFlags = (DWORD_PTR) pDLMD->pClassData + RidFromToken(pMTD->cl) - 1;            
1208             move_xp (flags, pTargetFlags);
1209
1210             *pFlags = flags;
1211         }         
1212     }
1213     return;
1214 }
1215
1216 void GetThreadStaticFieldPTR(DWORD_PTR* pOutPtr, DacpThreadLocalModuleData* pTLMD, DacpMethodTableData* pMTD, DacpFieldDescData* pFDD, BYTE* pFlags = 0)
1217 {
1218     DWORD_PTR dwTmp;
1219
1220     if (pFDD->Type == ELEMENT_TYPE_VALUETYPE
1221             || pFDD->Type == ELEMENT_TYPE_CLASS)
1222     {
1223         dwTmp = (DWORD_PTR) pTLMD->pGCStaticDataStart + pFDD->dwOffset;
1224     }
1225     else
1226     {
1227         dwTmp = (DWORD_PTR) pTLMD->pNonGCStaticDataStart + pFDD->dwOffset;
1228     }
1229
1230     *pOutPtr = 0;
1231     
1232     if (pMTD->bIsDynamic)
1233     {
1234         ExtOut("dynamic thread statics NYI");
1235         return;
1236     }
1237     else
1238     {
1239         if (pFlags)
1240         {
1241             BYTE flags;
1242             DWORD_PTR pTargetFlags = (DWORD_PTR) pTLMD->pClassData + RidFromToken(pMTD->cl) - 1;            
1243             move_xp (flags, pTargetFlags);
1244
1245             *pFlags = flags;
1246         }
1247                        
1248         *pOutPtr = dwTmp;            
1249     }
1250     return;
1251 }
1252
1253 void DisplaySharedStatic(ULONG64 dwModuleDomainID, DacpMethodTableData* pMT, DacpFieldDescData *pFD)
1254 {
1255     DacpAppDomainStoreData adsData;
1256     if (adsData.Request(g_sos)!=S_OK)
1257     {
1258         ExtOut("Unable to get AppDomain information\n");        
1259     }
1260
1261     ArrayHolder<CLRDATA_ADDRESS> pArray = new CLRDATA_ADDRESS[adsData.DomainCount];
1262     if (pArray==NULL)
1263     {
1264         ReportOOM();        
1265         return;
1266     }
1267
1268     if (g_sos->GetAppDomainList(adsData.DomainCount,pArray, NULL)!=S_OK)
1269     {
1270         ExtOut("Unable to get array of AppDomains\n");
1271         return;
1272     }
1273
1274 #if defined(_TARGET_WIN64_)
1275     ExtOut("                                 >> Domain:Value ");
1276 #else
1277     ExtOut("    >> Domain:Value ");
1278 #endif
1279     // Skip the SystemDomain and SharedDomain
1280     for (int i = 0; i < adsData.DomainCount ; i ++)
1281     {
1282         DacpAppDomainData appdomainData;
1283         if (appdomainData.Request(g_sos,pArray[i])!=S_OK)
1284         {
1285             ExtOut("Unable to get AppDomain %lx\n",pArray[i]);
1286             return;
1287         }
1288
1289         DacpDomainLocalModuleData vDomainLocalModule;
1290         if (g_sos->GetDomainLocalModuleDataFromAppDomain(appdomainData.AppDomainPtr, (int)dwModuleDomainID, &vDomainLocalModule) != S_OK)
1291         {
1292             DMLOut(" %s:NotInit ", DMLDomain(pArray[i]));
1293             continue;
1294         }
1295
1296         DWORD_PTR dwTmp;
1297         BYTE Flags = 0;
1298         GetStaticFieldPTR(&dwTmp, &vDomainLocalModule , pMT, pFD, &Flags);
1299
1300         if ((Flags&1) == 0) {
1301             // We have not initialized this yet.
1302             DMLOut(" %s:NotInit ", DMLDomain(pArray[i]));
1303             continue;
1304         }
1305         else if (Flags & 2) {
1306             // We have not initialized this yet.
1307             DMLOut(" %s:FailInit", DMLDomain(pArray[i]));
1308             continue;
1309         }
1310
1311         DMLOut(" %s:", DMLDomain(appdomainData.AppDomainPtr));
1312         DisplayDataMember(pFD, dwTmp, FALSE);               
1313     }    
1314     ExtOut(" <<\n");
1315 }
1316
1317 void DisplayThreadStatic (DacpModuleData* pModule, DacpMethodTableData* pMT, DacpFieldDescData *pFD, BOOL fIsShared)
1318 {
1319     SIZE_T dwModuleIndex = (SIZE_T)pModule->dwModuleIndex;
1320     SIZE_T dwModuleDomainID = (SIZE_T)pModule->dwModuleID;
1321
1322     DacpThreadStoreData ThreadStore;
1323     ThreadStore.Request(g_sos);
1324
1325     ExtOut("    >> Thread:Value");
1326     CLRDATA_ADDRESS CurThread = ThreadStore.firstThread;
1327     while (CurThread)
1328     {
1329         DacpThreadData vThread;
1330         if (vThread.Request(g_sos, CurThread) != S_OK)
1331         {
1332             ExtOut("  error getting thread %p, aborting this field\n", SOS_PTR(CurThread));
1333             return;
1334         }
1335         
1336         if (vThread.osThreadId != 0)
1337         {   
1338             CLRDATA_ADDRESS appDomainAddr = vThread.domain;
1339
1340             // Get the DLM (we need this to check the ClassInit flags).
1341             // It's annoying that we have to issue one request for
1342             // domain-neutral modules and domain-specific modules.
1343             DacpDomainLocalModuleData vDomainLocalModule;                
1344             if (fIsShared)
1345             {
1346                 if (g_sos->GetDomainLocalModuleDataFromAppDomain(appDomainAddr, (int)dwModuleDomainID, &vDomainLocalModule) != S_OK)
1347                 {
1348                     // Not initialized, go to next thread
1349                     // and continue looping
1350                     CurThread = vThread.nextThread;
1351                     continue;
1352                 }
1353             }
1354             else
1355             {
1356                 if (g_sos->GetDomainLocalModuleDataFromModule(pMT->Module, &vDomainLocalModule) != S_OK)
1357                 {
1358                     // Not initialized, go to next thread
1359                     // and continue looping
1360                     CurThread = vThread.nextThread;
1361                     continue;
1362                 }
1363             }
1364
1365             // Get the TLM
1366             DacpThreadLocalModuleData vThreadLocalModule;
1367             if (g_sos->GetThreadLocalModuleData(CurThread, (int)dwModuleIndex, &vThreadLocalModule) != S_OK)
1368             {
1369                 // Not initialized, go to next thread
1370                 // and continue looping
1371                 CurThread = vThread.nextThread;
1372                 continue;
1373             }
1374             
1375             DWORD_PTR dwTmp;
1376             BYTE Flags = 0;
1377             GetThreadStaticFieldPTR(&dwTmp, &vThreadLocalModule, pMT, pFD, &Flags);
1378          
1379             if ((Flags&4) == 0) 
1380             {
1381                 // Not allocated, go to next thread
1382                 // and continue looping
1383                 CurThread = vThread.nextThread;
1384                 continue;
1385             }
1386
1387             Flags = 0;
1388             GetDLMFlags(&vDomainLocalModule, pMT, &Flags);
1389
1390             if ((Flags&1) == 0) 
1391             {
1392                 // Not initialized, go to next thread
1393                 // and continue looping
1394                 CurThread = vThread.nextThread;
1395                 continue;
1396             }
1397             
1398             ExtOut(" %x:", vThread.osThreadId);
1399             DisplayDataMember(pFD, dwTmp, FALSE);               
1400         }
1401
1402         // Go to next thread
1403         CurThread = vThread.nextThread;
1404     }
1405     ExtOut(" <<\n");
1406 }
1407
1408 void DisplayContextStatic (DacpFieldDescData *pFD, size_t offset, BOOL fIsShared)
1409 {
1410     ExtOut("\nDisplay of context static variables is not implemented yet\n");
1411     /*
1412     int numDomain;
1413     DWORD_PTR *domainList = NULL;
1414     GetDomainList (domainList, numDomain);
1415     ToDestroy des0 ((void**)&domainList);
1416     AppDomain vAppDomain;
1417     Context vContext;
1418     
1419     ExtOut("    >> Domain:Value");
1420     for (int i = 0; i < numDomain; i ++)
1421     {
1422         DWORD_PTR dwAddr = domainList[i];
1423         if (dwAddr == 0) {
1424             continue;
1425         }
1426         vAppDomain.Fill (dwAddr);
1427         if (vAppDomain.m_pDefaultContext == 0)
1428             continue;
1429         dwAddr = (DWORD_PTR)vAppDomain.m_pDefaultContext;
1430         vContext.Fill (dwAddr);
1431         
1432         if (fIsShared)
1433             dwAddr = (DWORD_PTR)vContext.m_pSharedStaticData;
1434         else
1435             dwAddr = (DWORD_PTR)vContext.m_pUnsharedStaticData;
1436         if (dwAddr == 0)
1437             continue;
1438         dwAddr += offsetof(STATIC_DATA, dataPtr);
1439         dwAddr += offset;
1440         if (safemove (dwAddr, dwAddr) == 0)
1441             continue;
1442         if (dwAddr == 0)
1443             // We have not initialized this yet.
1444             continue;
1445         
1446         dwAddr += pFD->dwOffset;
1447         if (pFD->Type == ELEMENT_TYPE_CLASS
1448             || pFD->Type == ELEMENT_TYPE_VALUETYPE)
1449         {
1450             if (safemove (dwAddr, dwAddr) == 0)
1451                 continue;
1452         }
1453         if (dwAddr == 0)
1454             // We have not initialized this yet.
1455             continue;
1456         ExtOut(" %p:", (ULONG64)domainList[i]);
1457         DisplayDataMember (pFD, dwAddr, FALSE);
1458     }
1459     ExtOut(" <<\n");
1460     */
1461 }
1462
1463 const char * ElementTypeName(unsigned type)
1464 {
1465     switch (type) {
1466     case ELEMENT_TYPE_PTR:
1467         return "PTR";
1468         break;
1469     case ELEMENT_TYPE_BYREF:
1470         return "BYREF";
1471         break;
1472     case ELEMENT_TYPE_VALUETYPE:
1473         return "VALUETYPE";
1474         break;
1475     case ELEMENT_TYPE_CLASS:
1476         return "CLASS";
1477         break;
1478     case ELEMENT_TYPE_VAR:
1479         return "VAR";
1480         break;
1481     case ELEMENT_TYPE_ARRAY:
1482         return "ARRAY";
1483         break;
1484     case ELEMENT_TYPE_FNPTR:
1485         return "FNPTR";
1486         break;
1487     case ELEMENT_TYPE_SZARRAY:
1488         return "SZARRAY";
1489         break;
1490     case ELEMENT_TYPE_MVAR:
1491         return "MVAR";
1492         break;
1493     default:
1494         if ((type >= _countof(CorElementTypeName)) || (CorElementTypeName[type] == NULL))
1495         {
1496             return "";
1497         }
1498         return CorElementTypeName[type];
1499         break;
1500     }
1501 } // ElementTypeName
1502
1503 const char * ElementTypeNamespace(unsigned type)
1504 {
1505     if ((type >= _countof(CorElementTypeName)) || (CorElementTypeNamespace[type] == NULL))
1506     {
1507         return "";
1508     }
1509     return CorElementTypeNamespace[type];
1510 }
1511
1512 void ComposeName_s(CorElementType Type, __out_ecount(capacity_buffer) LPSTR buffer, size_t capacity_buffer)
1513 {
1514     const char *p = ElementTypeNamespace(Type);
1515     if ((p) && (*p != '\0'))
1516     {
1517         strcpy_s(buffer,capacity_buffer,p);
1518         strcat_s(buffer,capacity_buffer,".");
1519         strcat_s(buffer,capacity_buffer,ElementTypeName(Type));
1520     }
1521     else
1522     {
1523         strcpy_s(buffer,capacity_buffer,ElementTypeName(Type));
1524     }
1525 }
1526
1527 // NOTE: pszName is changed
1528 // INPUT            MAXCHARS        RETURN
1529 // HelloThere       5               ...re
1530 // HelloThere       8               ...There
1531 LPWSTR FormatTypeName (__out_ecount (maxChars) LPWSTR pszName, UINT maxChars)
1532 {
1533     UINT iStart = 0;
1534     UINT iLen = (int) _wcslen(pszName);
1535     if (iLen > maxChars)
1536     {
1537         iStart = iLen - maxChars;
1538         UINT numDots = (maxChars < 3) ? maxChars : 3;
1539         for (UINT i=0; i < numDots; i++)
1540             pszName[iStart+i] = '.';        
1541     }
1542     return pszName + iStart;
1543 }
1544
1545 /**********************************************************************\
1546 * Routine Description:                                                 *
1547 *                                                                      *
1548 *    This function is called to dump all fields of a managed object.   *  
1549 *    dwStartAddr specifies the beginning memory address.               *
1550 *    bFirst is used to avoid printing header everytime.                *
1551 *                                                                      *
1552 \**********************************************************************/
1553 void DisplayFields(CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodTableFieldData *pMTFD, DWORD_PTR dwStartAddr, BOOL bFirst, BOOL bValueClass)
1554 {
1555     static DWORD numInstanceFields = 0;
1556     if (bFirst)
1557     {
1558         ExtOutIndent();
1559         ExtOut("%" POINTERSIZE "s %8s %8s %20s %2s %8s %" POINTERSIZE "s %s\n", 
1560             "MT", "Field", "Offset", "Type", "VT", "Attr", "Value", "Name");
1561         numInstanceFields = 0;
1562     }
1563     
1564     BOOL fIsShared = pMTD->bIsShared;
1565
1566     if (pMTD->ParentMethodTable)
1567     {
1568         DacpMethodTableData vParentMethTable;
1569         if (vParentMethTable.Request(g_sos,pMTD->ParentMethodTable) != S_OK)
1570         {
1571             ExtOut("Invalid parent MethodTable\n");
1572             return;
1573         }            
1574
1575         DacpMethodTableFieldData vParentMethTableFields;
1576         if (vParentMethTableFields.Request(g_sos,pMTD->ParentMethodTable) != S_OK)
1577         {
1578             ExtOut("Invalid parent EEClass\n");
1579             return;
1580         }            
1581
1582         DisplayFields(pMTD->ParentMethodTable, &vParentMethTable, &vParentMethTableFields, dwStartAddr, FALSE, bValueClass);
1583     }
1584
1585     DWORD numStaticFields = 0;
1586     CLRDATA_ADDRESS dwAddr = pMTFD->FirstField;
1587     DacpFieldDescData vFieldDesc;
1588
1589     // Get the module name
1590     DacpModuleData module;
1591     if (module.Request(g_sos, pMTD->Module)!=S_OK)
1592         return;    
1593
1594     ToRelease<IMetaDataImport> pImport = MDImportForModule(&module);
1595     
1596     while (numInstanceFields < pMTFD->wNumInstanceFields
1597            || numStaticFields < pMTFD->wNumStaticFields)
1598     {
1599         if (IsInterrupt())
1600             return;
1601
1602         ExtOutIndent ();
1603         
1604         if ((vFieldDesc.Request(g_sos, dwAddr)!=S_OK) ||
1605             (vFieldDesc.Type >= ELEMENT_TYPE_MAX))
1606         {
1607             ExtOut("Unable to display fields\n");
1608             return;
1609         }
1610         dwAddr = vFieldDesc.NextField;
1611
1612         DWORD offset = vFieldDesc.dwOffset;
1613         if(!((vFieldDesc.bIsThreadLocal || vFieldDesc.bIsContextLocal || fIsShared) && vFieldDesc.bIsStatic))
1614         {
1615             if (!bValueClass)
1616             {
1617                 offset += sizeof(BaseObject);
1618             }
1619         }
1620
1621         DMLOut("%s %8x %8x ", DMLMethodTable(vFieldDesc.MTOfType),
1622                  TokenFromRid(vFieldDesc.mb, mdtFieldDef),
1623                  offset);
1624
1625         char ElementName[mdNameLen];
1626         if ((vFieldDesc.Type == ELEMENT_TYPE_VALUETYPE || 
1627             vFieldDesc.Type == ELEMENT_TYPE_CLASS) && vFieldDesc.MTOfType)
1628         {
1629             NameForMT_s((DWORD_PTR)vFieldDesc.MTOfType, g_mdName, mdNameLen);            
1630             ExtOut("%20.20S ", FormatTypeName(g_mdName, 20));            
1631         }
1632         else 
1633         {       
1634             if (vFieldDesc.Type == ELEMENT_TYPE_CLASS && vFieldDesc.TokenOfType != mdTypeDefNil)
1635             {
1636                 // Get the name from Metadata!!!
1637                 NameForToken_s(TokenFromRid(vFieldDesc.TokenOfType, mdtTypeDef), pImport, g_mdName, mdNameLen, false);
1638                 ExtOut("%20.20S ", FormatTypeName(g_mdName, 20));
1639             }
1640             else
1641             {
1642                 // If ET type from signature is different from fielddesc, then the signature one is more descriptive. 
1643                 // For example, E_T_STRING in field desc will be E_T_CLASS. In minidump's case, we won't have
1644                 // the method table for it.
1645                 ComposeName_s(vFieldDesc.Type != vFieldDesc.sigType ? vFieldDesc.sigType : vFieldDesc.Type, ElementName, sizeof(ElementName)/sizeof(ElementName[0]));
1646                 ExtOut("%20.20s ", ElementName); 
1647             }
1648         }
1649         
1650         ExtOut("%2s ", (IsElementValueType(vFieldDesc.Type)) ? "1" : "0");
1651
1652         if (vFieldDesc.bIsStatic && (vFieldDesc.bIsThreadLocal || vFieldDesc.bIsContextLocal))
1653         {
1654             numStaticFields ++;
1655             if (fIsShared)
1656                 ExtOut("%8s %" POINTERSIZE "s", "shared", vFieldDesc.bIsThreadLocal ? "TLstatic" : "CLstatic");
1657             else
1658                 ExtOut("%8s ", vFieldDesc.bIsThreadLocal ? "TLstatic" : "CLstatic");
1659
1660             NameForToken_s(TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false);
1661             ExtOut(" %S\n", g_mdName);
1662
1663             if (IsMiniDumpFile())
1664             {
1665                 ExtOut(" <no information>\n");
1666             }
1667             else
1668             {
1669                 if (vFieldDesc.bIsThreadLocal)
1670                 {
1671                     DacpModuleData vModule;
1672                     if (vModule.Request(g_sos,pMTD->Module) == S_OK)
1673                     {
1674                         DisplayThreadStatic(&vModule, pMTD, &vFieldDesc, fIsShared);
1675                     }
1676                 }
1677                 else if (vFieldDesc.bIsContextLocal)
1678                 {
1679                     DisplayContextStatic(&vFieldDesc,
1680                                          pMTFD->wContextStaticOffset,
1681                                          fIsShared);
1682                 }
1683             }
1684     
1685         }
1686         else if (vFieldDesc.bIsStatic)
1687         {
1688             numStaticFields ++;
1689
1690             if (fIsShared)
1691             {
1692                 ExtOut("%8s %" POINTERSIZE "s", "shared", "static");
1693
1694                 NameForToken_s(TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false);
1695                 ExtOut(" %S\n", g_mdName);
1696
1697                 if (IsMiniDumpFile())
1698                 {
1699                     ExtOut(" <no information>\n");
1700                 }
1701                 else
1702                 {
1703                     DacpModuleData vModule;
1704                     if (vModule.Request(g_sos,pMTD->Module) == S_OK)
1705                     {
1706                         DisplaySharedStatic(vModule.dwModuleID, pMTD, &vFieldDesc);
1707                     }
1708                 }
1709             }
1710             else
1711             {
1712                 ExtOut("%8s ", "static");
1713                 
1714                 DacpDomainLocalModuleData vDomainLocalModule;
1715                 
1716                 // The MethodTable isn't shared, so the module must not be loaded domain neutral.  We can
1717                 // get the specific DomainLocalModule instance without needing to know the AppDomain in advance.
1718                 if (g_sos->GetDomainLocalModuleDataFromModule(pMTD->Module, &vDomainLocalModule) != S_OK)
1719                 {
1720                     ExtOut(" <no information>\n");
1721                 }
1722                 else
1723                 {
1724                     DWORD_PTR dwTmp;
1725                     GetStaticFieldPTR(&dwTmp, &vDomainLocalModule, pMTD, &vFieldDesc);
1726                     DisplayDataMember(&vFieldDesc, dwTmp);
1727
1728                     NameForToken_s(TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false);
1729                     ExtOut(" %S\n", g_mdName);
1730                 }
1731             }
1732         }
1733         else
1734         {
1735             numInstanceFields ++;
1736
1737             ExtOut("%8s ", "instance");
1738
1739             if (dwStartAddr > 0)
1740             {
1741                 DWORD_PTR dwTmp = dwStartAddr + vFieldDesc.dwOffset + (bValueClass ? 0 : sizeof(BaseObject));
1742                 DisplayDataMember(&vFieldDesc, dwTmp);
1743             }
1744             else
1745             {
1746                 ExtOut(" %8s", " ");
1747             }
1748
1749
1750             NameForToken_s(TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false);
1751             ExtOut(" %S\n", g_mdName);
1752         }
1753         
1754     }
1755     
1756     return;
1757 }
1758
1759 // Return value: -1 = error, 
1760 //                0 = field not found, 
1761 //              > 0 = offset to field from objAddr
1762 int GetObjFieldOffset(CLRDATA_ADDRESS cdaObj, __in_z LPCWSTR wszFieldName, BOOL bFirst)
1763 {
1764     TADDR mt = NULL;
1765     if FAILED(GetMTOfObject(TO_TADDR(cdaObj), &mt))
1766         return -1;
1767
1768     return GetObjFieldOffset(cdaObj, TO_CDADDR(mt), wszFieldName, bFirst);
1769 }
1770
1771 // Return value: -1 = error, 
1772 //                0 = field not found, 
1773 //              > 0 = offset to field from objAddr
1774 int GetObjFieldOffset(CLRDATA_ADDRESS cdaObj, CLRDATA_ADDRESS cdaMT, __in_z LPCWSTR wszFieldName,
1775                         BOOL bFirst/*=TRUE*/)
1776 {
1777
1778 #define EXITPOINT(EXPR) do { if(!(EXPR)) { return -1; } } while (0)
1779     
1780     DacpObjectData objData;
1781     DacpMethodTableData dmtd;
1782     DacpMethodTableFieldData vMethodTableFields;
1783     DacpFieldDescData vFieldDesc;
1784     DacpModuleData module;
1785     static DWORD numInstanceFields = 0; // Static due to recursion visiting parents
1786
1787     if (bFirst)
1788     {
1789         numInstanceFields = 0;
1790     }
1791     
1792     EXITPOINT(objData.Request(g_sos, cdaObj) == S_OK);    
1793     EXITPOINT(dmtd.Request(g_sos, cdaMT) == S_OK);
1794
1795     if (dmtd.ParentMethodTable)
1796     {
1797         DWORD retVal = GetObjFieldOffset (cdaObj, dmtd.ParentMethodTable, 
1798                                           wszFieldName, FALSE);
1799         if (retVal != 0)
1800         {
1801             // return in case of error or success.
1802             // Fall through for field-not-found.
1803             return retVal;
1804         }
1805     }
1806     
1807     EXITPOINT (vMethodTableFields.Request(g_sos,cdaMT) == S_OK);
1808     EXITPOINT (module.Request(g_sos,dmtd.Module) == S_OK);
1809         
1810     CLRDATA_ADDRESS dwAddr = vMethodTableFields.FirstField;            
1811     ToRelease<IMetaDataImport> pImport = MDImportForModule(&module);
1812         
1813     while (numInstanceFields < vMethodTableFields.wNumInstanceFields)
1814     {        
1815         EXITPOINT (vFieldDesc.Request(g_sos, dwAddr) == S_OK);
1816
1817         if (!vFieldDesc.bIsStatic)
1818         {
1819             DWORD offset = vFieldDesc.dwOffset + sizeof(BaseObject);          
1820             NameForToken_s (TokenFromRid(vFieldDesc.mb, mdtFieldDef), pImport, g_mdName, mdNameLen, false);
1821             if (_wcscmp (wszFieldName, g_mdName) == 0)
1822             {
1823                 return offset;
1824             }
1825             numInstanceFields ++;                        
1826         }
1827
1828         dwAddr = vFieldDesc.NextField;        
1829     }
1830
1831     // Field name not found...
1832     return 0;
1833
1834 #undef EXITPOINT    
1835 }
1836
1837 // Returns an AppDomain address if AssemblyPtr is loaded into that domain only. Otherwise
1838 // returns NULL
1839 CLRDATA_ADDRESS IsInOneDomainOnly(CLRDATA_ADDRESS AssemblyPtr)
1840 {
1841     CLRDATA_ADDRESS appDomain = NULL;
1842
1843     DacpAppDomainStoreData adstore;
1844     if (adstore.Request(g_sos) != S_OK)
1845     {
1846         ExtOut("Unable to get appdomain store\n");
1847         return NULL;
1848     }    
1849
1850     size_t AllocSize;
1851     if (!ClrSafeInt<size_t>::multiply(sizeof(CLRDATA_ADDRESS), adstore.DomainCount, AllocSize))
1852     {
1853         ReportOOM();        
1854         return NULL;
1855     }
1856
1857     ArrayHolder<CLRDATA_ADDRESS> pArray = new CLRDATA_ADDRESS[adstore.DomainCount];
1858     if (pArray==NULL)
1859     {
1860         ReportOOM();        
1861         return NULL;
1862     }
1863     
1864     if (g_sos->GetAppDomainList(adstore.DomainCount, pArray, NULL)!=S_OK)
1865     {
1866         ExtOut ("Failed to get appdomain list\n");
1867         return NULL;
1868     }
1869
1870     for (int i = 0; i < adstore.DomainCount; i++)
1871     {
1872         if (IsInterrupt())
1873             return NULL;
1874
1875         DacpAppDomainData dadd;
1876         if (dadd.Request(g_sos, pArray[i]) != S_OK)
1877         {
1878             ExtOut ("Unable to get AppDomain %p\n", SOS_PTR(pArray[i]));
1879             return NULL;
1880         }
1881
1882         if (dadd.AssemblyCount)
1883         {
1884             size_t AssemblyAllocSize;
1885             if (!ClrSafeInt<size_t>::multiply(sizeof(CLRDATA_ADDRESS), dadd.AssemblyCount, AssemblyAllocSize))
1886             {
1887                 ReportOOM();                        
1888                 return NULL;
1889             }
1890
1891             ArrayHolder<CLRDATA_ADDRESS> pAsmArray = new CLRDATA_ADDRESS[dadd.AssemblyCount];
1892             if (pAsmArray==NULL)
1893             {
1894                 ReportOOM();                        
1895                 return NULL;
1896             }
1897     
1898             if (g_sos->GetAssemblyList(dadd.AppDomainPtr,dadd.AssemblyCount,pAsmArray, NULL)!=S_OK)
1899             {
1900                 ExtOut("Unable to get array of Assemblies\n");
1901                 return NULL;  
1902             }
1903       
1904             for (LONG n = 0; n < dadd.AssemblyCount; n ++)
1905             {
1906                 if (IsInterrupt())
1907                     return NULL;
1908
1909                 if (AssemblyPtr == pAsmArray[n])
1910                 {
1911                     if (appDomain != NULL)
1912                     {
1913                         // We have found more than one AppDomain that loaded this
1914                         // assembly, we must return NULL.
1915                         return NULL;
1916                     }
1917                     appDomain = dadd.AppDomainPtr;
1918                 }                
1919             }    
1920         }
1921     } 
1922
1923     
1924     return appDomain;
1925 }
1926
1927 CLRDATA_ADDRESS GetAppDomainForMT(CLRDATA_ADDRESS mtPtr)
1928 {
1929     DacpMethodTableData mt;
1930     if (mt.Request(g_sos, mtPtr) != S_OK)
1931     {
1932         return NULL;
1933     }
1934     
1935     DacpModuleData module;
1936     if (module.Request(g_sos, mt.Module) != S_OK)
1937     {
1938         return NULL;
1939     }
1940
1941     DacpAssemblyData assembly;
1942     if (assembly.Request(g_sos, module.Assembly) != S_OK)
1943     {
1944         return NULL;
1945     }
1946
1947     DacpAppDomainStoreData adstore;
1948     if (adstore.Request(g_sos) != S_OK)
1949     {
1950         return NULL;
1951     }
1952
1953     return (assembly.ParentDomain == adstore.sharedDomain) ?
1954             IsInOneDomainOnly(assembly.AssemblyPtr) :
1955             assembly.ParentDomain;
1956 }
1957
1958 CLRDATA_ADDRESS GetAppDomain(CLRDATA_ADDRESS objPtr)
1959 {
1960     CLRDATA_ADDRESS appDomain = NULL;
1961     
1962     DacpObjectData objData;
1963     if (objData.Request(g_sos,objPtr) != S_OK)
1964     {        
1965         return NULL;
1966     }
1967
1968     // First check  eeclass->module->assembly->domain.
1969     // Then check the object flags word
1970     // finally, search threads for a reference to the object, and look at the thread context.
1971
1972     DacpMethodTableData mt;
1973     if (mt.Request(g_sos,objData.MethodTable) != S_OK)
1974     {
1975         return NULL;
1976     }
1977
1978     DacpModuleData module;
1979     if (module.Request(g_sos,mt.Module) != S_OK)
1980     {
1981         return NULL;
1982     }
1983
1984     DacpAssemblyData assembly;
1985     if (assembly.Request(g_sos,module.Assembly) != S_OK)
1986     {
1987         return NULL;
1988     }
1989
1990     DacpAppDomainStoreData adstore;
1991     if (adstore.Request(g_sos) != S_OK)
1992     {
1993         return NULL;
1994     }    
1995     
1996     if (assembly.ParentDomain == adstore.sharedDomain)
1997     {
1998         sos::Object obj(TO_TADDR(objPtr));
1999         ULONG value = 0;
2000         if (!obj.TryGetHeader(value))
2001         {
2002             return NULL;
2003         }
2004         
2005         DWORD adIndex = (value >> SBLK_APPDOMAIN_SHIFT) & SBLK_MASK_APPDOMAININDEX;
2006         if ( ((value & BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX) != 0) || adIndex==0)
2007         {
2008             // No AppDomainID information. We'll make use of a heuristic.
2009             // If the assembly is in the shared domain, we can report it as
2010             // being in domain X if the only other domain that has the assembly
2011             // loaded is domain X.
2012             appDomain = IsInOneDomainOnly(assembly.AssemblyPtr);
2013             if (appDomain == NULL && ((value & BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX) != 0))
2014             {
2015                 if ((value & BIT_SBLK_IS_HASHCODE) == 0)
2016                 {
2017                     UINT index = value & MASK_SYNCBLOCKINDEX;
2018                     // We have a syncblock, the appdomain ID may be in there.
2019                     DacpSyncBlockData syncBlockData;
2020                     if (syncBlockData.Request(g_sos,index) == S_OK)
2021                     {
2022                         appDomain = syncBlockData.appDomainPtr;
2023                     }
2024                 }
2025             }
2026         }
2027         else if ((value & BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX) == 0)
2028         {            
2029             size_t AllocSize;
2030             if (!ClrSafeInt<size_t>::multiply(sizeof(CLRDATA_ADDRESS), adstore.DomainCount, AllocSize))
2031             {
2032                 return NULL;
2033             }
2034             // we know we have a non-zero adIndex. Find the appdomain.
2035             ArrayHolder<CLRDATA_ADDRESS> pArray = new CLRDATA_ADDRESS[adstore.DomainCount];
2036             if (pArray==NULL)
2037             {
2038                 return NULL;
2039             }
2040             
2041             if (g_sos->GetAppDomainList(adstore.DomainCount, pArray, NULL)!=S_OK)
2042             {
2043                 return NULL;
2044             }
2045
2046             for (int i = 0; i < adstore.DomainCount; i++)
2047             {
2048                 DacpAppDomainData dadd;
2049                 if (dadd.Request(g_sos, pArray[i]) != S_OK)
2050                 {
2051                     return NULL;
2052                 }
2053                 if (dadd.dwId == adIndex)
2054                 {
2055                     appDomain = pArray[i];
2056                     break;
2057                 }
2058             } 
2059         }
2060     }
2061     else
2062     {
2063         appDomain = assembly.ParentDomain;
2064     }
2065
2066     return appDomain;
2067 }
2068
2069 HRESULT FileNameForModule (DWORD_PTR pModuleAddr, __out_ecount (MAX_LONGPATH) WCHAR *fileName)
2070 {
2071     DacpModuleData ModuleData;
2072     fileName[0] = L'\0';
2073     
2074     HRESULT hr = ModuleData.Request(g_sos, TO_CDADDR(pModuleAddr));
2075     if (SUCCEEDED(hr))
2076     {
2077         hr = FileNameForModule(&ModuleData,fileName);
2078     }
2079     
2080     return hr;
2081 }
2082
2083 /**********************************************************************\
2084 * Routine Description:                                                 *
2085 *                                                                      *
2086 *    This function is called to find the file name given a Module.     *  
2087 *                                                                      *
2088 \**********************************************************************/
2089 // fileName should be at least MAX_LONGPATH
2090 HRESULT FileNameForModule (DacpModuleData *pModule, __out_ecount (MAX_LONGPATH) WCHAR *fileName)
2091 {
2092     fileName[0] = L'\0';
2093     
2094     HRESULT hr = S_OK;
2095     CLRDATA_ADDRESS dwAddr = pModule->File;
2096     if (dwAddr == 0)
2097     {
2098         // TODO:  We have dynamic module
2099         return E_NOTIMPL;
2100     }
2101     
2102     CLRDATA_ADDRESS base = 0;
2103     hr = g_sos->GetPEFileBase(dwAddr, &base);
2104     if (SUCCEEDED(hr))
2105     {
2106         hr = g_sos->GetPEFileName(dwAddr, MAX_LONGPATH, fileName, NULL);
2107         if (SUCCEEDED(hr))
2108         {
2109             if (fileName[0] != W('\0'))
2110                 return hr; // done
2111         }
2112 #ifndef FEATURE_PAL
2113         // Try the base *
2114         if (base)
2115         {
2116             hr = DllsName((ULONG_PTR) base, fileName);
2117         }
2118 #endif // !FEATURE_PAL
2119     }
2120     
2121     // If we got here, either DllsName worked, or we couldn't find a name
2122     return hr;
2123 }
2124
2125 void AssemblyInfo(DacpAssemblyData *pAssembly)
2126 {
2127     ExtOut("ClassLoader:        %p\n", SOS_PTR(pAssembly->ClassLoader));
2128     if ((ULONG64)pAssembly->AssemblySecDesc != NULL)
2129         ExtOut("SecurityDescriptor: %p\n", SOS_PTR(pAssembly->AssemblySecDesc));
2130     ExtOut("  Module Name\n");
2131     
2132     ArrayHolder<CLRDATA_ADDRESS> Modules = new CLRDATA_ADDRESS[pAssembly->ModuleCount];
2133     if (Modules == NULL 
2134         || g_sos->GetAssemblyModuleList(pAssembly->AssemblyPtr, pAssembly->ModuleCount, Modules, NULL) != S_OK)
2135     {
2136        ReportOOM();        
2137        return;
2138     }
2139     
2140     for (UINT n=0;n<pAssembly->ModuleCount;n++)
2141     {
2142         if (IsInterrupt())
2143         {
2144             return;
2145         }
2146
2147         CLRDATA_ADDRESS ModuleAddr = Modules[n];
2148         DMLOut("%s    " WIN86_8SPACES, DMLModule(ModuleAddr));
2149         DacpModuleData moduleData;
2150         if (moduleData.Request(g_sos,ModuleAddr)==S_OK)
2151         {
2152             WCHAR fileName[MAX_LONGPATH];
2153             FileNameForModule (&moduleData, fileName);
2154             if (fileName[0])
2155             {
2156                 ExtOut("%S\n", fileName);
2157             }
2158             else
2159             {
2160                 ExtOut("%S\n", (moduleData.bIsReflection) ? W("Dynamic Module") : W("Unknown Module"));
2161             }
2162         }        
2163     }
2164 }
2165
2166 const char *GetStageText(DacpAppDomainDataStage stage)
2167 {
2168     switch(stage)
2169     {
2170         case STAGE_CREATING:
2171             return "CREATING";
2172         case STAGE_READYFORMANAGEDCODE:
2173             return "READYFORMANAGEDCODE";
2174         case STAGE_ACTIVE:
2175             return "ACTIVE";
2176         case STAGE_OPEN:
2177             return "OPEN";
2178         case STAGE_UNLOAD_REQUESTED:
2179             return "UNLOAD_REQUESTED";
2180         case STAGE_EXITING:
2181             return "EXITING";
2182         case STAGE_EXITED:
2183             return "EXITED";
2184         case STAGE_FINALIZING:
2185             return "FINALIZING";
2186         case STAGE_FINALIZED:
2187             return "FINALIZED";
2188         case STAGE_HANDLETABLE_NOACCESS:
2189             return "HANDLETABLE_NOACCESS";
2190         case STAGE_CLEARED:
2191             return "CLEARED";
2192         case STAGE_COLLECTED:
2193             return "COLLECTED";
2194         case STAGE_CLOSED:
2195             return "CLOSED";
2196     }
2197     return "UNKNOWN";
2198 }
2199
2200 /**********************************************************************\
2201 * Routine Description:                                                 *
2202 *                                                                      *
2203 *    This function is called to dump the contents of a domain.         *  
2204 *                                                                      *
2205 \**********************************************************************/
2206 void DomainInfo (DacpAppDomainData *pDomain)
2207 {
2208     ExtOut("LowFrequencyHeap:   %p\n", SOS_PTR(pDomain->pLowFrequencyHeap));
2209     ExtOut("HighFrequencyHeap:  %p\n", SOS_PTR(pDomain->pHighFrequencyHeap));
2210     ExtOut("StubHeap:           %p\n", SOS_PTR(pDomain->pStubHeap));
2211     ExtOut("Stage:              %s\n", GetStageText(pDomain->appDomainStage));
2212     if ((ULONG64)pDomain->AppSecDesc != NULL)
2213         ExtOut("SecurityDescriptor: %p\n", SOS_PTR(pDomain->AppSecDesc));
2214     ExtOut("Name:               ");
2215
2216     if (g_sos->GetAppDomainName(pDomain->AppDomainPtr, mdNameLen, g_mdName, NULL)!=S_OK)
2217     {
2218         ExtOut("Error getting AppDomain friendly name\n");
2219     }
2220     else
2221     {
2222         ExtOut("%S\n", (g_mdName[0] != L'\0') ? g_mdName : W("None"));
2223     }
2224
2225     if (pDomain->AssemblyCount == 0)
2226         return;
2227     
2228     ArrayHolder<CLRDATA_ADDRESS> pArray = new CLRDATA_ADDRESS[pDomain->AssemblyCount];
2229     if (pArray==NULL)
2230     {
2231         ReportOOM();
2232         return;
2233     }
2234
2235     if (g_sos->GetAssemblyList(pDomain->AppDomainPtr,pDomain->AssemblyCount,pArray, NULL)!=S_OK)
2236     {
2237         ExtOut("Unable to get array of Assemblies\n");
2238         return;  
2239     }
2240
2241     LONG n;
2242     // Assembly vAssembly;
2243     for (n = 0; n < pDomain->AssemblyCount; n ++)
2244     {
2245         if (IsInterrupt())
2246             return;
2247         
2248         if (n != 0)
2249             ExtOut("\n");
2250
2251         DMLOut("Assembly:           %s", DMLAssembly(pArray[n]));
2252         DacpAssemblyData assemblyData;
2253         if (assemblyData.Request(g_sos, pArray[n], pDomain->AppDomainPtr) == S_OK)
2254         {
2255             if (assemblyData.isDynamic)
2256                 ExtOut(" (Dynamic)");
2257             
2258             ExtOut(" [");
2259             if (g_sos->GetAssemblyName(pArray[n], mdNameLen, g_mdName, NULL) == S_OK)
2260                 ExtOut("%S", g_mdName);
2261             ExtOut("]\n");
2262
2263             AssemblyInfo(&assemblyData);
2264         }
2265     }    
2266
2267     ExtOut("\n");
2268 }
2269
2270 /**********************************************************************\
2271 * Routine Description:                                                 *
2272 *                                                                      *
2273 *    This function is called to find the name of a MethodDesc using    *  
2274 *    metadata API.                                                     *
2275 *                                                                      *
2276 \**********************************************************************/
2277 BOOL NameForMD_s (DWORD_PTR pMD, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName)
2278 {
2279     mdName[0] = L'\0';
2280     CLRDATA_ADDRESS StartAddr = TO_CDADDR(pMD);
2281     DacpMethodDescData MethodDescData;
2282
2283     // don't need to check for minidump file as all commands are seals
2284     // We also do not have EEJitManager to validate anyway.
2285     //
2286     if (!IsMiniDumpFile() && MethodDescData.Request(g_sos,StartAddr) != S_OK)
2287     {
2288         ExtOut("%p is not a MethodDesc\n", SOS_PTR(StartAddr));
2289         return FALSE;
2290     }
2291
2292     if (g_sos->GetMethodDescName(StartAddr, mdNameLen, mdName, NULL) != S_OK)
2293     {
2294         wcscpy_s(mdName, capacity_mdName, W("UNKNOWN"));
2295         return FALSE;
2296     }
2297     return TRUE;
2298 }
2299
2300 /**********************************************************************\
2301 * Routine Description:                                                 *
2302 *                                                                      *
2303 *    This function is called to find the name of a MethodTable using   *  
2304 *    metadata API.                                                     *
2305 *                                                                      *
2306 \**********************************************************************/
2307 BOOL NameForMT_s(DWORD_PTR MTAddr, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName)
2308 {
2309     HRESULT hr = g_sos->GetMethodTableName(TO_CDADDR(MTAddr), (ULONG32)capacity_mdName, mdName, NULL);
2310     return SUCCEEDED(hr);
2311 }
2312
2313 WCHAR *CreateMethodTableName(TADDR mt, TADDR cmt)
2314 {
2315     bool array = false;
2316     WCHAR *res = NULL;
2317     
2318     if (mt == sos::MethodTable::GetFreeMT())
2319     {
2320         res = new WCHAR[5];
2321         wcscpy_s(res, 5, W("Free"));
2322         return res;
2323     }
2324     
2325     if (mt == sos::MethodTable::GetArrayMT() && cmt != NULL)
2326     {
2327         mt = cmt;
2328         array = true;
2329     }
2330     
2331     unsigned int needed = 0;
2332     HRESULT hr = g_sos->GetMethodTableName(mt, 0, NULL, &needed);
2333     
2334     // If failed, we will return null.
2335     if (SUCCEEDED(hr))
2336     {
2337         // +2 for [], if we need it.
2338         res = new WCHAR[needed+2];
2339         hr = g_sos->GetMethodTableName(mt, needed, res, NULL);
2340         
2341         if (FAILED(hr))
2342         {
2343             delete [] res;
2344             res = NULL;
2345         }
2346         else if (array)
2347         {        
2348             res[needed-1] = '[';
2349             res[needed] = ']';
2350             res[needed+1] = 0;
2351         }
2352     }
2353
2354     return res;
2355 }
2356
2357 /**********************************************************************\
2358 * Routine Description:                                                 *
2359 *                                                                      *
2360 *    Return TRUE if str2 is a substring of str1 and str1 and str2      *  
2361 *    share the same file path.
2362 *                                                                      *
2363 \**********************************************************************/
2364 BOOL IsSameModuleName (const char *str1, const char *str2)
2365 {
2366     if (strlen (str1) < strlen (str2))
2367         return FALSE;
2368     const char *ptr1 = str1 + strlen(str1)-1;
2369     const char *ptr2 = str2 + strlen(str2)-1;
2370     while (ptr2 >= str2)
2371     {
2372 #ifndef FEATURE_PAL
2373         if (tolower(*ptr1) != tolower(*ptr2))
2374 #else
2375         if (*ptr1 != *ptr2)
2376 #endif
2377         {
2378             return FALSE;
2379         }
2380         ptr2--;
2381         ptr1--;
2382     }
2383     if (ptr1 >= str1 && *ptr1 != DIRECTORY_SEPARATOR_CHAR_A && *ptr1 != ':')
2384     {
2385         return FALSE;
2386     }
2387     return TRUE;
2388 }
2389
2390 /**********************************************************************\
2391 * Routine Description:                                                 *
2392 *                                                                      *
2393 *    Return TRUE if moduleAddr is the address of a module.             *  
2394 *                                                                      *
2395 \**********************************************************************/
2396 BOOL IsModule (DWORD_PTR moduleAddr)
2397 {
2398     DacpModuleData module;
2399     return (module.Request(g_sos, TO_CDADDR(moduleAddr))==S_OK);
2400 }
2401
2402 /**********************************************************************\
2403 * Routine Description:                                                 *
2404 *                                                                      *
2405 *    Return TRUE if value is the address of a MethodTable.             *  
2406 *    We verify that MethodTable and EEClass are right.
2407 *                                                                      *
2408 \**********************************************************************/
2409 BOOL IsMethodTable (DWORD_PTR value)
2410 {
2411     DacpMethodTableData mtabledata;
2412     if (mtabledata.Request(g_sos, TO_CDADDR(value))!=S_OK)
2413     {
2414         return FALSE;
2415     }
2416     
2417     return TRUE;
2418 }
2419
2420 /**********************************************************************\
2421 * Routine Description:                                                 *
2422 *                                                                      *
2423 *    Return TRUE if value is the address of a MethodDesc.              *  
2424 *    We verify that MethodTable and EEClass are right.
2425 *                                                                      *
2426 \**********************************************************************/
2427 BOOL IsMethodDesc (DWORD_PTR value)
2428 {    
2429     // Just by retrieving one successfully from the DAC, we know we have a MethodDesc.
2430     DacpMethodDescData MethodDescData;
2431     if (MethodDescData.Request(g_sos, TO_CDADDR(value)) != S_OK)
2432     {
2433         return FALSE;
2434     }
2435     
2436     return TRUE;
2437 }
2438
2439 DacpUsefulGlobalsData g_special_usefulGlobals;
2440
2441 BOOL IsObjectArray (DacpObjectData *pData)
2442 {
2443     if (pData->ObjectType == OBJ_ARRAY)
2444         return g_special_usefulGlobals.ArrayMethodTable == pData->MethodTable;
2445     
2446     return FALSE;
2447 }
2448
2449 BOOL IsObjectArray (DWORD_PTR obj)
2450 {
2451     DWORD_PTR mtAddr = NULL;
2452     if (SUCCEEDED(GetMTOfObject(obj, &mtAddr)))
2453         return TO_TADDR(g_special_usefulGlobals.ArrayMethodTable) == mtAddr;
2454     
2455     return FALSE;
2456 }
2457
2458 BOOL IsStringObject (size_t obj)
2459 {
2460     DWORD_PTR mtAddr = NULL;
2461
2462     if (SUCCEEDED(GetMTOfObject(obj, &mtAddr)))
2463         return TO_TADDR(g_special_usefulGlobals.StringMethodTable) == mtAddr;
2464
2465     return FALSE;
2466 }
2467
2468 void DumpStackObjectsOutput(const char *location, DWORD_PTR objAddr, BOOL verifyFields)
2469 {
2470     // rule out pointers that are outside of the gc heap.
2471     if (g_snapshot.GetHeap(objAddr) == NULL)
2472         return;
2473
2474     DacpObjectData objectData;
2475     if (objectData.Request(g_sos, TO_CDADDR(objAddr)) != S_OK)
2476         return;
2477
2478     if (sos::IsObject(objAddr, verifyFields != FALSE)
2479         && !sos::MethodTable::IsFreeMT(TO_TADDR(objectData.MethodTable)))
2480     {
2481         DMLOut("%-" POINTERSIZE "s %s ", location, DMLObject(objAddr));
2482         if (g_sos->GetObjectClassName(TO_CDADDR(objAddr), mdNameLen, g_mdName, NULL)==S_OK)
2483         {
2484             ExtOut("%S", g_mdName);
2485
2486             if (IsStringObject(objAddr))
2487             {
2488                 ExtOut("    ");
2489                 StringObjectContent(objAddr, FALSE, 40);
2490             }
2491             else if (IsObjectArray(objAddr) && 
2492                      (g_sos->GetMethodTableName(objectData.ElementTypeHandle, mdNameLen, g_mdName, NULL) == S_OK))
2493             {
2494                 ExtOut("    ");
2495                 ExtOut("(%S[])", g_mdName);
2496             }
2497         }
2498         else
2499         {
2500             ExtOut("<unknown type>");
2501         }
2502         ExtOut("\n");
2503     }
2504 }
2505
2506 void DumpStackObjectsOutput(DWORD_PTR ptr, DWORD_PTR objAddr, BOOL verifyFields)
2507 {
2508     char location[64];
2509     sprintf_s(location, 64, "%p", (DWORD_PTR *)ptr);
2510
2511     DumpStackObjectsOutput(location, objAddr, verifyFields);
2512 }
2513
2514 void DumpStackObjectsInternal(size_t StackTop, size_t StackBottom, BOOL verifyFields)
2515 {
2516     for (DWORD_PTR ptr = StackTop; ptr <= StackBottom; ptr += sizeof(DWORD_PTR))
2517     {       
2518         if (IsInterrupt())
2519             return;
2520
2521         DWORD_PTR objAddr;
2522         move_xp(objAddr, ptr);
2523
2524         DumpStackObjectsOutput(ptr, objAddr, verifyFields);
2525     }
2526 }
2527
2528 void DumpRegObjectHelper(const char *regName, BOOL verifyFields)
2529 {
2530     DWORD_PTR reg;
2531 #ifdef FEATURE_PAL    
2532     if (FAILED(g_ExtRegisters->GetValueByName(regName, &reg)))
2533         return;
2534 #else
2535     DEBUG_VALUE value;
2536     ULONG IREG;
2537     if (FAILED(g_ExtRegisters->GetIndexByName(regName, &IREG)) ||
2538         FAILED(g_ExtRegisters->GetValue(IREG, &value)))
2539         return;
2540
2541 #if defined(SOS_TARGET_X86) || defined(SOS_TARGET_ARM)
2542     reg = (DWORD_PTR) value.I32;
2543 #elif defined(SOS_TARGET_AMD64) || defined(SOS_TARGET_ARM64)
2544     reg = (DWORD_PTR) value.I64;
2545 #else
2546 #error Unsupported target
2547 #endif
2548 #endif // FEATURE_PAL
2549
2550     DumpStackObjectsOutput(regName, reg, verifyFields);
2551 }
2552
2553 void DumpStackObjectsHelper (
2554                 TADDR StackTop, 
2555                 TADDR StackBottom, 
2556                 BOOL verifyFields)
2557 {
2558     ExtOut(g_targetMachine->GetDumpStackObjectsHeading());
2559
2560     LPCSTR* regs;
2561     unsigned int cnt;
2562     g_targetMachine->GetGCRegisters(&regs, &cnt);
2563
2564     for (size_t i = 0; i < cnt; ++i)
2565         DumpRegObjectHelper(regs[i], verifyFields);
2566
2567     // Make certain StackTop is dword aligned:
2568     DumpStackObjectsInternal(StackTop & ~ALIGNCONST, StackBottom, verifyFields);
2569 }
2570
2571 void AddToModuleList(DWORD_PTR * &moduleList, int &numModule, int &maxList,
2572                      DWORD_PTR dwModuleAddr)
2573 {
2574     int i;
2575     for (i = 0; i < numModule; i ++)
2576     {
2577         if (moduleList[i] == dwModuleAddr)
2578             break;
2579     }
2580     if (i == numModule)
2581     {
2582         moduleList[numModule] = dwModuleAddr;
2583         numModule ++;
2584         if (numModule == maxList)
2585         {
2586             int listLength = 0;
2587             if (!ClrSafeInt<int>::multiply(maxList, 2, listLength))
2588             {
2589                 ExtOut("<integer overflow>\n");
2590                 numModule = 0;
2591                 ControlC = 1;
2592                 return;
2593             }
2594             DWORD_PTR *list = new DWORD_PTR [listLength];
2595
2596             if (list == NULL)
2597             {
2598                 numModule = 0;
2599                 ControlC = 1;
2600                 return;
2601             }
2602             memcpy (list, moduleList, maxList * sizeof(PVOID));
2603             delete[] moduleList;
2604             moduleList = list;
2605             maxList *= 2;
2606         }
2607     }
2608 }
2609
2610 BOOL IsFusionLoadedModule (LPCSTR fusionName, LPCSTR mName)
2611 {
2612     // The fusion name will be in this format:
2613     // <module name>, Version=<version>, Culture=<culture>, PublicKeyToken=<token>
2614     // If fusionName up to the comma matches mName (case insensitive),
2615     // we consider that a match was found.
2616     LPCSTR commaPos = strchr (fusionName, ',');
2617     if (commaPos)
2618     {
2619         // verify that fusionName and mName match up to a comma.
2620         while (*fusionName != ',')
2621         {
2622             if (*mName == '\0')
2623             {
2624                 return FALSE;
2625             }
2626             
2627 #ifndef FEATURE_PAL
2628             if (tolower(*fusionName) != tolower(*mName))
2629 #else
2630             if (*fusionName != *mName)
2631 #endif
2632             {
2633                 return FALSE;
2634             }
2635             fusionName++;
2636             mName++;
2637         }
2638         return TRUE;        
2639     }
2640     return FALSE;
2641 }
2642     
2643 BOOL DebuggerModuleNamesMatch (CLRDATA_ADDRESS PEFileAddr, ___in __in_z LPSTR mName)
2644 {
2645     // Another way to see if a module is the same is
2646     // to accept that mName may be the debugger's name for
2647     // a loaded module. We can get the debugger's name for
2648     // the module we are looking at right now, and compare
2649     // it with mName, if they match exactly, we can add
2650     // the module to the list.
2651     if (PEFileAddr)
2652     {
2653         CLRDATA_ADDRESS pebase = 0;
2654         if (g_sos->GetPEFileBase(PEFileAddr, &pebase) == S_OK)
2655         {
2656             if (pebase)
2657             {
2658                 ULONG Index;
2659                 ULONG64 base;
2660                 if (g_ExtSymbols->GetModuleByOffset(pebase, 0, &Index, &base) == S_OK)
2661                 {                                    
2662                     CHAR ModuleName[MAX_LONGPATH+1];
2663
2664                     if (g_ExtSymbols->GetModuleNames(Index, base, NULL, 0, NULL, ModuleName, 
2665                         MAX_LONGPATH, NULL, NULL, 0, NULL) == S_OK)
2666                     {
2667                         if (_stricmp (ModuleName, mName) == 0)
2668                         {
2669                             return TRUE;
2670                         }
2671                     }
2672                 }                                
2673             }
2674         }                        
2675     }
2676     return FALSE;
2677 }
2678
2679 DWORD_PTR *ModuleFromName(__in_opt LPSTR mName, int *numModule)
2680 {
2681     if (numModule == NULL)
2682         return NULL;
2683
2684     DWORD_PTR *moduleList = NULL;
2685     *numModule = 0;
2686
2687     DacpAppDomainStoreData adsData;
2688     if (adsData.Request(g_sos)!=S_OK)
2689         return NULL;
2690
2691     ArrayHolder<CLRDATA_ADDRESS> pAssemblyArray = NULL;
2692     ArrayHolder<CLRDATA_ADDRESS> pModules = NULL;
2693     int arrayLength = 0;
2694     if (!ClrSafeInt<int>::addition(adsData.DomainCount, 2, arrayLength))
2695     {
2696         ExtOut("<integer overflow>\n");
2697         return NULL;
2698     }
2699     ArrayHolder<CLRDATA_ADDRESS> pArray = new CLRDATA_ADDRESS[arrayLength];
2700
2701     if (pArray==NULL)
2702     {
2703         ReportOOM();
2704         return NULL;
2705     }
2706
2707     pArray[0] = adsData.systemDomain;
2708     pArray[1] = adsData.sharedDomain;
2709     if (g_sos->GetAppDomainList(adsData.DomainCount, pArray.GetPtr()+2, NULL)!=S_OK)
2710     {
2711         ExtOut("Unable to get array of AppDomains\n");
2712         return NULL;
2713     }
2714
2715     // List all domain
2716     size_t AllocSize;
2717     int maxList = arrayLength; // account for system and shared domains
2718     if (maxList <= 0 || !ClrSafeInt<size_t>::multiply(maxList, sizeof(PVOID), AllocSize))
2719     {
2720         ExtOut("Integer overflow error.\n");
2721         return NULL;
2722     }
2723     
2724     moduleList = new DWORD_PTR[maxList];
2725     if (moduleList == NULL)
2726     {
2727         ReportOOM();
2728         return NULL;
2729     }
2730
2731     WCHAR StringData[MAX_LONGPATH];
2732     char fileName[sizeof(StringData)/2];
2733     
2734     // Search all domains to find a module
2735     for (int n = 0; n < adsData.DomainCount+2; n++)
2736     {
2737         if (IsInterrupt())
2738         {
2739             ExtOut("<interrupted>\n");
2740             goto Failure;
2741         }
2742         
2743         DacpAppDomainData appDomain;
2744         if (FAILED(appDomain.Request(g_sos,pArray[n])))
2745         {
2746             // Don't print a failure message here, there is a very normal case when checking
2747             // for modules after clr is loaded but before any AppDomains or assemblies are created
2748             // for example:
2749             // >sxe ld:clr
2750             // >g
2751             // ...
2752             // ModLoad: clr.dll
2753             // >!bpmd Foo.dll Foo.Bar
2754
2755             // we will correctly give the answer that whatever module you were looking for, it isn't loaded yet
2756             goto Failure;
2757         }
2758
2759         if (appDomain.AssemblyCount)
2760         {            
2761             pAssemblyArray = new CLRDATA_ADDRESS[appDomain.AssemblyCount];
2762             if (pAssemblyArray==NULL)
2763             {
2764                 ReportOOM();
2765                 goto Failure;
2766             }
2767
2768             if (FAILED(g_sos->GetAssemblyList(appDomain.AppDomainPtr, appDomain.AssemblyCount, pAssemblyArray, NULL)))
2769             {
2770                 ExtOut("Unable to get array of Assemblies for the given AppDomain..\n");
2771                 goto Failure;
2772             }
2773
2774             for (int nAssem = 0; nAssem < appDomain.AssemblyCount; nAssem ++)
2775             {
2776                 if (IsInterrupt())
2777                 {
2778                     ExtOut("<interrupted>\n");
2779                     goto Failure;
2780                 }
2781
2782                 DacpAssemblyData assemblyData;
2783                 if (FAILED(assemblyData.Request(g_sos, pAssemblyArray[nAssem])))
2784                 {
2785                     ExtOut("Failed to request assembly.\n");
2786                     goto Failure;
2787                 }
2788
2789                 pModules = new CLRDATA_ADDRESS[assemblyData.ModuleCount];
2790                 if (FAILED(g_sos->GetAssemblyModuleList(assemblyData.AssemblyPtr, assemblyData.ModuleCount, pModules, NULL)))
2791                 {
2792                     ExtOut("Failed to get the modules for the given assembly.\n");
2793                     goto Failure;
2794                 }
2795
2796                 for (UINT nModule = 0; nModule < assemblyData.ModuleCount; nModule++)
2797                 {
2798                     if (IsInterrupt())
2799                     {
2800                         ExtOut("<interrupted>\n");
2801                         goto Failure;
2802                     }
2803
2804                     CLRDATA_ADDRESS ModuleAddr = pModules[nModule];
2805                     DacpModuleData ModuleData;
2806                     if (FAILED(ModuleData.Request(g_sos,ModuleAddr)))
2807                     {
2808                         ExtOut("Failed to request Module data from assembly.\n");
2809                         goto Failure;
2810                     }
2811
2812                     FileNameForModule ((DWORD_PTR)ModuleAddr, StringData);
2813                     int m;
2814                     for (m = 0; StringData[m] != L'\0'; m++)
2815                     {
2816                         fileName[m] = (char)StringData[m];
2817                     }
2818                     fileName[m] = '\0';
2819                     
2820                     if ((mName == NULL) || 
2821                         IsSameModuleName(fileName, mName) ||
2822                         DebuggerModuleNamesMatch(ModuleData.File, mName) ||
2823                         IsFusionLoadedModule(fileName, mName))
2824                     {
2825                         AddToModuleList(moduleList, *numModule, maxList, (DWORD_PTR)ModuleAddr);
2826                     }    
2827                 }                        
2828
2829                 pModules = NULL;
2830             }
2831             pAssemblyArray = NULL;
2832         }
2833     }
2834
2835     return moduleList;
2836     
2837     // We do not want to return a half-constructed list.  Instead, we return NULL on a failure.
2838 Failure:
2839     delete [] moduleList;
2840     return NULL;
2841 }
2842
2843 /**********************************************************************\
2844 * Routine Description:                                                 *
2845 *                                                                      *
2846 *    Find the EE data given a name.                                    *  
2847 *                                                                      *
2848 \**********************************************************************/
2849 void GetInfoFromName(DWORD_PTR ModulePtr, const char* name)
2850 {
2851     ToRelease<IMetaDataImport> pImport = MDImportForModule (ModulePtr);    
2852     if (pImport == 0)
2853         return;
2854
2855     static WCHAR wszName[MAX_CLASSNAME_LENGTH];
2856     size_t n;
2857     size_t length = strlen (name);
2858     for (n = 0; n <= length; n ++)
2859         wszName[n] = name[n];
2860
2861     // First enumerate methods. We're taking advantage of the DAC's 
2862     // CLRDataModule::EnumMethodDefinitionByName which can parse
2863     // method names (whether in nested classes, or explicit interface
2864     // method implementations).
2865     ToRelease<IXCLRDataModule> ModuleDefinition;
2866     if (g_sos->GetModule(ModulePtr, &ModuleDefinition) == S_OK)
2867     {
2868         CLRDATA_ENUM h;
2869         if (ModuleDefinition->StartEnumMethodDefinitionsByName(wszName, 0, &h) == S_OK)
2870         {
2871             IXCLRDataMethodDefinition *pMeth = NULL;
2872             BOOL fStatus = FALSE;
2873             while (ModuleDefinition->EnumMethodDefinitionByName(&h, &pMeth) == S_OK)
2874             {
2875                 if (fStatus)
2876                     ExtOut("-----------------------\n");
2877
2878                 mdTypeDef token;
2879                 if (pMeth->GetTokenAndScope(&token, NULL) == S_OK)
2880                 {
2881                     GetInfoFromModule(ModulePtr, token);
2882                     fStatus = TRUE;
2883                 }
2884                 pMeth->Release();
2885             }
2886             ModuleDefinition->EndEnumMethodDefinitionsByName(h);
2887             if (fStatus)
2888                 return;
2889         }
2890     }
2891
2892     // Now look for types, type members and fields
2893     mdTypeDef cl;
2894     mdToken tkEnclose = mdTokenNil;
2895     WCHAR *pName;
2896     WCHAR *pHead = wszName;
2897     while ( ((pName = _wcschr (pHead,L'+')) != NULL) ||
2898              ((pName = _wcschr (pHead,L'/')) != NULL)) {
2899         pName[0] = L'\0';
2900         if (FAILED(pImport->FindTypeDefByName(pHead,tkEnclose,&tkEnclose)))
2901             return;
2902         pHead = pName+1;
2903     }
2904
2905     pName = pHead;
2906
2907     // @todo:  Handle Nested classes correctly.
2908     if (SUCCEEDED (pImport->FindTypeDefByName (pName, tkEnclose, &cl)))
2909     {
2910         GetInfoFromModule(ModulePtr, cl);
2911         return;
2912     }
2913     
2914     // See if it is a method
2915     WCHAR *pwzMethod;
2916     if ((pwzMethod = _wcsrchr(pName, L'.')) == NULL)
2917         return;
2918
2919     if (pwzMethod[-1] == L'.')
2920         pwzMethod --;
2921     pwzMethod[0] = L'\0';
2922     pwzMethod ++;
2923     
2924     // @todo:  Handle Nested classes correctly.
2925     if (SUCCEEDED(pImport->FindTypeDefByName (pName, tkEnclose, &cl)))
2926     {
2927         mdMethodDef token;
2928         ULONG cTokens;
2929         HCORENUM henum = NULL;
2930
2931         // is Member?
2932         henum = NULL;
2933         if (SUCCEEDED (pImport->EnumMembersWithName (&henum, cl, pwzMethod,
2934                                                      &token, 1, &cTokens))
2935             && cTokens == 1)
2936         {
2937             ExtOut("Member (mdToken token) of\n");
2938             GetInfoFromModule(ModulePtr, cl);
2939             return;
2940         }
2941
2942         // is Field?
2943         henum = NULL;
2944         if (SUCCEEDED (pImport->EnumFieldsWithName (&henum, cl, pwzMethod,
2945                                                      &token, 1, &cTokens))
2946             && cTokens == 1)
2947         {
2948             ExtOut("Field (mdToken token) of\n");
2949             GetInfoFromModule(ModulePtr, cl);
2950             return;
2951         }
2952     }
2953 }
2954
2955 /**********************************************************************\
2956 * Routine Description:                                                 *
2957 *                                                                      *
2958 *    Find the EE data given a token.                                   *  
2959 *                                                                      *
2960 \**********************************************************************/
2961 DWORD_PTR GetMethodDescFromModule(DWORD_PTR ModuleAddr, ULONG token)
2962 {
2963     if (TypeFromToken(token) != mdtMethodDef)
2964         return NULL;
2965
2966     CLRDATA_ADDRESS md = 0;
2967     if (FAILED(g_sos->GetMethodDescFromToken(ModuleAddr, token, &md)))
2968     {
2969         return NULL;
2970     }
2971     else if (0 == md)
2972     {
2973         // a NULL ReturnValue means the method desc is not loaded yet
2974         return MD_NOT_YET_LOADED;
2975     } 
2976     else if ( !IsMethodDesc((DWORD_PTR)md))
2977     {
2978         return NULL;
2979     }
2980     
2981     return (DWORD_PTR)md;    
2982 }
2983
2984 /**********************************************************************\
2985 * Routine Description:                                                 *
2986 *                                                                      *
2987 *    Find the MethodDefinitions given a name.                          *  
2988 *                                                                      *
2989 \**********************************************************************/
2990 HRESULT GetMethodDefinitionsFromName(TADDR ModulePtr, IXCLRDataModule* mod, const char *name, IXCLRDataMethodDefinition **ppOut, int numMethods, int *numMethodsNeeded)
2991 {
2992     if (name == NULL)
2993         return E_FAIL;
2994
2995     size_t n;
2996     size_t length = strlen (name);
2997     for (n = 0; n <= length; n ++)
2998         g_mdName[n] = name[n];
2999
3000     CLRDATA_ENUM h;
3001     int methodCount = 0;
3002     if (mod->StartEnumMethodDefinitionsByName(g_mdName, 0, &h) == S_OK)
3003     {
3004         IXCLRDataMethodDefinition *pMeth = NULL;
3005         while (mod->EnumMethodDefinitionByName(&h, &pMeth) == S_OK)
3006         {
3007             methodCount++;
3008             pMeth->Release();
3009         }
3010         mod->EndEnumMethodDefinitionsByName(h);
3011     }
3012
3013     if(numMethodsNeeded != NULL)
3014         *numMethodsNeeded = methodCount;
3015     if(ppOut == NULL)
3016         return S_OK;
3017     if(numMethods > methodCount)
3018         numMethods = methodCount;
3019
3020     if (methodCount > 0)
3021     {
3022         if (mod->StartEnumMethodDefinitionsByName(g_mdName, 0, &h) == S_OK)
3023         {
3024             IXCLRDataMethodDefinition *pMeth = NULL;
3025             for (int i = 0; i < numMethods && mod->EnumMethodDefinitionByName(&h, &pMeth) == S_OK; i++)
3026             {
3027                 ppOut[i] = pMeth;
3028             }
3029             mod->EndEnumMethodDefinitionsByName(h);
3030         }
3031     }
3032     
3033     return S_OK;
3034 }
3035
3036 /**********************************************************************\
3037 * Routine Description:                                                 *
3038 *                                                                      *
3039 *    Find the EE data given a name.                                    *  
3040 *                                                                      *
3041 \**********************************************************************/
3042 HRESULT GetMethodDescsFromName(TADDR ModulePtr, IXCLRDataModule* mod, const char *name, DWORD_PTR **pOut,int *numMethods)
3043 {
3044     if (name == NULL || pOut == NULL || numMethods == NULL)
3045         return E_FAIL;
3046
3047     *pOut = NULL;
3048     *numMethods = 0;
3049
3050     size_t n;
3051     size_t length = strlen (name);
3052     for (n = 0; n <= length; n ++)
3053         g_mdName[n] = name[n];
3054
3055     CLRDATA_ENUM h;
3056     int methodCount = 0;
3057     if (mod->StartEnumMethodDefinitionsByName(g_mdName, 0, &h) == S_OK)
3058     {
3059         IXCLRDataMethodDefinition *pMeth = NULL;
3060         while (mod->EnumMethodDefinitionByName(&h, &pMeth) == S_OK)
3061         {
3062             methodCount++;
3063             pMeth->Release();
3064         }
3065         mod->EndEnumMethodDefinitionsByName(h);
3066     }
3067
3068     if (methodCount > 0)
3069     {
3070         *pOut = new TADDR[methodCount];
3071         if (*pOut==NULL)
3072         {
3073             ReportOOM();
3074             return E_OUTOFMEMORY;
3075         }
3076
3077         *numMethods = methodCount;
3078
3079         if (mod->StartEnumMethodDefinitionsByName(g_mdName, 0, &h) == S_OK)
3080         {
3081             int i = 0;
3082             IXCLRDataMethodDefinition *pMeth = NULL;
3083             while (mod->EnumMethodDefinitionByName(&h, &pMeth) == S_OK)
3084             {
3085                 mdTypeDef token;
3086                 if (pMeth->GetTokenAndScope(&token, NULL) != S_OK)
3087                     (*pOut)[i] = NULL;
3088                 (*pOut)[i] = GetMethodDescFromModule(ModulePtr, token);
3089                 if ((*pOut)[i] == NULL)
3090                 {
3091                     *numMethods = 0;
3092                     return E_FAIL;
3093                 }
3094                 i++;
3095                 pMeth->Release();
3096             }
3097             mod->EndEnumMethodDefinitionsByName(h);
3098         }
3099     }
3100     
3101     return S_OK;
3102 }
3103     
3104 /**********************************************************************\
3105 * Routine Description:                                                 *
3106 *                                                                      *
3107 *    Find the EE data given a token.                                   *  
3108 *                                                                      *
3109 \**********************************************************************/
3110 void GetInfoFromModule (DWORD_PTR ModuleAddr, ULONG token, DWORD_PTR *ret)
3111 {
3112     switch (TypeFromToken(token))
3113     {
3114         case mdtMethodDef:
3115             break;
3116         case mdtTypeDef:
3117             break;
3118         case mdtTypeRef:
3119             break;
3120         case mdtFieldDef:
3121             break;            
3122         default:
3123             ExtOut("This token type is not supported\n");
3124             return;
3125             break;
3126     }
3127     
3128     CLRDATA_ADDRESS md = 0;
3129     if (FAILED(g_sos->GetMethodDescFromToken(ModuleAddr, token, &md)) || !IsValidToken (ModuleAddr, token))
3130     {
3131         ExtOut("<invalid module token>\n");
3132         return;
3133     }
3134     
3135     if (ret != NULL)
3136     {
3137         *ret = (DWORD_PTR)md;
3138         return;
3139     }
3140
3141     ExtOut("Token:       %p\n", SOS_PTR(token));
3142  
3143     switch (TypeFromToken(token))
3144     {
3145         case mdtFieldDef:
3146         {
3147             NameForToken_s(ModuleAddr, token, g_mdName, mdNameLen);
3148             ExtOut("Field name:  %S\n", g_mdName);
3149             break;
3150         }
3151         case mdtMethodDef:
3152         {
3153             if (md)
3154             {
3155                 DMLOut("MethodDesc:  %s\n", DMLMethodDesc(md));
3156
3157                 // Easiest to get full parameterized method name from ..::GetMethodName
3158                 if (g_sos->GetMethodDescName(md, mdNameLen, g_mdName, NULL) != S_OK)
3159                 {
3160                     // Fall back to just method name without parameters..
3161                     NameForToken_s(ModuleAddr, token, g_mdName, mdNameLen);
3162                 }
3163             }
3164             else
3165             {
3166                 ExtOut("MethodDesc:  <not loaded yet>\n");  
3167                 NameForToken_s(ModuleAddr, token, g_mdName, mdNameLen);
3168             }
3169             
3170             ExtOut("Name:        %S\n", g_mdName);
3171             // Nice to have a little more data
3172             if (md)
3173             {
3174                 DacpMethodDescData MethodDescData;
3175                 if (MethodDescData.Request(g_sos, md) == S_OK)
3176                 {
3177                     if (MethodDescData.bHasNativeCode)
3178                     {
3179                         DMLOut("JITTED Code Address: %s\n", DMLIP(MethodDescData.NativeCodeAddr));                
3180                     }
3181                     else
3182                     {
3183 #ifndef FEATURE_PAL
3184                         if (IsDMLEnabled())
3185                             DMLOut("Not JITTED yet. Use <exec cmd=\"!bpmd -md %p\">!bpmd -md %p</exec> to break on run.\n",
3186                                 SOS_PTR(md), SOS_PTR(md));
3187                         else
3188                             ExtOut("Not JITTED yet. Use !bpmd -md %p to break on run.\n", SOS_PTR(md));
3189 #else
3190                         ExtOut("Not JITTED yet. Use 'bpmd -md %p' to break on run.\n", SOS_PTR(md));
3191 #endif
3192                     }
3193                 }
3194                 else
3195                 {
3196                     ExtOut ("<Error getting MethodDesc information>\n");
3197                 }
3198             }
3199             else
3200             {
3201                 ExtOut("Not JITTED yet.\n");    
3202             }
3203             break;
3204         }
3205         case mdtTypeDef:
3206         case mdtTypeRef:
3207         {
3208             if (md)
3209             {
3210                 DMLOut("MethodTable: %s\n", DMLMethodTable(md));
3211                 DacpMethodTableData mtabledata;
3212                 if (mtabledata.Request(g_sos, md) == S_OK)
3213                 {
3214                     DMLOut("EEClass:     %s\n", DMLClass(mtabledata.Class));
3215                 }
3216                 else
3217                 {
3218                     ExtOut("EEClass:     <error getting EEClass>\n");
3219                 }                
3220             }
3221             else
3222             {
3223                 ExtOut("MethodTable: <not loaded yet>\n");
3224                 ExtOut("EEClass:     <not loaded yet>\n");                
3225             }
3226             NameForToken_s(ModuleAddr, token, g_mdName, mdNameLen);
3227             ExtOut("Name:        %S\n", g_mdName);
3228             break;
3229         }
3230         default:
3231             break;
3232     }
3233     return;
3234 }
3235
3236 BOOL IsMTForFreeObj(DWORD_PTR pMT)
3237 {
3238     return (pMT == g_special_usefulGlobals.FreeMethodTable);
3239 }
3240
3241 const char *EHTypeName(EHClauseType et)
3242 {
3243     if (et == EHFault)
3244         return "FAULT";
3245     else if (et == EHFinally)
3246         return "FINALLY";
3247     else if (et == EHFilter)
3248         return "FILTER";
3249     else if (et == EHTyped)
3250         return "TYPED";
3251     else
3252         return "UNKNOWN";
3253 }
3254
3255 void DumpTieredNativeCodeAddressInfo(struct DacpTieredVersionData * pTieredVersionData, const UINT cTieredVersionData)
3256 {
3257     ExtOut("Code Version History:\n");
3258
3259     for(int i = cTieredVersionData - 1; i >= 0; --i)
3260     {
3261         const char *descriptor = NULL;
3262         switch(pTieredVersionData[i].TieredInfo)
3263         {
3264         case DacpTieredVersionData::TIERED_UNKNOWN:
3265         default:
3266             _ASSERTE(!"Update SOS to understand the new tier");
3267             descriptor = "Unknown Tier";
3268             break;
3269         case DacpTieredVersionData::NON_TIERED:
3270             descriptor = "Non-Tiered";
3271             break;
3272         case DacpTieredVersionData::TIERED_0:
3273             descriptor = "Tier 0";
3274             break;
3275         case DacpTieredVersionData::TIERED_1:
3276             descriptor = "Tier 1";
3277             break;
3278         }
3279
3280         DMLOut("  CodeAddr:           %s  (%s)\n", DMLIP(pTieredVersionData[i].NativeCodeAddr), descriptor);
3281         ExtOut("  NativeCodeVersion:  %p\n", SOS_PTR(pTieredVersionData[i].NativeCodeVersionNodePtr));
3282     }
3283 }
3284
3285 void DumpRejitData(CLRDATA_ADDRESS pMethodDesc, DacpReJitData * pReJitData)
3286 {
3287     ExtOut("    ReJITID %p: ", SOS_PTR(pReJitData->rejitID));
3288
3289     struct DacpTieredVersionData codeAddrs[kcMaxTieredVersions];
3290     int cCodeAddrs;
3291
3292     ReleaseHolder<ISOSDacInterface5> sos5;
3293     if (SUCCEEDED(g_sos->QueryInterface(__uuidof(ISOSDacInterface5), &sos5)) && 
3294         SUCCEEDED(sos5->GetTieredVersions(pMethodDesc, 
3295                                             (int)pReJitData->rejitID,
3296                                             codeAddrs,
3297                                             kcMaxTieredVersions,
3298                                             &cCodeAddrs)))
3299     {
3300         DumpTieredNativeCodeAddressInfo(codeAddrs, cCodeAddrs);
3301     }
3302
3303     LPCSTR szFlags;
3304     switch (pReJitData->flags)
3305     {
3306     default:
3307     case DacpReJitData::kUnknown:
3308         szFlags = "";
3309         break;
3310
3311     case DacpReJitData::kRequested:
3312         szFlags = " (READY to jit on next call)";
3313         break;
3314
3315     case DacpReJitData::kActive:
3316         szFlags = " (CURRENT)";
3317         break;
3318
3319     case DacpReJitData::kReverted:
3320         szFlags = " (reverted)";
3321         break;
3322     }
3323     
3324     ExtOut("%s\n", szFlags);
3325 }
3326
3327 // For !ip2md requests, this function helps us ensure that rejitted version corresponding
3328 // to the specified IP always gets dumped. It may have already been dumped if it was the
3329 // current rejit version (which is always dumped) or one of the reverted versions that we
3330 // happened to dump before we clipped their number down to kcRejitDataRevertedMax.
3331 BOOL ShouldDumpRejitDataRequested(DacpMethodDescData * pMethodDescData, DacpReJitData * pRevertedRejitData, UINT cRevertedRejitData)
3332 {
3333     if (pMethodDescData->rejitDataRequested.rejitID == 0)
3334         return FALSE;
3335
3336     if (pMethodDescData->rejitDataRequested.rejitID == pMethodDescData->rejitDataCurrent.rejitID)
3337         return FALSE;
3338
3339     for (ULONG i=0; i < cRevertedRejitData; i++)
3340     {
3341         if (pMethodDescData->rejitDataRequested.rejitID == pRevertedRejitData[i].rejitID)
3342             return FALSE;
3343     }
3344
3345     return TRUE;
3346 }
3347
3348
3349 void DumpAllRejitDataIfNecessary(DacpMethodDescData * pMethodDescData, DacpReJitData * pRevertedRejitData, UINT cRevertedRejitData)
3350 {
3351     // If there's no rejit info to output, then skip
3352     if ((pMethodDescData->rejitDataCurrent.rejitID == 0) &&
3353         (pMethodDescData->rejitDataRequested.rejitID == 0) &&
3354         (cRevertedRejitData == 0))
3355     {
3356         return;
3357     }
3358     ExtOut("ReJITed versions:\n");
3359
3360     // Dump CURRENT rejit info
3361     DumpRejitData(pMethodDescData->MethodDescPtr, &pMethodDescData->rejitDataCurrent);
3362
3363     // Dump reverted rejit infos
3364     for (ULONG i=0; i < cRevertedRejitData; i++)
3365     {
3366         DumpRejitData(pMethodDescData->MethodDescPtr, &pRevertedRejitData[i]);
3367     }
3368
3369     // For !ip2md, ensure we dump the rejit version corresponding to the specified IP
3370     // (if not already dumped)
3371     if (ShouldDumpRejitDataRequested(pMethodDescData, pRevertedRejitData, cRevertedRejitData))
3372         DumpRejitData(pMethodDescData->MethodDescPtr, &pMethodDescData->rejitDataRequested);
3373
3374     // If we maxed out the reverted versions we dumped, let user know there may be more
3375     if (cRevertedRejitData == kcMaxRevertedRejitData)
3376         ExtOut("    (... possibly more reverted versions ...)\n");
3377 }
3378
3379 void DumpMDInfoFromMethodDescData(DacpMethodDescData * pMethodDescData, DacpReJitData * pRevertedRejitData, UINT cRevertedRejitData, BOOL fStackTraceFormat)
3380 {
3381     static WCHAR wszNameBuffer[1024]; // should be large enough
3382     BOOL bFailed = FALSE;
3383     if (g_sos->GetMethodDescName(pMethodDescData->MethodDescPtr, 1024, wszNameBuffer, NULL) != S_OK)
3384     {
3385         wcscpy_s(wszNameBuffer, _countof(wszNameBuffer), W("UNKNOWN"));        
3386         bFailed = TRUE;        
3387     }
3388
3389     if (!fStackTraceFormat)
3390     {
3391         ExtOut("Method Name:          %S\n", wszNameBuffer);
3392
3393         DacpMethodTableData mtdata;
3394         if (SUCCEEDED(mtdata.Request(g_sos, pMethodDescData->MethodTablePtr)))
3395         {
3396             DMLOut("Class:                %s\n", DMLClass(mtdata.Class));
3397         }            
3398
3399         DMLOut("MethodTable:          %s\n", DMLMethodTable(pMethodDescData->MethodTablePtr));
3400         ExtOut("mdToken:              %p\n", SOS_PTR(pMethodDescData->MDToken));
3401         DMLOut("Module:               %s\n", DMLModule(pMethodDescData->ModulePtr));
3402         ExtOut("IsJitted:             %s\n", pMethodDescData->bHasNativeCode ? "yes" : "no");
3403
3404         DMLOut("Current CodeAddr:     %s\n", DMLIP(pMethodDescData->NativeCodeAddr));                
3405
3406         struct DacpTieredVersionData codeAddrs[kcMaxTieredVersions];
3407         int cCodeAddrs;
3408
3409         ReleaseHolder<ISOSDacInterface5> sos5;
3410         if (SUCCEEDED(g_sos->QueryInterface(__uuidof(ISOSDacInterface5), &sos5)) && 
3411             SUCCEEDED(sos5->GetTieredVersions(pMethodDescData->MethodDescPtr, 
3412                                                                 (int)pMethodDescData->rejitDataCurrent.rejitID,
3413                                                                 codeAddrs,
3414                                                                 kcMaxTieredVersions,
3415                                                                 &cCodeAddrs)))
3416         {
3417             DumpTieredNativeCodeAddressInfo(codeAddrs, cCodeAddrs);
3418         }
3419         
3420         DacpMethodDescTransparencyData transparency;
3421         if (SUCCEEDED(transparency.Request(g_sos, pMethodDescData->MethodDescPtr)))
3422         {
3423             ExtOut("Transparency: %s\n", GetTransparency(transparency));
3424         }
3425
3426         DumpAllRejitDataIfNecessary(pMethodDescData, pRevertedRejitData, cRevertedRejitData);
3427     }
3428     else
3429     {
3430         if (!bFailed)
3431         {
3432             ExtOut("%S", wszNameBuffer);
3433         }
3434         else
3435         {
3436             // Only clutter the display with module/token for cases where we
3437             // can't get the MethodDesc name for some reason.
3438             DMLOut("Unknown MethodDesc (Module %s, mdToken %08x)", 
3439                     DMLModule(pMethodDescData->ModulePtr),
3440                     pMethodDescData->MDToken);
3441         }
3442     }
3443 }
3444
3445 void DumpMDInfo(DWORD_PTR dwMethodDescAddr, CLRDATA_ADDRESS dwRequestedIP /* = 0 */, BOOL fStackTraceFormat /*  = FALSE */)
3446 {
3447     DacpMethodDescData MethodDescData;
3448     DacpReJitData revertedRejitData[kcMaxRevertedRejitData];
3449     ULONG cNeededRevertedRejitData;
3450     if (g_sos->GetMethodDescData(
3451         TO_CDADDR(dwMethodDescAddr), 
3452         dwRequestedIP,
3453         &MethodDescData, 
3454         _countof(revertedRejitData),
3455         revertedRejitData,
3456         &cNeededRevertedRejitData) != S_OK)
3457     {
3458         ExtOut("%p is not a MethodDesc\n", SOS_PTR(dwMethodDescAddr));
3459         return;
3460     }
3461
3462     DumpMDInfoFromMethodDescData(&MethodDescData, revertedRejitData, cNeededRevertedRejitData, fStackTraceFormat);
3463 }
3464
3465 void GetDomainList (DWORD_PTR *&domainList, int &numDomain)
3466 {
3467     DacpAppDomainStoreData adsData;
3468
3469     numDomain = 0;            
3470     
3471     if (adsData.Request(g_sos)!=S_OK)
3472     {
3473         return;
3474     }
3475
3476     // Do prefast integer checks before the malloc.
3477     size_t AllocSize;
3478     LONG DomainAllocCount;
3479     if (!ClrSafeInt<LONG>::addition(adsData.DomainCount, 2, DomainAllocCount) ||
3480         !ClrSafeInt<size_t>::multiply(DomainAllocCount, sizeof(PVOID), AllocSize) ||
3481         (domainList = new DWORD_PTR[DomainAllocCount]) == NULL)
3482     {
3483         return;
3484     }
3485
3486     domainList[numDomain++] = (DWORD_PTR) adsData.systemDomain;
3487     domainList[numDomain++] = (DWORD_PTR) adsData.sharedDomain;
3488     
3489     CLRDATA_ADDRESS *pArray = new CLRDATA_ADDRESS[adsData.DomainCount];
3490     if (pArray==NULL)
3491     {
3492         return;
3493     }
3494
3495     if (g_sos->GetAppDomainList(adsData.DomainCount, pArray, NULL)!=S_OK)
3496     {
3497         delete [] pArray;
3498         return;
3499     }
3500
3501     for (int n=0;n<adsData.DomainCount;n++)
3502     {
3503         if (IsInterrupt())
3504             break;
3505         domainList[numDomain++] = (DWORD_PTR) pArray[n];
3506     }
3507
3508     delete [] pArray;
3509 }
3510
3511
3512 HRESULT GetThreadList(DWORD_PTR **threadList, int *numThread)
3513 {
3514     _ASSERTE(threadList != NULL);
3515     _ASSERTE(numThread != NULL);
3516
3517     if (threadList == NULL || numThread == NULL)
3518     {
3519         return E_FAIL;
3520     }
3521
3522     *numThread = 0;
3523
3524     DacpThreadStoreData ThreadStore;
3525     if ( ThreadStore.Request(g_sos) != S_OK)
3526     {
3527         ExtOut("Failed to request threads from the thread store.");
3528         return E_FAIL;
3529     }
3530      
3531     *threadList = new DWORD_PTR[ThreadStore.threadCount];
3532     if (*threadList == NULL)
3533     {
3534         ReportOOM();
3535         return E_OUTOFMEMORY;
3536     }
3537     
3538     CLRDATA_ADDRESS CurThread = ThreadStore.firstThread;
3539     while (CurThread != NULL)
3540     {
3541         if (IsInterrupt())
3542             return S_FALSE;
3543
3544         DacpThreadData Thread;
3545         if (Thread.Request(g_sos, CurThread) != S_OK)
3546         {
3547             ExtOut("Failed to request Thread at %p\n", SOS_PTR(CurThread));
3548             return E_FAIL;
3549         }
3550
3551         (*threadList)[(*numThread)++] = (DWORD_PTR)CurThread;
3552         CurThread = Thread.nextThread;
3553     }
3554
3555     return S_OK;
3556 }
3557
3558 CLRDATA_ADDRESS GetCurrentManagedThread ()
3559 {
3560     DacpThreadStoreData ThreadStore;
3561     ThreadStore.Request(g_sos);
3562
3563     ULONG Tid;
3564     g_ExtSystem->GetCurrentThreadSystemId(&Tid);
3565     
3566     CLRDATA_ADDRESS CurThread = ThreadStore.firstThread;
3567     while (CurThread)
3568     {
3569         DacpThreadData Thread;
3570         if (Thread.Request(g_sos, CurThread) != S_OK)
3571         {
3572             return NULL;
3573         }        
3574         
3575         if (Thread.osThreadId == Tid)
3576         {        
3577             return CurThread;
3578         }
3579         
3580         CurThread = Thread.nextThread;
3581     }
3582     return NULL;
3583 }
3584
3585
3586 void ReloadSymbolWithLineInfo()
3587 {
3588 #ifndef FEATURE_PAL
3589     static BOOL bLoadSymbol = FALSE;
3590     if (!bLoadSymbol)
3591     {
3592         ULONG Options;
3593         g_ExtSymbols->GetSymbolOptions(&Options);
3594         if (!(Options & SYMOPT_LOAD_LINES))
3595         {
3596             g_ExtSymbols->AddSymbolOptions(SYMOPT_LOAD_LINES);
3597             
3598             if (SUCCEEDED(g_ExtSymbols->GetModuleByModuleName(MSCOREE_SHIM_A, 0, NULL, NULL)))
3599                 g_ExtSymbols->Reload("/f " MSCOREE_SHIM_A);
3600             
3601             EEFLAVOR flavor = GetEEFlavor();
3602             if (flavor == MSCORWKS)
3603                 g_ExtSymbols->Reload("/f " MAIN_CLR_DLL_NAME_A);
3604         }
3605         
3606         // reload mscoree.pdb and clrjit.pdb to get line info
3607         bLoadSymbol = TRUE;
3608     }
3609 #endif
3610 }
3611
3612 // Return 1 if the function is our stub
3613 // Return MethodDesc if the function is managed
3614 // Otherwise return 0
3615 size_t FunctionType (size_t EIP)
3616 {
3617     ULONG64 base = 0;
3618     ULONG   ulLoaded, ulUnloaded, ulIndex;
3619
3620     // Get the number of loaded and unloaded modules
3621     if (FAILED(g_ExtSymbols->GetNumberModules(&ulLoaded, &ulUnloaded)))
3622         return 0;
3623
3624
3625     if (SUCCEEDED(g_ExtSymbols->GetModuleByOffset(TO_CDADDR(EIP), 0, &ulIndex, &base)) && base != 0)
3626     {
3627         if (ulIndex < ulLoaded)
3628         {
3629             IMAGE_DOS_HEADER DosHeader;
3630             if (g_ExtData->ReadVirtual(TO_CDADDR(base), &DosHeader, sizeof(DosHeader), NULL) != S_OK)
3631                 return 0;
3632             IMAGE_NT_HEADERS Header;
3633             if (g_ExtData->ReadVirtual(TO_CDADDR(base + DosHeader.e_lfanew), &Header, sizeof(Header), NULL) != S_OK)
3634                 return 0;
3635             // If there is no COMHeader, this can not be managed code.
3636             if (Header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COMHEADER].VirtualAddress == 0)
3637                 return 0;
3638             
3639             IMAGE_COR20_HEADER ComPlusHeader;
3640             if (g_ExtData->ReadVirtual(TO_CDADDR(base + Header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COMHEADER].VirtualAddress),
3641                                        &ComPlusHeader, sizeof(ComPlusHeader), NULL) != S_OK)
3642                 return 0;
3643             
3644             // If there is no Precompiled image info, it can not be prejit code
3645             if (ComPlusHeader.ManagedNativeHeader.VirtualAddress == 0) {
3646                 return 0;
3647             }
3648         }
3649     }
3650
3651     CLRDATA_ADDRESS dwStartAddr = TO_CDADDR(EIP);
3652     CLRDATA_ADDRESS pMD;
3653     if (g_sos->GetMethodDescPtrFromIP(dwStartAddr, &pMD) != S_OK)
3654     {
3655         return 1;
3656     }
3657
3658     return (size_t) pMD;
3659 }
3660
3661 #ifndef FEATURE_PAL
3662
3663 //
3664 // Gets version info for the CLR in the debuggee process.
3665 //
3666 BOOL GetEEVersion(VS_FIXEDFILEINFO *pFileInfo)
3667 {
3668     _ASSERTE(g_ExtSymbols2);
3669     _ASSERTE(pFileInfo);
3670     // Grab the version info directly from the module.
3671     return g_ExtSymbols2->GetModuleVersionInformation(DEBUG_ANY_ID,
3672                                                    moduleInfo[GetEEFlavor()].baseAddr,
3673                                                    "\\", pFileInfo, sizeof(VS_FIXEDFILEINFO), NULL) == S_OK;
3674 }
3675
3676 extern HMODULE g_hInstance;
3677 BOOL GetSOSVersion(VS_FIXEDFILEINFO *pFileInfo)
3678 {
3679     _ASSERTE(pFileInfo);
3680     
3681     WCHAR wszFullPath[MAX_LONGPATH];
3682     DWORD cchFullPath = GetModuleFileNameW(g_hInstance, wszFullPath, _countof(wszFullPath));
3683     
3684     DWORD dwHandle = 0;
3685     DWORD infoSize = GetFileVersionInfoSizeW(wszFullPath, &dwHandle);
3686     if (infoSize)
3687     {
3688         ArrayHolder<BYTE> pVersionInfo = new BYTE[infoSize];
3689         if (pVersionInfo)
3690         {
3691             if (GetFileVersionInfoW(wszFullPath, NULL, infoSize, pVersionInfo))
3692             {
3693                 VS_FIXEDFILEINFO *pTmpFileInfo = NULL;
3694                 UINT uLen = 0;
3695                 if (VerQueryValue(pVersionInfo, "\\", (LPVOID *) &pTmpFileInfo, &uLen))
3696                 {
3697                     *pFileInfo = *pTmpFileInfo; // Copy the info
3698                     return TRUE;
3699                 }
3700             }
3701         }
3702     }
3703     
3704     return FALSE;
3705 }
3706
3707 #endif // !FEATURE_PAL
3708     
3709 size_t ObjectSize(DWORD_PTR obj,BOOL fIsLargeObject)
3710 {
3711     DWORD_PTR dwMT;
3712     MOVE(dwMT, obj);
3713     return ObjectSize(obj, dwMT, FALSE, fIsLargeObject);
3714 }
3715
3716 size_t ObjectSize(DWORD_PTR obj, DWORD_PTR mt, BOOL fIsValueClass, BOOL fIsLargeObject)
3717 {
3718     BOOL bContainsPointers;
3719     size_t size = 0;
3720     if (!GetSizeEfficient(obj, mt, fIsLargeObject, size, bContainsPointers))
3721     {
3722         return 0;
3723     }
3724     return size;
3725 }
3726
3727 // This takes an array of values and sets every non-printable character
3728 // to be a period.
3729 void Flatten(__out_ecount(len) char *data, unsigned int len)
3730 {
3731     for (unsigned int i = 0; i < len; ++i)
3732         if (data[i] < 32 || data[i] > 126)
3733             data[i] = '.';
3734     data[len] = 0;
3735 }
3736
3737 void CharArrayContent(TADDR pos, ULONG num, bool widechar)
3738 {
3739     if (!pos || num <= 0)
3740         return;
3741
3742     if (widechar)
3743     {
3744         ArrayHolder<WCHAR> data = new WCHAR[num+1];
3745         if (!data)
3746         {
3747             ReportOOM();
3748             return;
3749         }
3750
3751         ULONG readLen = 0;
3752         if (!SafeReadMemory(pos, data, num<<1, &readLen))
3753             return;
3754
3755         Flatten(data.GetPtr(), readLen >> 1);
3756         ExtOut("%S", data.GetPtr());
3757     }
3758     else
3759     {
3760         ArrayHolder<char> data = new char[num+1];
3761         if (!data)
3762         {
3763             ReportOOM();
3764             return;
3765         }
3766
3767         ULONG readLen = 0;
3768         if (!SafeReadMemory(pos, data, num, &readLen))
3769             return;
3770
3771         _ASSERTE(readLen <= num);
3772         Flatten(data, readLen);
3773         
3774         ExtOut("%s", data.GetPtr());
3775     }
3776 }
3777
3778 void StringObjectContent(size_t obj, BOOL fLiteral, const int length)
3779 {
3780     DacpObjectData objData;
3781     if (objData.Request(g_sos, TO_CDADDR(obj))!=S_OK)
3782     {
3783         ExtOut("<Invalid Object>");
3784         return;
3785     }
3786     
3787     strobjInfo stInfo;
3788
3789     if (MOVE(stInfo,obj) != S_OK)
3790     {
3791         ExtOut ("Error getting string data\n");
3792         return;
3793     }
3794
3795     if (objData.Size > 0x200000 ||
3796         stInfo.m_StringLength > 0x200000)
3797     {
3798         ExtOut ("<String is invalid or too large to print>\n");
3799         return;
3800     }
3801     
3802     ArrayHolder<WCHAR> pwszBuf = new WCHAR[stInfo.m_StringLength+1];
3803     if (pwszBuf == NULL)
3804     {
3805         return;
3806     }
3807     
3808     DWORD_PTR dwAddr = (DWORD_PTR)pwszBuf.GetPtr();
3809     if (g_sos->GetObjectStringData(TO_CDADDR(obj), stInfo.m_StringLength+1, pwszBuf, NULL)!=S_OK)
3810     {
3811         ExtOut("Error getting string data\n");
3812         return;
3813     }
3814
3815     if (!fLiteral) 
3816     {
3817         pwszBuf[stInfo.m_StringLength] = L'\0';
3818         ExtOut ("%S", pwszBuf.GetPtr());
3819     }
3820     else
3821     {
3822         ULONG32 count = stInfo.m_StringLength;
3823         WCHAR buffer[256];
3824         WCHAR out[512];
3825         while (count) 
3826         {
3827             DWORD toRead = 255;
3828             if (count < toRead)
3829                 toRead = count;
3830
3831             ULONG bytesRead;
3832             wcsncpy_s(buffer,_countof(buffer),(LPWSTR) dwAddr, toRead);
3833             bytesRead = toRead*sizeof(WCHAR);
3834             DWORD wcharsRead = bytesRead/2;
3835             buffer[wcharsRead] = L'\0';
3836             
3837             ULONG j,k=0;
3838             for (j = 0; j < wcharsRead; j ++) 
3839             {
3840                 if (_iswprint (buffer[j])) {
3841                     out[k] = buffer[j];
3842                     k ++;
3843                 }
3844                 else
3845                 {
3846                     out[k++] = L'\\';
3847                     switch (buffer[j]) {
3848                     case L'\n':
3849                         out[k++] = L'n';
3850                         break;
3851                     case L'\0':
3852                         out[k++] = L'0';
3853                         break;
3854                     case L'\t':
3855                         out[k++] = L't';
3856                         break;
3857                     case L'\v':
3858                         out[k++] = L'v';
3859                         break;
3860                     case L'\b':
3861                         out[k++] = L'b';
3862                         break;
3863                     case L'\r':
3864                         out[k++] = L'r';
3865                         break;
3866                     case L'\f':
3867                         out[k++] = L'f';
3868                         break;
3869                     case L'\a':
3870                         out[k++] = L'a';
3871                         break;
3872                     case L'\\':
3873                         break;
3874                     case L'\?':
3875                         out[k++] = L'?';
3876                         break;
3877                     default:
3878                         out[k++] = L'?';
3879                         break;
3880                     }
3881                 }
3882             }
3883
3884             out[k] = L'\0';
3885             ExtOut ("%S", out);
3886
3887             count -= wcharsRead;
3888             dwAddr += bytesRead;
3889         }
3890     }
3891 }
3892
3893 #ifdef _TARGET_WIN64_
3894
3895 #include <limits.h>
3896
3897 __int64 str64hex(const char *ptr)
3898 {
3899     __int64 value = 0;
3900     unsigned char nCount = 0;
3901     
3902     if(ptr==NULL)
3903         return 0;
3904
3905     // Ignore leading 0x if present
3906     if (*ptr=='0' && toupper(*(ptr+1))=='X') {
3907         ptr = ptr + 2;
3908     }
3909
3910     while (1) {        
3911
3912         char digit;
3913         
3914         if (isdigit(*ptr)) {
3915             digit = *ptr - '0';
3916         } else if (isalpha(*ptr)) {
3917             digit = (((char)toupper(*ptr)) - 'A') + 10;
3918             if (digit >= 16) {
3919                 break; // terminate
3920             }
3921         } else {
3922             break;
3923         }
3924
3925         if (nCount>15) {
3926             return _UI64_MAX;     // would be an overflow
3927         }
3928             
3929         value = value << 4;        
3930         value |= digit;
3931
3932         ptr++;
3933         nCount++;
3934     }
3935     
3936     return value;    
3937 }
3938
3939 #endif // _TARGET_WIN64_
3940
3941 BOOL GetValueForCMD (const char *ptr, const char *end, ARGTYPE type, size_t *value)
3942 {   
3943     if (type == COSTRING) {
3944         // Allocate memory for the length of the string. Whitespace terminates
3945         // User must free the string data. 
3946         char *pszValue = NULL;
3947         size_t dwSize = (end - ptr);    
3948         pszValue= new char[dwSize+1];
3949         if (pszValue == NULL)
3950         {
3951             return FALSE;
3952         }
3953         strncpy_s(pszValue,dwSize+1,ptr,dwSize); // _TRUNCATE
3954         *value = (size_t) pszValue;               
3955     } else {
3956         char *last;
3957         if (type == COHEX) {
3958 #ifdef _TARGET_WIN64_
3959             *value = str64hex(ptr);
3960 #else
3961             *value = strtoul(ptr,&last,16);
3962 #endif
3963         }
3964         else {     
3965 #ifdef _TARGET_WIN64_
3966             *value = _atoi64(ptr);
3967 #else
3968             *value = strtoul(ptr,&last,10);
3969 #endif
3970         }
3971
3972 #ifdef _TARGET_WIN64_
3973         last = (char *) ptr;
3974         // Ignore leading 0x if present
3975         if (*last=='0' && toupper(*(last+1))=='X') {
3976             last = last + 2;
3977         }
3978
3979         while (isdigit(*last) || (toupper(*last)>='A' && toupper(*last)<='F')) {
3980             last++;
3981         }
3982 #endif
3983
3984         if (last != end) {
3985             return FALSE;
3986         }
3987     }
3988
3989     return TRUE;
3990 }
3991
3992 void SetValueForCMD (void *vptr, ARGTYPE type, size_t value)
3993 {
3994     switch (type) {
3995     case COBOOL:
3996         *(BOOL*)vptr = (BOOL) value;
3997         break;
3998     case COSIZE_T:
3999     case COSTRING:
4000     case COHEX:
4001         *(SIZE_T*)vptr = value;
4002         break;
4003     }
4004 }
4005
4006 BOOL GetCMDOption(const char *string, CMDOption *option, size_t nOption,
4007                   CMDValue *arg, size_t maxArg, size_t *nArg)
4008 {
4009     const char *end;
4010     const char *ptr = string;
4011     BOOL endofOption = FALSE;
4012
4013     for (size_t n = 0; n < nOption; n ++)
4014     {
4015         if (IsInterrupt())
4016             return FALSE;
4017         
4018         option[n].hasSeen = FALSE;
4019     }
4020
4021     if (nArg) {
4022         *nArg = 0;
4023     }
4024
4025     while (ptr[0] != '\0')
4026     {
4027         if (IsInterrupt())
4028             return FALSE;
4029         
4030         // skip any space
4031         if (isspace (ptr[0])) {
4032             while (isspace (ptr[0]))
4033             {
4034                 if (IsInterrupt())
4035                     return FALSE;
4036         
4037                 ptr ++;
4038             }
4039             
4040             continue;
4041         }
4042
4043         end = ptr;
4044
4045         // Arguments can be quoted with ". We'll remove the quotes and
4046         // allow spaces to exist in the string.
4047         BOOL bQuotedArg = FALSE;
4048         if (ptr[0] == '\'' && ptr[1] != '-')
4049         {            
4050             bQuotedArg = TRUE;
4051
4052             // skip quote
4053             ptr++;
4054             end++;
4055             
4056             while (end[0] != '\'' && end[0] != '\0')
4057             {
4058                 if (IsInterrupt())
4059                     return FALSE;
4060             
4061                 end ++;
4062             }
4063             if (end[0] != '\'')
4064             {
4065                 // Error, th ere was a start quote but no end quote
4066                 ExtOut ("Missing quote in %s\n", ptr);
4067                 return FALSE;
4068             }
4069         }
4070         else // whitespace terminates
4071         {
4072             while (!isspace(end[0]) && end[0] != '\0')
4073             {
4074                 if (IsInterrupt())
4075                     return FALSE;
4076             
4077                 end ++;
4078             }
4079         }
4080
4081 #ifndef FEATURE_PAL
4082         if (ptr[0] != '-' && ptr[0] != '/') {
4083 #else
4084         if (ptr[0] != '-') {
4085 #endif
4086             if (maxArg == 0) {
4087                 ExtOut ("Incorrect argument: %s\n", ptr);
4088                 return FALSE;
4089             }
4090             endofOption = TRUE;
4091             if (*nArg >= maxArg) {
4092                 ExtOut ("Incorrect argument: %s\n", ptr);
4093                 return FALSE;
4094             }
4095             
4096             size_t value;
4097             if (!GetValueForCMD (ptr,end,arg[*nArg].type,&value)) {
4098
4099                 char oldChar = *end;
4100                 *(char *)end = '\0';
4101                 value = (size_t)GetExpression (ptr);
4102                 *(char *)end = oldChar;
4103                 
4104                 /*
4105
4106                     It is silly to do this, what if 0 is a valid expression for
4107                     the command?
4108                     
4109                 if (value == 0) {
4110                     ExtOut ("Invalid argument: %s\n", ptr);
4111                     return FALSE;
4112                 }
4113                 */
4114             }
4115
4116             SetValueForCMD (arg[*nArg].vptr, arg[*nArg].type, value);
4117
4118             (*nArg) ++;
4119         }
4120         else if (endofOption) {
4121             ExtOut ("Wrong option: %s\n", ptr);
4122             return FALSE;
4123         }
4124         else {
4125             char buffer[80];
4126             if (end-ptr > 79) {
4127                 ExtOut ("Invalid option %s\n", ptr);
4128                 return FALSE;
4129             }
4130             strncpy_s (buffer,_countof(buffer), ptr, end-ptr);
4131
4132             size_t n;
4133             for (n = 0; n < nOption; n ++)
4134             {
4135                 if (IsInterrupt())
4136                     return FALSE;
4137         
4138                 if (_stricmp (buffer, option[n].name) == 0) {
4139                     if (option[n].hasSeen) {
4140                         ExtOut ("Invalid option: option specified multiple times: %s\n", buffer);
4141                         return FALSE;
4142                     }
4143                     option[n].hasSeen = TRUE;
4144                     if (option[n].hasValue) {
4145                         // skip any space
4146                         ptr = end;
4147                         if (isspace (ptr[0])) {
4148                             while (isspace (ptr[0]))
4149                             {
4150                                 if (IsInterrupt())
4151                                     return FALSE;
4152         
4153                                 ptr ++;
4154                             }
4155                         }
4156                         if (ptr[0] == '\0') {
4157                             ExtOut ("Missing value for option %s\n", buffer);
4158                             return FALSE;
4159                         }
4160                         end = ptr;
4161                         while (!isspace(end[0]) && end[0] != '\0')
4162                         {
4163                             if (IsInterrupt())
4164                                 return FALSE;
4165         
4166                             end ++;
4167                         }
4168
4169                         size_t value;
4170                         if (!GetValueForCMD (ptr,end,option[n].type,&value)) {
4171
4172                             char oldChar = *end;
4173                             *(char *)end = '\0';
4174                             value = (size_t)GetExpression (ptr);
4175                             *(char *)end = oldChar;
4176                         }
4177
4178                         SetValueForCMD (option[n].vptr,option[n].type,value);
4179                     }
4180                     else {
4181                         SetValueForCMD (option[n].vptr,option[n].type,TRUE);
4182                     }
4183                     break;
4184                 }
4185             }
4186             if (n == nOption) {
4187                 ExtOut ("Unknown option: %s\n", buffer);
4188                 return FALSE;
4189             }
4190         }
4191
4192         ptr = end;
4193         if (bQuotedArg)
4194         {
4195             ptr++;
4196         }
4197     }
4198     return TRUE;
4199 }
4200
4201 ReadVirtualCache g_special_rvCacheSpace;
4202 ReadVirtualCache *rvCache = &g_special_rvCacheSpace;
4203
4204 void ResetGlobals(void)
4205 {
4206     // There are some globals used in SOS that exist for efficiency in one command,
4207     // but should be reset because the next execution of an SOS command could be on
4208     // another managed process. Reset them to a default state here, as this command
4209     // is called on every SOS entry point.
4210     g_sos->GetUsefulGlobals(&g_special_usefulGlobals);
4211     g_special_mtCache.Clear();
4212     g_special_rvCacheSpace.Clear();
4213     Output::ResetIndent();
4214 }
4215
4216 //---------------------------------------------------------------------------------------
4217 //
4218 // Loads private DAC interface, and points g_clrData to it.
4219 //
4220 // Return Value:
4221 //      HRESULT indicating success or failure
4222 //
4223 HRESULT LoadClrDebugDll(void)
4224 {
4225     HRESULT hr = S_OK;
4226 #ifdef FEATURE_PAL
4227     static IXCLRDataProcess* s_clrDataProcess = NULL;
4228     if (s_clrDataProcess == NULL)
4229     {
4230         int err = PAL_InitializeDLL();
4231         if(err != 0)
4232         {
4233             return CORDBG_E_UNSUPPORTED;
4234         }
4235         char dacModulePath[MAX_LONGPATH];
4236         strcpy_s(dacModulePath, _countof(dacModulePath), g_ExtServices->GetCoreClrDirectory());
4237         strcat_s(dacModulePath, _countof(dacModulePath), MAKEDLLNAME_A("mscordaccore"));
4238
4239         HMODULE hdac = LoadLibraryA(dacModulePath);
4240         if (hdac == NULL)
4241         {
4242             return CORDBG_E_MISSING_DEBUGGER_EXPORTS;
4243         }
4244         PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance");
4245         if (pfnCLRDataCreateInstance == NULL)
4246         {
4247             FreeLibrary(hdac);
4248             return CORDBG_E_MISSING_DEBUGGER_EXPORTS;
4249         }
4250         ICLRDataTarget *target = new DataTarget();
4251         hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), target, (void**)&s_clrDataProcess);
4252         if (FAILED(hr))
4253         {
4254             s_clrDataProcess = NULL;
4255             return hr;
4256         }
4257         ULONG32 flags = 0;
4258         s_clrDataProcess->GetOtherNotificationFlags(&flags);
4259         flags |= (CLRDATA_NOTIFY_ON_MODULE_LOAD | CLRDATA_NOTIFY_ON_MODULE_UNLOAD | CLRDATA_NOTIFY_ON_EXCEPTION);
4260         s_clrDataProcess->SetOtherNotificationFlags(flags);
4261     }
4262     g_clrData = s_clrDataProcess;
4263     g_clrData->AddRef();
4264     g_clrData->Flush();
4265 #else
4266     WDBGEXTS_CLR_DATA_INTERFACE Query;
4267
4268     Query.Iid = &__uuidof(IXCLRDataProcess);
4269     if (!Ioctl(IG_GET_CLR_DATA_INTERFACE, &Query, sizeof(Query)))
4270     {
4271         return E_FAIL;
4272     }
4273
4274     g_clrData = (IXCLRDataProcess*)Query.Iface;
4275 #endif
4276     hr = g_clrData->QueryInterface(__uuidof(ISOSDacInterface), (void**)&g_sos);
4277     if (FAILED(hr))
4278     {
4279         g_sos = NULL;
4280         return hr;
4281     }
4282     return S_OK;
4283 }
4284
4285 #ifndef FEATURE_PAL
4286
4287 // This structure carries some input/output data to the FindFileInPathCallback below
4288 typedef struct _FindFileCallbackData
4289 {
4290     DWORD timestamp;
4291     DWORD filesize;
4292     HMODULE hModule;
4293 } FindFileCallbackData;
4294
4295
4296 // A callback used by SymFindFileInPath - called once for each file that matches
4297 // the initial search criteria and allows the user to do arbitrary processing
4298 // This implementation checks that filesize and timestamp are correct, then
4299 // saves the loaded module handle
4300 // Parameters
4301 //           filename - the full path the file which was found
4302 //           context - a user specified pointer to arbitrary data, in this case a FindFileCallbackData
4303 // Return Value
4304 //           TRUE if the search should continue (the file is no good)
4305 //           FALSE if the search should stop (the file is good)
4306 BOOL
4307 FindFileInPathCallback(
4308     ___in PCWSTR filename,
4309     ___in PVOID context
4310     )
4311 {
4312     HRESULT hr;
4313     FindFileCallbackData* pCallbackData;
4314     pCallbackData = (FindFileCallbackData*)context;
4315     if (!pCallbackData)
4316         return TRUE;
4317
4318     pCallbackData->hModule = LoadLibraryExW(
4319         filename,
4320         NULL,                               //  __reserved
4321         LOAD_WITH_ALTERED_SEARCH_PATH);     // Ensure we check the dir in wszFullPath first
4322     if (pCallbackData->hModule == NULL)
4323     {
4324         hr = HRESULT_FROM_WIN32(GetLastError());
4325         ExtOut("Unable to load '%S'.  HRESULT = 0x%x.\n", filename, hr);
4326         return TRUE;
4327     }
4328     
4329     // Did we load the right one?
4330     MODULEINFO modInfo = {0};
4331     if (!GetModuleInformation(
4332         GetCurrentProcess(),
4333         pCallbackData->hModule,
4334         &modInfo,
4335         sizeof(modInfo)))
4336     {
4337         ExtOut("Failed to read module information for '%S'.  HRESULT = 0x%x.\n", filename, HRESULT_FROM_WIN32(GetLastError()));
4338         FreeLibrary(pCallbackData->hModule);
4339         return TRUE;
4340     }
4341
4342     IMAGE_DOS_HEADER * pDOSHeader = (IMAGE_DOS_HEADER *) modInfo.lpBaseOfDll;
4343     IMAGE_NT_HEADERS * pNTHeaders = (IMAGE_NT_HEADERS *) (((LPBYTE) modInfo.lpBaseOfDll) + pDOSHeader->e_lfanew);
4344     DWORD dwSizeActual = pNTHeaders->OptionalHeader.SizeOfImage;
4345     DWORD dwTimeStampActual = pNTHeaders->FileHeader.TimeDateStamp;
4346     if ((dwSizeActual != pCallbackData->filesize) || (dwTimeStampActual != pCallbackData->timestamp))
4347     {
4348         ExtOut("Found '%S', but it does not match the CLR being debugged.\n", filename);
4349         ExtOut("Size: Expected '0x%x', Actual '0x%x'\n", pCallbackData->filesize, dwSizeActual);
4350         ExtOut("Time stamp: Expected '0x%x', Actual '0x%x'\n", pCallbackData->timestamp, dwTimeStampActual);
4351         FreeLibrary(pCallbackData->hModule);
4352         return TRUE;
4353     }
4354
4355     ExtOut("Loaded %S\n", filename);
4356     return FALSE;
4357 }
4358
4359 #endif // FEATURE_PAL
4360
4361 //---------------------------------------------------------------------------------------
4362 // Provides a way for the public CLR debugging interface to find the appropriate
4363 // mscordbi.dll, DAC, etc.
4364 class SOSLibraryProvider : public ICLRDebuggingLibraryProvider
4365 {
4366 public:
4367     SOSLibraryProvider() : m_ref(0)
4368     {
4369     }
4370
4371     virtual ~SOSLibraryProvider() {}
4372
4373     virtual HRESULT STDMETHODCALLTYPE QueryInterface(
4374         REFIID InterfaceId,
4375         PVOID* pInterface)
4376     {
4377         if (InterfaceId == IID_IUnknown)
4378         {
4379             *pInterface = static_cast<IUnknown *>(this);
4380         }
4381         else if (InterfaceId == IID_ICLRDebuggingLibraryProvider)
4382         {
4383             *pInterface = static_cast<ICLRDebuggingLibraryProvider *>(this);
4384         }
4385         else
4386         {
4387             *pInterface = NULL;
4388             return E_NOINTERFACE;
4389         }
4390
4391         AddRef();
4392         return S_OK;
4393     }
4394     
4395     virtual ULONG STDMETHODCALLTYPE AddRef()
4396     {
4397         return InterlockedIncrement(&m_ref);    
4398     }
4399
4400     virtual ULONG STDMETHODCALLTYPE Release()
4401     {
4402         LONG ref = InterlockedDecrement(&m_ref);
4403         if (ref == 0)
4404         {
4405             delete this;
4406         }
4407         return ref;
4408     }
4409
4410
4411
4412     // Called by the shim to locate and load mscordacwks and mscordbi
4413     // Parameters:
4414     //    pwszFileName - the name of the file to load
4415     //    dwTimestamp - the expected timestamp of the file
4416     //    dwSizeOfImage - the expected SizeOfImage (a PE header data value)
4417     //    phModule - a handle to loaded module
4418     //
4419     // Return Value
4420     //    S_OK if the file was loaded, or any error if not
4421     virtual HRESULT STDMETHODCALLTYPE ProvideLibrary(
4422         const WCHAR * pwszFileName,
4423         DWORD dwTimestamp,
4424         DWORD dwSizeOfImage,
4425         HMODULE * phModule)
4426     {
4427 #ifndef FEATURE_PAL
4428         HRESULT hr;
4429         FindFileCallbackData callbackData = {0};
4430         callbackData.timestamp = dwTimestamp;
4431         callbackData.filesize = dwSizeOfImage;
4432
4433         if ((phModule == NULL) || (pwszFileName == NULL))
4434         {
4435             return E_INVALIDARG;
4436         }
4437
4438         HMODULE dacModule;
4439         if(g_sos == NULL)
4440         {
4441             // we ensure that windbg loads DAC first so that we can be sure to use the same one
4442             return E_UNEXPECTED;
4443         }
4444         if (FAILED(hr = g_sos->GetDacModuleHandle(&dacModule)))
4445         {
4446             ExtOut("Failed to get the dac module handle. hr=0x%x.\n", hr);
4447             return hr;
4448         }
4449
4450         WCHAR dacPath[MAX_LONGPATH];
4451         DWORD len = GetModuleFileNameW(dacModule, dacPath, MAX_LONGPATH);
4452         if(len == 0 || len == MAX_LONGPATH)
4453         {
4454             ExtOut("GetModuleFileName(dacModuleHandle) failed. Last error = 0x%x\n", GetLastError());
4455             return E_FAIL;
4456         }
4457
4458         // if we are looking for the DAC, just load the one windbg already found
4459         if(_wcsncmp(pwszFileName, W("mscordac"), _wcslen(W("mscordac")))==0)
4460         {
4461             FindFileInPathCallback(dacPath, &callbackData);
4462             *phModule = callbackData.hModule;
4463             return hr;
4464         }
4465
4466         ULONG64 hProcess;
4467         hr = g_ExtSystem->GetCurrentProcessHandle(&hProcess);
4468         if (FAILED(hr))
4469         {
4470             ExtOut("IDebugSystemObjects::GetCurrentProcessHandle HRESULT=0x%x.\n", hr);
4471             return hr;
4472         }
4473
4474         ToRelease<IDebugSymbols3> spSym3(NULL);
4475         hr = g_ExtSymbols->QueryInterface(__uuidof(IDebugSymbols3), (void**)&spSym3);
4476         if (FAILED(hr))
4477         {
4478             ExtOut("Unable to query IDebugSymbol3 HRESULT=0x%x.\n", hr);
4479             return hr;
4480         }
4481
4482         ULONG pathSize = 0;
4483         hr = spSym3->GetSymbolPathWide(NULL, 0, &pathSize);
4484         if(FAILED(hr)) //S_FALSE if the path doesn't fit, but if the path was size 0 perhaps we would get S_OK?
4485         {
4486             ExtOut("Unable to get symbol path length. IDebugSymbols3::GetSymbolPathWide HRESULT=0x%x.\n", hr);
4487             return hr;
4488         }
4489
4490         ArrayHolder<WCHAR> symbolPath = new WCHAR[pathSize+MAX_LONGPATH+1];
4491
4492
4493
4494         hr = spSym3->GetSymbolPathWide(symbolPath, pathSize, NULL);
4495         if(S_OK != hr)
4496         {
4497             ExtOut("Unable to get symbol path. IDebugSymbols3::GetSymbolPathWide HRESULT=0x%x.\n", hr);
4498             return hr;
4499         }
4500         
4501         WCHAR foundPath[MAX_LONGPATH];
4502         BOOL rc = SymFindFileInPathW((HANDLE)hProcess,
4503                                 symbolPath,
4504                                 pwszFileName,
4505                                 (PVOID)(ULONG_PTR) dwTimestamp,
4506                                 dwSizeOfImage,
4507                                 0,
4508                                 SSRVOPT_DWORD,
4509                                 foundPath,
4510                                 (PFINDFILEINPATHCALLBACKW) &FindFileInPathCallback,
4511                                 (PVOID) &callbackData
4512                                );
4513         if(!rc)
4514         {
4515             hr = HRESULT_FROM_WIN32(GetLastError());
4516             ExtOut("SymFindFileInPath failed for %S. HRESULT=0x%x.\nPlease ensure that %S is on your symbol path.", pwszFileName, hr, pwszFileName);
4517         }
4518
4519         *phModule = callbackData.hModule;
4520         return hr;
4521 #else
4522         WCHAR modulePath[MAX_LONGPATH];
4523         int length = MultiByteToWideChar(CP_ACP, 0, g_ExtServices->GetCoreClrDirectory(), -1, modulePath, _countof(modulePath));
4524         if (0 >= length)
4525         {
4526             ExtOut("MultiByteToWideChar(coreclrDirectory) failed. Last error = 0x%x\n", GetLastError());
4527             return E_FAIL;
4528         }
4529         wcscat_s(modulePath, _countof(modulePath), pwszFileName);
4530
4531         *phModule = LoadLibraryW(modulePath);
4532         if (*phModule == NULL)
4533         {
4534             HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
4535             ExtOut("Unable to load '%S'.  HRESULT = 0x%x.\n", pwszFileName, hr);
4536             return hr;
4537         }
4538         return S_OK;
4539 #endif // FEATURE_PAL
4540     }
4541
4542 protected:
4543     LONG m_ref;
4544 };
4545
4546 //---------------------------------------------------------------------------------------
4547 // Data target for the debugged process.   Provided to OpenVirtualProcess in order to
4548 // get an ICorDebugProcess back
4549 // 
4550 class SOSDataTarget : public ICorDebugMutableDataTarget
4551 #ifdef FEATURE_PAL
4552 , public ICorDebugDataTarget4
4553 #endif
4554 {
4555 public:
4556     SOSDataTarget() : m_ref(0)
4557     {
4558     }
4559
4560     virtual ~SOSDataTarget() {}
4561
4562     virtual HRESULT STDMETHODCALLTYPE QueryInterface(
4563         REFIID InterfaceId,
4564         PVOID* pInterface)
4565     {
4566         if (InterfaceId == IID_IUnknown)
4567         {
4568             *pInterface = static_cast<IUnknown *>(static_cast<ICorDebugDataTarget *>(this));
4569         }
4570         else if (InterfaceId == IID_ICorDebugDataTarget)
4571         {
4572             *pInterface = static_cast<ICorDebugDataTarget *>(this);
4573         }
4574         else if (InterfaceId == IID_ICorDebugMutableDataTarget)
4575         {
4576             *pInterface = static_cast<ICorDebugMutableDataTarget *>(this);
4577         }
4578 #ifdef FEATURE_PAL
4579         else if (InterfaceId == IID_ICorDebugDataTarget4)
4580         {
4581             *pInterface = static_cast<ICorDebugDataTarget4 *>(this);
4582         }
4583 #endif
4584         else
4585         {
4586             *pInterface = NULL;
4587             return E_NOINTERFACE;
4588         }
4589
4590         AddRef();
4591         return S_OK;
4592     }
4593     
4594     virtual ULONG STDMETHODCALLTYPE AddRef()
4595     {
4596         return InterlockedIncrement(&m_ref);    
4597     }
4598
4599     virtual ULONG STDMETHODCALLTYPE Release()
4600     {
4601         LONG ref = InterlockedDecrement(&m_ref);
4602         if (ref == 0)
4603         {
4604             delete this;
4605         }
4606         return ref;
4607     }
4608
4609     //
4610     // ICorDebugDataTarget.
4611     //
4612
4613     virtual HRESULT STDMETHODCALLTYPE GetPlatform(CorDebugPlatform * pPlatform)
4614     {
4615         ULONG platformKind = g_targetMachine->GetPlatform();
4616 #ifdef FEATURE_PAL        
4617         if(platformKind == IMAGE_FILE_MACHINE_I386)
4618             *pPlatform = CORDB_PLATFORM_POSIX_X86;
4619         else if(platformKind == IMAGE_FILE_MACHINE_AMD64)
4620             *pPlatform = CORDB_PLATFORM_POSIX_AMD64;
4621         else if(platformKind == IMAGE_FILE_MACHINE_ARMNT)
4622             *pPlatform = CORDB_PLATFORM_POSIX_ARM;
4623         else
4624             return E_FAIL;
4625 #else
4626         if(platformKind == IMAGE_FILE_MACHINE_I386)
4627             *pPlatform = CORDB_PLATFORM_WINDOWS_X86;
4628         else if(platformKind == IMAGE_FILE_MACHINE_AMD64)
4629             *pPlatform = CORDB_PLATFORM_WINDOWS_AMD64;
4630         else if(platformKind == IMAGE_FILE_MACHINE_ARMNT)
4631             *pPlatform = CORDB_PLATFORM_WINDOWS_ARM;
4632         else if(platformKind == IMAGE_FILE_MACHINE_ARM64)
4633             *pPlatform = CORDB_PLATFORM_WINDOWS_ARM64;
4634         else
4635             return E_FAIL;        
4636 #endif        
4637     
4638         return S_OK;
4639     }
4640
4641     virtual HRESULT STDMETHODCALLTYPE ReadVirtual( 
4642         CORDB_ADDRESS address,
4643         BYTE * pBuffer,
4644         ULONG32 request,
4645         ULONG32 * pcbRead)
4646     {
4647         if (g_ExtData == NULL)
4648         {
4649             return E_UNEXPECTED;
4650         }
4651         return g_ExtData->ReadVirtual(address, pBuffer, request, (PULONG) pcbRead);
4652     }
4653
4654     virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
4655         DWORD dwThreadOSID,
4656         ULONG32 contextFlags,
4657         ULONG32 contextSize,
4658         BYTE * context)
4659     {
4660 #ifdef FEATURE_PAL
4661         if (g_ExtSystem == NULL)
4662         {
4663             return E_UNEXPECTED;
4664         }
4665         return g_ExtSystem->GetThreadContextById(dwThreadOSID, contextFlags, contextSize, context);
4666 #else
4667         ULONG ulThreadIDOrig;
4668         ULONG ulThreadIDRequested;
4669         HRESULT hr;
4670         HRESULT hrRet;
4671
4672         hr = g_ExtSystem->GetCurrentThreadId(&ulThreadIDOrig);
4673         if (FAILED(hr))
4674         {
4675             return hr;
4676         }
4677
4678         hr = g_ExtSystem->GetThreadIdBySystemId(dwThreadOSID, &ulThreadIDRequested);
4679         if (FAILED(hr))
4680         {
4681             return hr;
4682         }
4683
4684         hr = g_ExtSystem->SetCurrentThreadId(ulThreadIDRequested);
4685         if (FAILED(hr))
4686         {
4687             return hr;
4688         }
4689
4690         // Prepare context structure
4691         ZeroMemory(context, contextSize);
4692         ((CONTEXT*) context)->ContextFlags = contextFlags;
4693
4694         // Ok, do it!
4695         hrRet = g_ExtAdvanced3->GetThreadContext((LPVOID) context, contextSize);
4696
4697         // This is cleanup; failure here doesn't mean GetThreadContext should fail
4698         // (that's determined by hrRet).
4699         g_ExtSystem->SetCurrentThreadId(ulThreadIDOrig);
4700
4701         return hrRet;
4702 #endif // FEATURE_PAL
4703     }
4704
4705     //
4706     // ICorDebugMutableDataTarget.
4707     //
4708     virtual HRESULT STDMETHODCALLTYPE WriteVirtual(CORDB_ADDRESS address,
4709                                                    const BYTE * pBuffer,
4710                                                    ULONG32 bytesRequested)
4711     {
4712         if (g_ExtData == NULL)
4713         {
4714             return E_UNEXPECTED;
4715         }
4716         return g_ExtData->WriteVirtual(address, (PVOID)pBuffer, bytesRequested, NULL);
4717     }
4718
4719     virtual HRESULT STDMETHODCALLTYPE SetThreadContext(DWORD dwThreadID,
4720                                                        ULONG32 contextSize,
4721                                                        const BYTE * pContext)
4722     {
4723         return E_NOTIMPL;
4724     }
4725
4726     virtual HRESULT STDMETHODCALLTYPE ContinueStatusChanged(DWORD dwThreadId,
4727                                                             CORDB_CONTINUE_STATUS continueStatus)
4728     {
4729         return E_NOTIMPL;
4730     }
4731
4732 #ifdef FEATURE_PAL
4733     //
4734     // ICorDebugDataTarget4
4735     //
4736     virtual HRESULT STDMETHODCALLTYPE VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context)
4737     {
4738         if (g_ExtServices == NULL)
4739         {
4740             return E_UNEXPECTED;
4741         }
4742         return g_ExtServices->VirtualUnwind(threadId, contextSize, context);
4743
4744     }
4745 #endif // FEATURE_PAL
4746
4747 protected:
4748     LONG m_ref;
4749 };
4750
4751 HRESULT InitCorDebugInterfaceFromModule(ULONG64 ulBase, ICLRDebugging * pClrDebugging)
4752 {
4753     HRESULT hr;
4754
4755     ToRelease<ICorDebugMutableDataTarget> pSOSDataTarget = new SOSDataTarget;
4756     pSOSDataTarget->AddRef();
4757
4758     ToRelease<ICLRDebuggingLibraryProvider> pSOSLibraryProvider = new SOSLibraryProvider;
4759     pSOSLibraryProvider->AddRef();
4760
4761     CLR_DEBUGGING_VERSION clrDebuggingVersionRequested = {0};
4762     clrDebuggingVersionRequested.wMajor = 4;
4763
4764     CLR_DEBUGGING_VERSION clrDebuggingVersionActual = {0};
4765
4766     CLR_DEBUGGING_PROCESS_FLAGS clrDebuggingFlags = (CLR_DEBUGGING_PROCESS_FLAGS)0;
4767
4768     ToRelease<IUnknown> pUnkProcess;
4769
4770     hr = pClrDebugging->OpenVirtualProcess(
4771         ulBase,
4772         pSOSDataTarget,
4773         pSOSLibraryProvider,
4774         &clrDebuggingVersionRequested,
4775         IID_ICorDebugProcess,
4776         &pUnkProcess,
4777         &clrDebuggingVersionActual,
4778         &clrDebuggingFlags);
4779     if (FAILED(hr))
4780     {
4781         return hr;
4782     }
4783
4784     ICorDebugProcess * pCorDebugProcess = NULL;
4785     hr = pUnkProcess->QueryInterface(IID_ICorDebugProcess, (PVOID*) &pCorDebugProcess);
4786     if (FAILED(hr))
4787     {
4788         return hr;
4789     }
4790
4791     // Transfer memory ownership of refcount to global
4792     g_pCorDebugProcess = pCorDebugProcess;
4793     return S_OK;
4794 }
4795
4796 //---------------------------------------------------------------------------------------
4797 //
4798 // Unloads public ICorDebug interfaces, and clears g_pCorDebugProcess
4799 // This is only needed once after CLR unloads, not after every InitCorDebugInterface call
4800 //
4801 VOID UninitCorDebugInterface()
4802 {
4803     if(g_pCorDebugProcess != NULL)
4804     {
4805         g_pCorDebugProcess->Detach();
4806         g_pCorDebugProcess->Release();
4807         g_pCorDebugProcess = NULL;
4808     }
4809 }
4810
4811 //---------------------------------------------------------------------------------------
4812 //
4813 // Loads public ICorDebug interfaces, and points g_pCorDebugProcess to them
4814 // This should be called at least once per windbg stop state to ensure that
4815 // the interface is available and that it doesn't hold stale data. Calling it
4816 // more than once isn't an error, but does have perf overhead from needlessly
4817 // flushing memory caches.
4818 //
4819 // Return Value:
4820 //      HRESULT indicating success or failure
4821 //
4822
4823 HRESULT InitCorDebugInterface()
4824 {
4825     HMODULE hModule = NULL;
4826     HRESULT hr;
4827     ToRelease<ICLRDebugging> pClrDebugging;
4828
4829     // we may already have an ICorDebug instance we can use
4830     if(g_pCorDebugProcess != NULL)
4831     {
4832         // ICorDebugProcess4 is currently considered a private experimental interface on ICorDebug, it might go away so
4833         // we need to be sure to handle its absense gracefully
4834         ToRelease<ICorDebugProcess4> pProcess4 = NULL;
4835         if(SUCCEEDED(g_pCorDebugProcess->QueryInterface(__uuidof(ICorDebugProcess4), (void**)&pProcess4)))
4836         {
4837             // FLUSH_ALL is more expensive than PROCESS_RUNNING, but this allows us to be safe even if things
4838             // like IDNA are in use where we might be looking at non-sequential snapshots of process state
4839             if(SUCCEEDED(pProcess4->ProcessStateChanged(FLUSH_ALL)))
4840             {
4841                 // we already have an ICorDebug instance loaded and flushed, nothing more to do
4842                 return S_OK;
4843             }
4844         }
4845
4846         // this is a very heavy handed way of reseting
4847         UninitCorDebugInterface();
4848     }
4849
4850     // SOS now has a statically linked version of the loader code that is normally found in mscoree/mscoreei.dll
4851     // Its not much code and takes a big step towards 0 install dependencies
4852     // Need to pick the appropriate SKU of CLR to detect
4853 #if defined(FEATURE_CORESYSTEM)
4854     GUID skuId = CLR_ID_ONECORE_CLR;
4855 #else
4856     GUID skuId = CLR_ID_CORECLR;
4857 #endif
4858     CLRDebuggingImpl* pDebuggingImpl = new CLRDebuggingImpl(skuId);
4859     hr = pDebuggingImpl->QueryInterface(IID_ICLRDebugging, (LPVOID *)&pClrDebugging);
4860     if (FAILED(hr))
4861     {
4862         delete pDebuggingImpl;
4863         return hr;
4864     }
4865
4866 #ifndef FEATURE_PAL
4867     ULONG cLoadedModules;
4868     ULONG cUnloadedModules;
4869     hr = g_ExtSymbols->GetNumberModules(&cLoadedModules, &cUnloadedModules);
4870     if (FAILED(hr))
4871     {
4872         return hr;
4873     }
4874
4875     ULONG64 ulBase;
4876     for (ULONG i = 0; i < cLoadedModules; i++)
4877     {
4878         hr = g_ExtSymbols->GetModuleByIndex(i, &ulBase);
4879         if (FAILED(hr))
4880         {
4881             return hr;
4882         }
4883
4884         // Dunno if this is a CLR module or not (or even if it's the particular one the
4885         // user cares about during inproc SxS scenarios).  For now, just try to use it
4886         // to grab an ICorDebugProcess.  If it works, great.  Else, continue the loop
4887         // until we find the first one that works.
4888         hr = InitCorDebugInterfaceFromModule(ulBase, pClrDebugging);
4889         if (SUCCEEDED(hr))
4890         {
4891             return hr;
4892         }
4893
4894         // On failure, just iterate to the next module and try again...
4895     }
4896
4897     // Still here?  Didn't find the right module.
4898     // TODO: Anything useful to return or log here?
4899     return E_FAIL;
4900 #else
4901     ULONG64 ulBase;
4902     hr = g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_DLL_NAME_A, 0, NULL, &ulBase);
4903     if (SUCCEEDED(hr))
4904     {
4905         hr = InitCorDebugInterfaceFromModule(ulBase, pClrDebugging);
4906     }
4907     return hr;
4908 #endif // FEATURE_PAL
4909 }
4910
4911
4912 typedef enum
4913 {
4914     GC_HEAP_INVALID = 0,
4915     GC_HEAP_WKS     = 1,
4916     GC_HEAP_SVR     = 2
4917 } GC_HEAP_TYPE;
4918
4919 /**********************************************************************\
4920 * Routine Description:                                                 *
4921 *                                                                      *
4922 *    This function is called to find out if runtime is server build    *  
4923 *                                                                      *
4924 \**********************************************************************/
4925
4926 DacpGcHeapData *g_pHeapData = NULL;
4927 DacpGcHeapData g_HeapData;
4928
4929 BOOL InitializeHeapData()
4930 {
4931     if (g_pHeapData == NULL)
4932     {        
4933         if (g_HeapData.Request(g_sos) != S_OK)
4934         {
4935             return FALSE;
4936         }
4937         g_pHeapData = &g_HeapData;
4938     }
4939     return TRUE;
4940 }
4941
4942 BOOL IsServerBuild() 
4943 {
4944     return InitializeHeapData() ? g_pHeapData->bServerMode : FALSE;     
4945 }
4946
4947 UINT GetMaxGeneration()
4948 {
4949     return InitializeHeapData() ? g_pHeapData->g_max_generation : 0;    
4950 }
4951
4952 UINT GetGcHeapCount()
4953 {
4954     return InitializeHeapData() ? g_pHeapData->HeapCount : 0;   
4955 }
4956
4957 BOOL GetGcStructuresValid()
4958 {
4959     // We don't want to use the cached HeapData, because this can change
4960     // each time the program runs for a while.
4961     DacpGcHeapData heapData;
4962     if (heapData.Request(g_sos) != S_OK)
4963     {
4964         return FALSE;
4965     }
4966
4967     return heapData.bGcStructuresValid;
4968 }
4969
4970 void GetAllocContextPtrs(AllocInfo *pallocInfo)
4971 {
4972     // gets the allocation contexts for all threads. This provides information about how much of 
4973     // the current allocation quantum has been allocated and the heap to which the quantum belongs. 
4974     // The allocation quantum is a fixed size chunk of zeroed memory from which allocations will come
4975     // until it's filled. Each managed thread has its own allocation context. 
4976      
4977     pallocInfo->num = 0;
4978     pallocInfo->array = NULL;    
4979     
4980     // get the thread store (See code:ClrDataAccess::RequestThreadStoreData for details)
4981     DacpThreadStoreData ThreadStore;
4982     if ( ThreadStore.Request(g_sos) != S_OK)
4983     {
4984         return;
4985     }
4986
4987     int numThread = ThreadStore.threadCount;
4988     if (numThread)
4989     {
4990         pallocInfo->array = new needed_alloc_context[numThread];
4991         if (pallocInfo->array == NULL)
4992         {
4993             return;
4994         }
4995     }
4996
4997     // get details for each thread in the thread store
4998     CLRDATA_ADDRESS CurThread = ThreadStore.firstThread;
4999     while (CurThread != NULL)
5000     {
5001         if (IsInterrupt())
5002             return;
5003
5004         DacpThreadData Thread;
5005         // Get information about the thread (we're getting the values of several of the
5006         // fields of the Thread instance from the target) See code:ClrDataAccess::RequestThreadData for
5007         // details
5008         if (Thread.Request(g_sos, CurThread) != S_OK)
5009         {
5010             return;
5011         }
5012
5013         if (Thread.allocContextPtr != 0)
5014         {
5015             // get a list of all the allocation contexts 
5016             int j;      
5017             for (j = 0; j < pallocInfo->num; j ++)
5018             {
5019                 if (pallocInfo->array[j].alloc_ptr == (BYTE *) Thread.allocContextPtr)
5020                     break;
5021             }
5022             if (j == pallocInfo->num)
5023             {
5024                 pallocInfo->num ++;
5025                 pallocInfo->array[j].alloc_ptr = (BYTE *) Thread.allocContextPtr;
5026                 pallocInfo->array[j].alloc_limit = (BYTE *) Thread.allocContextLimit;
5027             }
5028         }
5029         
5030         CurThread = Thread.nextThread;
5031     }
5032 }
5033
5034 HRESULT ReadVirtualCache::Read(TADDR taOffset, PVOID Buffer, ULONG BufferSize, PULONG lpcbBytesRead)
5035 {
5036     // sign extend the passed in Offset so we can use it in when calling 
5037     // IDebugDataSpaces::ReadVirtual()
5038
5039     CLRDATA_ADDRESS Offset = TO_CDADDR(taOffset);
5040     // Offset can be any random ULONG64, as it can come from VerifyObjectMember(), and this
5041     // can pass random pointer values in case of GC heap corruption
5042     HRESULT ret;
5043     ULONG cbBytesRead = 0;
5044
5045     if (BufferSize == 0)
5046         return S_OK;
5047
5048     if (BufferSize > CACHE_SIZE)
5049     {
5050         // Don't even try with the cache
5051         return g_ExtData->ReadVirtual(Offset, Buffer, BufferSize, lpcbBytesRead);
5052     }
5053
5054     if ((m_cacheValid)
5055         && (taOffset >= m_startCache) 
5056         && (taOffset <= m_startCache + m_cacheSize - BufferSize))
5057
5058     {
5059         // It is within the cache
5060         memcpy(Buffer,(LPVOID) ((ULONG64)m_cache + (taOffset - m_startCache)), BufferSize);
5061
5062         if (lpcbBytesRead != NULL)
5063         {
5064            *lpcbBytesRead = BufferSize;
5065         }
5066  
5067         return S_OK;
5068     }
5069  
5070     m_cacheValid = FALSE;
5071     m_startCache = taOffset;
5072
5073     // avoid an int overflow
5074     if (m_startCache + CACHE_SIZE < m_startCache)
5075         m_startCache = (TADDR)(-CACHE_SIZE);
5076
5077     ret = g_ExtData->ReadVirtual(TO_CDADDR(m_startCache), m_cache, CACHE_SIZE, &cbBytesRead);
5078     if (ret != S_OK)
5079     {
5080         return ret;
5081     }
5082     
5083     m_cacheSize = cbBytesRead;     
5084     m_cacheValid = TRUE;
5085     memcpy(Buffer, (LPVOID) ((ULONG64)m_cache + (taOffset - m_startCache)), BufferSize);
5086
5087     if (lpcbBytesRead != NULL)
5088     {
5089         *lpcbBytesRead = cbBytesRead;
5090     }
5091
5092     return S_OK;
5093 }
5094
5095 HRESULT GetMTOfObject(TADDR obj, TADDR *mt)
5096 {
5097     if (!mt)
5098         return E_POINTER;
5099
5100     // Read the MethodTable and if we succeed, get rid of the mark bits.
5101     HRESULT hr = rvCache->Read(obj, mt, sizeof(TADDR), NULL);
5102     if (SUCCEEDED(hr))
5103         *mt &= ~3;
5104
5105     return hr;
5106 }
5107
5108 #ifndef FEATURE_PAL
5109
5110 StressLogMem::~StressLogMem ()
5111 {
5112     MemRange * range = list;
5113     
5114     while (range)
5115     {
5116         MemRange * temp = range->next;
5117         delete range;
5118         range = temp;
5119     }
5120 }
5121
5122 bool StressLogMem::Init (ULONG64 stressLogAddr, IDebugDataSpaces* memCallBack)
5123 {
5124     size_t ThreadStressLogAddr = NULL;
5125     HRESULT hr = memCallBack->ReadVirtual(UL64_TO_CDA(stressLogAddr + offsetof (StressLog, logs)), 
5126             &ThreadStressLogAddr, sizeof (ThreadStressLogAddr), 0);
5127     if (hr != S_OK)
5128     {
5129         return false;
5130     }    
5131    
5132     while(ThreadStressLogAddr != NULL) 
5133     {
5134         size_t ChunkListHeadAddr = NULL;
5135         hr = memCallBack->ReadVirtual(TO_CDADDR(ThreadStressLogAddr + ThreadStressLog::OffsetOfListHead ()), 
5136             &ChunkListHeadAddr, sizeof (ChunkListHeadAddr), 0);
5137         if (hr != S_OK || ChunkListHeadAddr == NULL)
5138         {
5139             return false;
5140         }
5141
5142         size_t StressLogChunkAddr = ChunkListHeadAddr;
5143         
5144         do
5145         {
5146             AddRange (StressLogChunkAddr, sizeof (StressLogChunk));
5147             hr = memCallBack->ReadVirtual(TO_CDADDR(StressLogChunkAddr + offsetof (StressLogChunk, next)), 
5148                 &StressLogChunkAddr, sizeof (StressLogChunkAddr), 0);
5149             if (hr != S_OK)
5150             {
5151                 return false;
5152             }
5153             if (StressLogChunkAddr == NULL)
5154             {
5155                 return true;
5156             }            
5157         } while (StressLogChunkAddr != ChunkListHeadAddr);
5158
5159         hr = memCallBack->ReadVirtual(TO_CDADDR(ThreadStressLogAddr + ThreadStressLog::OffsetOfNext ()), 
5160             &ThreadStressLogAddr, sizeof (ThreadStressLogAddr), 0);
5161         if (hr != S_OK)
5162         {
5163             return false;
5164         }        
5165     }
5166
5167     return true;
5168 }
5169
5170 bool StressLogMem::IsInStressLog (ULONG64 addr)
5171 {
5172     MemRange * range = list;
5173     while (range)
5174     {
5175         if (range->InRange (addr))
5176             return true;
5177         range = range->next;
5178     }
5179
5180     return false;
5181 }
5182
5183 #endif // !FEATURE_PAL
5184
5185 unsigned int Output::g_bSuppressOutput = 0;
5186 unsigned int Output::g_Indent = 0;
5187 bool Output::g_bDbgOutput = false;
5188 bool Output::g_bDMLExposed = false;
5189 unsigned int Output::g_DMLEnable = 0;
5190
5191 template <class T, int count, int size> const int StaticData<T, count, size>::Count = count;
5192 template <class T, int count, int size> const int StaticData<T, count, size>::Size  = size;
5193
5194 StaticData<char, 4, 1024> CachedString::cache;
5195
5196 CachedString::CachedString()
5197 : mPtr(0), mRefCount(0), mIndex(~0), mSize(cache.Size)
5198 {
5199     Create();
5200 }
5201
5202 CachedString::CachedString(const CachedString &rhs)
5203 : mPtr(0), mRefCount(0), mIndex(~0), mSize(cache.Size)
5204 {
5205     Copy(rhs);
5206 }
5207
5208 CachedString::~CachedString()
5209 {
5210     Clear();
5211 }
5212
5213 const CachedString &CachedString::operator=(const CachedString &rhs)
5214 {
5215     Clear();
5216     Copy(rhs);
5217     return *this;
5218 }
5219
5220 void CachedString::Copy(const CachedString &rhs)
5221 {
5222     if (rhs.IsOOM())
5223     {
5224         SetOOM();
5225     }
5226     else
5227     {
5228         mPtr = rhs.mPtr;
5229         mIndex = rhs.mIndex;
5230         mSize = rhs.mSize;
5231
5232         if (rhs.mRefCount)
5233         {
5234             mRefCount = rhs.mRefCount;
5235             (*mRefCount)++;
5236         }
5237         else
5238         {
5239             // We only create count the first time we copy it, so
5240             // we initialize it to 2.
5241             mRefCount = rhs.mRefCount = new unsigned int(2);
5242             if (!mRefCount)
5243                 SetOOM();
5244         }
5245     }
5246 }
5247
5248 void CachedString::Clear()
5249 {
5250     if (!mRefCount || --*mRefCount == 0)
5251     {
5252         if (mIndex == -1)
5253         {
5254             if (mPtr)
5255                 delete [] mPtr;
5256         }
5257         else if (mIndex >= 0 && mIndex < cache.Count)
5258         {
5259             cache.InUse[mIndex] = false;
5260         }
5261
5262         if (mRefCount)
5263             delete mRefCount;
5264     }
5265
5266     mPtr = 0;
5267     mIndex = ~0;
5268     mRefCount = 0;
5269     mSize = cache.Size;
5270 }
5271
5272
5273 void CachedString::Create()
5274 {
5275     mIndex = -1;
5276     mRefCount = 0;
5277
5278     // First try to find a string in the cache to use.
5279     for (int i = 0; i < cache.Count; ++i)
5280         if (!cache.InUse[i])
5281         {
5282             cache.InUse[i] = true;
5283             mPtr = cache.Data[i];
5284             mIndex = i;
5285             break;
5286         }
5287
5288     // We did not find a string to use, so we'll create a new one.
5289     if (mIndex == -1)
5290     {
5291         mPtr = new char[cache.Size];
5292         if (!mPtr)
5293             SetOOM();
5294     }
5295 }
5296
5297
5298 void CachedString::SetOOM()
5299 {
5300     Clear();
5301     mIndex = -2;
5302 }
5303
5304 void CachedString::Allocate(int size)
5305 {
5306     Clear();
5307     mPtr = new char[size];
5308     
5309     if (mPtr)
5310     {
5311         mSize = size;
5312         mIndex = -1;
5313     }
5314     else
5315     {
5316         SetOOM();
5317     }
5318 }
5319
5320 size_t CountHexCharacters(CLRDATA_ADDRESS val)
5321 {
5322     size_t ret = 0;
5323
5324     while (val)
5325     {
5326         val >>= 4;
5327         ret++;
5328     }
5329
5330     return ret;
5331 }
5332
5333 void WhitespaceOut(int count)
5334 {
5335     static const int FixedIndentWidth = 0x40;
5336     static const char FixedIndentString[FixedIndentWidth+1] =
5337         "                                                                ";
5338
5339     if (count <= 0)
5340         return;
5341
5342     int mod = count & 0x3F;
5343     count &= ~0x3F;
5344
5345     if (mod > 0)
5346         g_ExtControl->Output(DEBUG_OUTPUT_NORMAL, "%.*s", mod, FixedIndentString);
5347
5348     for ( ; count > 0; count -= FixedIndentWidth)
5349         g_ExtControl->Output(DEBUG_OUTPUT_NORMAL, FixedIndentString);
5350 }
5351
5352 void DMLOut(PCSTR format, ...)
5353 {
5354     if (Output::IsOutputSuppressed())
5355         return;
5356
5357     va_list args;
5358     va_start(args, format);
5359     ExtOutIndent();
5360
5361 #ifndef FEATURE_PAL
5362     if (IsDMLEnabled() && !Output::IsDMLExposed())
5363     {
5364         g_ExtControl->ControlledOutputVaList(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, format, args);
5365     }
5366     else
5367 #endif
5368     {
5369         g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, format, args);
5370     }
5371
5372     va_end(args);
5373 }
5374
5375 void IfDMLOut(PCSTR format, ...)
5376 {
5377 #ifndef FEATURE_PAL
5378     if (Output::IsOutputSuppressed() || !IsDMLEnabled())
5379         return;
5380
5381     va_list args;
5382     
5383     va_start(args, format);
5384     ExtOutIndent();
5385     g_ExtControl->ControlledOutputVaList(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, format, args);
5386     va_end(args);
5387 #endif
5388 }
5389
5390 void ExtOut(PCSTR Format, ...)
5391 {
5392     if (Output::IsOutputSuppressed())
5393         return;
5394
5395     va_list Args;
5396     
5397     va_start(Args, Format);
5398     ExtOutIndent();
5399     g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args);
5400     va_end(Args);
5401 }
5402
5403 void ExtWarn(PCSTR Format, ...)
5404 {
5405     if (Output::IsOutputSuppressed())
5406         return;
5407
5408     va_list Args;
5409     
5410     va_start(Args, Format);
5411     g_ExtControl->OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args);
5412     va_end(Args);
5413 }
5414
5415 void ExtErr(PCSTR Format, ...)
5416 {
5417     va_list Args;
5418     
5419     va_start(Args, Format);
5420     g_ExtControl->OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args);
5421     va_end(Args);
5422 }
5423
5424
5425 void ExtDbgOut(PCSTR Format, ...)
5426 {
5427 #ifdef _DEBUG
5428     if (Output::g_bDbgOutput)
5429     {
5430         va_list Args;
5431
5432         va_start(Args, Format);
5433         ExtOutIndent();
5434         g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args);
5435         va_end(Args);
5436     }
5437 #endif
5438 }
5439
5440 const char * const DMLFormats[] =
5441 {
5442     NULL,                                           // DML_None (do not use)
5443     "<exec cmd=\"!DumpMT /d %s\">%s</exec>",        // DML_MethodTable
5444     "<exec cmd=\"!DumpMD /d %s\">%s</exec>",        // DML_MethodDesc
5445     "<exec cmd=\"!DumpClass /d %s\">%s</exec>",     // DML_EEClass
5446     "<exec cmd=\"!DumpModule /d %s\">%s</exec>",    // DML_Module
5447     "<exec cmd=\"!U /d %s\">%s</exec>",             // DML_IP
5448     "<exec cmd=\"!DumpObj /d %s\">%s</exec>",       // DML_Object
5449     "<exec cmd=\"!DumpDomain /d %s\">%s</exec>",    // DML_Domain
5450     "<exec cmd=\"!DumpAssembly /d %s\">%s</exec>",  // DML_Assembly
5451     "<exec cmd=\"~~[%s]s\">%s</exec>",              // DML_ThreadID
5452     "<exec cmd=\"!DumpVC /d %s %s\">%s</exec>",     // DML_ValueClass
5453     "<exec cmd=\"!DumpHeap /d -mt %s\">%s</exec>",  // DML_DumpHeapMT
5454     "<exec cmd=\"!ListNearObj /d %s\">%s</exec>",   // DML_ListNearObj
5455     "<exec cmd=\"!ThreadState %s\">%s</exec>",      // DML_ThreadState
5456     "<exec cmd=\"!PrintException /d %s\">%s</exec>",// DML_PrintException
5457     "<exec cmd=\"!DumpRCW /d %s\">%s</exec>",       // DML_RCWrapper
5458     "<exec cmd=\"!DumpCCW /d %s\">%s</exec>",       // DML_CCWrapper
5459     "<exec cmd=\"!ClrStack -i %S %d\">%S</exec>",   // DML_ManagedVar
5460 };
5461
5462 void ConvertToLower(__out_ecount(len) char *buffer, size_t len)
5463 {
5464     for (size_t i = 0; i < len && buffer[i]; ++i)
5465         buffer[i] = (char)tolower(buffer[i]);
5466 }
5467
5468 /* Build a hex display of addr.
5469  */
5470 int GetHex(CLRDATA_ADDRESS addr, __out_ecount(len) char *out, size_t len, bool fill)
5471 {
5472     int count = sprintf_s(out, len, fill ? "%p" : "%x", (size_t)addr);
5473     
5474     ConvertToLower(out, len);
5475     
5476     return count;
5477 }
5478
5479 CachedString Output::BuildHexValue(CLRDATA_ADDRESS addr, FormatType type, bool fill)
5480 {
5481     CachedString ret;
5482     if (ret.IsOOM())
5483     {
5484         ReportOOM();
5485         return ret;
5486     }
5487
5488     if (IsDMLEnabled())
5489     {
5490         char hex[POINTERSIZE_BYTES*2 + 1];
5491         GetHex(addr, hex, _countof(hex), fill);
5492         sprintf_s(ret, ret.GetStrLen(), DMLFormats[type], hex, hex);
5493     }
5494     else
5495     {
5496         GetHex(addr, ret, ret.GetStrLen(), fill);
5497     }
5498
5499     return ret;
5500 }
5501
5502 CachedString Output::BuildVCValue(CLRDATA_ADDRESS mt, CLRDATA_ADDRESS addr, FormatType type, bool fill)
5503 {
5504     _ASSERTE(type == DML_ValueClass);
5505     CachedString ret;
5506     if (ret.IsOOM())
5507     {
5508         ReportOOM();
5509         return ret;
5510     }
5511
5512     if (IsDMLEnabled())
5513     {
5514         char hexaddr[POINTERSIZE_BYTES*2 + 1];
5515         char hexmt[POINTERSIZE_BYTES*2 + 1];
5516
5517         GetHex(addr, hexaddr, _countof(hexaddr), fill);
5518         GetHex(mt, hexmt, _countof(hexmt), fill);
5519
5520         sprintf_s(ret, ret.GetStrLen(), DMLFormats[type], hexmt, hexaddr, hexaddr);
5521     }
5522     else
5523     {
5524         GetHex(addr, ret, ret.GetStrLen(), fill);
5525     }
5526
5527     return ret;
5528 }
5529
5530 CachedString Output::BuildManagedVarValue(__in_z LPCWSTR expansionName, ULONG frame, __in_z LPCWSTR simpleName, FormatType type)
5531 {
5532     _ASSERTE(type == DML_ManagedVar);
5533     CachedString ret;
5534     if (ret.IsOOM())
5535     {
5536         ReportOOM();
5537         return ret;
5538     }
5539
5540     // calculate the number of digits in frame (this assumes base-10 display of frames)
5541     int numFrameDigits = 0;
5542     if (frame > 0)
5543     {
5544         ULONG tempFrame = frame;
5545         while (tempFrame > 0)
5546         {
5547             ++numFrameDigits;
5548             tempFrame /= 10;
5549         }
5550     }
5551     else
5552     {
5553         numFrameDigits = 1;
5554     }
5555     
5556     size_t totalStringLength = strlen(DMLFormats[type]) + _wcslen(expansionName) + numFrameDigits + _wcslen(simpleName) + 1;
5557     if (totalStringLength > ret.GetStrLen())
5558     {
5559         ret.Allocate(static_cast<int>(totalStringLength));
5560         if (ret.IsOOM())
5561         {
5562             ReportOOM();
5563             return ret;
5564         }
5565     }
5566     
5567     if (IsDMLEnabled())
5568     {
5569         sprintf_s(ret, ret.GetStrLen(), DMLFormats[type], expansionName, frame, simpleName);
5570     }
5571     else
5572     {
5573         sprintf_s(ret, ret.GetStrLen(), "%S", simpleName);
5574     }
5575
5576     return ret;
5577 }
5578
5579 CachedString Output::BuildManagedVarValue(__in_z LPCWSTR expansionName, ULONG frame, int indexInArray, FormatType type)
5580 {
5581     WCHAR indexString[24];
5582     swprintf_s(indexString, _countof(indexString), W("[%d]"), indexInArray);
5583     return BuildManagedVarValue(expansionName, frame, indexString, type);
5584 }
5585
5586 EnableDMLHolder::EnableDMLHolder(BOOL enable)
5587     : mEnable(enable)
5588 {
5589 #ifndef FEATURE_PAL
5590     // If the user has not requested that we use DML, it's still possible that
5591     // they have instead specified ".prefer_dml 1".  If enable is false,
5592     // we will check here for .prefer_dml.  Since this class is only used once
5593     // per command issued to SOS, this should only check the setting once per
5594     // sos command issued.
5595     if (!mEnable && Output::g_DMLEnable <= 0)
5596     {
5597         ULONG opts;
5598         HRESULT hr = g_ExtControl->GetEngineOptions(&opts);
5599         mEnable = SUCCEEDED(hr) && (opts & DEBUG_ENGOPT_PREFER_DML) == DEBUG_ENGOPT_PREFER_DML;
5600     }
5601
5602     if (mEnable)
5603     {
5604         Output::g_DMLEnable++;
5605     }
5606 #endif // FEATURE_PAL
5607 }
5608
5609 EnableDMLHolder::~EnableDMLHolder()
5610 {
5611 #ifndef FEATURE_PAL
5612     if (mEnable)
5613         Output::g_DMLEnable--;
5614 #endif
5615 }
5616
5617 bool IsDMLEnabled()
5618 {
5619     return Output::g_DMLEnable > 0;
5620 }
5621
5622 NoOutputHolder::NoOutputHolder(BOOL bSuppress)
5623     : mSuppress(bSuppress)
5624 {
5625     if (mSuppress)
5626         Output::g_bSuppressOutput++;
5627 }
5628
5629 NoOutputHolder::~NoOutputHolder()
5630 {
5631     if (mSuppress)
5632         Output::g_bSuppressOutput--;
5633 }
5634
5635 //
5636 // Code to support mapping RVAs to managed code line numbers.
5637 //
5638
5639 // 
5640 // Retrieves the IXCLRDataMethodInstance* instance associated with the
5641 // passed in native offset.
5642 HRESULT
5643 GetClrMethodInstance(
5644     ___in ULONG64 NativeOffset,
5645     ___out IXCLRDataMethodInstance** Method)
5646 {
5647     HRESULT Status;
5648     CLRDATA_ENUM MethEnum;
5649
5650     Status = g_clrData->StartEnumMethodInstancesByAddress(NativeOffset, NULL, &MethEnum);
5651
5652     if (Status == S_OK)
5653     {
5654         Status = g_clrData->EnumMethodInstanceByAddress(&MethEnum, Method);
5655         g_clrData->EndEnumMethodInstancesByAddress(MethEnum);
5656     }
5657
5658     // Any alternate success is a true failure here.
5659     return (Status == S_OK || FAILED(Status)) ? Status : E_NOINTERFACE;
5660 }
5661
5662 // 
5663 // Enumerates over the IL address map associated with the passed in 
5664 // managed method, and returns the highest non-epilog offset.
5665 HRESULT
5666 GetLastMethodIlOffset(
5667     ___in IXCLRDataMethodInstance* Method, 
5668     ___out PULONG32 MethodOffs)
5669 {
5670     HRESULT Status;
5671     CLRDATA_IL_ADDRESS_MAP MapLocal[16];
5672     CLRDATA_IL_ADDRESS_MAP* Map = MapLocal;
5673     ULONG32 MapCount = _countof(MapLocal);
5674     ULONG32 MapNeeded;
5675     ULONG32 HighestOffset;
5676
5677     for (;;)
5678     {
5679         if ((Status = Method->GetILAddressMap(MapCount, &MapNeeded, Map)) != S_OK)
5680         {
5681             return Status;
5682         }
5683
5684         if (MapNeeded <= MapCount)
5685         {
5686             break;
5687         }
5688
5689         // Need more map entries.
5690         if (Map != MapLocal)
5691         {
5692             // Already went around and the answer changed,
5693             // which should not be possible.
5694             delete[] Map;
5695             return E_UNEXPECTED;
5696         }
5697
5698         Map = new CLRDATA_IL_ADDRESS_MAP[MapNeeded];
5699         if (!Map)
5700         {
5701             return E_OUTOFMEMORY;
5702         }
5703
5704         MapCount = MapNeeded;
5705     }
5706
5707     HighestOffset = 0;
5708     for (size_t i = 0; i < MapNeeded; i++)
5709     {
5710         if (Map[i].ilOffset != (ULONG32)CLRDATA_IL_OFFSET_NO_MAPPING &&
5711             Map[i].ilOffset != (ULONG32)CLRDATA_IL_OFFSET_PROLOG &&
5712             Map[i].ilOffset != (ULONG32)CLRDATA_IL_OFFSET_EPILOG &&
5713             Map[i].ilOffset > HighestOffset)
5714         {
5715             HighestOffset = Map[i].ilOffset;
5716         }
5717     }
5718
5719     if (Map != MapLocal)
5720     {
5721         delete[] Map;
5722     }
5723
5724     *MethodOffs = HighestOffset;
5725     return S_OK;
5726 }
5727
5728 // 
5729 // Convert a native offset (possibly already associated with a managed
5730 // method identified by the passed in IXCLRDataMethodInstance) to a
5731 // triplet (ImageInfo, MethodToken, MethodOffset) that can be used to 
5732 // represent an "IL offset".
5733 HRESULT
5734 ConvertNativeToIlOffset(
5735     ___in ULONG64 native,
5736     ___out IXCLRDataModule** ppModule,
5737     ___out mdMethodDef* methodToken,
5738     ___out PULONG32 methodOffs)
5739 {
5740     ToRelease<IXCLRDataMethodInstance> pMethodInst(NULL);
5741     HRESULT Status;
5742
5743     if ((Status = GetClrMethodInstance(native, &pMethodInst)) != S_OK)
5744     {
5745         return Status;
5746     }
5747
5748     if ((Status = pMethodInst->GetILOffsetsByAddress(native, 1, NULL, methodOffs)) != S_OK)
5749     {
5750         *methodOffs = 0;
5751     }
5752     else
5753     {
5754         switch((LONG)*methodOffs)
5755         {
5756         case CLRDATA_IL_OFFSET_NO_MAPPING:
5757             return E_NOINTERFACE;
5758             
5759         case CLRDATA_IL_OFFSET_PROLOG:
5760             // Treat all of the prologue as part of
5761             // the first source line.
5762             *methodOffs = 0;
5763             break;
5764             
5765         case CLRDATA_IL_OFFSET_EPILOG:
5766             // Back up until we find the last real
5767             // IL offset.
5768             if ((Status = GetLastMethodIlOffset(pMethodInst, methodOffs)) != S_OK)
5769             {
5770                 return Status;
5771             }
5772             break;
5773         }
5774     }
5775
5776     return pMethodInst->GetTokenAndScope(methodToken, ppModule);
5777 }
5778
5779 // Based on a native offset, passed in the first argument this function
5780 // identifies the corresponding source file name and line number.
5781 HRESULT
5782 GetLineByOffset(
5783     ___in ULONG64 offset,
5784     ___out ULONG *pLinenum,
5785     __out_ecount(cchFileName) WCHAR* pwszFileName,
5786     ___in ULONG cchFileName)
5787 {
5788     HRESULT Status = S_OK;
5789     ULONG32 methodToken;
5790     ULONG32 methodOffs;
5791
5792     // Find the image, method token and IL offset that correspond to "offset"
5793     ToRelease<IXCLRDataModule> pModule(NULL);
5794     IfFailRet(ConvertNativeToIlOffset(offset, &pModule, &methodToken, &methodOffs));
5795
5796     ToRelease<IMetaDataImport> pMDImport(NULL);
5797     IfFailRet(pModule->QueryInterface(IID_IMetaDataImport, (LPVOID *) &pMDImport));
5798
5799     SymbolReader symbolReader;
5800     IfFailRet(symbolReader.LoadSymbols(pMDImport, pModule));
5801
5802     return symbolReader.GetLineByILOffset(methodToken, methodOffs, pLinenum, pwszFileName, cchFileName);
5803 }
5804
5805 void TableOutput::ReInit(int numColumns, int defaultColumnWidth, Alignment alignmentDefault, int indent, int padding)
5806 {
5807     Clear();
5808
5809     mColumns = numColumns;
5810     mDefaultWidth = defaultColumnWidth;
5811     mIndent = indent;
5812     mPadding = padding;
5813     mCurrCol = 0;
5814     mDefaultAlign = alignmentDefault;
5815 }
5816
5817 void TableOutput::SetWidths(int columns, ...)
5818 {
5819     SOS_Assert(columns > 0);
5820     SOS_Assert(columns <= mColumns);
5821
5822     AllocWidths();
5823
5824     va_list list;
5825     va_start(list, columns);
5826
5827     for (int i = 0; i < columns; ++i)
5828         mWidths[i] = va_arg(list, int);
5829
5830     va_end(list);
5831 }
5832
5833 void TableOutput::SetColWidth(int col, int width)
5834 {
5835     SOS_Assert(col >= 0 && col < mColumns);
5836     SOS_Assert(width >= 0);
5837
5838     AllocWidths();
5839
5840     mWidths[col] = width;
5841 }
5842
5843 void TableOutput::SetColAlignment(int col, Alignment align)
5844 {
5845     SOS_Assert(col >= 0 && col < mColumns);
5846
5847     if (!mAlignments)
5848     {
5849         mAlignments = new Alignment[mColumns];
5850         for (int i = 0; i < mColumns; ++i)
5851             mAlignments[i] = mDefaultAlign;
5852     }
5853
5854     mAlignments[col] = align;
5855 }
5856
5857
5858
5859 void TableOutput::Clear()
5860 {
5861     if (mAlignments)
5862     {
5863         delete [] mAlignments;
5864         mAlignments = 0;
5865     }
5866
5867     if (mWidths)
5868     {
5869         delete [] mWidths;
5870         mWidths = 0;
5871     }
5872 }
5873
5874 void TableOutput::AllocWidths()
5875 {
5876     if (!mWidths)
5877     {
5878         mWidths = new int[mColumns];
5879         for (int i = 0; i < mColumns; ++i)
5880             mWidths[i] = mDefaultWidth;
5881     }
5882 }
5883
5884 int TableOutput::GetColumnWidth(int col)
5885 {
5886     SOS_Assert(col < mColumns);
5887
5888     if (mWidths)
5889         return mWidths[col];
5890
5891     return mDefaultWidth;
5892 }
5893
5894 Alignment TableOutput::GetColAlign(int col)
5895 {
5896     SOS_Assert(col < mColumns);
5897     if (mAlignments)
5898         return mAlignments[col];
5899
5900     return mDefaultAlign;
5901 }
5902
5903 const char *TableOutput::GetWhitespace(int amount)
5904 {
5905     static char WhiteSpace[256] = "";
5906     static int count = 0;
5907
5908     if (count == 0)
5909     {
5910         count = _countof(WhiteSpace);
5911         for (int i = 0; i < count-1; ++i)
5912             WhiteSpace[i] = ' ';
5913         WhiteSpace[count-1] = 0;
5914     }
5915
5916     SOS_Assert(amount < count);
5917     return &WhiteSpace[count-amount-1];
5918 }
5919
5920 void TableOutput::OutputBlankColumns(int col)
5921 {
5922     if (col < mCurrCol)
5923     {
5924         ExtOut("\n");
5925         mCurrCol = 0;
5926     }
5927
5928     int whitespace = 0;
5929     for (int i = mCurrCol; i < col; ++i)
5930         whitespace += GetColumnWidth(i) + mPadding;
5931
5932     ExtOut(GetWhitespace(whitespace));
5933 }
5934
5935 void TableOutput::OutputIndent()
5936 {
5937     if (mIndent)
5938         ExtOut(GetWhitespace(mIndent));
5939 }
5940
5941 #ifndef FEATURE_PAL
5942
5943 PEOffsetMemoryReader::PEOffsetMemoryReader(TADDR moduleBaseAddress) :
5944     m_moduleBaseAddress(moduleBaseAddress),
5945     m_refCount(1)
5946     {}
5947
5948 HRESULT __stdcall PEOffsetMemoryReader::QueryInterface(REFIID riid, VOID** ppInterface)
5949 {
5950     if(riid == __uuidof(IDiaReadExeAtOffsetCallback))
5951     {
5952         *ppInterface = static_cast<IDiaReadExeAtOffsetCallback*>(this);
5953         AddRef();
5954         return S_OK;
5955     }
5956     else if(riid == __uuidof(IUnknown))
5957     {
5958         *ppInterface = static_cast<IUnknown*>(this);
5959         AddRef();
5960         return S_OK;
5961     }
5962     else
5963     {
5964         return E_NOINTERFACE;
5965     }
5966 }
5967
5968 ULONG __stdcall PEOffsetMemoryReader::AddRef()
5969 {
5970     return InterlockedIncrement((volatile LONG *) &m_refCount);
5971 }
5972
5973 ULONG __stdcall PEOffsetMemoryReader::Release()
5974 {
5975     ULONG count = InterlockedDecrement((volatile LONG *) &m_refCount);
5976     if(count == 0)
5977     {
5978         delete this;
5979     }
5980     return count;
5981 }
5982     
5983 // IDiaReadExeAtOffsetCallback implementation
5984 HRESULT __stdcall PEOffsetMemoryReader::ReadExecutableAt(DWORDLONG fileOffset, DWORD cbData, DWORD* pcbData, BYTE data[])
5985 {
5986     return SafeReadMemory(m_moduleBaseAddress + fileOffset, data, cbData, pcbData) ? S_OK : E_FAIL;
5987 }
5988
5989 PERvaMemoryReader::PERvaMemoryReader(TADDR moduleBaseAddress) :
5990     m_moduleBaseAddress(moduleBaseAddress),
5991     m_refCount(1)
5992     {}
5993
5994 HRESULT __stdcall PERvaMemoryReader::QueryInterface(REFIID riid, VOID** ppInterface)
5995 {
5996     if(riid == __uuidof(IDiaReadExeAtRVACallback))
5997     {
5998         *ppInterface = static_cast<IDiaReadExeAtRVACallback*>(this);
5999         AddRef();
6000         return S_OK;
6001     }
6002     else if(riid == __uuidof(IUnknown))
6003     {
6004         *ppInterface = static_cast<IUnknown*>(this);
6005         AddRef();
6006         return S_OK;
6007     }
6008     else
6009     {
6010         return E_NOINTERFACE;
6011     }
6012 }
6013
6014 ULONG __stdcall PERvaMemoryReader::AddRef()
6015 {
6016     return InterlockedIncrement((volatile LONG *) &m_refCount);
6017 }
6018
6019 ULONG __stdcall PERvaMemoryReader::Release()
6020 {
6021     ULONG count = InterlockedDecrement((volatile LONG *) &m_refCount);
6022     if(count == 0)
6023     {
6024         delete this;
6025     }
6026     return count;
6027 }
6028     
6029 // IDiaReadExeAtOffsetCallback implementation
6030 HRESULT __stdcall PERvaMemoryReader::ReadExecutableAtRVA(DWORD relativeVirtualAddress, DWORD cbData, DWORD* pcbData, BYTE data[])
6031 {
6032     return SafeReadMemory(m_moduleBaseAddress + relativeVirtualAddress, data, cbData, pcbData) ? S_OK : E_FAIL;
6033 }
6034
6035 #endif // FEATURE_PAL
6036
6037 HRESULT SymbolReader::LoadSymbols(___in IMetaDataImport* pMD, ___in ICorDebugModule* pModule)
6038 {
6039     HRESULT Status = S_OK;
6040     BOOL isDynamic = FALSE;
6041     BOOL isInMemory = FALSE;
6042     IfFailRet(pModule->IsDynamic(&isDynamic));
6043     IfFailRet(pModule->IsInMemory(&isInMemory));
6044
6045     if (isDynamic)
6046     {
6047         // Dynamic and in memory assemblies are a special case which we will ignore for now
6048         ExtWarn("SOS Warning: Loading symbols for dynamic assemblies is not yet supported\n");
6049         return E_FAIL;
6050     }
6051
6052     ULONG64 peAddress = 0;
6053     ULONG32 peSize = 0;
6054     IfFailRet(pModule->GetBaseAddress(&peAddress));
6055     IfFailRet(pModule->GetSize(&peSize));
6056
6057     ULONG32 len = 0; 
6058     WCHAR moduleName[MAX_LONGPATH];
6059     IfFailRet(pModule->GetName(_countof(moduleName), &len, moduleName));
6060
6061 #ifndef FEATURE_PAL
6062     if (SUCCEEDED(LoadSymbolsForWindowsPDB(pMD, peAddress, moduleName, isInMemory)))
6063     {
6064         return S_OK;
6065     }
6066 #endif // FEATURE_PAL
6067     return LoadSymbolsForPortablePDB(moduleName, isInMemory, isInMemory, peAddress, peSize, 0, 0);
6068 }
6069
6070 HRESULT SymbolReader::LoadSymbols(___in IMetaDataImport* pMD, ___in IXCLRDataModule* pModule)
6071 {
6072     DacpGetModuleData moduleData;
6073     HRESULT hr = moduleData.Request(pModule);
6074     if (FAILED(hr))
6075     {
6076         ExtOut("LoadSymbols moduleData.Request FAILED 0x%08x\n", hr);
6077         return hr;
6078     }
6079
6080     if (moduleData.IsDynamic)
6081     {
6082         ExtWarn("SOS Warning: Loading symbols for dynamic assemblies is not yet supported\n");
6083         return E_FAIL;
6084     }
6085
6086     ArrayHolder<WCHAR> pModuleName = new WCHAR[MAX_LONGPATH + 1];
6087     ULONG32 nameLen = 0;
6088     hr = pModule->GetFileName(MAX_LONGPATH, &nameLen, pModuleName);
6089     if (FAILED(hr))
6090     {
6091         ExtOut("LoadSymbols: IXCLRDataModule->GetFileName FAILED 0x%08x\n", hr);
6092         return hr;
6093     }
6094
6095 #ifndef FEATURE_PAL
6096     // TODO: in-memory windows PDB not supported
6097     hr = LoadSymbolsForWindowsPDB(pMD, moduleData.LoadedPEAddress, pModuleName, moduleData.IsFileLayout);
6098     if (SUCCEEDED(hr))
6099     {
6100         return hr;
6101     }
6102 #endif // FEATURE_PAL
6103
6104     return LoadSymbolsForPortablePDB(
6105         pModuleName, 
6106         moduleData.IsInMemory,
6107         moduleData.IsFileLayout,
6108         moduleData.LoadedPEAddress,
6109         moduleData.LoadedPESize, 
6110         moduleData.InMemoryPdbAddress,
6111         moduleData.InMemoryPdbSize);
6112 }
6113
6114 #ifndef FEATURE_PAL
6115
6116 HRESULT SymbolReader::LoadSymbolsForWindowsPDB(___in IMetaDataImport* pMD, ___in ULONG64 peAddress, __in_z WCHAR* pModuleName, ___in BOOL isFileLayout)
6117 {
6118     HRESULT Status = S_OK;
6119
6120     if (m_pSymReader != NULL) 
6121         return S_OK;
6122
6123     IfFailRet(CoInitialize(NULL));
6124
6125     // We now need a binder object that will take the module and return a 
6126     // reader object
6127     ToRelease<ISymUnmanagedBinder3> pSymBinder;
6128     if (FAILED(Status = CreateInstanceCustom(CLSID_CorSymBinder_SxS, 
6129                         IID_ISymUnmanagedBinder3, 
6130                         W("diasymreader.dll"),
6131                         cciLatestFx|cciDacColocated|cciDbgPath, 
6132                         (void**)&pSymBinder)))
6133     {
6134         ExtOut("SOS Error: Unable to CoCreateInstance class=CLSID_CorSymBinder_SxS, interface=IID_ISymUnmanagedBinder3, hr=0x%x\n", Status);
6135         ExtOut("This usually means the installation of .Net Framework on your machine is missing or needs repair\n");
6136         return Status;
6137     }
6138
6139     ToRelease<IDebugSymbols3> spSym3(NULL);
6140     Status = g_ExtSymbols->QueryInterface(__uuidof(IDebugSymbols3), (void**)&spSym3);
6141     if (FAILED(Status))
6142     {
6143         ExtOut("SOS Error: Unable to query IDebugSymbols3 HRESULT=0x%x.\n", Status);
6144         return Status;
6145     }
6146
6147     ULONG pathSize = 0;
6148     Status = spSym3->GetSymbolPathWide(NULL, 0, &pathSize);
6149     if (FAILED(Status)) //S_FALSE if the path doesn't fit, but if the path was size 0 perhaps we would get S_OK?
6150     {
6151         ExtOut("SOS Error: Unable to get symbol path length. IDebugSymbols3::GetSymbolPathWide HRESULT=0x%x.\n", Status);
6152         return Status;
6153     }
6154
6155     ArrayHolder<WCHAR> symbolPath = new WCHAR[pathSize];
6156     Status = spSym3->GetSymbolPathWide(symbolPath, pathSize, NULL);
6157     if (S_OK != Status)
6158     {
6159         ExtOut("SOS Error: Unable to get symbol path. IDebugSymbols3::GetSymbolPathWide HRESULT=0x%x.\n", Status);
6160         return Status;
6161     }
6162
6163     ToRelease<IUnknown> pCallback = NULL;
6164     if (isFileLayout)
6165     {
6166         pCallback = (IUnknown*) new PEOffsetMemoryReader(TO_TADDR(peAddress));
6167     }
6168     else
6169     {
6170         pCallback = (IUnknown*) new PERvaMemoryReader(TO_TADDR(peAddress));
6171     }
6172
6173     // TODO: this should be better integrated with windbg's symbol lookup
6174     Status = pSymBinder->GetReaderFromCallback(pMD, pModuleName, symbolPath, 
6175         AllowRegistryAccess | AllowSymbolServerAccess | AllowOriginalPathAccess | AllowReferencePathAccess, pCallback, &m_pSymReader);
6176
6177     if (FAILED(Status) && m_pSymReader != NULL)
6178     {
6179         m_pSymReader->Release();
6180         m_pSymReader = NULL;
6181     }
6182     return Status;
6183 }
6184
6185 #endif // FEATURE_PAL
6186
6187 //
6188 // Pass to managed helper code to read in-memory PEs/PDBs
6189 // Returns the number of bytes read.
6190 //
6191 int ReadMemoryForSymbols(ULONG64 address, char *buffer, int cb)
6192 {
6193     ULONG read;
6194     if (SafeReadMemory(TO_TADDR(address), (PVOID)buffer, cb, &read))
6195     {
6196         return read;
6197     }
6198     return 0;
6199 }
6200
6201 HRESULT SymbolReader::LoadSymbolsForPortablePDB(__in_z WCHAR* pModuleName, ___in BOOL isInMemory, ___in BOOL isFileLayout,
6202     ___in ULONG64 peAddress, ___in ULONG64 peSize, ___in ULONG64 inMemoryPdbAddress, ___in ULONG64 inMemoryPdbSize)
6203 {
6204     HRESULT Status = S_OK;
6205
6206     if (loadSymbolsForModuleDelegate == nullptr)
6207     {
6208         IfFailRet(PrepareSymbolReader());
6209     }
6210
6211     // The module name needs to be null for in-memory PE's.
6212     ArrayHolder<char> szModuleName = nullptr;
6213     if (!isInMemory && pModuleName != nullptr)
6214     {
6215         szModuleName = new char[MAX_LONGPATH];
6216         if (WideCharToMultiByte(CP_ACP, 0, pModuleName, (int)(_wcslen(pModuleName) + 1), szModuleName, MAX_LONGPATH, NULL, NULL) == 0)
6217         {
6218             return E_FAIL;
6219         }
6220     }
6221
6222     m_symbolReaderHandle = loadSymbolsForModuleDelegate(szModuleName, isFileLayout, peAddress, 
6223         (int)peSize, inMemoryPdbAddress, (int)inMemoryPdbSize, ReadMemoryForSymbols);
6224
6225     if (m_symbolReaderHandle == 0)
6226     {
6227         return E_FAIL;
6228     }
6229
6230     return Status;
6231 }
6232
6233 #ifndef FEATURE_PAL
6234
6235 void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList)
6236 {
6237     const char * const tpaExtensions[] = {
6238         "*.ni.dll",      // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir
6239         "*.dll",
6240         "*.ni.exe",
6241         "*.exe",
6242     };
6243
6244     std::set<std::string> addedAssemblies;
6245
6246     // Walk the directory for each extension separately so that we first get files with .ni.dll extension,
6247     // then files with .dll extension, etc.
6248     for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++)
6249     {
6250         const char* ext = tpaExtensions[extIndex];
6251         size_t extLength = strlen(ext);
6252
6253         std::string assemblyPath(directory);
6254         assemblyPath.append(DIRECTORY_SEPARATOR_STR_A);
6255         assemblyPath.append(tpaExtensions[extIndex]);
6256
6257         WIN32_FIND_DATAA data;
6258         HANDLE findHandle = FindFirstFileA(assemblyPath.c_str(), &data);
6259
6260         if (findHandle != INVALID_HANDLE_VALUE) 
6261         {
6262             do
6263             {
6264                 if (!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
6265                 {
6266
6267                     std::string filename(data.cFileName);
6268                     size_t extPos = filename.length() - extLength;
6269                     std::string filenameWithoutExt(filename.substr(0, extPos));
6270
6271                     // Make sure if we have an assembly with multiple extensions present,
6272                     // we insert only one version of it.
6273                     if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end())
6274                     {
6275                         addedAssemblies.insert(filenameWithoutExt);
6276
6277                         tpaList.append(directory);
6278                         tpaList.append(DIRECTORY_SEPARATOR_STR_A);
6279                         tpaList.append(filename);
6280                         tpaList.append(";");
6281                     }
6282                 }
6283             } 
6284             while (0 != FindNextFileA(findHandle, &data));
6285
6286             FindClose(findHandle);
6287         }
6288     }
6289 }
6290
6291 bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutable)
6292 {
6293     ArrayHolder<char> hostPath = new char[MAX_LONGPATH+1];
6294     if (::GetModuleFileName(NULL, hostPath, MAX_LONGPATH) == 0)
6295     {
6296         return false;
6297     }
6298
6299     entrypointExecutable.clear();
6300     entrypointExecutable.append(hostPath);
6301
6302     return true;
6303 }
6304
6305 #endif // FEATURE_PAL
6306
6307 HRESULT SymbolReader::PrepareSymbolReader()
6308 {
6309     static bool attemptedSymbolReaderPreparation = false;
6310     if (attemptedSymbolReaderPreparation)
6311     {
6312         // If we already tried to set up the symbol reader, we won't try again.
6313         return E_FAIL;
6314     }
6315
6316     attemptedSymbolReaderPreparation = true;
6317
6318     std::string absolutePath;
6319     std::string coreClrPath;
6320     HRESULT Status;
6321
6322 #ifdef FEATURE_PAL
6323     coreClrPath = g_ExtServices->GetCoreClrDirectory();
6324     if (!GetAbsolutePath(coreClrPath.c_str(), absolutePath))
6325     {
6326         ExtErr("Error: Failed to get coreclr absolute path\n");
6327         return E_FAIL;
6328     }
6329     coreClrPath.append(DIRECTORY_SEPARATOR_STR_A);
6330     coreClrPath.append(MAIN_CLR_DLL_NAME_A);
6331 #else
6332     ULONG index;
6333     Status = g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, &index, NULL);
6334     if (FAILED(Status))
6335     {
6336         ExtErr("Error: Can't find coreclr module\n");
6337         return Status;
6338     }
6339     ArrayHolder<char> szModuleName = new char[MAX_LONGPATH + 1];
6340     Status = g_ExtSymbols->GetModuleNames(index, 0, szModuleName, MAX_LONGPATH, NULL, NULL, 0, NULL, NULL, 0, NULL);
6341     if (FAILED(Status))
6342     {
6343         ExtErr("Error: Failed to get coreclr module name\n");
6344         return Status;
6345     }
6346     coreClrPath = szModuleName;
6347
6348     // Parse off the module name to get just the path
6349     size_t pos = coreClrPath.rfind(DIRECTORY_SEPARATOR_CHAR_A);
6350     if (pos == std::string::npos)
6351     {
6352         ExtErr("Error: Failed to parse coreclr module name\n");
6353         return E_FAIL;
6354     }
6355     absolutePath.assign(coreClrPath, 0, pos);
6356 #endif // FEATURE_PAL
6357
6358     HMODULE coreclrLib = LoadLibraryA(coreClrPath.c_str());
6359     if (coreclrLib == nullptr)
6360     {
6361         ExtErr("Error: Failed to load %s\n", coreClrPath.c_str());
6362         return E_FAIL;
6363     }
6364
6365     void *hostHandle;
6366     unsigned int domainId;
6367     coreclr_initialize_ptr initializeCoreCLR = (coreclr_initialize_ptr)GetProcAddress(coreclrLib, "coreclr_initialize");
6368     if (initializeCoreCLR == nullptr)
6369     {
6370         ExtErr("Error: coreclr_initialize not found\n");
6371         return E_FAIL;
6372     }
6373
6374     std::string tpaList;
6375     AddFilesFromDirectoryToTpaList(absolutePath.c_str(), tpaList);
6376
6377     const char *propertyKeys[] = {
6378         "TRUSTED_PLATFORM_ASSEMBLIES", "APP_PATHS", "APP_NI_PATHS",
6379         "NATIVE_DLL_SEARCH_DIRECTORIES", "AppDomainCompatSwitch"};
6380
6381     const char *propertyValues[] = {// TRUSTED_PLATFORM_ASSEMBLIES
6382                                     tpaList.c_str(),
6383                                     // APP_PATHS
6384                                     absolutePath.c_str(),
6385                                     // APP_NI_PATHS
6386                                     absolutePath.c_str(),
6387                                     // NATIVE_DLL_SEARCH_DIRECTORIES
6388                                     absolutePath.c_str(),
6389                                     // AppDomainCompatSwitch
6390                                     "UseLatestBehaviorWhenTFMNotSpecified"};
6391
6392     std::string entryPointExecutablePath;
6393     if (!GetEntrypointExecutableAbsolutePath(entryPointExecutablePath))
6394     {
6395         ExtErr("Could not get full path to current executable");
6396         return E_FAIL;
6397     }
6398
6399     Status = initializeCoreCLR(entryPointExecutablePath.c_str(), "sos", 
6400         sizeof(propertyKeys) / sizeof(propertyKeys[0]), propertyKeys, propertyValues, &hostHandle, &domainId);
6401
6402     if (FAILED(Status))
6403     {
6404         ExtErr("Error: Fail to initialize CoreCLR %08x\n", Status);
6405         return Status;
6406     }
6407
6408     coreclr_create_delegate_ptr createDelegate = (coreclr_create_delegate_ptr)GetProcAddress(coreclrLib, "coreclr_create_delegate");
6409     if (createDelegate == nullptr)
6410     {
6411         ExtErr("Error: coreclr_create_delegate not found\n");
6412         return E_FAIL;
6413     }
6414
6415     IfFailRet(createDelegate(hostHandle, domainId, SymbolReaderDllName, SymbolReaderClassName, "LoadSymbolsForModule", (void **)&loadSymbolsForModuleDelegate));
6416     IfFailRet(createDelegate(hostHandle, domainId, SymbolReaderDllName, SymbolReaderClassName, "Dispose", (void **)&disposeDelegate));
6417     IfFailRet(createDelegate(hostHandle, domainId, SymbolReaderDllName, SymbolReaderClassName, "ResolveSequencePoint", (void **)&resolveSequencePointDelegate));
6418     IfFailRet(createDelegate(hostHandle, domainId, SymbolReaderDllName, SymbolReaderClassName, "GetLocalVariableName", (void **)&getLocalVariableNameDelegate));
6419     IfFailRet(createDelegate(hostHandle, domainId, SymbolReaderDllName, SymbolReaderClassName, "GetLineByILOffset", (void **)&getLineByILOffsetDelegate));
6420
6421     return Status;
6422 }
6423
6424 HRESULT SymbolReader::GetLineByILOffset(___in mdMethodDef methodToken, ___in ULONG64 ilOffset,
6425     ___out ULONG *pLinenum, __out_ecount(cchFileName) WCHAR* pwszFileName, ___in ULONG cchFileName)
6426 {
6427     HRESULT Status = S_OK;
6428
6429     if (m_symbolReaderHandle != 0)
6430     {
6431         _ASSERTE(getLineByILOffsetDelegate != nullptr);
6432
6433         BSTR bstrFileName = SysAllocStringLen(0, MAX_LONGPATH);
6434         if (bstrFileName == nullptr)
6435         {
6436             return E_OUTOFMEMORY;
6437         }
6438         // Source lines with 0xFEEFEE markers are filtered out on the managed side.
6439         if ((getLineByILOffsetDelegate(m_symbolReaderHandle, methodToken, ilOffset, pLinenum, &bstrFileName) == FALSE) || (*pLinenum == 0))
6440         {
6441             SysFreeString(bstrFileName);
6442             return E_FAIL;
6443         }
6444         wcscpy_s(pwszFileName, cchFileName, bstrFileName);
6445         SysFreeString(bstrFileName);
6446         return S_OK;
6447     }
6448
6449 #ifndef FEATURE_PAL
6450     if (m_pSymReader == NULL)
6451         return E_FAIL;
6452
6453     ToRelease<ISymUnmanagedMethod> pSymMethod(NULL);
6454     IfFailRet(m_pSymReader->GetMethod(methodToken, &pSymMethod));
6455
6456     ULONG32 seqPointCount = 0;
6457     IfFailRet(pSymMethod->GetSequencePointCount(&seqPointCount));
6458
6459     if (seqPointCount == 0)
6460         return E_FAIL;
6461
6462     // allocate memory for the objects to be fetched
6463     ArrayHolder<ULONG32> offsets(new ULONG32[seqPointCount]);
6464     ArrayHolder<ULONG32> lines(new ULONG32[seqPointCount]);
6465     ArrayHolder<ULONG32> columns(new ULONG32[seqPointCount]);
6466     ArrayHolder<ULONG32> endlines(new ULONG32[seqPointCount]);
6467     ArrayHolder<ULONG32> endcolumns(new ULONG32[seqPointCount]);
6468     ArrayHolder<ToRelease<ISymUnmanagedDocument>> documents(new ToRelease<ISymUnmanagedDocument>[seqPointCount]);
6469
6470     ULONG32 realSeqPointCount = 0;
6471     IfFailRet(pSymMethod->GetSequencePoints(seqPointCount, &realSeqPointCount, offsets, &(documents[0]), lines, columns, endlines, endcolumns));
6472
6473     const ULONG32 HiddenLine = 0x00feefee;
6474     int bestSoFar = -1;
6475
6476     for (int i = 0; i < (int)realSeqPointCount; i++)
6477     {
6478         if (offsets[i] > ilOffset)
6479             break;
6480
6481         if (lines[i] != HiddenLine)
6482             bestSoFar = i;
6483     }
6484
6485     if (bestSoFar != -1)
6486     {
6487         ULONG32 cchNeeded = 0;
6488         IfFailRet(documents[bestSoFar]->GetURL(cchFileName, &cchNeeded, pwszFileName));
6489
6490         *pLinenum = lines[bestSoFar];
6491         return S_OK;
6492     }
6493 #endif // FEATURE_PAL
6494
6495     return E_FAIL;
6496 }
6497
6498 HRESULT SymbolReader::GetNamedLocalVariable(___in ISymUnmanagedScope * pScope, ___in ICorDebugILFrame * pILFrame, ___in mdMethodDef methodToken, 
6499     ___in ULONG localIndex, __out_ecount(paramNameLen) WCHAR* paramName, ___in ULONG paramNameLen, ICorDebugValue** ppValue)
6500 {
6501     HRESULT Status = S_OK;
6502
6503     if (m_symbolReaderHandle != 0)
6504     {
6505         _ASSERTE(getLocalVariableNameDelegate != nullptr);
6506
6507         BSTR wszParamName = SysAllocStringLen(0, mdNameLen);
6508         if (wszParamName == NULL)
6509         {
6510             return E_OUTOFMEMORY;
6511         }
6512
6513         if (getLocalVariableNameDelegate(m_symbolReaderHandle, methodToken, localIndex, &wszParamName) == FALSE)
6514         {
6515             SysFreeString(wszParamName);
6516             return E_FAIL;
6517         }
6518
6519         wcscpy_s(paramName, paramNameLen, wszParamName);
6520         SysFreeString(wszParamName);
6521
6522         if (FAILED(pILFrame->GetLocalVariable(localIndex, ppValue)) || (*ppValue == NULL))
6523         {
6524             *ppValue = NULL;
6525             return E_FAIL;
6526         }
6527         return S_OK;
6528     }
6529
6530 #ifndef FEATURE_PAL
6531     if (m_pSymReader == NULL)
6532         return E_FAIL;
6533
6534     if (pScope == NULL)
6535     {
6536         ToRelease<ISymUnmanagedMethod> pSymMethod;
6537         IfFailRet(m_pSymReader->GetMethod(methodToken, &pSymMethod));
6538
6539         ToRelease<ISymUnmanagedScope> pScope;
6540         IfFailRet(pSymMethod->GetRootScope(&pScope));
6541
6542         return GetNamedLocalVariable(pScope, pILFrame, methodToken, localIndex, paramName, paramNameLen, ppValue);
6543     }
6544     else
6545     {
6546         ULONG32 numVars = 0;
6547         IfFailRet(pScope->GetLocals(0, &numVars, NULL));
6548
6549         ArrayHolder<ISymUnmanagedVariable*> pLocals = new ISymUnmanagedVariable*[numVars];
6550         IfFailRet(pScope->GetLocals(numVars, &numVars, pLocals));
6551
6552         for (ULONG i = 0; i < numVars; i++)
6553         {
6554             ULONG32 varIndexInMethod = 0;
6555             if (SUCCEEDED(pLocals[i]->GetAddressField1(&varIndexInMethod)))
6556             {
6557                 if (varIndexInMethod != localIndex)
6558                     continue;
6559
6560                 ULONG32 nameLen = 0;
6561                 if (FAILED(pLocals[i]->GetName(paramNameLen, &nameLen, paramName)))
6562                         swprintf_s(paramName, paramNameLen, W("local_%d\0"), localIndex);
6563
6564                 if (SUCCEEDED(pILFrame->GetLocalVariable(varIndexInMethod, ppValue)) && (*ppValue != NULL))
6565                 {
6566                     for(ULONG j = 0; j < numVars; j++) pLocals[j]->Release();
6567                     return S_OK;
6568                 }
6569                 else
6570                 {
6571                     *ppValue = NULL;
6572                     for(ULONG j = 0; j < numVars; j++) pLocals[j]->Release();
6573                     return E_FAIL;
6574                 }
6575             }
6576         }
6577
6578         ULONG32 numChildren = 0;
6579         IfFailRet(pScope->GetChildren(0, &numChildren, NULL));
6580
6581         ArrayHolder<ISymUnmanagedScope*> pChildren = new ISymUnmanagedScope*[numChildren];
6582         IfFailRet(pScope->GetChildren(numChildren, &numChildren, pChildren));
6583
6584         for (ULONG i = 0; i < numChildren; i++)
6585         {
6586             if (SUCCEEDED(GetNamedLocalVariable(pChildren[i], pILFrame, methodToken, localIndex, paramName, paramNameLen, ppValue)))
6587             {
6588                 for (ULONG j = 0; j < numChildren; j++) pChildren[j]->Release();
6589                 return S_OK;
6590             }
6591         }
6592
6593         for (ULONG j = 0; j < numChildren; j++) pChildren[j]->Release();
6594     }
6595 #endif // FEATURE_PAL
6596
6597     return E_FAIL;
6598 }
6599
6600 HRESULT SymbolReader::GetNamedLocalVariable(___in ICorDebugFrame * pFrame, ___in ULONG localIndex, __out_ecount(paramNameLen) WCHAR* paramName, 
6601     ___in ULONG paramNameLen, ___out ICorDebugValue** ppValue)
6602 {
6603     HRESULT Status = S_OK;
6604
6605     *ppValue = NULL;
6606     paramName[0] = L'\0';
6607
6608     ToRelease<ICorDebugILFrame> pILFrame;
6609     IfFailRet(pFrame->QueryInterface(IID_ICorDebugILFrame, (LPVOID*) &pILFrame));
6610
6611     ToRelease<ICorDebugFunction> pFunction;
6612     IfFailRet(pFrame->GetFunction(&pFunction));
6613
6614     mdMethodDef methodDef;
6615     ToRelease<ICorDebugClass> pClass;
6616     ToRelease<ICorDebugModule> pModule;
6617     IfFailRet(pFunction->GetClass(&pClass));
6618     IfFailRet(pFunction->GetModule(&pModule));
6619     IfFailRet(pFunction->GetToken(&methodDef));
6620
6621     return GetNamedLocalVariable(NULL, pILFrame, methodDef, localIndex, paramName, paramNameLen, ppValue);
6622 }
6623
6624 HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ___in ULONG32 lineNumber, ___in TADDR mod, ___out mdMethodDef* pToken, ___out ULONG32* pIlOffset)
6625 {
6626     HRESULT Status = S_OK;
6627
6628     if (m_symbolReaderHandle != 0)
6629     {
6630         _ASSERTE(resolveSequencePointDelegate != nullptr);
6631
6632         char szName[mdNameLen];
6633         if (WideCharToMultiByte(CP_ACP, 0, pFilename, (int)(_wcslen(pFilename) + 1), szName, mdNameLen, NULL, NULL) == 0)
6634         { 
6635             return E_FAIL;
6636         }
6637         if (resolveSequencePointDelegate(m_symbolReaderHandle, szName, lineNumber, pToken, pIlOffset) == FALSE)
6638         {
6639             return E_FAIL;
6640         }
6641         return S_OK;
6642     }
6643
6644 #ifndef FEATURE_PAL
6645     if (m_pSymReader == NULL)
6646         return E_FAIL;
6647
6648     ULONG32 cDocs = 0;
6649     ULONG32 cDocsNeeded = 0;
6650     ArrayHolder<ToRelease<ISymUnmanagedDocument>> pDocs = NULL;
6651
6652     IfFailRet(m_pSymReader->GetDocuments(cDocs, &cDocsNeeded, NULL));
6653     pDocs = new ToRelease<ISymUnmanagedDocument>[cDocsNeeded];
6654     cDocs = cDocsNeeded;
6655     IfFailRet(m_pSymReader->GetDocuments(cDocs, &cDocsNeeded, &(pDocs[0])));
6656
6657     ULONG32 filenameLen = (ULONG32) _wcslen(pFilename);
6658
6659     for (ULONG32 i = 0; i < cDocs; i++)
6660     {
6661         ULONG32 cchUrl = 0;
6662         ULONG32 cchUrlNeeded = 0;
6663         ArrayHolder<WCHAR> pUrl = NULL;
6664         IfFailRet(pDocs[i]->GetURL(cchUrl, &cchUrlNeeded, pUrl));
6665         pUrl = new WCHAR[cchUrlNeeded];
6666         cchUrl = cchUrlNeeded;
6667         IfFailRet(pDocs[i]->GetURL(cchUrl, &cchUrlNeeded, pUrl));
6668
6669         // If the URL is exactly as long as the filename then compare the two names directly
6670         if (cchUrl-1 == filenameLen)
6671         {
6672             if (0!=_wcsicmp(pUrl, pFilename))
6673                 continue;
6674         }
6675         // does the URL suffix match [back]slash + filename?
6676         else if (cchUrl-1 > filenameLen)
6677         {
6678             WCHAR* slashLocation = pUrl + (cchUrl - filenameLen - 2);
6679             if (*slashLocation != L'\\' && *slashLocation != L'/')
6680                 continue;
6681             if (0 != _wcsicmp(slashLocation+1, pFilename))
6682                 continue;
6683         }
6684         // URL is too short to match
6685         else
6686             continue;
6687
6688         ULONG32 closestLine = 0;
6689         if (FAILED(pDocs[i]->FindClosestLine(lineNumber, &closestLine)))
6690             continue;
6691
6692         ToRelease<ISymUnmanagedMethod> pSymUnmanagedMethod;
6693         IfFailRet(m_pSymReader->GetMethodFromDocumentPosition(pDocs[i], closestLine, 0, &pSymUnmanagedMethod));
6694         IfFailRet(pSymUnmanagedMethod->GetToken(pToken));
6695         IfFailRet(pSymUnmanagedMethod->GetOffset(pDocs[i], closestLine, 0, pIlOffset));
6696
6697         // If this IL 
6698         if (*pIlOffset == -1)
6699         {
6700             return E_FAIL;
6701         }
6702         return S_OK;
6703     }
6704 #endif // FEATURE_PAL
6705
6706     return E_FAIL;
6707 }
6708
6709 static void AddAssemblyName(WString& methodOutput, CLRDATA_ADDRESS mdesc)
6710 {
6711     DacpMethodDescData mdescData;
6712     if (SUCCEEDED(mdescData.Request(g_sos, mdesc)))
6713     {
6714         DacpModuleData dmd;
6715         if (SUCCEEDED(dmd.Request(g_sos, mdescData.ModulePtr)))
6716         {
6717             ToRelease<IXCLRDataModule> pModule;
6718             if (SUCCEEDED(g_sos->GetModule(mdescData.ModulePtr, &pModule)))
6719             {
6720                 ArrayHolder<WCHAR> wszFileName = new WCHAR[MAX_LONGPATH + 1];
6721                 ULONG32 nameLen = 0;
6722                 if (SUCCEEDED(pModule->GetFileName(MAX_LONGPATH, &nameLen, wszFileName)))
6723                 {
6724                     if (wszFileName[0] != W('\0'))
6725                     {
6726                         WCHAR *pJustName = _wcsrchr(wszFileName, DIRECTORY_SEPARATOR_CHAR_W);
6727                         if (pJustName == NULL)
6728                             pJustName = wszFileName - 1;
6729                         methodOutput += (pJustName + 1);
6730                         methodOutput += W("!");
6731                     }
6732                 }
6733             }
6734         }
6735     }
6736 }
6737
6738 WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackWalk, BOOL bAssemblyName)
6739 {
6740     TADDR vtAddr;
6741     MOVE(vtAddr, frameAddr);
6742
6743     WString frameOutput;
6744     frameOutput += W("[");
6745
6746     if (SUCCEEDED(g_sos->GetFrameName(TO_CDADDR(vtAddr), mdNameLen, g_mdName, NULL)))
6747         frameOutput += g_mdName;
6748     else
6749         frameOutput += W("Frame");
6750         
6751     frameOutput += WString(W(": ")) + Pointer(frameAddr) + W("] ");
6752
6753     // Print the frame's associated function info, if it has any.
6754     CLRDATA_ADDRESS mdesc = 0;
6755     if (SUCCEEDED(g_sos->GetMethodDescPtrFromFrame(frameAddr, &mdesc)))
6756     {
6757         if (SUCCEEDED(g_sos->GetMethodDescName(mdesc, mdNameLen, g_mdName, NULL)))
6758         {
6759             if (bAssemblyName)
6760             {
6761                 AddAssemblyName(frameOutput, mdesc);
6762             }
6763
6764             frameOutput += g_mdName;
6765         }
6766         else
6767         {
6768             frameOutput += W("<unknown method>");
6769         }
6770     }
6771     else if (pStackWalk)
6772     {
6773         // The Frame did not have direct function info, so try to get the method instance
6774         // (in this case a MethodDesc), and read the name from it.
6775         ToRelease<IXCLRDataFrame> frame;
6776         if (SUCCEEDED(pStackWalk->GetFrame(&frame)))
6777         {
6778             ToRelease<IXCLRDataMethodInstance> methodInstance;
6779             if (SUCCEEDED(frame->GetMethodInstance(&methodInstance)))
6780             {
6781                 // GetName can return S_FALSE if mdNameLen is not large enough.  However we are already
6782                 // passing a pretty big buffer in.  If this returns S_FALSE (meaning the buffer is too
6783                 // small) then we should not output it anyway.
6784                 if (methodInstance->GetName(0, mdNameLen, NULL, g_mdName) == S_OK)
6785                     frameOutput += g_mdName;
6786             }
6787         }
6788     }
6789     
6790     return frameOutput;
6791 }
6792
6793 WString MethodNameFromIP(CLRDATA_ADDRESS ip, BOOL bSuppressLines, BOOL bAssemblyName, BOOL bDisplacement)
6794 {
6795     ULONG linenum;
6796     WString methodOutput;
6797     CLRDATA_ADDRESS mdesc = 0;
6798     
6799     if (FAILED(g_sos->GetMethodDescPtrFromIP(ip, &mdesc)))
6800     {
6801         methodOutput = W("<unknown>");
6802     }
6803     else
6804     {
6805         DacpMethodDescData mdescData;
6806         if (SUCCEEDED(g_sos->GetMethodDescName(mdesc, mdNameLen, g_mdName, NULL)))
6807         {
6808             if (bAssemblyName)
6809             {
6810                 AddAssemblyName(methodOutput, mdesc);
6811             }
6812
6813             methodOutput += g_mdName;
6814
6815             if (bDisplacement)
6816             {
6817                 if (SUCCEEDED(mdescData.Request(g_sos, mdesc)))
6818                 {
6819                     ULONG64 disp = (ip - mdescData.NativeCodeAddr);
6820                     if (disp)
6821                     {
6822                         methodOutput += W(" + ");
6823                         methodOutput += Decimal(disp);
6824                     }
6825                 }
6826             }
6827         }
6828         else if (SUCCEEDED(mdescData.Request(g_sos, mdesc)))
6829         {
6830             DacpModuleData dmd;
6831             BOOL bModuleNameWorked = FALSE;
6832             ULONG64 addrInModule = ip;
6833             if (SUCCEEDED(dmd.Request(g_sos, mdescData.ModulePtr)))
6834             {
6835                 CLRDATA_ADDRESS peFileBase = 0;
6836                 if (SUCCEEDED(g_sos->GetPEFileBase(dmd.File, &peFileBase)))
6837                 {
6838                     if (peFileBase)
6839                     {
6840                         addrInModule = peFileBase;
6841                     }
6842                 }
6843             }
6844             ULONG Index;
6845             ULONG64 moduleBase;
6846             if (SUCCEEDED(g_ExtSymbols->GetModuleByOffset(UL64_TO_CDA(addrInModule), 0, &Index, &moduleBase)))
6847             {                                    
6848                 ArrayHolder<char> szModuleName = new char[MAX_LONGPATH+1];
6849
6850                 if (SUCCEEDED(g_ExtSymbols->GetModuleNames(Index, moduleBase, NULL, 0, NULL, szModuleName, MAX_LONGPATH, NULL, NULL, 0, NULL)))
6851                 {
6852                     MultiByteToWideChar (CP_ACP, 0, szModuleName, MAX_LONGPATH, g_mdName, _countof(g_mdName));
6853                     methodOutput += g_mdName;
6854                     methodOutput += W("!");
6855                 }
6856             }
6857             methodOutput += W("<unknown method>");
6858         }
6859         else
6860         {
6861             methodOutput = W("<unknown>");
6862         }
6863
6864         ArrayHolder<WCHAR> wszFileName = new WCHAR[MAX_LONGPATH];
6865         if (!bSuppressLines &&
6866             SUCCEEDED(GetLineByOffset(TO_CDADDR(ip), &linenum, wszFileName, MAX_LONGPATH)))
6867         {
6868             methodOutput += WString(W(" [")) + wszFileName + W(" @ ") + Decimal(linenum) + W("]");
6869         }
6870     }
6871     
6872     return methodOutput;
6873 }
6874
6875 HRESULT GetGCRefs(ULONG osID, SOSStackRefData **ppRefs, unsigned int *pRefCnt, SOSStackRefError **ppErrors, unsigned int *pErrCount)
6876 {
6877     if (ppRefs == NULL || pRefCnt == NULL)
6878         return E_POINTER;
6879     
6880     if (pErrCount)
6881         *pErrCount = 0;
6882     
6883     *pRefCnt = 0;
6884     unsigned int count = 0;
6885     ToRelease<ISOSStackRefEnum> pEnum;
6886     if (FAILED(g_sos->GetStackReferences(osID, &pEnum)) || FAILED(pEnum->GetCount(&count)))
6887     {
6888         ExtOut("Failed to enumerate GC references.\n");
6889                 return E_FAIL;
6890     }
6891     
6892     *ppRefs = new SOSStackRefData[count];
6893     if (FAILED(pEnum->Next(count, *ppRefs, pRefCnt)))
6894     {
6895         ExtOut("Failed to enumerate GC references.\n");
6896         return E_FAIL;
6897     }
6898     
6899     SOS_Assert(count == *pRefCnt);
6900     
6901     // Enumerate errors found.  Any bad HRESULT recieved while enumerating errors is NOT a fatal error.
6902     // Hence we return S_FALSE if we encounter one.
6903     
6904     if (ppErrors && pErrCount)
6905     {
6906         ToRelease<ISOSStackRefErrorEnum> pErrors;
6907         if (FAILED(pEnum->EnumerateErrors(&pErrors)))
6908         {
6909             ExtOut("Failed to enumerate GC reference errors.\n");
6910             return S_FALSE;
6911         }
6912         
6913         if (FAILED(pErrors->GetCount(&count)))
6914         {
6915             ExtOut("Failed to enumerate GC reference errors.\n");
6916             return S_FALSE;
6917         }
6918         
6919         *ppErrors = new SOSStackRefError[count];
6920         if (FAILED(pErrors->Next(count, *ppErrors, pErrCount)))
6921         {
6922             ExtOut("Failed to enumerate GC reference errors.\n");
6923             *pErrCount = 0;
6924             return S_FALSE;
6925         }
6926                   
6927         SOS_Assert(count == *pErrCount);
6928     }
6929     return S_OK;
6930 }
6931
6932
6933 InternalFrameManager::InternalFrameManager() : m_cInternalFramesActual(0), m_iInternalFrameCur(0) {}
6934
6935 HRESULT InternalFrameManager::Init(ICorDebugThread3 * pThread3)
6936 {
6937     _ASSERTE(pThread3 != NULL);
6938
6939     return pThread3->GetActiveInternalFrames(
6940         _countof(m_rgpInternalFrame2),
6941         &m_cInternalFramesActual,
6942         &(m_rgpInternalFrame2[0]));
6943 }
6944
6945 HRESULT InternalFrameManager::PrintPrecedingInternalFrames(ICorDebugFrame * pFrame)
6946 {
6947     HRESULT Status;
6948
6949     for (; m_iInternalFrameCur < m_cInternalFramesActual; m_iInternalFrameCur++)
6950     {
6951         BOOL bIsCloser = FALSE;
6952         IfFailRet(m_rgpInternalFrame2[m_iInternalFrameCur]->IsCloserToLeaf(pFrame, &bIsCloser));
6953
6954         if (!bIsCloser)
6955         {
6956             // Current internal frame is now past pFrame, so we're done
6957             return S_OK;
6958         }
6959
6960         IfFailRet(PrintCurrentInternalFrame());
6961     }
6962
6963     // Exhausted list of internal frames.  Done!
6964     return S_OK;
6965 }
6966
6967 HRESULT InternalFrameManager::PrintCurrentInternalFrame()
6968 {
6969     _ASSERTE(m_iInternalFrameCur < m_cInternalFramesActual);
6970
6971     HRESULT Status;
6972
6973     CORDB_ADDRESS address;
6974     IfFailRet(m_rgpInternalFrame2[m_iInternalFrameCur]->GetAddress(&address));
6975
6976     ToRelease<ICorDebugInternalFrame> pInternalFrame;
6977     IfFailRet(m_rgpInternalFrame2[m_iInternalFrameCur]->QueryInterface(IID_ICorDebugInternalFrame, (LPVOID *) &pInternalFrame));
6978
6979     CorDebugInternalFrameType type;
6980     IfFailRet(pInternalFrame->GetFrameType(&type));
6981
6982     LPCSTR szFrameType = NULL;
6983     switch(type)
6984     {
6985     default:
6986         szFrameType = "Unknown internal frame.";
6987         break;
6988
6989     case STUBFRAME_M2U:
6990         szFrameType = "Managed to Unmanaged transition";
6991         break;
6992
6993     case STUBFRAME_U2M:
6994         szFrameType = "Unmanaged to Managed transition";
6995         break;
6996
6997     case STUBFRAME_APPDOMAIN_TRANSITION:
6998         szFrameType = "AppDomain transition";
6999         break;
7000
7001     case STUBFRAME_LIGHTWEIGHT_FUNCTION:
7002         szFrameType = "Lightweight function";
7003         break;
7004
7005     case STUBFRAME_FUNC_EVAL:
7006         szFrameType = "Function evaluation";
7007         break;
7008
7009     case STUBFRAME_INTERNALCALL:
7010         szFrameType = "Internal call";
7011         break;
7012
7013     case STUBFRAME_CLASS_INIT:
7014         szFrameType = "Class initialization";
7015         break;
7016
7017     case STUBFRAME_EXCEPTION:
7018         szFrameType = "Exception";
7019         break;
7020
7021     case STUBFRAME_SECURITY:
7022         szFrameType = "Security";
7023         break;
7024
7025     case STUBFRAME_JIT_COMPILATION:
7026         szFrameType = "JIT Compilation";
7027         break;
7028     }
7029
7030     DMLOut("%p %s ", SOS_PTR(address), SOS_PTR(0));
7031     ExtOut("[%s: %p]\n", szFrameType, SOS_PTR(address));
7032
7033     return S_OK;
7034 }