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#ifndef __util_h__
11#define __util_h__
12
13#define LIMITED_METHOD_CONTRACT
14
15// So we can use the PAL_TRY_NAKED family of macros without dependencies on utilcode.
16inline void RestoreSOToleranceState() {}
17
18#include <cor.h>
19#include <corsym.h>
20#include <clrdata.h>
21#include <palclr.h>
22#include <metahost.h>
23#include <new>
24
25#if !defined(FEATURE_PAL)
26#include <dia2.h>
27#endif
28
29#ifdef STRIKE
30#if defined(_MSC_VER)
31#pragma warning(disable:4200)
32#pragma warning(default:4200)
33#endif
34#include "data.h"
35#endif //STRIKE
36
37#include "cordebug.h"
38#include "static_assert.h"
39
40typedef LPCSTR LPCUTF8;
41typedef LPSTR LPUTF8;
42
43DECLARE_HANDLE(OBJECTHANDLE);
44
45struct IMDInternalImport;
46
47#if defined(_TARGET_WIN64_)
48#define WIN64_8SPACES ""
49#define WIN86_8SPACES " "
50#define POINTERSIZE "16"
51#define POINTERSIZE_HEX 16
52#define POINTERSIZE_BYTES 8
53#define POINTERSIZE_TYPE "I64"
54#else
55#define WIN64_8SPACES " "
56#define WIN86_8SPACES ""
57#define POINTERSIZE "8"
58#define POINTERSIZE_HEX 8
59#define POINTERSIZE_BYTES 4
60#define POINTERSIZE_TYPE "I32"
61#endif
62
63#ifndef TARGET_POINTER_SIZE
64#define TARGET_POINTER_SIZE POINTERSIZE_BYTES
65#endif // TARGET_POINTER_SIZE
66
67#if defined(_MSC_VER)
68#pragma warning(disable:4510 4512 4610)
69#endif
70
71#ifndef _ASSERTE
72#ifdef _DEBUG
73#define _ASSERTE(expr) \
74 do { if (!(expr) ) { ExtErr("_ASSERTE fired:\n\t%s\n", #expr); if (IsDebuggerPresent()) DebugBreak(); } } while (0)
75#else
76#define _ASSERTE(x)
77#endif
78#endif // ASSERTE
79
80#ifdef _DEBUG
81#define ASSERT_CHECK(expr, msg, reason) \
82 do { if (!(expr) ) { ExtOut(reason); ExtOut(msg); ExtOut(#expr); DebugBreak(); } } while (0)
83#endif
84
85// The native symbol reader dll name
86#if defined(_AMD64_)
87#define NATIVE_SYMBOL_READER_DLL W("Microsoft.DiaSymReader.Native.amd64.dll")
88#elif defined(_X86_)
89#define NATIVE_SYMBOL_READER_DLL W("Microsoft.DiaSymReader.Native.x86.dll")
90#elif defined(_ARM_)
91#define NATIVE_SYMBOL_READER_DLL W("Microsoft.DiaSymReader.Native.arm.dll")
92#elif defined(_ARM64_)
93// Use diasymreader until the package has an arm64 version - issue #7360
94//#define NATIVE_SYMBOL_READER_DLL W("Microsoft.DiaSymReader.Native.arm64.dll")
95#define NATIVE_SYMBOL_READER_DLL W("diasymreader.dll")
96#endif
97
98// PREFIX macros - Begin
99
100// SOS does not have support for Contracts. Therefore we needed to duplicate
101// some of the PREFIX infrastructure from inc\check.h in here.
102
103// Issue - PREFast_:510 v4.51 does not support __assume(0)
104#if (defined(_MSC_VER) && !defined(_PREFAST_)) || defined(_PREFIX_)
105#if defined(_AMD64_)
106// Empty methods that consist of UNREACHABLE() result in a zero-sized declspec(noreturn) method
107// which causes the pdb file to make the next method declspec(noreturn) as well, thus breaking BBT
108// Remove when we get a VC compiler that fixes VSW 449170
109# define __UNREACHABLE() DebugBreak(); __assume(0);
110#else
111# define __UNREACHABLE() __assume(0)
112#endif
113#else
114#define __UNREACHABLE() do { } while(true)
115#endif
116
117
118#if defined(_PREFAST_) || defined(_PREFIX_)
119#define COMPILER_ASSUME_MSG(_condition, _message) if (!(_condition)) __UNREACHABLE();
120#else
121
122#if defined(DACCESS_COMPILE)
123#define COMPILER_ASSUME_MSG(_condition, _message) do { } while (0)
124#else
125
126#if defined(_DEBUG)
127#define COMPILER_ASSUME_MSG(_condition, _message) \
128 ASSERT_CHECK(_condition, _message, "Compiler optimization assumption invalid")
129#else
130#define COMPILER_ASSUME_MSG(_condition, _message) __assume(_condition)
131#endif // _DEBUG
132
133#endif // DACCESS_COMPILE
134
135#endif // _PREFAST_ || _PREFIX_
136
137#define PREFIX_ASSUME(_condition) \
138 COMPILER_ASSUME_MSG(_condition, "")
139
140// PREFIX macros - End
141
142class MethodTable;
143
144#define MD_NOT_YET_LOADED ((DWORD_PTR)-1)
145/*
146 * HANDLES
147 *
148 * The default type of handle is a strong handle.
149 *
150 */
151#define HNDTYPE_DEFAULT HNDTYPE_STRONG
152#define HNDTYPE_WEAK_DEFAULT HNDTYPE_WEAK_LONG
153#define HNDTYPE_WEAK_SHORT (0)
154#define HNDTYPE_WEAK_LONG (1)
155#define HNDTYPE_STRONG (2)
156#define HNDTYPE_PINNED (3)
157#define HNDTYPE_VARIABLE (4)
158#define HNDTYPE_REFCOUNTED (5)
159#define HNDTYPE_DEPENDENT (6)
160#define HNDTYPE_ASYNCPINNED (7)
161#define HNDTYPE_SIZEDREF (8)
162#define HNDTYPE_WEAK_WINRT (9)
163
164// Anything above this we consider abnormal and stop processing heap information
165const int nMaxHeapSegmentCount = 1000;
166
167class BaseObject
168{
169 MethodTable *m_pMethTab;
170};
171
172
173const BYTE gElementTypeInfo[] = {
174#define TYPEINFO(e,ns,c,s,g,ia,ip,if,im,gv) s,
175#include "cortypeinfo.h"
176#undef TYPEINFO
177};
178
179typedef struct tagLockEntry
180{
181 tagLockEntry *pNext; // next entry
182 tagLockEntry *pPrev; // prev entry
183 DWORD dwULockID;
184 DWORD dwLLockID; // owning lock
185 WORD wReaderLevel; // reader nesting level
186} LockEntry;
187
188#define MAX_CLASSNAME_LENGTH 1024
189
190enum EEFLAVOR {UNKNOWNEE, MSCOREE, MSCORWKS, MSCOREND};
191
192#include "sospriv.h"
193extern IXCLRDataProcess *g_clrData;
194extern ISOSDacInterface *g_sos;
195
196#include "dacprivate.h"
197
198interface ICorDebugProcess;
199extern ICorDebugProcess * g_pCorDebugProcess;
200
201// This class is templated for easy modification. We may need to update the CachedString
202// or related classes to use WCHAR instead of char in the future.
203template <class T, int count, int size>
204class StaticData
205{
206public:
207 StaticData()
208 {
209 for (int i = 0; i < count; ++i)
210 InUse[i] = false;
211 }
212
213 // Whether the individual data pointers in the cache are in use.
214 bool InUse[count];
215
216 // The actual data itself.
217 T Data[count][size];
218
219 // The number of arrays in the cache.
220 static const int Count;
221
222 // The size of each individual array.
223 static const int Size;
224};
225
226class CachedString
227{
228public:
229 CachedString();
230 CachedString(const CachedString &str);
231 ~CachedString();
232
233 const CachedString &operator=(const CachedString &str);
234
235 // Returns the capacity of this string.
236 size_t GetStrLen() const
237 {
238 return mSize;
239 }
240
241 // Returns a mutable character pointer. Be sure not to write past the
242 // length of this string.
243 inline operator char *()
244 {
245 return mPtr;
246 }
247
248 // Returns a const char representation of this string.
249 inline operator const char *() const
250 {
251 return GetPtr();
252 }
253
254 // To ensure no AV's, any time a constant pointer is requested, we will
255 // return an empty string "" if we hit an OOM. This will only happen
256 // if we hit an OOM and do not check for it before using the string.
257 // If you request a non-const char pointer out of this class, it may be
258 // null (see operator char *).
259 inline const char *GetPtr() const
260 {
261 if (!mPtr || IsOOM())
262 return "";
263
264 return mPtr;
265 }
266
267 // Returns true if we ran out of memory trying to allocate the string
268 // or the refcount.
269 bool IsOOM() const
270 {
271 return mIndex == -2;
272 }
273
274 // allocate a string of the specified size. this will Clear() any
275 // previously allocated string. call IsOOM() to check for failure.
276 void Allocate(int size);
277
278private:
279 // Copies rhs into this string.
280 void Copy(const CachedString &rhs);
281
282 // Clears this string, releasing any underlying memory.
283 void Clear();
284
285 // Creates a new string.
286 void Create();
287
288 // Sets an out of memory state.
289 void SetOOM();
290
291private:
292 char *mPtr;
293
294 // The reference count. This may be null if there is only one copy
295 // of this string.
296 mutable unsigned int *mRefCount;
297
298 // mIndex contains the index of the cached pointer we are using, or:
299 // ~0 - poison value we initialize it to for debugging purposes
300 // -1 - mPtr points to a pointer we have new'ed
301 // -2 - We hit an oom trying to allocate either mCount or mPtr
302 int mIndex;
303
304 // contains the size of current string
305 int mSize;
306
307private:
308 static StaticData<char, 4, 1024> cache;
309};
310
311// Things in this namespace should not be directly accessed/called outside of
312// the output-related functions.
313namespace Output
314{
315 extern unsigned int g_bSuppressOutput;
316 extern unsigned int g_Indent;
317 extern unsigned int g_DMLEnable;
318 extern bool g_bDbgOutput;
319 extern bool g_bDMLExposed;
320
321 inline bool IsOutputSuppressed()
322 { return g_bSuppressOutput > 0; }
323
324 inline void ResetIndent()
325 { g_Indent = 0; }
326
327 inline void SetDebugOutputEnabled(bool enabled)
328 { g_bDbgOutput = enabled; }
329
330 inline bool IsDebugOutputEnabled()
331 { return g_bDbgOutput; }
332
333 inline void SetDMLExposed(bool exposed)
334 { g_bDMLExposed = exposed; }
335
336 inline bool IsDMLExposed()
337 { return g_bDMLExposed; }
338
339 enum FormatType
340 {
341 DML_None,
342 DML_MethodTable,
343 DML_MethodDesc,
344 DML_EEClass,
345 DML_Module,
346 DML_IP,
347 DML_Object,
348 DML_Domain,
349 DML_Assembly,
350 DML_ThreadID,
351 DML_ValueClass,
352 DML_DumpHeapMT,
353 DML_ListNearObj,
354 DML_ThreadState,
355 DML_PrintException,
356 DML_RCWrapper,
357 DML_CCWrapper,
358 DML_ManagedVar,
359 DML_Async,
360 };
361
362 /**********************************************************************\
363 * This function builds a DML string for a ValueClass. If DML is *
364 * enabled, this function returns a DML string based on the format *
365 * type. Otherwise this returns a string containing only the hex value *
366 * of addr. *
367 * *
368 * Params: *
369 * mt - the method table of the ValueClass *
370 * addr - the address of the ValueClass *
371 * type - the format type to use to output this object *
372 * fill - whether or not to pad the hex value with zeros *
373 * *
374 \**********************************************************************/
375 CachedString BuildVCValue(CLRDATA_ADDRESS mt, CLRDATA_ADDRESS addr, FormatType type, bool fill = true);
376
377
378 /**********************************************************************\
379 * This function builds a DML string for an object. If DML is enabled, *
380 * this function returns a DML string based on the format type. *
381 * Otherwise this returns a string containing only the hex value of *
382 * addr. *
383 * *
384 * Params: *
385 * addr - the address of the object *
386 * type - the format type to use to output this object *
387 * fill - whether or not to pad the hex value with zeros *
388 * *
389 \**********************************************************************/
390 CachedString BuildHexValue(CLRDATA_ADDRESS addr, FormatType type, bool fill = true);
391
392 /**********************************************************************\
393 * This function builds a DML string for an managed variable name. *
394 * If DML is enabled, this function returns a DML string that will *
395 * enable the expansion of that managed variable using the !ClrStack *
396 * command to display the variable's fields, otherwise it will just *
397 * return the variable's name as a string.
398 * *
399 * Params: *
400 * expansionName - the current variable expansion string *
401 * frame - the frame that contains the variable of interest *
402 * simpleName - simple name of the managed variable *
403 * *
404 \**********************************************************************/
405 CachedString BuildManagedVarValue(__in_z LPCWSTR expansionName, ULONG frame, __in_z LPCWSTR simpleName, FormatType type);
406 CachedString BuildManagedVarValue(__in_z LPCWSTR expansionName, ULONG frame, int indexInArray, FormatType type); //used for array indices (simpleName = "[<indexInArray>]")
407}
408
409class NoOutputHolder
410{
411public:
412 NoOutputHolder(BOOL bSuppress = TRUE);
413 ~NoOutputHolder();
414
415private:
416 BOOL mSuppress;
417};
418
419class EnableDMLHolder
420{
421public:
422 EnableDMLHolder(BOOL enable);
423 ~EnableDMLHolder();
424
425private:
426 BOOL mEnable;
427};
428
429size_t CountHexCharacters(CLRDATA_ADDRESS val);
430
431// Normal output.
432void DMLOut(PCSTR format, ...); /* Prints out DML strings. */
433void IfDMLOut(PCSTR format, ...); /* Prints given DML string ONLY if DML is enabled; prints nothing otherwise. */
434void ExtOut(PCSTR Format, ...); /* Prints out to ExtOut (no DML). */
435void ExtWarn(PCSTR Format, ...); /* Prints out to ExtWarn (no DML). */
436void ExtErr(PCSTR Format, ...); /* Prints out to ExtErr (no DML). */
437void ExtDbgOut(PCSTR Format, ...); /* Prints out to ExtOut in a checked build (no DML). */
438void WhitespaceOut(int count); /* Prints out "count" number of spaces in the output. */
439
440// Change indent for ExtOut
441inline void IncrementIndent() { Output::g_Indent++; }
442inline void DecrementIndent() { if (Output::g_Indent > 0) Output::g_Indent--; }
443inline void ExtOutIndent() { WhitespaceOut(Output::g_Indent << 2); }
444
445// DML Generation Methods
446#define DMLListNearObj(addr) Output::BuildHexValue(addr, Output::DML_ListNearObj).GetPtr()
447#define DMLDumpHeapMT(addr) Output::BuildHexValue(addr, Output::DML_DumpHeapMT).GetPtr()
448#define DMLMethodTable(addr) Output::BuildHexValue(addr, Output::DML_MethodTable).GetPtr()
449#define DMLMethodDesc(addr) Output::BuildHexValue(addr, Output::DML_MethodDesc).GetPtr()
450#define DMLClass(addr) Output::BuildHexValue(addr, Output::DML_EEClass).GetPtr()
451#define DMLModule(addr) Output::BuildHexValue(addr, Output::DML_Module).GetPtr()
452#define DMLIP(ip) Output::BuildHexValue(ip, Output::DML_IP).GetPtr()
453#define DMLObject(addr) Output::BuildHexValue(addr, Output::DML_Object).GetPtr()
454#define DMLDomain(addr) Output::BuildHexValue(addr, Output::DML_Domain).GetPtr()
455#define DMLAssembly(addr) Output::BuildHexValue(addr, Output::DML_Assembly).GetPtr()
456#define DMLThreadID(id) Output::BuildHexValue(id, Output::DML_ThreadID, false).GetPtr()
457#define DMLValueClass(mt, addr) Output::BuildVCValue(mt, addr, Output::DML_ValueClass).GetPtr()
458#define DMLRCWrapper(addr) Output::BuildHexValue(addr, Output::DML_RCWrapper).GetPtr()
459#define DMLCCWrapper(addr) Output::BuildHexValue(addr, Output::DML_CCWrapper).GetPtr()
460#define DMLManagedVar(expansionName,frame,simpleName) Output::BuildManagedVarValue(expansionName, frame, simpleName, Output::DML_ManagedVar).GetPtr()
461#define DMLAsync(addr) Output::BuildHexValue(addr, Output::DML_Async).GetPtr()
462
463bool IsDMLEnabled();
464
465
466#ifndef SOS_Assert
467#define SOS_Assert(x)
468#endif
469
470void ConvertToLower(__out_ecount(len) char *buffer, size_t len);
471
472extern const char * const DMLFormats[];
473int GetHex(CLRDATA_ADDRESS addr, __out_ecount(len) char *out, size_t len, bool fill);
474
475// A simple string class for mutable strings. We cannot use STL, so this is a stand in replacement
476// for std::string (though it doesn't use the same interface).
477template <class T, size_t (__cdecl *LEN)(const T *), errno_t (__cdecl *COPY)(T *, size_t, const T * _Src)>
478class BaseString
479{
480public:
481 BaseString()
482 : mStr(0), mSize(0), mLength(0)
483 {
484 const size_t size = 64;
485
486 mStr = new T[size];
487 mSize = size;
488 mStr[0] = 0;
489 }
490
491 BaseString(const T *str)
492 : mStr(0), mSize(0), mLength(0)
493 {
494 CopyFrom(str, LEN(str));
495 }
496
497 BaseString(const BaseString<T, LEN, COPY> &rhs)
498 : mStr(0), mSize(0), mLength(0)
499 {
500 *this = rhs;
501 }
502
503 ~BaseString()
504 {
505 Clear();
506 }
507
508 const BaseString<T, LEN, COPY> &operator=(const BaseString<T, LEN, COPY> &rhs)
509 {
510 Clear();
511 CopyFrom(rhs.mStr, rhs.mLength);
512 return *this;
513 }
514
515 const BaseString<T, LEN, COPY> &operator=(const T *str)
516 {
517 Clear();
518 CopyFrom(str, LEN(str));
519 return *this;
520 }
521
522 const BaseString<T, LEN, COPY> &operator +=(const T *str)
523 {
524 size_t len = LEN(str);
525 CopyFrom(str, len);
526 return *this;
527 }
528
529 const BaseString<T, LEN, COPY> &operator +=(const BaseString<T, LEN, COPY> &str)
530 {
531 CopyFrom(str.mStr, str.mLength);
532 return *this;
533 }
534
535 BaseString<T, LEN, COPY> operator+(const T *str) const
536 {
537 return BaseString<T, LEN, COPY>(mStr, mLength, str, LEN(str));
538 }
539
540 BaseString<T, LEN, COPY> operator+(const BaseString<T, LEN, COPY> &str) const
541 {
542 return BaseString<T, LEN, COPY>(mStr, mLength, str.mStr, str.mLength);
543 }
544
545 operator const T *() const
546 {
547 return mStr;
548 }
549
550 const T *c_str() const
551 {
552 return mStr;
553 }
554
555 size_t GetLength() const
556 {
557 return mLength;
558 }
559
560private:
561 BaseString(const T * str1, size_t len1, const T * str2, size_t len2)
562 : mStr(0), mSize(0), mLength(0)
563 {
564 const size_t size = len1 + len2 + 1 + ((len1 + len2) >> 1);
565 mStr = new T[size];
566 mSize = size;
567
568 CopyFrom(str1, len1);
569 CopyFrom(str2, len2);
570 }
571
572 void Clear()
573 {
574 mLength = 0;
575 mSize = 0;
576 if (mStr)
577 {
578 delete [] mStr;
579 mStr = 0;
580 }
581 }
582
583 void CopyFrom(const T *str, size_t len)
584 {
585 if (mLength + len + 1 >= mSize)
586 Resize(mLength + len + 1);
587
588 COPY(mStr+mLength, mSize-mLength, str);
589 mLength += len;
590 }
591
592 void Resize(size_t size)
593 {
594 /* We always resize at least one half bigger than we need. When CopyFrom requests a resize
595 * it asks for the exact size that's needed to concatenate strings. However in practice
596 * it's common to add multiple strings together in a row, e.g.:
597 * String foo = "One " + "Two " + "Three " + "Four " + "\n";
598 * Ensuring the size of the string is bigger than we need, and that the minimum size is 64,
599 * we will cut down on a lot of needless resizes at the cost of a few bytes wasted in some
600 * cases.
601 */
602 size += size >> 1;
603 if (size < 64)
604 size = 64;
605
606 T *newStr = new T[size];
607
608 if (mStr)
609 {
610 COPY(newStr, size, mStr);
611 delete [] mStr;
612 }
613 else
614 {
615 newStr[0] = 0;
616 }
617
618 mStr = newStr;
619 mSize = size;
620 }
621private:
622 T *mStr;
623 size_t mSize, mLength;
624};
625
626typedef BaseString<char, strlen, strcpy_s> String;
627typedef BaseString<WCHAR, _wcslen, wcscpy_s> WString;
628
629
630template<class T>
631void Flatten(__out_ecount(len) T *data, unsigned int len)
632{
633 for (unsigned int i = 0; i < len; ++i)
634 if (data[i] < 32 || (data[i] > 126 && data[i] <= 255))
635 data[i] = '.';
636 data[len] = 0;
637}
638
639void Flatten(__out_ecount(len) char *data, unsigned int len);
640
641/* Formats for the Format class. We support the following formats:
642 * Pointer - Same as %p.
643 * Hex - Same as %x (same as %p, but does not output preceding zeros.
644 * PrefixHex - Same as %x, but prepends 0x.
645 * Decimal - Same as %d.
646 * Strings and wide strings don't use this.
647 */
648class Formats
649{
650public:
651 enum Format
652 {
653 Default,
654 Pointer,
655 Hex,
656 PrefixHex,
657 Decimal,
658 };
659};
660
661enum Alignment
662{
663 AlignLeft,
664 AlignRight
665};
666
667namespace Output
668{
669 /* Defines how a value will be printed. This class understands how to format
670 * and print values according to the format and DML settings provided.
671 * The raw templated class handles the pointer/integer case. Support for
672 * character arrays and wide character arrays are handled by template
673 * specializations.
674 *
675 * Note that this class is not used directly. Instead use the typedefs and
676 * macros which define the type of data you are outputing (for example ObjectPtr,
677 * MethodTablePtr, etc).
678 */
679 template <class T>
680 class Format
681 {
682 public:
683 Format(T value)
684 : mValue(value), mFormat(Formats::Default), mDml(Output::DML_None)
685 {
686 }
687
688 Format(T value, Formats::Format format, Output::FormatType dmlType)
689 : mValue(value), mFormat(format), mDml(dmlType)
690 {
691 }
692
693 Format(const Format<T> &rhs)
694 : mValue(rhs.mValue), mFormat(rhs.mFormat), mDml(rhs.mDml)
695 {
696 }
697
698 /* Prints out the value according to the Format and DML settings provided.
699 */
700 void Output() const
701 {
702 if (IsDMLEnabled() && mDml != Output::DML_None)
703 {
704 const int len = GetDMLWidth(mDml);
705 char *buffer = (char*)alloca(len);
706
707 BuildDML(buffer, len, (CLRDATA_ADDRESS)mValue, mFormat, mDml);
708 DMLOut(buffer);
709 }
710 else
711 {
712 if (mFormat == Formats::Default || mFormat == Formats::Pointer)
713 {
714 ExtOut("%p", SOS_PTR(mValue));
715 }
716 else
717 {
718 const char *format = NULL;
719 if (mFormat == Formats::PrefixHex)
720 {
721 format = "0x%x";
722 }
723 else if (mFormat == Formats::Hex)
724 {
725 format = "%x";
726 }
727 else if (mFormat == Formats::Decimal)
728 {
729 format = "%d";
730 }
731
732 ExtOut(format, (__int32)mValue);
733 }
734
735 }
736 }
737
738 /* Prints out the value based on a specified width and alignment.
739 * Params:
740 * align - Whether the output should be left or right justified.
741 * width - The output width to fill.
742 * Note:
743 * This function guarantees that exactly width will be printed out (so if width is 24,
744 * exactly 24 characters will be printed), even if the output wouldn't normally fit
745 * in the space provided. This function makes no guarantees as to what part of the
746 * data will be printed in the case that width isn't wide enough.
747 */
748 void OutputColumn(Alignment align, int width) const
749 {
750 bool leftAlign = align == AlignLeft;
751 if (IsDMLEnabled() && mDml != Output::DML_None)
752 {
753 const int len = GetDMLColWidth(mDml, width);
754 char *buffer = (char*)alloca(len);
755
756 BuildDMLCol(buffer, len, (CLRDATA_ADDRESS)mValue, mFormat, mDml, leftAlign, width);
757 DMLOut(buffer);
758 }
759 else
760 {
761 int precision = GetPrecision();
762 if (mFormat == Formats::Default || mFormat == Formats::Pointer)
763 {
764 if (precision > width)
765 precision = width;
766
767 ExtOut(leftAlign ? "%-*.*p" : "%*.*p", width, precision, SOS_PTR(mValue));
768 }
769 else
770 {
771 const char *format = NULL;
772 if (mFormat == Formats::PrefixHex)
773 {
774 format = leftAlign ? "0x%-*.*x" : "0x%*.*x";
775 width -= 2;
776 }
777 else if (mFormat == Formats::Hex)
778 {
779 format = leftAlign ? "%-*.*x" : "%*.*x";
780 }
781 else if (mFormat == Formats::Decimal)
782 {
783 format = leftAlign ? "%-*.*d" : "%*.*d";
784 }
785
786 if (precision > width)
787 precision = width;
788
789 ExtOut(format, width, precision, (__int32)mValue);
790 }
791 }
792 }
793
794 /* Converts this object into a Wide char string. This allows you to write the following code:
795 * WString foo = L"bar " + ObjectPtr(obj);
796 * Where ObjectPtr is a subclass/typedef of this Format class.
797 */
798 operator WString() const
799 {
800 String str = *this;
801 const char *cstr = (const char *)str;
802
803 int len = MultiByteToWideChar(CP_ACP, 0, cstr, -1, NULL, 0);
804 WCHAR *buffer = (WCHAR *)alloca(len*sizeof(WCHAR));
805
806 MultiByteToWideChar(CP_ACP, 0, cstr, -1, buffer, len);
807
808 return WString(buffer);
809 }
810
811 /* Converts this object into a String object. This allows you to write the following code:
812 * String foo = "bar " + ObjectPtr(obj);
813 * Where ObjectPtr is a subclass/typedef of this Format class.
814 */
815 operator String() const
816 {
817 if (IsDMLEnabled() && mDml != Output::DML_None)
818 {
819 const int len = GetDMLColWidth(mDml, 0);
820 char *buffer = (char*)alloca(len);
821
822 BuildDMLCol(buffer, len, (CLRDATA_ADDRESS)mValue, mFormat, mDml, false, 0);
823 return buffer;
824 }
825 else
826 {
827 char buffer[64];
828 if (mFormat == Formats::Default || mFormat == Formats::Pointer)
829 {
830 sprintf_s(buffer, _countof(buffer), "%p", (int *)(SIZE_T)mValue);
831 ConvertToLower(buffer, _countof(buffer));
832 }
833 else
834 {
835 const char *format = NULL;
836 if (mFormat == Formats::PrefixHex)
837 format = "0x%x";
838 else if (mFormat == Formats::Hex)
839 format = "%x";
840 else if (mFormat == Formats::Decimal)
841 format = "%d";
842
843 sprintf_s(buffer, _countof(buffer), format, (__int32)mValue);
844 ConvertToLower(buffer, _countof(buffer));
845 }
846
847 return buffer;
848 }
849 }
850
851 private:
852 int GetPrecision() const
853 {
854 if (mFormat == Formats::Hex || mFormat == Formats::PrefixHex)
855 {
856 ULONGLONG val = mValue;
857 int count = 0;
858 while (val)
859 {
860 val >>= 4;
861 count++;
862 }
863
864 if (count == 0)
865 count = 1;
866
867 return count;
868 }
869
870 else if (mFormat == Formats::Decimal)
871 {
872 T val = mValue;
873 int count = (val > 0) ? 0 : 1;
874 while (val)
875 {
876 val /= 10;
877 count++;
878 }
879
880 return count;
881 }
882
883 // mFormat == Formats::Pointer
884 return sizeof(int*)*2;
885 }
886
887 static inline void BuildDML(__out_ecount(len) char *result, int len, CLRDATA_ADDRESS value, Formats::Format format, Output::FormatType dmlType)
888 {
889 BuildDMLCol(result, len, value, format, dmlType, true, 0);
890 }
891
892 static int GetDMLWidth(Output::FormatType dmlType)
893 {
894 return GetDMLColWidth(dmlType, 0);
895 }
896
897 static void BuildDMLCol(__out_ecount(len) char *result, int len, CLRDATA_ADDRESS value, Formats::Format format, Output::FormatType dmlType, bool leftAlign, int width)
898 {
899 char hex[64];
900 int count = GetHex(value, hex, _countof(hex), format != Formats::Hex);
901 int i = 0;
902
903 if (!leftAlign)
904 {
905 for (; i < width - count; ++i)
906 result[i] = ' ';
907
908 result[i] = 0;
909 }
910
911 int written = sprintf_s(result+i, len - i, DMLFormats[dmlType], hex, hex);
912
913 SOS_Assert(written != -1);
914 if (written != -1)
915 {
916 for (i = i + written; i < width; ++i)
917 result[i] = ' ';
918
919 result[i] = 0;
920 }
921 }
922
923 static int GetDMLColWidth(Output::FormatType dmlType, int width)
924 {
925 return 1 + 4*sizeof(int*) + (int)strlen(DMLFormats[dmlType]) + width;
926 }
927
928 private:
929 T mValue;
930 Formats::Format mFormat;
931 Output::FormatType mDml;
932 };
933
934 /* Format class used for strings.
935 */
936 template <>
937 class Format<const char *>
938 {
939 public:
940 Format(const char *value)
941 : mValue(value)
942 {
943 }
944
945 Format(const Format<const char *> &rhs)
946 : mValue(rhs.mValue)
947 {
948 }
949
950 void Output() const
951 {
952 if (IsDMLEnabled())
953 DMLOut("%s", mValue);
954 else
955 ExtOut("%s", mValue);
956 }
957
958 void OutputColumn(Alignment align, int width) const
959 {
960 int precision = (int)strlen(mValue);
961
962 if (precision > width)
963 precision = width;
964
965 const char *format = align == AlignLeft ? "%-*.*s" : "%*.*s";
966
967 if (IsDMLEnabled())
968 DMLOut(format, width, precision, mValue);
969 else
970 ExtOut(format, width, precision, mValue);
971 }
972
973 private:
974 const char *mValue;
975 };
976
977 /* Format class for wide char strings.
978 */
979 template <>
980 class Format<const WCHAR *>
981 {
982 public:
983 Format(const WCHAR *value)
984 : mValue(value)
985 {
986 }
987
988 Format(const Format<const WCHAR *> &rhs)
989 : mValue(rhs.mValue)
990 {
991 }
992
993 void Output() const
994 {
995 if (IsDMLEnabled())
996 DMLOut("%S", mValue);
997 else
998 ExtOut("%S", mValue);
999 }
1000
1001 void OutputColumn(Alignment align, int width) const
1002 {
1003 int precision = (int)_wcslen(mValue);
1004 if (precision > width)
1005 precision = width;
1006
1007 const char *format = align == AlignLeft ? "%-*.*S" : "%*.*S";
1008
1009 if (IsDMLEnabled())
1010 DMLOut(format, width, precision, mValue);
1011 else
1012 ExtOut(format, width, precision, mValue);
1013 }
1014
1015 private:
1016 const WCHAR *mValue;
1017 };
1018
1019
1020 template <class T>
1021 void InternalPrint(const T &t)
1022 {
1023 Format<T>(t).Output();
1024 }
1025
1026 template <class T>
1027 void InternalPrint(const Format<T> &t)
1028 {
1029 t.Output();
1030 }
1031
1032 inline void InternalPrint(const char t[])
1033 {
1034 Format<const char *>(t).Output();
1035 }
1036}
1037
1038#define DefineFormatClass(name, format, dml) \
1039 template <class T> \
1040 Output::Format<T> name(T value) \
1041 { return Output::Format<T>(value, format, dml); }
1042
1043DefineFormatClass(EEClassPtr, Formats::Pointer, Output::DML_EEClass);
1044DefineFormatClass(ObjectPtr, Formats::Pointer, Output::DML_Object);
1045DefineFormatClass(ExceptionPtr, Formats::Pointer, Output::DML_PrintException);
1046DefineFormatClass(ModulePtr, Formats::Pointer, Output::DML_Module);
1047DefineFormatClass(MethodDescPtr, Formats::Pointer, Output::DML_MethodDesc);
1048DefineFormatClass(AppDomainPtr, Formats::Pointer, Output::DML_Domain);
1049DefineFormatClass(ThreadState, Formats::Hex, Output::DML_ThreadState);
1050DefineFormatClass(ThreadID, Formats::Hex, Output::DML_ThreadID);
1051DefineFormatClass(RCWrapper, Formats::Pointer, Output::DML_RCWrapper);
1052DefineFormatClass(CCWrapper, Formats::Pointer, Output::DML_CCWrapper);
1053DefineFormatClass(InstructionPtr, Formats::Pointer, Output::DML_IP);
1054DefineFormatClass(NativePtr, Formats::Pointer, Output::DML_None);
1055
1056DefineFormatClass(Decimal, Formats::Decimal, Output::DML_None);
1057DefineFormatClass(Pointer, Formats::Pointer, Output::DML_None);
1058DefineFormatClass(PrefixHex, Formats::PrefixHex, Output::DML_None);
1059DefineFormatClass(Hex, Formats::Hex, Output::DML_None);
1060
1061#undef DefineFormatClass
1062
1063template <class T0>
1064void Print(const T0 &val0)
1065{
1066 Output::InternalPrint(val0);
1067}
1068
1069template <class T0, class T1>
1070void Print(const T0 &val0, const T1 &val1)
1071{
1072 Output::InternalPrint(val0);
1073 Output::InternalPrint(val1);
1074}
1075
1076template <class T0>
1077void PrintLn(const T0 &val0)
1078{
1079 Output::InternalPrint(val0);
1080 ExtOut("\n");
1081}
1082
1083template <class T0, class T1>
1084void PrintLn(const T0 &val0, const T1 &val1)
1085{
1086 Output::InternalPrint(val0);
1087 Output::InternalPrint(val1);
1088 ExtOut("\n");
1089}
1090
1091template <class T0, class T1, class T2>
1092void PrintLn(const T0 &val0, const T1 &val1, const T2 &val2)
1093{
1094 Output::InternalPrint(val0);
1095 Output::InternalPrint(val1);
1096 Output::InternalPrint(val2);
1097 ExtOut("\n");
1098}
1099
1100
1101/* This class handles the formatting for output which is in a table format. To use this class you define
1102 * how the table is formatted by setting the number of columns in the table, the default column width,
1103 * the default column alignment, the indentation (whitespace) for the table, and the amount of padding
1104 * (whitespace) between each column. Once this has been setup, you output rows at a time or individual
1105 * columns to build the output instead of manually tabbing out space.
1106 * Also note that this class was built to work with the Format class. When outputing data, use the
1107 * predefined output types to specify the format (such as ObjectPtr, MethodDescPtr, Decimal, etc). This
1108 * tells the TableOutput class how to display the data, and where applicable, it automatically generates
1109 * the appropriate DML output. See the DefineFormatClass macro.
1110 */
1111class TableOutput
1112{
1113public:
1114
1115 TableOutput()
1116 : mColumns(0), mDefaultWidth(0), mIndent(0), mPadding(0), mCurrCol(0), mDefaultAlign(AlignLeft),
1117 mWidths(0), mAlignments(0)
1118 {
1119 }
1120 /* Constructor.
1121 * Params:
1122 * numColumns - the number of columns the table has
1123 * defaultColumnWidth - the default width of each column
1124 * alignmentDefault - whether columns are by default left aligned or right aligned
1125 * indent - the amount of whitespace to prefix at the start of the row (in characters)
1126 * padding - the amount of whitespace to place between each column (in characters)
1127 */
1128 TableOutput(int numColumns, int defaultColumnWidth, Alignment alignmentDefault = AlignLeft, int indent = 0, int padding = 1)
1129 : mColumns(numColumns), mDefaultWidth(defaultColumnWidth), mIndent(indent), mPadding(padding), mCurrCol(0), mDefaultAlign(alignmentDefault),
1130 mWidths(0), mAlignments(0)
1131 {
1132 }
1133
1134 ~TableOutput()
1135 {
1136 Clear();
1137 }
1138
1139 /* See the documentation for the constructor.
1140 */
1141 void ReInit(int numColumns, int defaultColumnWidth, Alignment alignmentDefault = AlignLeft, int indent = 0, int padding = 1);
1142
1143 /* Sets the amount of whitespace to prefix at the start of the row (in characters).
1144 */
1145 void SetIndent(int indent)
1146 {
1147 SOS_Assert(indent >= 0);
1148
1149 mIndent = indent;
1150 }
1151
1152 /* Sets the exact widths for the the given columns.
1153 * Params:
1154 * columns - the number of columns you are providing the width for, starting at the first column
1155 * ... - an int32 for each column (given by the number of columns in the first parameter).
1156 * Example:
1157 * If you have 5 columns in the table, you can set their widths like so:
1158 * tableOutput.SetWidths(5, 2, 3, 5, 7, 13);
1159 * Note:
1160 * It's fine to pass a value for "columns" less than the number of columns in the table. This
1161 * is useful when you set the default column width to be correct for most of the table, and need
1162 * to make a minor adjustment to a few.
1163 */
1164 void SetWidths(int columns, ...);
1165
1166 /* Individually sets a column to the given width.
1167 * Params:
1168 * col - the column to set, 0 indexed
1169 * width - the width of the column (note this must be non-negative)
1170 */
1171 void SetColWidth(int col, int width);
1172
1173 /* Individually sets the column alignment.
1174 * Params:
1175 * col - the column to set, 0 indexed
1176 * align - the new alignment (left or right) for the column
1177 */
1178 void SetColAlignment(int col, Alignment align);
1179
1180
1181 /* The WriteRow family of functions allows you to write an entire row of the table at once.
1182 * The common use case for the TableOutput class is to individually output each column after
1183 * calculating what the value should contain. However, this would be tedious if you already
1184 * knew the contents of the entire row which usually happenes when you are printing out the
1185 * header for the table. To use this, simply pass each column as an individual parameter,
1186 * for example:
1187 * tableOutput.WriteRow("First Column", "Second Column", Decimal(3), PrefixHex(4), "Fifth Column");
1188 */
1189 template <class T0, class T1>
1190 void WriteRow(T0 t0, T1 t1)
1191 {
1192 WriteColumn(0, t0);
1193 WriteColumn(1, t1);
1194 }
1195
1196 template <class T0, class T1, class T2>
1197 void WriteRow(T0 t0, T1 t1, T2 t2)
1198 {
1199 WriteColumn(0, t0);
1200 WriteColumn(1, t1);
1201 WriteColumn(2, t2);
1202 }
1203
1204
1205 template <class T0, class T1, class T2, class T3>
1206 void WriteRow(T0 t0, T1 t1, T2 t2, T3 t3)
1207 {
1208 WriteColumn(0, t0);
1209 WriteColumn(1, t1);
1210 WriteColumn(2, t2);
1211 WriteColumn(3, t3);
1212 }
1213
1214
1215 template <class T0, class T1, class T2, class T3, class T4>
1216 void WriteRow(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)
1217 {
1218 WriteColumn(0, t0);
1219 WriteColumn(1, t1);
1220 WriteColumn(2, t2);
1221 WriteColumn(3, t3);
1222 WriteColumn(4, t4);
1223 }
1224
1225 template <class T0, class T1, class T2, class T3, class T4, class T5>
1226 void WriteRow(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
1227 {
1228 WriteColumn(0, t0);
1229 WriteColumn(1, t1);
1230 WriteColumn(2, t2);
1231 WriteColumn(3, t3);
1232 WriteColumn(4, t4);
1233 WriteColumn(5, t5);
1234 }
1235
1236 template <class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9>
1237 void WriteRow(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9)
1238 {
1239 WriteColumn(0, t0);
1240 WriteColumn(1, t1);
1241 WriteColumn(2, t2);
1242 WriteColumn(3, t3);
1243 WriteColumn(4, t4);
1244 WriteColumn(5, t5);
1245 WriteColumn(6, t6);
1246 WriteColumn(7, t7);
1247 WriteColumn(8, t8);
1248 WriteColumn(9, t9);
1249 }
1250
1251 /* The WriteColumn family of functions is used to output individual columns in the table.
1252 * The intent is that the bulk of the table will be generated in a loop like so:
1253 * while (condition) {
1254 * int value1 = CalculateFirstColumn();
1255 * table.WriteColumn(0, value1);
1256 *
1257 * String value2 = CalculateSecondColumn();
1258 * table.WriteColumn(1, value2);
1259 * }
1260 * Params:
1261 * col - the column to write, 0 indexed
1262 * t - the value to write
1263 * Note:
1264 * You should generally use the specific instances of the Format class to generate output.
1265 * For example, use the "Decimal", "Pointer", "ObjectPtr", etc. When passing data to this
1266 * function. This tells the Table class how to display the value.
1267 */
1268 template <class T>
1269 void WriteColumn(int col, const Output::Format<T> &t)
1270 {
1271 SOS_Assert(col >= 0);
1272 SOS_Assert(col < mColumns);
1273
1274 if (col != mCurrCol)
1275 OutputBlankColumns(col);
1276
1277 if (col == 0)
1278 OutputIndent();
1279
1280 bool lastCol = col == mColumns - 1;
1281
1282 if (!lastCol)
1283 t.OutputColumn(GetColAlign(col), GetColumnWidth(col));
1284 else
1285 t.Output();
1286
1287 ExtOut(lastCol ? "\n" : GetWhitespace(mPadding));
1288
1289 if (lastCol)
1290 mCurrCol = 0;
1291 else
1292 mCurrCol = col+1;
1293 }
1294
1295 template <class T>
1296 void WriteColumn(int col, T t)
1297 {
1298 WriteColumn(col, Output::Format<T>(t));
1299 }
1300
1301 void WriteColumn(int col, const String &str)
1302 {
1303 WriteColumn(col, Output::Format<const char *>(str));
1304 }
1305
1306 void WriteColumn(int col, const WString &str)
1307 {
1308 WriteColumn(col, Output::Format<const WCHAR *>(str));
1309 }
1310
1311 void WriteColumn(int col, __in_z WCHAR *str)
1312 {
1313 WriteColumn(col, Output::Format<const WCHAR *>(str));
1314 }
1315
1316 void WriteColumn(int col, const WCHAR *str)
1317 {
1318 WriteColumn(col, Output::Format<const WCHAR *>(str));
1319 }
1320
1321 inline void WriteColumn(int col, __in_z char *str)
1322 {
1323 WriteColumn(col, Output::Format<const char *>(str));
1324 }
1325
1326 /* Writes a column using a printf style format. You cannot use the Format class with
1327 * this function to specify how the output should look, use printf style formatting
1328 * with the appropriate parameters instead.
1329 */
1330 void WriteColumnFormat(int col, const char *fmt, ...)
1331 {
1332 SOS_Assert(strstr(fmt, "%S") == NULL);
1333
1334 char result[128];
1335
1336 va_list list;
1337 va_start(list, fmt);
1338 vsprintf_s(result, _countof(result), fmt, list);
1339 va_end(list);
1340
1341 WriteColumn(col, result);
1342 }
1343
1344 void WriteColumnFormat(int col, const WCHAR *fmt, ...)
1345 {
1346 WCHAR result[128];
1347
1348 va_list list;
1349 va_start(list, fmt);
1350 vswprintf_s(result, _countof(result), fmt, list);
1351 va_end(list);
1352
1353 WriteColumn(col, result);
1354 }
1355
1356 /* This function is a shortcut for writing the next column. (That is, the one after the
1357 * one you just wrote.)
1358 */
1359 template <class T>
1360 void WriteColumn(T t)
1361 {
1362 WriteColumn(mCurrCol, t);
1363 }
1364
1365private:
1366 void Clear();
1367 void AllocWidths();
1368 int GetColumnWidth(int col);
1369 Alignment GetColAlign(int col);
1370 const char *GetWhitespace(int amount);
1371 void OutputBlankColumns(int col);
1372 void OutputIndent();
1373
1374private:
1375 int mColumns, mDefaultWidth, mIndent, mPadding, mCurrCol;
1376 Alignment mDefaultAlign;
1377 int *mWidths;
1378 Alignment *mAlignments;
1379};
1380
1381HRESULT GetMethodDefinitionsFromName(DWORD_PTR ModulePtr, IXCLRDataModule* mod, const char* name, IXCLRDataMethodDefinition **ppMethodDefinitions, int numMethods, int *numMethodsNeeded);
1382HRESULT GetMethodDescsFromName(DWORD_PTR ModulePtr, IXCLRDataModule* mod, const char* name, DWORD_PTR **pOut, int *numMethodDescs);
1383
1384HRESULT FileNameForModule (DacpModuleData *pModule, __out_ecount (MAX_LONGPATH) WCHAR *fileName);
1385HRESULT FileNameForModule (DWORD_PTR pModuleAddr, __out_ecount (MAX_LONGPATH) WCHAR *fileName);
1386void IP2MethodDesc (DWORD_PTR IP, DWORD_PTR &methodDesc, JITTypes &jitType,
1387 DWORD_PTR &gcinfoAddr);
1388const char *ElementTypeName (unsigned type);
1389void DisplayFields (CLRDATA_ADDRESS cdaMT, DacpMethodTableData *pMTD, DacpMethodTableFieldData *pMTFD,
1390 DWORD_PTR dwStartAddr = 0, BOOL bFirst=TRUE, BOOL bValueClass=FALSE);
1391int GetObjFieldOffset(CLRDATA_ADDRESS cdaObj, __in_z LPCWSTR wszFieldName, BOOL bFirst=TRUE);
1392int GetObjFieldOffset(CLRDATA_ADDRESS cdaObj, CLRDATA_ADDRESS cdaMT, __in_z LPCWSTR wszFieldName, BOOL bFirst=TRUE, DacpFieldDescData* pDacpFieldDescData=NULL);
1393int GetValueFieldOffset(CLRDATA_ADDRESS cdaMT, __in_z LPCWSTR wszFieldName, DacpFieldDescData* pDacpFieldDescData);
1394
1395BOOL IsValidToken(DWORD_PTR ModuleAddr, mdTypeDef mb);
1396void NameForToken_s(DacpModuleData *pModule, mdTypeDef mb, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName,
1397 bool bClassName=true);
1398void NameForToken_s(DWORD_PTR ModuleAddr, mdTypeDef mb, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName,
1399 bool bClassName=true);
1400HRESULT NameForToken_s(mdTypeDef mb, IMetaDataImport *pImport, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName,
1401 bool bClassName);
1402HRESULT NameForTokenNew_s(mdTypeDef mb, IMDInternalImport *pImport, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName,
1403 bool bClassName);
1404
1405void vmmap();
1406void vmstat();
1407
1408#ifndef FEATURE_PAL
1409///////////////////////////////////////////////////////////////////////////////////////////////////
1410// Support for managed stack tracing
1411//
1412
1413DWORD_PTR GetDebuggerJitInfo(DWORD_PTR md);
1414
1415///////////////////////////////////////////////////////////////////////////////////////////////////
1416#endif // FEATURE_PAL
1417
1418template <typename SCALAR>
1419inline
1420int bitidx(SCALAR bitflag)
1421{
1422 for (int idx = 0; idx < static_cast<int>(sizeof(bitflag))*8; ++idx)
1423 {
1424 if (bitflag & (1 << idx))
1425 {
1426 _ASSERTE((bitflag & (~(1 << idx))) == 0);
1427 return idx;
1428 }
1429 }
1430 return -1;
1431}
1432
1433HRESULT
1434DllsName(
1435 ULONG_PTR addrContaining,
1436 __out_ecount (MAX_LONGPATH) WCHAR *dllName
1437 );
1438
1439inline
1440BOOL IsElementValueType (CorElementType cet)
1441{
1442 return (cet >= ELEMENT_TYPE_BOOLEAN && cet <= ELEMENT_TYPE_R8)
1443 || cet == ELEMENT_TYPE_VALUETYPE || cet == ELEMENT_TYPE_I || cet == ELEMENT_TYPE_U;
1444}
1445
1446
1447#define safemove(dst, src) \
1448SafeReadMemory (TO_TADDR(src), &(dst), sizeof(dst), NULL)
1449
1450extern "C" PDEBUG_DATA_SPACES g_ExtData;
1451
1452#include <arrayholder.h>
1453
1454// This class acts a smart pointer which calls the Release method on any object
1455// you place in it when the ToRelease class falls out of scope. You may use it
1456// just like you would a standard pointer to a COM object (including if (foo),
1457// if (!foo), if (foo == 0), etc) except for two caveats:
1458// 1. This class never calls AddRef and it always calls Release when it
1459// goes out of scope.
1460// 2. You should never use & to try to get a pointer to a pointer unless
1461// you call Release first, or you will leak whatever this object contains
1462// prior to updating its internal pointer.
1463template<class T>
1464class ToRelease
1465{
1466public:
1467 ToRelease()
1468 : m_ptr(NULL)
1469 {}
1470
1471 ToRelease(T* ptr)
1472 : m_ptr(ptr)
1473 {}
1474
1475 ~ToRelease()
1476 {
1477 Release();
1478 }
1479
1480 void operator=(T *ptr)
1481 {
1482 Release();
1483
1484 m_ptr = ptr;
1485 }
1486
1487 T* operator->()
1488 {
1489 return m_ptr;
1490 }
1491
1492 operator T*()
1493 {
1494 return m_ptr;
1495 }
1496
1497 T** operator&()
1498 {
1499 return &m_ptr;
1500 }
1501
1502 T* GetPtr() const
1503 {
1504 return m_ptr;
1505 }
1506
1507 T* Detach()
1508 {
1509 T* pT = m_ptr;
1510 m_ptr = NULL;
1511 return pT;
1512 }
1513
1514 void Release()
1515 {
1516 if (m_ptr != NULL)
1517 {
1518 m_ptr->Release();
1519 m_ptr = NULL;
1520 }
1521 }
1522
1523private:
1524 T* m_ptr;
1525};
1526
1527struct ModuleInfo
1528{
1529 ULONG64 baseAddr;
1530 ULONG64 size;
1531 BOOL hasPdb;
1532};
1533extern ModuleInfo moduleInfo[];
1534
1535BOOL InitializeHeapData();
1536BOOL IsServerBuild ();
1537UINT GetMaxGeneration();
1538UINT GetGcHeapCount();
1539BOOL GetGcStructuresValid();
1540
1541ULONG GetILSize(DWORD_PTR ilAddr); // REturns 0 if error occurs
1542HRESULT DecodeILFromAddress(IMetaDataImport *pImport, TADDR ilAddr);
1543void DecodeIL(IMetaDataImport *pImport, BYTE *buffer, ULONG bufSize);
1544void DecodeDynamicIL(BYTE *data, ULONG Size, DacpObjectData& tokenArray);
1545
1546BOOL IsRetailBuild (size_t base);
1547EEFLAVOR GetEEFlavor ();
1548HRESULT InitCorDebugInterface();
1549VOID UninitCorDebugInterface();
1550#ifndef FEATURE_PAL
1551BOOL GetEEVersion(VS_FIXEDFILEINFO *pFileInfo);
1552BOOL GetSOSVersion(VS_FIXEDFILEINFO *pFileInfo);
1553#endif
1554
1555BOOL IsDumpFile ();
1556
1557// IsMiniDumpFile will return true if 1) we are in
1558// a small format minidump, and g_InMinidumpSafeMode is true.
1559extern BOOL g_InMinidumpSafeMode;
1560
1561BOOL IsMiniDumpFile();
1562void ReportOOM();
1563
1564BOOL SafeReadMemory (TADDR offset, PVOID lpBuffer, ULONG cb, PULONG lpcbBytesRead);
1565#if !defined(_TARGET_WIN64_) && !defined(_ARM64_)
1566// on 64-bit platforms TADDR and CLRDATA_ADDRESS are identical
1567inline BOOL SafeReadMemory (CLRDATA_ADDRESS offset, PVOID lpBuffer, ULONG cb, PULONG lpcbBytesRead)
1568{ return SafeReadMemory(TO_TADDR(offset), lpBuffer, cb, lpcbBytesRead); }
1569#endif
1570
1571BOOL NameForMD_s (DWORD_PTR pMD, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName);
1572BOOL NameForMT_s (DWORD_PTR MTAddr, __out_ecount (capacity_mdName) WCHAR *mdName, size_t capacity_mdName);
1573
1574WCHAR *CreateMethodTableName(TADDR mt, TADDR cmt = NULL);
1575
1576void isRetAddr(DWORD_PTR retAddr, DWORD_PTR* whereCalled);
1577DWORD_PTR GetValueFromExpression (___in __in_z const char *const str);
1578
1579enum ModuleHeapType
1580{
1581 ModuleHeapType_ThunkHeap,
1582 ModuleHeapType_LookupTableHeap
1583};
1584
1585HRESULT PrintDomainHeapInfo(const char *name, CLRDATA_ADDRESS adPtr, DWORD_PTR *size, DWORD_PTR *wasted = 0);
1586DWORD_PTR PrintModuleHeapInfo(DWORD_PTR *moduleList, int count, ModuleHeapType type, DWORD_PTR *wasted = 0);
1587void PrintHeapSize(DWORD_PTR total, DWORD_PTR wasted);
1588void DomainInfo(DacpAppDomainData *pDomain);
1589void AssemblyInfo(DacpAssemblyData *pAssembly);
1590DWORD_PTR LoaderHeapInfo(CLRDATA_ADDRESS pLoaderHeapAddr, DWORD_PTR *wasted = 0);
1591DWORD_PTR JitHeapInfo();
1592DWORD_PTR VSDHeapInfo(CLRDATA_ADDRESS appDomain, DWORD_PTR *wasted = 0);
1593
1594DWORD GetNumComponents(TADDR obj);
1595
1596struct GenUsageStat
1597{
1598 size_t allocd;
1599 size_t freed;
1600 size_t unrooted;
1601};
1602
1603struct HeapUsageStat
1604{
1605 GenUsageStat genUsage[4]; // gen0, 1, 2, LOH
1606};
1607
1608extern DacpUsefulGlobalsData g_special_usefulGlobals;
1609BOOL GCHeapUsageStats(const DacpGcHeapDetails& heap, BOOL bIncUnreachable, HeapUsageStat *hpUsage);
1610
1611class HeapStat
1612{
1613protected:
1614 struct Node
1615 {
1616 DWORD_PTR data;
1617 DWORD count;
1618 size_t totalSize;
1619 Node* left;
1620 Node* right;
1621 Node ()
1622 : data(0), count(0), totalSize(0), left(NULL), right(NULL)
1623 {
1624 }
1625 };
1626 BOOL bHasStrings;
1627 Node *head;
1628 BOOL fLinear;
1629public:
1630 HeapStat ()
1631 : bHasStrings(FALSE), head(NULL), fLinear(FALSE)
1632 {}
1633 ~HeapStat()
1634 {
1635 Delete();
1636 }
1637 // TODO: Change the aSize argument to size_t when we start supporting
1638 // TODO: object sizes above 4GB
1639 void Add (DWORD_PTR aData, DWORD aSize);
1640 void Sort ();
1641 void Print (const char* label = NULL);
1642 void Delete ();
1643 void HasStrings(BOOL abHasStrings)
1644 {
1645 bHasStrings = abHasStrings;
1646 }
1647private:
1648 int CompareData(DWORD_PTR n1, DWORD_PTR n2);
1649 void SortAdd (Node *&root, Node *entry);
1650 void LinearAdd (Node *&root, Node *entry);
1651 void ReverseLeftMost (Node *root);
1652 void Linearize();
1653};
1654
1655class CGCDesc;
1656
1657// The information MethodTableCache returns.
1658struct MethodTableInfo
1659{
1660 bool IsInitialized() { return BaseSize != 0; }
1661
1662 DWORD BaseSize; // Caching BaseSize and ComponentSize for a MethodTable
1663 DWORD ComponentSize; // here has HUGE perf benefits in heap traversals.
1664 BOOL bContainsPointers;
1665 BOOL bCollectible;
1666 DWORD_PTR* GCInfoBuffer; // Start of memory of GC info
1667 CGCDesc* GCInfo; // Just past GC info (which is how it is stored)
1668 bool ArrayOfVC;
1669 TADDR LoaderAllocatorObjectHandle;
1670};
1671
1672class MethodTableCache
1673{
1674protected:
1675
1676 struct Node
1677 {
1678 DWORD_PTR data; // This is the key (the method table pointer)
1679 MethodTableInfo info; // The info associated with this MethodTable
1680 Node* left;
1681 Node* right;
1682 Node (DWORD_PTR aData) : data(aData), left(NULL), right(NULL)
1683 {
1684 info.BaseSize = 0;
1685 info.ComponentSize = 0;
1686 info.bContainsPointers = false;
1687 info.bCollectible = false;
1688 info.GCInfo = NULL;
1689 info.ArrayOfVC = false;
1690 info.GCInfoBuffer = NULL;
1691 info.LoaderAllocatorObjectHandle = NULL;
1692 }
1693 };
1694 Node *head;
1695public:
1696 MethodTableCache ()
1697 : head(NULL)
1698 {}
1699 ~MethodTableCache() { Clear(); }
1700
1701 // Always succeeds, if it is not present it adds an empty Info struct and returns that
1702 // Thus you must call 'IsInitialized' on the returned value before using it
1703 MethodTableInfo* Lookup(DWORD_PTR aData);
1704
1705 void Clear ();
1706private:
1707 int CompareData(DWORD_PTR n1, DWORD_PTR n2);
1708 void ReverseLeftMost (Node *root);
1709};
1710
1711extern MethodTableCache g_special_mtCache;
1712
1713struct DumpArrayFlags
1714{
1715 DWORD_PTR startIndex;
1716 DWORD_PTR Length;
1717 BOOL bDetail;
1718 LPSTR strObject;
1719 BOOL bNoFieldsForElement;
1720
1721 DumpArrayFlags ()
1722 : startIndex(0), Length((DWORD_PTR)-1), bDetail(FALSE), strObject (0), bNoFieldsForElement(FALSE)
1723 {}
1724 ~DumpArrayFlags ()
1725 {
1726 if (strObject)
1727 delete [] strObject;
1728 }
1729}; //DumpArrayFlags
1730
1731
1732
1733// -----------------------------------------------------------------------
1734
1735#define BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX 0x08000000
1736#define BIT_SBLK_FINALIZER_RUN 0x40000000
1737#define BIT_SBLK_SPIN_LOCK 0x10000000
1738#define SBLK_MASK_LOCK_THREADID 0x000003FF // special value of 0 + 1023 thread ids
1739#define SBLK_MASK_LOCK_RECLEVEL 0x0000FC00 // 64 recursion levels
1740#define SBLK_APPDOMAIN_SHIFT 16 // shift right this much to get appdomain index
1741#define SBLK_MASK_APPDOMAININDEX 0x000007FF // 2048 appdomain indices
1742#define SBLK_RECLEVEL_SHIFT 10 // shift right this much to get recursion level
1743#define BIT_SBLK_IS_HASHCODE 0x04000000
1744#define MASK_HASHCODE ((1<<HASHCODE_BITS)-1)
1745#define SYNCBLOCKINDEX_BITS 26
1746#define MASK_SYNCBLOCKINDEX ((1<<SYNCBLOCKINDEX_BITS)-1)
1747
1748HRESULT GetMTOfObject(TADDR obj, TADDR *mt);
1749
1750struct needed_alloc_context
1751{
1752 BYTE* alloc_ptr; // starting point for next allocation
1753 BYTE* alloc_limit; // ending point for allocation region/quantum
1754};
1755
1756struct AllocInfo
1757{
1758 needed_alloc_context *array;
1759 int num; // number of allocation contexts in array
1760
1761 AllocInfo()
1762 : array(NULL)
1763 , num(0)
1764 {}
1765 void Init()
1766 {
1767 extern void GetAllocContextPtrs(AllocInfo *pallocInfo);
1768 GetAllocContextPtrs(this);
1769 }
1770 ~AllocInfo()
1771 {
1772 if (array != NULL)
1773 delete[] array;
1774 }
1775};
1776
1777struct GCHandleStatistics
1778{
1779 HeapStat hs;
1780
1781 DWORD strongHandleCount;
1782 DWORD pinnedHandleCount;
1783 DWORD asyncPinnedHandleCount;
1784 DWORD refCntHandleCount;
1785 DWORD weakLongHandleCount;
1786 DWORD weakShortHandleCount;
1787 DWORD variableCount;
1788 DWORD sizedRefCount;
1789 DWORD dependentCount;
1790 DWORD weakWinRTHandleCount;
1791 DWORD unknownHandleCount;
1792 GCHandleStatistics()
1793 : strongHandleCount(0), pinnedHandleCount(0), asyncPinnedHandleCount(0), refCntHandleCount(0),
1794 weakLongHandleCount(0), weakShortHandleCount(0), variableCount(0), sizedRefCount(0),
1795 dependentCount(0), weakWinRTHandleCount(0), unknownHandleCount(0)
1796 {}
1797 ~GCHandleStatistics()
1798 {
1799 hs.Delete();
1800 }
1801};
1802
1803struct SegmentLookup
1804{
1805 DacpHeapSegmentData *m_segments;
1806 int m_iSegmentsSize;
1807 int m_iSegmentCount;
1808
1809 SegmentLookup();
1810 ~SegmentLookup();
1811
1812 void Clear();
1813 BOOL AddSegment(DacpHeapSegmentData *pData);
1814 CLRDATA_ADDRESS GetHeap(CLRDATA_ADDRESS object, BOOL& bFound);
1815};
1816
1817class GCHeapSnapshot
1818{
1819private:
1820 BOOL m_isBuilt;
1821 DacpGcHeapDetails *m_heapDetails;
1822 DacpGcHeapData m_gcheap;
1823 SegmentLookup m_segments;
1824
1825 BOOL AddSegments(DacpGcHeapDetails& details);
1826public:
1827 GCHeapSnapshot();
1828
1829 BOOL Build();
1830 void Clear();
1831 BOOL IsBuilt() { return m_isBuilt; }
1832
1833 DacpGcHeapData *GetHeapData() { return &m_gcheap; }
1834
1835 int GetHeapCount() { return m_gcheap.HeapCount; }
1836
1837 DacpGcHeapDetails *GetHeap(CLRDATA_ADDRESS objectPointer);
1838 int GetGeneration(CLRDATA_ADDRESS objectPointer);
1839
1840
1841};
1842extern GCHeapSnapshot g_snapshot;
1843
1844BOOL IsSameModuleName (const char *str1, const char *str2);
1845BOOL IsModule (DWORD_PTR moduleAddr);
1846BOOL IsMethodDesc (DWORD_PTR value);
1847BOOL IsMethodTable (DWORD_PTR value);
1848BOOL IsStringObject (size_t obj);
1849BOOL IsObjectArray (DWORD_PTR objPointer);
1850BOOL IsObjectArray (DacpObjectData *pData);
1851BOOL IsDerivedFrom(CLRDATA_ADDRESS mtObj, __in_z LPCWSTR baseString);
1852BOOL TryGetMethodDescriptorForDelegate(CLRDATA_ADDRESS delegateAddr, CLRDATA_ADDRESS* pMD);
1853
1854/* Returns a list of all modules in the process.
1855 * Params:
1856 * name - The name of the module you would like. If mName is NULL the all modules are returned.
1857 * numModules - The number of modules in the array returned.
1858 * Returns:
1859 * An array of modules whose length is *numModules, NULL if an error occurred. Note that if this
1860 * function succeeds but finds no modules matching the name given, this function returns a valid
1861 * array, but *numModules will equal 0.
1862 * Note:
1863 * You must clean up the return value of this array by calling delete [] on it, or using the
1864 * ArrayHolder class.
1865 */
1866DWORD_PTR *ModuleFromName(__in_opt LPSTR name, int *numModules);
1867void GetInfoFromName(DWORD_PTR ModuleAddr, const char* name);
1868void GetInfoFromModule (DWORD_PTR ModuleAddr, ULONG token, DWORD_PTR *ret=NULL);
1869
1870
1871typedef void (*VISITGCHEAPFUNC)(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable,LPVOID token);
1872BOOL GCHeapsTraverse(VISITGCHEAPFUNC pFunc, LPVOID token, BOOL verify=true);
1873
1874/////////////////////////////////////////////////////////////////////////////////////////////////////////
1875
1876struct strobjInfo
1877{
1878 size_t methodTable;
1879 DWORD m_StringLength;
1880};
1881
1882// Just to make figuring out which fill pointer element matches a generation
1883// a bit less confusing. This gen_segment function is ported from gc.cpp.
1884inline unsigned int gen_segment (int gen)
1885{
1886 return (DAC_NUMBERGENERATIONS - gen - 1);
1887}
1888
1889inline CLRDATA_ADDRESS SegQueue(DacpGcHeapDetails& heapDetails, int seg)
1890{
1891 return heapDetails.finalization_fill_pointers[seg - 1];
1892}
1893
1894inline CLRDATA_ADDRESS SegQueueLimit(DacpGcHeapDetails& heapDetails, int seg)
1895{
1896 return heapDetails.finalization_fill_pointers[seg];
1897}
1898
1899#define FinalizerListSeg (DAC_NUMBERGENERATIONS+1)
1900#define CriticalFinalizerListSeg (DAC_NUMBERGENERATIONS)
1901
1902void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, BOOL bAllReady, BOOL bShort);
1903
1904CLRDATA_ADDRESS GetAppDomainForMT(CLRDATA_ADDRESS mtPtr);
1905CLRDATA_ADDRESS GetAppDomain(CLRDATA_ADDRESS objPtr);
1906void GCHeapInfo(const DacpGcHeapDetails &heap, DWORD_PTR &total_size);
1907BOOL GCObjInHeap(TADDR taddrObj, const DacpGcHeapDetails &heap,
1908 TADDR_SEGINFO& trngSeg, int& gen, TADDR_RANGE& allocCtx, BOOL &bLarge);
1909
1910BOOL VerifyObject(const DacpGcHeapDetails &heap, const DacpHeapSegmentData &seg, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize,
1911 BOOL bVerifyMember);
1912BOOL VerifyObject(const DacpGcHeapDetails &heap, DWORD_PTR objAddr, DWORD_PTR MTAddr, size_t objSize,
1913 BOOL bVerifyMember);
1914
1915BOOL IsMTForFreeObj(DWORD_PTR pMT);
1916void DumpStackObjectsHelper (TADDR StackTop, TADDR StackBottom, BOOL verifyFields);
1917
1918
1919enum ARGTYPE {COBOOL,COSIZE_T,COHEX,COSTRING};
1920struct CMDOption
1921{
1922 const char* name;
1923 void *vptr;
1924 ARGTYPE type;
1925 BOOL hasValue;
1926 BOOL hasSeen;
1927};
1928struct CMDValue
1929{
1930 void *vptr;
1931 ARGTYPE type;
1932};
1933BOOL GetCMDOption(const char *string, CMDOption *option, size_t nOption,
1934 CMDValue *arg, size_t maxArg, size_t *nArg);
1935
1936void DumpMDInfo(DWORD_PTR dwStartAddr, CLRDATA_ADDRESS dwRequestedIP = 0, BOOL fStackTraceFormat = FALSE);
1937void DumpMDInfoFromMethodDescData(DacpMethodDescData * pMethodDescData, BOOL fStackTraceFormat);
1938void GetDomainList(DWORD_PTR *&domainList, int &numDomain);
1939HRESULT GetThreadList(DWORD_PTR **threadList, int *numThread);
1940CLRDATA_ADDRESS GetCurrentManagedThread(); // returns current managed thread if any
1941void GetAllocContextPtrs(AllocInfo *pallocInfo);
1942
1943void ReloadSymbolWithLineInfo();
1944
1945size_t FunctionType (size_t EIP);
1946
1947size_t Align (size_t nbytes);
1948// Aligns large objects
1949size_t AlignLarge (size_t nbytes);
1950
1951ULONG OSPageSize ();
1952size_t NextOSPageAddress (size_t addr);
1953
1954// This version of objectsize reduces the lookup of methodtables in the DAC.
1955// It uses g_special_mtCache for it's work.
1956BOOL GetSizeEfficient(DWORD_PTR dwAddrCurrObj,
1957 DWORD_PTR dwAddrMethTable, BOOL bLarge, size_t& s, BOOL& bContainsPointers);
1958
1959BOOL GetCollectibleDataEfficient(DWORD_PTR dwAddrMethTable, BOOL& bCollectible, TADDR& loaderAllocatorObjectHandle);
1960
1961// ObjSize now uses the methodtable cache for its work too.
1962size_t ObjectSize (DWORD_PTR obj, BOOL fIsLargeObject=FALSE);
1963size_t ObjectSize(DWORD_PTR obj, DWORD_PTR mt, BOOL fIsValueClass, BOOL fIsLargeObject=FALSE);
1964
1965void CharArrayContent(TADDR pos, ULONG num, bool widechar);
1966void StringObjectContent (size_t obj, BOOL fLiteral=FALSE, const int length=-1); // length=-1: dump everything in the string object.
1967
1968UINT FindAllPinnedAndStrong (DWORD_PTR handlearray[],UINT arraySize);
1969void PrintNotReachableInRange(TADDR rngStart, TADDR rngEnd, BOOL bExcludeReadyForFinalization,
1970 HeapStat* stat, BOOL bShort);
1971
1972const char *EHTypeName(EHClauseType et);
1973
1974struct StringHolder
1975{
1976 LPSTR data;
1977 StringHolder() : data(NULL) { }
1978 ~StringHolder() { if(data) delete [] data; }
1979};
1980
1981
1982ULONG DebuggeeType();
1983
1984inline BOOL IsKernelDebugger ()
1985{
1986 return DebuggeeType() == DEBUG_CLASS_KERNEL;
1987}
1988
1989void ResetGlobals(void);
1990HRESULT LoadClrDebugDll(void);
1991extern "C" void UnloadClrDebugDll(void);
1992
1993extern IMetaDataImport* MDImportForModule (DacpModuleData *pModule);
1994extern IMetaDataImport* MDImportForModule (DWORD_PTR pModule);
1995
1996//*****************************************************************************
1997//
1998// **** CQuickBytes
1999// This helper class is useful for cases where 90% of the time you allocate 512
2000// or less bytes for a data structure. This class contains a 512 byte buffer.
2001// Alloc() will return a pointer to this buffer if your allocation is small
2002// enough, otherwise it asks the heap for a larger buffer which is freed for
2003// you. No mutex locking is required for the small allocation case, making the
2004// code run faster, less heap fragmentation, etc... Each instance will allocate
2005// 520 bytes, so use accordinly.
2006//
2007//*****************************************************************************
2008template <DWORD SIZE, DWORD INCREMENT>
2009class CQuickBytesBase
2010{
2011public:
2012 CQuickBytesBase() :
2013 pbBuff(0),
2014 iSize(0),
2015 cbTotal(SIZE)
2016 { }
2017
2018 void Destroy()
2019 {
2020 if (pbBuff)
2021 {
2022 delete[] (BYTE*)pbBuff;
2023 pbBuff = 0;
2024 }
2025 }
2026
2027 void *Alloc(SIZE_T iItems)
2028 {
2029 iSize = iItems;
2030 if (iItems <= SIZE)
2031 {
2032 cbTotal = SIZE;
2033 return (&rgData[0]);
2034 }
2035 else
2036 {
2037 if (pbBuff)
2038 delete[] (BYTE*)pbBuff;
2039 pbBuff = new BYTE[iItems];
2040 cbTotal = pbBuff ? iItems : 0;
2041 return (pbBuff);
2042 }
2043 }
2044
2045 // This is for conformity to the CQuickBytesBase that is defined by the runtime so
2046 // that we can use it inside of some GC code that SOS seems to include as well.
2047 //
2048 // The plain vanilla "Alloc" version on this CQuickBytesBase doesn't throw either,
2049 // so we'll just forward the call.
2050 void *AllocNoThrow(SIZE_T iItems)
2051 {
2052 return Alloc(iItems);
2053 }
2054
2055 HRESULT ReSize(SIZE_T iItems)
2056 {
2057 void *pbBuffNew;
2058 if (iItems <= cbTotal)
2059 {
2060 iSize = iItems;
2061 return NOERROR;
2062 }
2063
2064 pbBuffNew = new BYTE[iItems + INCREMENT];
2065 if (!pbBuffNew)
2066 return E_OUTOFMEMORY;
2067 if (pbBuff)
2068 {
2069 memcpy(pbBuffNew, pbBuff, cbTotal);
2070 delete[] (BYTE*)pbBuff;
2071 }
2072 else
2073 {
2074 _ASSERTE(cbTotal == SIZE);
2075 memcpy(pbBuffNew, rgData, SIZE);
2076 }
2077 cbTotal = iItems + INCREMENT;
2078 iSize = iItems;
2079 pbBuff = pbBuffNew;
2080 return NOERROR;
2081
2082 }
2083
2084 operator PVOID()
2085 { return ((pbBuff) ? pbBuff : &rgData[0]); }
2086
2087 void *Ptr()
2088 { return ((pbBuff) ? pbBuff : &rgData[0]); }
2089
2090 SIZE_T Size()
2091 { return (iSize); }
2092
2093 SIZE_T MaxSize()
2094 { return (cbTotal); }
2095
2096 void *pbBuff;
2097 SIZE_T iSize; // number of bytes used
2098 SIZE_T cbTotal; // total bytes allocated in the buffer
2099 // use UINT64 to enforce the alignment of the memory
2100 UINT64 rgData[(SIZE+sizeof(UINT64)-1)/sizeof(UINT64)];
2101};
2102
2103#define CQUICKBYTES_BASE_SIZE 512
2104#define CQUICKBYTES_INCREMENTAL_SIZE 128
2105
2106class CQuickBytesNoDtor : public CQuickBytesBase<CQUICKBYTES_BASE_SIZE, CQUICKBYTES_INCREMENTAL_SIZE>
2107{
2108};
2109
2110class CQuickBytes : public CQuickBytesNoDtor
2111{
2112public:
2113 CQuickBytes() { }
2114
2115 ~CQuickBytes()
2116 {
2117 Destroy();
2118 }
2119};
2120
2121template <DWORD CQUICKBYTES_BASE_SPECIFY_SIZE>
2122class CQuickBytesNoDtorSpecifySize : public CQuickBytesBase<CQUICKBYTES_BASE_SPECIFY_SIZE, CQUICKBYTES_INCREMENTAL_SIZE>
2123{
2124};
2125
2126template <DWORD CQUICKBYTES_BASE_SPECIFY_SIZE>
2127class CQuickBytesSpecifySize : public CQuickBytesNoDtorSpecifySize<CQUICKBYTES_BASE_SPECIFY_SIZE>
2128{
2129public:
2130 CQuickBytesSpecifySize() { }
2131
2132 ~CQuickBytesSpecifySize()
2133 {
2134 CQuickBytesNoDtorSpecifySize<CQUICKBYTES_BASE_SPECIFY_SIZE>::Destroy();
2135 }
2136};
2137
2138
2139#define STRING_SIZE 10
2140class CQuickString : public CQuickBytesBase<STRING_SIZE, STRING_SIZE>
2141{
2142public:
2143 CQuickString() { }
2144
2145 ~CQuickString()
2146 {
2147 Destroy();
2148 }
2149
2150 void *Alloc(SIZE_T iItems)
2151 {
2152 return CQuickBytesBase<STRING_SIZE, STRING_SIZE>::Alloc(iItems*sizeof(WCHAR));
2153 }
2154
2155 HRESULT ReSize(SIZE_T iItems)
2156 {
2157 return CQuickBytesBase<STRING_SIZE, STRING_SIZE>::ReSize(iItems * sizeof(WCHAR));
2158 }
2159
2160 SIZE_T Size()
2161 {
2162 return CQuickBytesBase<STRING_SIZE, STRING_SIZE>::Size() / sizeof(WCHAR);
2163 }
2164
2165 SIZE_T MaxSize()
2166 {
2167 return CQuickBytesBase<STRING_SIZE, STRING_SIZE>::MaxSize() / sizeof(WCHAR);
2168 }
2169
2170 WCHAR* String()
2171 {
2172 return (WCHAR*) Ptr();
2173 }
2174
2175};
2176
2177enum GetSignatureStringResults
2178{
2179 GSS_SUCCESS,
2180 GSS_ERROR,
2181 GSS_INSUFFICIENT_DATA,
2182};
2183
2184GetSignatureStringResults GetMethodSignatureString (PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, DWORD_PTR dwModuleAddr, CQuickBytes *sigString);
2185GetSignatureStringResults GetSignatureString (PCCOR_SIGNATURE pbSigBlob, ULONG ulSigBlob, DWORD_PTR dwModuleAddr, CQuickBytes *sigString);
2186void GetMethodName(mdMethodDef methodDef, IMetaDataImport * pImport, CQuickBytes *fullName);
2187
2188#ifndef _TARGET_WIN64_
2189#define itoa_s_ptr _itoa_s
2190#define itow_s_ptr _itow_s
2191#else
2192#define itoa_s_ptr _i64toa_s
2193#define itow_s_ptr _i64tow_s
2194#endif
2195
2196#ifdef FEATURE_PAL
2197extern "C"
2198int _itoa_s( int inValue, char* outBuffer, size_t inDestBufferSize, int inRadix );
2199extern "C"
2200int _ui64toa_s( unsigned __int64 inValue, char* outBuffer, size_t inDestBufferSize, int inRadix );
2201#endif // FEATURE_PAL
2202
2203struct MemRange
2204{
2205 MemRange (ULONG64 s = NULL, size_t l = 0, MemRange * n = NULL)
2206 : start(s), len (l), next (n)
2207 {}
2208
2209 bool InRange (ULONG64 addr)
2210 {
2211 return addr >= start && addr < start + len;
2212 }
2213
2214 ULONG64 start;
2215 size_t len;
2216 MemRange * next;
2217}; //struct MemRange
2218
2219#ifndef FEATURE_PAL
2220
2221class StressLogMem
2222{
2223private:
2224 // use a linked list for now, could be optimazied later
2225 MemRange * list;
2226
2227 void AddRange (ULONG64 s, size_t l)
2228 {
2229 list = new MemRange (s, l, list);
2230 }
2231
2232public:
2233 StressLogMem () : list (NULL)
2234 {}
2235 ~StressLogMem ();
2236 bool Init (ULONG64 stressLogAddr, IDebugDataSpaces* memCallBack);
2237 bool IsInStressLog (ULONG64 addr);
2238}; //class StressLogMem
2239
2240// An adapter class that DIA consumes so that it can read PE data from the an image
2241// This implementation gets the backing data from the image loaded in debuggee memory
2242// that has been layed out identical to the disk format (ie not seperated by section)
2243class PEOffsetMemoryReader : IDiaReadExeAtOffsetCallback
2244{
2245public:
2246 PEOffsetMemoryReader(TADDR moduleBaseAddress);
2247
2248 // IUnknown implementation
2249 HRESULT __stdcall QueryInterface(REFIID riid, VOID** ppInterface);
2250 ULONG __stdcall AddRef();
2251 ULONG __stdcall Release();
2252
2253 // IDiaReadExeAtOffsetCallback implementation
2254 HRESULT __stdcall ReadExecutableAt(DWORDLONG fileOffset, DWORD cbData, DWORD* pcbData, BYTE data[]);
2255
2256private:
2257 TADDR m_moduleBaseAddress;
2258 volatile ULONG m_refCount;
2259};
2260
2261// An adapter class that DIA consumes so that it can read PE data from the an image
2262// This implementation gets the backing data from the image loaded in debuggee memory
2263// that has been layed out in LoadLibrary format
2264class PERvaMemoryReader : IDiaReadExeAtRVACallback
2265{
2266public:
2267 PERvaMemoryReader(TADDR moduleBaseAddress);
2268
2269 // IUnknown implementation
2270 HRESULT __stdcall QueryInterface(REFIID riid, VOID** ppInterface);
2271 ULONG __stdcall AddRef();
2272 ULONG __stdcall Release();
2273
2274 // IDiaReadExeAtOffsetCallback implementation
2275 HRESULT __stdcall ReadExecutableAtRVA(DWORD relativeVirtualAddress, DWORD cbData, DWORD* pcbData, BYTE data[]);
2276
2277private:
2278 TADDR m_moduleBaseAddress;
2279 volatile ULONG m_refCount;
2280};
2281
2282#endif // !FEATURE_PAL
2283
2284static const char *SymbolReaderDllName = "SOS.NETCore";
2285static const char *SymbolReaderClassName = "SOS.SymbolReader";
2286
2287typedef int (*ReadMemoryDelegate)(ULONG64, char *, int);
2288typedef PVOID (*LoadSymbolsForModuleDelegate)(const char*, BOOL, ULONG64, int, ULONG64, int, ReadMemoryDelegate);
2289typedef void (*DisposeDelegate)(PVOID);
2290typedef BOOL (*ResolveSequencePointDelegate)(PVOID, const char*, unsigned int, unsigned int*, unsigned int*);
2291typedef BOOL (*GetLocalVariableName)(PVOID, int, int, BSTR*);
2292typedef BOOL (*GetLineByILOffsetDelegate)(PVOID, mdMethodDef, ULONG64, ULONG *, BSTR*);
2293
2294class SymbolReader
2295{
2296private:
2297#ifndef FEATURE_PAL
2298 ISymUnmanagedReader* m_pSymReader;
2299#endif
2300 PVOID m_symbolReaderHandle;
2301
2302 static LoadSymbolsForModuleDelegate loadSymbolsForModuleDelegate;
2303 static DisposeDelegate disposeDelegate;
2304 static ResolveSequencePointDelegate resolveSequencePointDelegate;
2305 static GetLocalVariableName getLocalVariableNameDelegate;
2306 static GetLineByILOffsetDelegate getLineByILOffsetDelegate;
2307 static HRESULT PrepareSymbolReader();
2308
2309 HRESULT GetNamedLocalVariable(___in ISymUnmanagedScope* pScope, ___in ICorDebugILFrame* pILFrame, ___in mdMethodDef methodToken, ___in ULONG localIndex,
2310 __out_ecount(paramNameLen) WCHAR* paramName, ___in ULONG paramNameLen, ___out ICorDebugValue** ppValue);
2311 HRESULT LoadSymbolsForWindowsPDB(___in IMetaDataImport* pMD, ___in ULONG64 peAddress, __in_z WCHAR* pModuleName, ___in BOOL isFileLayout);
2312 HRESULT LoadSymbolsForPortablePDB(__in_z WCHAR* pModuleName, ___in BOOL isInMemory, ___in BOOL isFileLayout, ___in ULONG64 peAddress, ___in ULONG64 peSize,
2313 ___in ULONG64 inMemoryPdbAddress, ___in ULONG64 inMemoryPdbSize);
2314
2315public:
2316 SymbolReader()
2317 {
2318#ifndef FEATURE_PAL
2319 m_pSymReader = NULL;
2320#endif
2321 m_symbolReaderHandle = 0;
2322 }
2323
2324 ~SymbolReader()
2325 {
2326#ifndef FEATURE_PAL
2327 if(m_pSymReader != NULL)
2328 {
2329 m_pSymReader->Release();
2330 m_pSymReader = NULL;
2331 }
2332#endif
2333 if (m_symbolReaderHandle != 0)
2334 {
2335 disposeDelegate(m_symbolReaderHandle);
2336 m_symbolReaderHandle = 0;
2337 }
2338 }
2339
2340 HRESULT LoadSymbols(___in IMetaDataImport* pMD, ___in ICorDebugModule* pModule);
2341 HRESULT LoadSymbols(___in IMetaDataImport* pMD, ___in IXCLRDataModule* pModule);
2342 HRESULT GetLineByILOffset(___in mdMethodDef MethodToken, ___in ULONG64 IlOffset, ___out ULONG *pLinenum, __out_ecount(cchFileName) WCHAR* pwszFileName, ___in ULONG cchFileName);
2343 HRESULT GetNamedLocalVariable(___in ICorDebugFrame * pFrame, ___in ULONG localIndex, __out_ecount(paramNameLen) WCHAR* paramName, ___in ULONG paramNameLen, ___out ICorDebugValue** ppValue);
2344 HRESULT ResolveSequencePoint(__in_z WCHAR* pFilename, ___in ULONG32 lineNumber, ___in TADDR mod, ___out mdMethodDef* ___out pToken, ___out ULONG32* pIlOffset);
2345};
2346
2347HRESULT
2348GetLineByOffset(
2349 ___in ULONG64 IP,
2350 ___out ULONG *pLinenum,
2351 __out_ecount(cchFileName) WCHAR* pwszFileName,
2352 ___in ULONG cchFileName);
2353
2354/// X86 Context
2355#define X86_SIZE_OF_80387_REGISTERS 80
2356#define X86_MAXIMUM_SUPPORTED_EXTENSION 512
2357
2358typedef struct {
2359 DWORD ControlWord;
2360 DWORD StatusWord;
2361 DWORD TagWord;
2362 DWORD ErrorOffset;
2363 DWORD ErrorSelector;
2364 DWORD DataOffset;
2365 DWORD DataSelector;
2366 BYTE RegisterArea[X86_SIZE_OF_80387_REGISTERS];
2367 DWORD Cr0NpxState;
2368} X86_FLOATING_SAVE_AREA;
2369
2370typedef struct {
2371
2372 DWORD ContextFlags;
2373 DWORD Dr0;
2374 DWORD Dr1;
2375 DWORD Dr2;
2376 DWORD Dr3;
2377 DWORD Dr6;
2378 DWORD Dr7;
2379
2380 X86_FLOATING_SAVE_AREA FloatSave;
2381
2382 DWORD SegGs;
2383 DWORD SegFs;
2384 DWORD SegEs;
2385 DWORD SegDs;
2386
2387 DWORD Edi;
2388 DWORD Esi;
2389 DWORD Ebx;
2390 DWORD Edx;
2391 DWORD Ecx;
2392 DWORD Eax;
2393
2394 DWORD Ebp;
2395 DWORD Eip;
2396 DWORD SegCs;
2397 DWORD EFlags;
2398 DWORD Esp;
2399 DWORD SegSs;
2400
2401 BYTE ExtendedRegisters[X86_MAXIMUM_SUPPORTED_EXTENSION];
2402
2403} X86_CONTEXT;
2404
2405typedef struct {
2406 ULONGLONG Low;
2407 LONGLONG High;
2408} M128A_XPLAT;
2409
2410
2411/// AMD64 Context
2412typedef struct {
2413 WORD ControlWord;
2414 WORD StatusWord;
2415 BYTE TagWord;
2416 BYTE Reserved1;
2417 WORD ErrorOpcode;
2418 DWORD ErrorOffset;
2419 WORD ErrorSelector;
2420 WORD Reserved2;
2421 DWORD DataOffset;
2422 WORD DataSelector;
2423 WORD Reserved3;
2424 DWORD MxCsr;
2425 DWORD MxCsr_Mask;
2426 M128A_XPLAT FloatRegisters[8];
2427
2428#if defined(_WIN64)
2429 M128A_XPLAT XmmRegisters[16];
2430 BYTE Reserved4[96];
2431#else
2432 M128A_XPLAT XmmRegisters[8];
2433 BYTE Reserved4[220];
2434
2435 DWORD Cr0NpxState;
2436#endif
2437
2438} AMD64_XMM_SAVE_AREA32;
2439
2440typedef struct {
2441
2442 DWORD64 P1Home;
2443 DWORD64 P2Home;
2444 DWORD64 P3Home;
2445 DWORD64 P4Home;
2446 DWORD64 P5Home;
2447 DWORD64 P6Home;
2448
2449 DWORD ContextFlags;
2450 DWORD MxCsr;
2451
2452 WORD SegCs;
2453 WORD SegDs;
2454 WORD SegEs;
2455 WORD SegFs;
2456 WORD SegGs;
2457 WORD SegSs;
2458 DWORD EFlags;
2459
2460 DWORD64 Dr0;
2461 DWORD64 Dr1;
2462 DWORD64 Dr2;
2463 DWORD64 Dr3;
2464 DWORD64 Dr6;
2465 DWORD64 Dr7;
2466
2467 DWORD64 Rax;
2468 DWORD64 Rcx;
2469 DWORD64 Rdx;
2470 DWORD64 Rbx;
2471 DWORD64 Rsp;
2472 DWORD64 Rbp;
2473 DWORD64 Rsi;
2474 DWORD64 Rdi;
2475 DWORD64 R8;
2476 DWORD64 R9;
2477 DWORD64 R10;
2478 DWORD64 R11;
2479 DWORD64 R12;
2480 DWORD64 R13;
2481 DWORD64 R14;
2482 DWORD64 R15;
2483
2484 DWORD64 Rip;
2485
2486 union {
2487 AMD64_XMM_SAVE_AREA32 FltSave;
2488 struct {
2489 M128A_XPLAT Header[2];
2490 M128A_XPLAT Legacy[8];
2491 M128A_XPLAT Xmm0;
2492 M128A_XPLAT Xmm1;
2493 M128A_XPLAT Xmm2;
2494 M128A_XPLAT Xmm3;
2495 M128A_XPLAT Xmm4;
2496 M128A_XPLAT Xmm5;
2497 M128A_XPLAT Xmm6;
2498 M128A_XPLAT Xmm7;
2499 M128A_XPLAT Xmm8;
2500 M128A_XPLAT Xmm9;
2501 M128A_XPLAT Xmm10;
2502 M128A_XPLAT Xmm11;
2503 M128A_XPLAT Xmm12;
2504 M128A_XPLAT Xmm13;
2505 M128A_XPLAT Xmm14;
2506 M128A_XPLAT Xmm15;
2507 } DUMMYSTRUCTNAME;
2508 } DUMMYUNIONNAME;
2509
2510 M128A_XPLAT VectorRegister[26];
2511 DWORD64 VectorControl;
2512
2513 DWORD64 DebugControl;
2514 DWORD64 LastBranchToRip;
2515 DWORD64 LastBranchFromRip;
2516 DWORD64 LastExceptionToRip;
2517 DWORD64 LastExceptionFromRip;
2518
2519} AMD64_CONTEXT;
2520
2521typedef struct{
2522 __int64 LowPart;
2523 __int64 HighPart;
2524} FLOAT128_XPLAT;
2525
2526
2527/// ARM Context
2528#define ARM_MAX_BREAKPOINTS_CONST 8
2529#define ARM_MAX_WATCHPOINTS_CONST 1
2530typedef DECLSPEC_ALIGN(8) struct {
2531
2532 DWORD ContextFlags;
2533
2534 DWORD R0;
2535 DWORD R1;
2536 DWORD R2;
2537 DWORD R3;
2538 DWORD R4;
2539 DWORD R5;
2540 DWORD R6;
2541 DWORD R7;
2542 DWORD R8;
2543 DWORD R9;
2544 DWORD R10;
2545 DWORD R11;
2546 DWORD R12;
2547
2548 DWORD Sp;
2549 DWORD Lr;
2550 DWORD Pc;
2551 DWORD Cpsr;
2552
2553 DWORD Fpscr;
2554 DWORD Padding;
2555 union {
2556 M128A_XPLAT Q[16];
2557 ULONGLONG D[32];
2558 DWORD S[32];
2559 } DUMMYUNIONNAME;
2560
2561 DWORD Bvr[ARM_MAX_BREAKPOINTS_CONST];
2562 DWORD Bcr[ARM_MAX_BREAKPOINTS_CONST];
2563 DWORD Wvr[ARM_MAX_WATCHPOINTS_CONST];
2564 DWORD Wcr[ARM_MAX_WATCHPOINTS_CONST];
2565
2566 DWORD Padding2[2];
2567
2568} ARM_CONTEXT;
2569
2570// On ARM this mask is or'ed with the address of code to get an instruction pointer
2571#ifndef THUMB_CODE
2572#define THUMB_CODE 1
2573#endif
2574
2575///ARM64 Context
2576#define ARM64_MAX_BREAKPOINTS 8
2577#define ARM64_MAX_WATCHPOINTS 2
2578typedef struct {
2579
2580 DWORD ContextFlags;
2581 DWORD Cpsr; // NZVF + DAIF + CurrentEL + SPSel
2582 union {
2583 struct {
2584 DWORD64 X0;
2585 DWORD64 X1;
2586 DWORD64 X2;
2587 DWORD64 X3;
2588 DWORD64 X4;
2589 DWORD64 X5;
2590 DWORD64 X6;
2591 DWORD64 X7;
2592 DWORD64 X8;
2593 DWORD64 X9;
2594 DWORD64 X10;
2595 DWORD64 X11;
2596 DWORD64 X12;
2597 DWORD64 X13;
2598 DWORD64 X14;
2599 DWORD64 X15;
2600 DWORD64 X16;
2601 DWORD64 X17;
2602 DWORD64 X18;
2603 DWORD64 X19;
2604 DWORD64 X20;
2605 DWORD64 X21;
2606 DWORD64 X22;
2607 DWORD64 X23;
2608 DWORD64 X24;
2609 DWORD64 X25;
2610 DWORD64 X26;
2611 DWORD64 X27;
2612 DWORD64 X28;
2613 };
2614
2615 DWORD64 X[29];
2616 };
2617
2618 DWORD64 Fp;
2619 DWORD64 Lr;
2620 DWORD64 Sp;
2621 DWORD64 Pc;
2622
2623
2624 M128A_XPLAT V[32];
2625 DWORD Fpcr;
2626 DWORD Fpsr;
2627
2628 DWORD Bcr[ARM64_MAX_BREAKPOINTS];
2629 DWORD64 Bvr[ARM64_MAX_BREAKPOINTS];
2630 DWORD Wcr[ARM64_MAX_WATCHPOINTS];
2631 DWORD64 Wvr[ARM64_MAX_WATCHPOINTS];
2632
2633} ARM64_CONTEXT;
2634
2635typedef struct _CROSS_PLATFORM_CONTEXT {
2636
2637 _CROSS_PLATFORM_CONTEXT() {}
2638
2639 union {
2640 X86_CONTEXT X86Context;
2641 AMD64_CONTEXT Amd64Context;
2642 ARM_CONTEXT ArmContext;
2643 ARM64_CONTEXT Arm64Context;
2644 };
2645
2646} CROSS_PLATFORM_CONTEXT, *PCROSS_PLATFORM_CONTEXT;
2647
2648
2649
2650WString BuildRegisterOutput(const SOSStackRefData &ref, bool printObj = true);
2651WString MethodNameFromIP(CLRDATA_ADDRESS methodDesc, BOOL bSuppressLines = FALSE, BOOL bAssemblyName = FALSE, BOOL bDisplacement = FALSE);
2652HRESULT GetGCRefs(ULONG osID, SOSStackRefData **ppRefs, unsigned int *pRefCnt, SOSStackRefError **ppErrors, unsigned int *pErrCount);
2653WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackwalk = NULL, BOOL bAssemblyName = FALSE);
2654
2655/* This cache is used to read data from the target process if the reads are known
2656 * to be sequential.
2657 */
2658class LinearReadCache
2659{
2660public:
2661 LinearReadCache(ULONG pageSize = 0x10000);
2662 ~LinearReadCache();
2663
2664 /* Reads an address out of the target process, caching the page of memory read.
2665 * Params:
2666 * addr - The address to read out of the target process.
2667 * t - A pointer to the data to stuff it in. We will read sizeof(T) data
2668 * from the process and write it into the location t points to. This
2669 * parameter must be non-null.
2670 * Returns:
2671 * True if the read succeeded. False if it did not, usually as a result
2672 * of the memory simply not being present in the target process.
2673 * Note:
2674 * The state of *t is undefined if this function returns false. We may
2675 * have written partial data to it if we return false, so you must
2676 * absolutely NOT use it if Read returns false.
2677 */
2678 template <class T>
2679 bool Read(TADDR addr, T *t, bool update = true)
2680 {
2681 _ASSERTE(t);
2682
2683 // Unfortunately the ctor can fail the alloc for the byte array. In this case
2684 // we'll just fall back to non-cached reads.
2685 if (mPage == NULL)
2686 return MisalignedRead(addr, t);
2687
2688 // Is addr on the current page? If not read the page of memory addr is on.
2689 // If this fails, we will fall back to a raw read out of the process (which
2690 // is what MisalignedRead does).
2691 if ((addr < mCurrPageStart) || (addr - mCurrPageStart > mCurrPageSize))
2692 if (!update || !MoveToPage(addr))
2693 return MisalignedRead(addr, t);
2694
2695 // If MoveToPage succeeds, we MUST be on the right page.
2696 _ASSERTE(addr >= mCurrPageStart);
2697
2698 // However, the amount of data requested may fall off of the page. In that case,
2699 // fall back to MisalignedRead.
2700 TADDR offset = addr - mCurrPageStart;
2701 if (offset + sizeof(T) > mCurrPageSize)
2702 return MisalignedRead(addr, t);
2703
2704 // If we reach here we know we are on the right page of memory in the cache, and
2705 // that the read won't fall off of the end of the page.
2706#ifdef _DEBUG
2707 mReads++;
2708#endif
2709
2710 *t = *reinterpret_cast<T*>(mPage+offset);
2711 return true;
2712 }
2713
2714 void EnsureRangeInCache(TADDR start, unsigned int size)
2715 {
2716 if (mCurrPageStart == start)
2717 {
2718 if (size <= mCurrPageSize)
2719 return;
2720
2721 // Total bytes to read, don't overflow buffer.
2722 unsigned int total = size + mCurrPageSize;
2723 if (total + mCurrPageSize > mPageSize)
2724 total = mPageSize-mCurrPageSize;
2725
2726 // Read into the middle of the buffer, update current page size.
2727 ULONG read = 0;
2728 HRESULT hr = g_ExtData->ReadVirtual(mCurrPageStart+mCurrPageSize, mPage+mCurrPageSize, total, &read);
2729 mCurrPageSize += read;
2730
2731 if (hr != S_OK)
2732 {
2733 mCurrPageStart = 0;
2734 mCurrPageSize = 0;
2735 }
2736 }
2737 else
2738 {
2739 MoveToPage(start, size);
2740 }
2741 }
2742
2743 void ClearStats()
2744 {
2745#ifdef _DEBUG
2746 mMisses = 0;
2747 mReads = 0;
2748 mMisaligned = 0;
2749#endif
2750 }
2751
2752 void PrintStats(const char *func)
2753 {
2754#ifdef _DEBUG
2755 char buffer[1024];
2756 sprintf_s(buffer, _countof(buffer), "Cache (%s): %d reads (%2.1f%% hits), %d misses (%2.1f%%), %d misaligned (%2.1f%%).\n",
2757 func, mReads, 100*(mReads-mMisses)/(float)(mReads+mMisaligned), mMisses,
2758 100*mMisses/(float)(mReads+mMisaligned), mMisaligned, 100*mMisaligned/(float)(mReads+mMisaligned));
2759 OutputDebugStringA(buffer);
2760#endif
2761 }
2762
2763private:
2764 /* Sets the cache to the page specified by addr, or false if we could not move to
2765 * that page.
2766 */
2767 bool MoveToPage(TADDR addr, unsigned int size = 0x18);
2768
2769 /* Attempts to read from the target process if the data is possibly hanging off
2770 * the end of a page.
2771 */
2772 template<class T>
2773 inline bool MisalignedRead(TADDR addr, T *t)
2774 {
2775 ULONG fetched = 0;
2776 HRESULT hr = g_ExtData->ReadVirtual(addr, (BYTE*)t, sizeof(T), &fetched);
2777
2778 if (FAILED(hr) || fetched != sizeof(T))
2779 return false;
2780
2781 mMisaligned++;
2782 return true;
2783 }
2784
2785private:
2786 TADDR mCurrPageStart;
2787 ULONG mPageSize, mCurrPageSize;
2788 BYTE *mPage;
2789
2790 int mMisses, mReads, mMisaligned;
2791};
2792
2793
2794///////////////////////////////////////////////////////////////////////////////////////////
2795//
2796// Methods for creating a database out of the gc heap and it's roots in xml format or CLRProfiler format
2797//
2798
2799#include <unordered_map>
2800#include <unordered_set>
2801#include <list>
2802
2803class TypeTree;
2804enum { FORMAT_XML=0, FORMAT_CLRPROFILER=1 };
2805enum { TYPE_START=0,TYPE_TYPES=1,TYPE_ROOTS=2,TYPE_OBJECTS=3,TYPE_HIGHEST=4};
2806class HeapTraverser
2807{
2808private:
2809 TypeTree *m_pTypeTree;
2810 size_t m_curNID;
2811 FILE *m_file;
2812 int m_format; // from the enum above
2813 size_t m_objVisited; // for UI updates
2814 bool m_verify;
2815 LinearReadCache mCache;
2816
2817 std::unordered_map<TADDR, std::list<TADDR>> mDependentHandleMap;
2818
2819public:
2820 HeapTraverser(bool verify);
2821 ~HeapTraverser();
2822
2823 FILE *getFile() { return m_file; }
2824
2825 BOOL Initialize();
2826 BOOL CreateReport (FILE *fp, int format);
2827
2828private:
2829 // First all types are added to a tree
2830 void insert(size_t mTable);
2831 size_t getID(size_t mTable);
2832
2833 // Functions for writing to the output file.
2834 void PrintType(size_t ID,LPCWSTR name);
2835
2836 void PrintObjectHead(size_t objAddr,size_t typeID,size_t Size);
2837 void PrintObjectMember(size_t memberValue, bool dependentHandle);
2838 void PrintLoaderAllocator(size_t memberValue);
2839 void PrintObjectTail();
2840
2841 void PrintRootHead();
2842 void PrintRoot(LPCWSTR kind,size_t Value);
2843 void PrintRootTail();
2844
2845 void PrintSection(int Type,BOOL bOpening);
2846
2847 // Root and object member helper functions
2848 void FindGCRootOnStacks();
2849 void PrintRefs(size_t obj, size_t methodTable, size_t size);
2850
2851 // Callback functions used during traversals
2852 static void GatherTypes(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable, LPVOID token);
2853 static void PrintHeap(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable, LPVOID token);
2854 static void PrintOutTree(size_t methodTable, size_t ID, LPVOID token);
2855 void TraceHandles();
2856};
2857
2858
2859class GCRootImpl
2860{
2861private:
2862 struct MTInfo
2863 {
2864 TADDR MethodTable;
2865 WCHAR *TypeName;
2866
2867 TADDR *Buffer;
2868 CGCDesc *GCDesc;
2869
2870 TADDR LoaderAllocatorObjectHandle;
2871 bool ArrayOfVC;
2872 bool ContainsPointers;
2873 bool Collectible;
2874 size_t BaseSize;
2875 size_t ComponentSize;
2876
2877 const WCHAR *GetTypeName()
2878 {
2879 if (!TypeName)
2880 TypeName = CreateMethodTableName(MethodTable);
2881
2882 if (!TypeName)
2883 return W("<error>");
2884
2885 return TypeName;
2886 }
2887
2888 MTInfo()
2889 : MethodTable(0), TypeName(0), Buffer(0), GCDesc(0),
2890 ArrayOfVC(false), ContainsPointers(false), Collectible(false), BaseSize(0), ComponentSize(0)
2891 {
2892 }
2893
2894 ~MTInfo()
2895 {
2896 if (Buffer)
2897 delete [] Buffer;
2898
2899 if (TypeName)
2900 delete [] TypeName;
2901 }
2902 };
2903
2904 struct RootNode
2905 {
2906 RootNode *Next;
2907 RootNode *Prev;
2908 TADDR Object;
2909 MTInfo *MTInfo;
2910
2911 bool FilledRefs;
2912 bool FromDependentHandle;
2913 RootNode *GCRefs;
2914
2915
2916 const WCHAR *GetTypeName()
2917 {
2918 if (!MTInfo)
2919 return W("<unknown>");
2920
2921 return MTInfo->GetTypeName();
2922 }
2923
2924 RootNode()
2925 : Next(0), Prev(0)
2926 {
2927 Clear();
2928 }
2929
2930 void Clear()
2931 {
2932 if (Next && Next->Prev == this)
2933 Next->Prev = NULL;
2934
2935 if (Prev && Prev->Next == this)
2936 Prev->Next = NULL;
2937
2938 Next = 0;
2939 Prev = 0;
2940 Object = 0;
2941 MTInfo = 0;
2942 FilledRefs = false;
2943 FromDependentHandle = false;
2944 GCRefs = 0;
2945 }
2946
2947 void Remove(RootNode *&list)
2948 {
2949 RootNode *curr_next = Next;
2950
2951 // We've already considered this object, remove it.
2952 if (Prev == NULL)
2953 {
2954 // If we've filtered out the head, update it.
2955 list = curr_next;
2956
2957 if (curr_next)
2958 curr_next->Prev = NULL;
2959 }
2960 else
2961 {
2962 // Otherwise remove the current item from the list
2963 Prev->Next = curr_next;
2964
2965 if (curr_next)
2966 curr_next->Prev = Prev;
2967 }
2968 }
2969 };
2970
2971public:
2972 static void GetDependentHandleMap(std::unordered_map<TADDR, std::list<TADDR>> &map);
2973
2974public:
2975 // Finds all objects which root "target" and prints the path from the root
2976 // to "target". If all is true, all possible paths to the object are printed.
2977 // If all is false, only completely unique paths will be printed.
2978 int PrintRootsForObject(TADDR obj, bool all, bool noStacks);
2979
2980 // Finds a path from root to target if it exists and prints it out. Returns
2981 // true if it found a path, false otherwise.
2982 bool PrintPathToObject(TADDR root, TADDR target);
2983
2984 // Calculates the size of the closure of objects kept alive by root.
2985 size_t ObjSize(TADDR root);
2986
2987 // Walks each root, printing out the total amount of memory held alive by it.
2988 void ObjSize();
2989
2990 // Returns the set of all live objects in the process.
2991 const std::unordered_set<TADDR> &GetLiveObjects(bool excludeFQ = false);
2992
2993 // See !FindRoots.
2994 int FindRoots(int gen, TADDR target);
2995
2996private:
2997 // typedefs
2998 typedef void (*ReportCallback)(TADDR root, RootNode *path, bool printHeader);
2999
3000 // Book keeping and debug.
3001 void ClearAll();
3002 void ClearNodes();
3003 void ClearSizeData();
3004
3005 // Printing roots
3006 int PrintRootsOnHandleTable(int gen = -1);
3007 int PrintRootsOnAllThreads();
3008 int PrintRootsOnThread(DWORD osThreadId);
3009 int PrintRootsOnFQ(bool notReadyForFinalization = false);
3010 int PrintRootsInOlderGen();
3011 int PrintRootsInRange(LinearReadCache &cache, TADDR start, TADDR stop, ReportCallback func, bool printHeader);
3012
3013 // Calculate gc root
3014 RootNode *FilterRoots(RootNode *&list);
3015 RootNode *FindPathToTarget(TADDR root);
3016 RootNode *GetGCRefs(RootNode *path, RootNode *node);
3017
3018 void InitDependentHandleMap();
3019
3020 //Reporting:
3021 void ReportOneHandlePath(const SOSHandleData &handle, RootNode *node, bool printHeader);
3022 void ReportOnePath(DWORD thread, const SOSStackRefData &stackRef, RootNode *node, bool printThread, bool printFrame);
3023 static void ReportOneFQEntry(TADDR root, RootNode *path, bool printHeader);
3024 static void ReportOlderGenEntry(TADDR root, RootNode *path, bool printHeader);
3025 void ReportSizeInfo(const SOSHandleData &handle, TADDR obj);
3026 void ReportSizeInfo(DWORD thread, const SOSStackRefData &ref, TADDR obj);
3027
3028 // Data reads:
3029 TADDR ReadPointer(TADDR location);
3030 TADDR ReadPointerCached(TADDR location);
3031
3032 // Object/MT data:
3033 MTInfo *GetMTInfo(TADDR mt);
3034 DWORD GetComponents(TADDR obj, TADDR mt);
3035 size_t GetSizeOfObject(TADDR obj, MTInfo *info);
3036
3037 // RootNode management:
3038 RootNode *NewNode(TADDR obj = 0, MTInfo *mtinfo = 0, bool fromDependent = false);
3039 void DeleteNode(RootNode *node);
3040
3041private:
3042
3043 bool mAll, // Print all roots or just unique roots?
3044 mSize; // Print rooting information or total size info?
3045
3046 std::list<RootNode*> mCleanupList; // A list of RootNode's we've newed up. This is only used to delete all of them later.
3047 std::list<RootNode*> mRootNewList; // A list of unused RootNodes that are free to use instead of having to "new" up more.
3048
3049 std::unordered_map<TADDR, MTInfo*> mMTs; // The MethodTable cache which maps from MT -> MethodTable data (size, gcdesc, string typename)
3050 std::unordered_map<TADDR, RootNode*> mTargets; // The objects that we are searching for.
3051 std::unordered_set<TADDR> mConsidered; // A hashtable of objects we've already visited.
3052 std::unordered_map<TADDR, size_t> mSizes; // A mapping from object address to total size of data the object roots.
3053
3054 std::unordered_map<TADDR, std::list<TADDR>> mDependentHandleMap;
3055
3056 LinearReadCache mCache; // A linear cache which stops us from having to read from the target process more than 1-2 times per object.
3057};
3058
3059//
3060// Helper class used for type-safe bitflags
3061// T - the enum type specifying the individual bit flags
3062// U - the underlying/storage type
3063// Requirement:
3064// sizeof(T) <= sizeof(U)
3065//
3066template <typename T, typename U>
3067struct Flags
3068{
3069 typedef T UnderlyingType;
3070 typedef U BitFlagEnumType;
3071
3072 static_assert_no_msg(sizeof(BitFlagEnumType) <= sizeof(UnderlyingType));
3073
3074 Flags(UnderlyingType v)
3075 : m_val(v)
3076 { }
3077
3078 Flags(BitFlagEnumType v)
3079 : m_val(v)
3080 { }
3081
3082 Flags(const Flags& other)
3083 : m_val(other.m_val)
3084 { }
3085
3086 Flags& operator = (const Flags& other)
3087 { m_val = other.m_val; return *this; }
3088
3089 Flags operator | (Flags other) const
3090 { return Flags<T, U>(m_val | other._val); }
3091
3092 void operator |= (Flags other)
3093 { m_val |= other.m_val; }
3094
3095 Flags operator & (Flags other) const
3096 { return Flags<T, U>(m_val & other.m_val); }
3097
3098 void operator &= (Flags other)
3099 { m_val &= other.m_val; }
3100
3101 Flags operator ^ (Flags other) const
3102 { return Flags<T, U>(m_val ^ other._val); }
3103
3104 void operator ^= (Flags other)
3105 { m_val ^= other.m_val; }
3106
3107 BOOL operator == (Flags other) const
3108 { return m_val == other.m_val; }
3109
3110 BOOL operator != (Flags other) const
3111 { return m_val != other.m_val; }
3112
3113
3114private:
3115 UnderlyingType m_val;
3116};
3117
3118#ifndef FEATURE_PAL
3119
3120// Flags defining activation policy for COM objects
3121enum CIOptionsBits
3122{
3123 cciLatestFx = 0x01, // look in the most recent .NETFx installation
3124 cciMatchFx = 0x02, // NYI: Look in the .NETFx installation matching the debuggee's runtime
3125 cciAnyFx = 0x04, // look in any .NETFx installation
3126 cciFxMask = 0x0f,
3127 cciDbiColocated = 0x10, // NYI: Look next to the already loaded DBI module
3128 cciDacColocated = 0x20, // Look next to the already loaded DAC module
3129 cciDbgPath = 0x40, // Look in all folders in the debuggers symbols and binary path
3130};
3131
3132typedef Flags<DWORD, CIOptionsBits> CIOptions;
3133
3134/**********************************************************************\
3135* Routine Description: *
3136* *
3137* CreateInstanceCustom() provides a way to activate a COM object w/o *
3138* triggering the FeatureOnDemand dialog. In order to do this we *
3139* must avoid using the CoCreateInstance() API, which, on a machine *
3140* with v4+ installed and w/o v2, would trigger this. *
3141* CreateInstanceCustom() activates the requested COM object according *
3142* to the specified passed in CIOptions, in the following order *
3143* (skipping the steps not enabled in the CIOptions flags passed in): *
3144* 1. Attempt to activate the COM object using a framework install: *
3145* a. If the debugger machine has a V4+ shell shim use the shim *
3146* to activate the object *
3147* b. Otherwise simply call CoCreateInstance *
3148* 2. If unsuccessful attempt to activate looking for the dllName in *
3149* the same folder as the DAC was loaded from *
3150* 3. If unsuccessful attempt to activate the COM object looking in *
3151* every path specified in the debugger's .exepath and .sympath *
3152\**********************************************************************/
3153HRESULT CreateInstanceCustom(
3154 REFCLSID clsid,
3155 REFIID iid,
3156 LPCWSTR dllName,
3157 CIOptions cciOptions,
3158 void** ppItf);
3159
3160
3161//------------------------------------------------------------------------
3162// A typesafe version of GetProcAddress
3163//------------------------------------------------------------------------
3164template <typename T>
3165BOOL
3166GetProcAddressT(
3167 ___in PCSTR FunctionName,
3168 __in_opt PCWSTR DllName,
3169 __inout T* OutFunctionPointer,
3170 __inout HMODULE* InOutDllHandle
3171 )
3172{
3173 _ASSERTE(InOutDllHandle != NULL);
3174 _ASSERTE(OutFunctionPointer != NULL);
3175
3176 T FunctionPointer = NULL;
3177 HMODULE DllHandle = *InOutDllHandle;
3178 if (DllHandle == NULL)
3179 {
3180 DllHandle = LoadLibraryExW(DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
3181 if (DllHandle != NULL)
3182 *InOutDllHandle = DllHandle;
3183 }
3184 if (DllHandle != NULL)
3185 {
3186 FunctionPointer = (T) GetProcAddress(DllHandle, FunctionName);
3187 }
3188 *OutFunctionPointer = FunctionPointer;
3189 return FunctionPointer != NULL;
3190}
3191
3192
3193#endif // FEATURE_PAL
3194
3195struct ImageInfo
3196{
3197 ULONG64 modBase;
3198};
3199
3200// Helper class used in ClrStackFromPublicInterface() to keep track of explicit EE Frames
3201// (i.e., "internal frames") on the stack. Call Init() with the appropriate
3202// ICorDebugThread3, and this class will initialize itself with the set of internal
3203// frames. You can then call PrintPrecedingInternalFrames during your stack walk to
3204// have this class output any internal frames that "precede" (i.e., that are closer to
3205// the leaf than) the specified ICorDebugFrame.
3206class InternalFrameManager
3207{
3208private:
3209 // TODO: Verify constructor AND destructor is called for each array element
3210 // TODO: Comment about hard-coding 1000
3211 ToRelease<ICorDebugInternalFrame2> m_rgpInternalFrame2[1000];
3212 ULONG32 m_cInternalFramesActual;
3213 ULONG32 m_iInternalFrameCur;
3214
3215public:
3216 InternalFrameManager();
3217 HRESULT Init(ICorDebugThread3 * pThread3);
3218 HRESULT PrintPrecedingInternalFrames(ICorDebugFrame * pFrame);
3219
3220private:
3221 HRESULT PrintCurrentInternalFrame();
3222};
3223
3224#endif // __util_h__
3225