// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//*****************************************************************************
// File: daccess.h
//

//
// Support for external access of runtime data structures.  These
// macros and templates hide the details of pointer and data handling
// so that data structures and code can be compiled to work both
// in-process and through a special memory access layer.
//
// This code assumes the existence of two different pieces of code,
// the target, the runtime code that is going to be examined, and
// the host, the code that's doing the examining.  Access to the
// target is abstracted so the target may be a live process on the
// same machine, a live process on a different machine, a dump file
// or whatever.  No assumptions should be made about accessibility
// of the target.
//
// This code assumes that the data in the target is static.  Any
// time the target's data changes the interfaces must be reset so
// that potentially stale data is discarded.
//
// This code is intended for read access and there is no
// way to write data back currently.
//
// DAC-ized code:
// - is read-only (non-invasive). So DACized codepaths can not trigger a GC.
// - has no Thread* object.  In reality, DAC-ized codepaths are
//   ReadProcessMemory calls from out-of-process. Conceptually, they
//   are like a pure-native (preemptive) thread.
////
// This means that in particular, you cannot DACize a GCTRIGGERS function.
// Neither can you DACize a function that throws if this will involve
// allocating a new exception object. There may be
// exceptions to these rules if you can guarantee that the DACized
// part of the code path cannot cause a garbage collection (see
// EditAndContinueModule::ResolveField for an example).
// If you need to DACize a function that may trigger
// a GC, it is probably best to refactor the function so that the DACized
// part of the code path is in a separate function. For instance,
// functions with GetOrCreate() semantics are hard to DAC-ize because
// they the Create portion is inherently invasive. Instead, consider refactoring
// into a GetOrFail() function that DAC can call; and then make GetOrCreate()
// a wrapper around that.

//
// This code works by hiding the details of access to target memory.
// Access is divided into two types:
// 1. DPTR - access to a piece of data.
// 2. VPTR - access to a class with a vtable.  The class can only have
//           a single vtable pointer at the beginning of the class instance.
// Things only need to be declared as VPTRs when it is necessary to
// call virtual functions in the host.  In that case the access layer
// must do extra work to provide a host vtable for the object when
// it is retrieved so that virtual functions can be called.
//
// When compiling with DACCESS_COMPILE the macros turn into templates
// which replace pointers with smart pointers that know how to fetch
// data from the target process and provide a host process version of it.
// Normal data structure access will transparently receive a host copy
// of the data and proceed, so code such as
//     typedef DPTR(Class) PTR_Class;
//     PTR_Class cls;
//     int val = cls->m_Int;
// will work without modification.  The appropriate operators are overloaded
// to provide transparent access, such as the -> operator in this case.
// Note that the convention is to create an appropriate typedef for
// each type that will be accessed.  This hides the particular details
// of the type declaration and makes the usage look more like regular code.
//
// The ?PTR classes also have an implicit base type cast operator to
// produce a host-pointer instance of the given type.  For example
//     Class* cls = PTR_Class(addr);
// works by implicit conversion from the PTR_Class created by wrapping
// to a host-side Class instance.  Again, this means that existing code
// can work without modification.
//
// Code Example:
//
// typedef struct _rangesection
// {
//     PTR_IJitManager pjit;
//     PTR_RangeSection pright;
//     PTR_RangeSection pleft;
//     ... Other fields omitted ...
// } RangeSection;
//
//     RangeSection* pRS = m_RangeTree;
//
//     while (pRS != NULL)
//     {
//         if (currentPC < pRS->LowAddress)
//             pRS=pRS->pleft;
//         else if (currentPC > pRS->HighAddress)
//             pRS=pRS->pright;
//         else
//         {
//             return pRS->_pjit;
//         }
//     }
//
// This code does not require any modifications.  The global reference
// provided by m_RangeTree will be a host version of the RangeSection
// instantiated by conversion.  The references to pRS->pleft and
// pRS->pright will refer to DPTRs due to the modified declaration.
// In the assignment statement the compiler will automatically use
// the implicit conversion from PTR_RangeSection to RangeSection*,
// causing a host instance to be created.  Finally, if an appropriate
// section is found the use of pRS->_pjit will cause an implicit
// conversion from PTR_IJitManager to IJitManager.  The VPTR code
// will look at target memory to determine the actual derived class
// for the JitManager and instantiate the right class in the host so
// that host virtual functions can be used just as they would in
// the target.
//
// There are situations where code modifications are required, though.
//
// 1.  Any time the actual value of an address matters, such as using
//     it as a search key in a tree, the target address must be used.
//
// An example of this is the RangeSection tree used to locate JIT
// managers.  A portion of this code is shown above.  Each
// RangeSection node in the tree describes a range of addresses
// managed by the JitMan.  These addresses are just being used as
// values, not to dereference through, so there are not DPTRs.  When
// searching the range tree for an address the address used in the
// search must be a target address as that's what values are kept in
// the RangeSections.  In the code shown above, currentPC must be a
// target address as the RangeSections in the tree are all target
// addresses.  Use dac_cast<TADDR> to retrieve the target address
// of a ?PTR, as well as to convert a host address to the
// target address used to retrieve that particular instance. Do not
// use dac_cast with any raw target pointer types (such as BYTE*).
//
// 2.  Any time an address is modified, such as by address arithmetic,
//     the arithmetic must be performed on the target address.
//
// When a host instance is created it is created for the type in use.
// There is no particular relation to any other instance, so address
// arithmetic cannot be used to get from one instance to any other
// part of memory.  For example
//     char* Func(Class* cls)
//     {
//         // String follows the basic Class data.
//         return (char*)(cls + 1);
//     }
// does not work with external access because the Class* used would
// have retrieved only a Class worth of data.  There is no string
// following the host instance.  Instead, this code should use
// dac_cast<TADDR> to get the target address of the Class
// instance, add sizeof(*cls) and then create a new ?PTR to access
// the desired data.  Note that the newly retrieved data will not
// be contiguous with the Class instance, so address arithmetic
// will still not work.
//
// Previous Code:
//
//     BOOL IsTarget(LPVOID ip)
//     {
//         StubCallInstrs* pStubCallInstrs = GetStubCallInstrs();
//
//         if (ip == (LPVOID) &(pStubCallInstrs->m_op))
//         {
//             return TRUE;
//         }
//
// Modified Code:
//
//     BOOL IsTarget(LPVOID ip)
//     {
//         StubCallInstrs* pStubCallInstrs = GetStubCallInstrs();
//
//         if ((TADDR)ip == dac_cast<TADDR>(pStubCallInstrs) +
//             (TADDR)offsetof(StubCallInstrs, m_op))
//         {
//             return TRUE;
//         }
//
// The parameter ip is a target address, so the host pStubCallInstrs
// cannot be used to derive an address from.  The member & reference
// has to be replaced with a conversion from host to target address
// followed by explicit offsetting for the field.
//
// PTR_HOST_MEMBER_TADDR is a convenience macro that encapsulates
// these two operations, so the above code could also be:
//
//     if ((TADDR)ip ==
//         PTR_HOST_MEMBER_TADDR(StubCallInstrs, pStubCallInstrs, m_op))
//
// 3.  Any time the amount of memory referenced through an address
//     changes, such as by casting to a different type, a new ?PTR
//     must be created.
//
// Host instances are created and stored based on both the target
// address and size of access.  The access code has no way of knowing
// all possible ways that data will be retrieved for a given address
// so if code changes the way it accesses through an address a new
// ?PTR must be used, which may lead to a difference instance and
// different host address.  This means that pointer identity does not hold
// across casts, so code like
//     Class* cls = PTR_Class(addr);
//     Class2* cls2 = PTR_Class2(addr);
//     return cls == cls2;
// will fail because the host-side instances have no relation to each
// other.  That isn't a problem, since by rule #1 you shouldn't be
// relying on specific host address values.
//
// Previous Code:
//
//     return (ArrayClass *) m_pMethTab->GetClass();
//
// Modified Code:
//
//     return PTR_ArrayClass(m_pMethTab->GetClass());
//
// The ?PTR templates have an implicit conversion from a host pointer
// to a target address, so the cast above constructs a new
// PTR_ArrayClass by implicitly converting the host pointer result
// from GetClass() to its target address and using that as the address
// of the new PTR_ArrayClass.  As mentioned, the actual host-side
// pointer values may not be the same.
//
// Host pointer identity can be assumed as long as the type of access
// is the same.  In the example above, if both accesses were of type
// Class then the host pointer will be the same, so it is safe to
// retrieve the target address of an instance and then later get
// a new host pointer for the target address using the same type as
// the host pointer in that case will be the same.  This is enabled
// by caching all of the retrieved host instances.  This cache is searched
// by the addr:size pair and when there's a match the existing instance
// is reused.  This increases performance and also allows simple
// pointer identity to hold.  It does mean that host memory grows
// in proportion to the amount of target memory being referenced,
// so retrieving extraneous data should be avoided.
// The host-side data cache grows until the Flush() method is called,
// at which point all host-side data is discarded.  No host
// instance pointers should be held across a Flush().
//
// Accessing into an object can lead to some unusual behavior.  For
// example, the SList class relies on objects to contain an SLink
// instance that it uses for list maintenance.  This SLink can be
// embedded anywhere in the larger object.  The SList access is always
// purely to an SLink, so when using the access layer it will only
// retrieve an SLink's worth of data.  The SList template will then
// do some address arithmetic to determine the start of the real
// object and cast the resulting pointer to the final object type.
// When using the access layer this results in a new ?PTR being
// created and used, so a new instance will result.  The internal
// SLink instance will have no relation to the new object instance
// even though in target address terms one is embedded in the other.
// The assumption of data stability means that this won't cause
// a problem, but care must be taken with the address arithmetic,
// as laid out in rules #2 and #3.
//
// 4.  Global address references cannot be used.  Any reference to a
//     global piece of code or data, such as a function address, global
//     variable or class static variable, must be changed.
//
// The external access code may load at a different base address than
// the target process code.  Global addresses are therefore not
// meaningful and must be replaced with something else.  There isn't
// a single solution, so replacements must be done on a case-by-case
// basis.
//
// The simplest case is a global or class static variable.  All
// declarations must be replaced with a special declaration that
// compiles into a modified accessor template value when compiled for
// external data access.  Uses of the variable automatically are fixed
// up by the template instance.  Note that assignment to the global
// must be independently ifdef'ed as the external access layer should
// not make any modifications.
//
// Macros allow for simple declaration of a class static and global
// values that compile into an appropriate templated value.
//
// Previous Code:
//
//     static RangeSection* m_RangeTree;
//     RangeSection* ExecutionManager::m_RangeTree;
//
//     extern ThreadStore* g_pThreadStore;
//     ThreadStore* g_pThreadStore = &StaticStore;
//     class SystemDomain : public BaseDomain {
//         ...
//         ArrayListStatic m_appDomainIndexList;
//         ...
//     }
//
//     SystemDomain::m_appDomainIndexList;
//
//     extern DWORD gThreadTLSIndex;
//
//     DWORD gThreadTLSIndex = TLS_OUT_OF_INDEXES;
//
// Modified Code:
//
//     typedef DPTR(RangeSection) PTR_RangeSection;
//     SPTR_DECL(RangeSection, m_RangeTree);
//     SPTR_IMPL(RangeSection, ExecutionManager, m_RangeTree);
//
//     typedef DPTR(ThreadStore) PTR_ThreadStore
//     GPTR_DECL(ThreadStore, g_pThreadStore);
//     GPTR_IMPL_INIT(ThreadStore, g_pThreadStore, &StaticStore);
//
//     class SystemDomain : public BaseDomain {
//         ...
//         SVAL_DECL(ArrayListStatic; m_appDomainIndexList);
//         ...
//     }
//
//     SVAL_IMPL(ArrayListStatic, SystemDomain, m_appDomainIndexList);
//
//     GVAL_DECL(DWORD, gThreadTLSIndex);
//
//     GVAL_IMPL_INIT(DWORD, gThreadTLSIndex, TLS_OUT_OF_INDEXES);
//
// When declaring the variable, the first argument declares the
// variable's type and the second argument declares the variable's
// name.  When defining the variable the arguments are similar, with
// an extra class name parameter for the static class variable case.
// If an initializer is needed the IMPL_INIT macro should be used.
//
// Things get slightly more complicated when declaring an embedded
// array.  In this case the data element is not a single element and
// therefore cannot be represented by a ?PTR. In the case of a global
// array, you should use the GARY_DECL and GARY_IMPL macros.
// We durrently have no support for declaring static array data members
// or initialized arrays. Array data members that are dynamically allocated
// need to be treated as pointer members. To reference individual elements
// you must use pointer arithmetic (see rule 2 above). An array declared
// as a local variable within a function does not need to be DACized.
//
//
// All uses of ?VAL_DECL must have a corresponding entry given in the
// DacGlobals structure in src\inc\dacvars.h.  For SVAL_DECL the entry
// is class__name.  For GVAL_DECL the entry is dac__name. You must add
// these entries in dacvars.h using the DEFINE_DACVAR macro. Note that
// these entries also are used for dumping memory in mini dumps and
// heap dumps. If it's not appropriate to dump a variable, (e.g.,
// it's an array or some other value that is not important to have
// in a minidump) a second macro, DEFINE_DACVAR_NO_DUMP, will allow
// you to make the required entry in the DacGlobals structure without
// dumping its value. If the variable is implemented with one of the VOLATILE_* macros
// then the DEFINE_DACVAR_VOLATILE macro must be used.
//
// For convenience, here is a list of the various variable declaration and
// initialization macros:
// SVAL_DECL(type, name)      static non-pointer data   class MyClass
//                            member declared within    {
//                            the class declaration        // static int i;
//                                                         SVAL_DECL(int, i);
//                                                      }
//
// SVAL_IMPL(type, cls, name) static non-pointer data   // int MyClass::i;
//                            member defined outside    SVAL_IMPL(int, MyClass, i);
//                            the class declaration
//
// SVAL_IMPL_INIT(type, cls,  static non-pointer data   // int MyClass::i = 0;
//                name, val)  member defined and        SVAL_IMPL_INIT(int, MyClass, i, 0);
//                            initialized outside the
//                            class declaration
// ------------------------------------------------------------------------------------------------
// VOLATILE_SVAL_DECL(type, name)    static volatile   class MyClass
//                                   non-pointer data  {
//                                   member declared      // static Volatile<int> i;
//                                   within the class     VOLATILE_SVAL_DECL(int, i);
//                                    declaration      }
//
// VOLATILE_SVAL_IMPL(type, cls,     static volatile
//                    name)          non-pointer data  // Volatile<int> MyClass::i;
//                                   member defined    VOLATILE_SVAL_IMPL(int, MyClass, i);
//                                   outside the
//                                   class declaration
//
// VOLATILE_SVAL_IMPL_INIT(          static volatile
//    type, cls, name)               non-pointer data  // Volatile<int> MyClass::i = 0;
//                                   member defined    VOLATILE_SVAL_IMPL_INIT(int, MyClass, i, 0);
//                                   and initialized
//                                   outside the
//                                   class declaration
// ------------------------------------------------------------------------------------------------
// SPTR_DECL(type, name)      static pointer data       class MyClass
//                            member declared within    {
//                            the class declaration        // static int * pInt;
//                                                         SPTR_DECL(int, pInt);
//                                                      }
//
// SPTR_IMPL(type, cls, name) static pointer data       // int * MyClass::pInt;
//                            member defined outside    SPTR_IMPL(int, MyClass, pInt);
//                            the class declaration
//
// SPTR_IMPL_INIT(type, cls,  static pointer data       // int * MyClass::pInt = NULL;
//                name, val)  member defined and        SPTR_IMPL_INIT(int, MyClass, pInt, NULL);
//                            initialized outside the
//                            class declaration
// ------------------------------------------------------------------------------------------------
// VOLATILE_SPTR_DECL(type, name)    static volatile   class MyClass
//                                   pointer data      {
//                                   member declared      // static Volatile<int*> i;
//                                   within the class     VOLATILE_SPTR_DECL(int, i);
//                                    declaration      }
//
// VOLATILE_SPTR_IMPL(type, cls,     static volatile
//                    name)          pointer data      // Volatile<int*> MyClass::i;
//                                   member defined    VOLATILE_SPTR_IMPL(int, MyClass, i);
//                                   outside the
//                                   class declaration
//
// VOLATILE_SPTR_IMPL_INIT(          static volatile
//    type, cls, name)               pointer data      // Volatile<int*> MyClass::i = 0;
//                                   member defined    VOLATILE_SPTR_IMPL_INIT(int, MyClass, i, 0);
//                                   and initialized
//                                   outside the
//                                   class declaration
// ------------------------------------------------------------------------------------------------
// GVAL_DECL(type, name)      extern declaration of     // extern int g_i
//                            global non-pointer        GVAL_DECL(int, g_i);
//                            variable
//
// GVAL_IMPL(type, name)      declaration of a          // int g_i
//                            global non-pointer        GVAL_IMPL(int, g_i);
//                            variable
//
// GVAL_IMPL_INIT (type,      declaration and           // int g_i = 0;
//                 name,      initialization of a       GVAL_IMPL_INIT(int, g_i, 0);
//                 val)       global non-pointer
//                            variable
// ****Note****
// If you use GVAL_? to declare a global variable of a structured type and you need to
// access a member of the type, you cannot use the dot operator. Instead, you must take the
// address of the variable and use the arrow operator. For example:
// struct
// {
//    int x;
//    char ch;
// } MyStruct;
// GVAL_IMPL(MyStruct, g_myStruct);
// int i = (&g_myStruct)->x;
// ------------------------------------------------------------------------------------------------
// GPTR_DECL(type, name)      extern declaration of     // extern int * g_pInt
//                            global pointer            GPTR_DECL(int, g_pInt);
//                            variable
//
// GPTR_IMPL(type, name)      declaration of a          // int * g_pInt
//                            global pointer            GPTR_IMPL(int, g_pInt);
//                            variable
//
// GPTR_IMPL_INIT (type,      declaration and           // int * g_pInt = 0;
//                 name,      initialization of a       GPTR_IMPL_INIT(int, g_pInt, NULL);
//                 val)       global pointer
//                            variable
// ------------------------------------------------------------------------------------------------
// GARY_DECL(type, name)      extern declaration of     // extern int g_rgIntList[MAX_ELEMENTS];
//                            a global array            GPTR_DECL(int, g_rgIntList, MAX_ELEMENTS);
//                            variable
//
// GARY_IMPL(type, name)      declaration of a          // int g_rgIntList[MAX_ELEMENTS];
//                            global pointer            GPTR_IMPL(int, g_rgIntList, MAX_ELEMENTS);
//                            variable
//
//
// Certain pieces of code, such as the stack walker, rely on identifying
// an object from its vtable address.  As the target vtable addresses
// do not necessarily correspond to the vtables used in the host, these
// references must be translated.  The access layer maintains translation
// tables for all classes used with VPTR and can return the target
// vtable pointer for any host vtable in the known list of VPTR classes.
//
// ----- Errors:
//
// All errors in the access layer are reported via exceptions.  The
// formal access layer methods catch all such exceptions and turn
// them into the appropriate error, so this generally isn't visible
// to users of the access layer.
//
// ----- DPTR Declaration:
//
// Create a typedef for the type with typedef DPTR(type) PTR_type;
// Replace type* with PTR_type.
//
// ----- VPTR Declaration:
//
// VPTR can only be used on classes that have a single vtable
// pointer at the beginning of the object.  This should be true
// for a normal single-inheritance object.
//
// All of the classes that may be instantiated need to be identified
// and marked.  In the base class declaration add either
// VPTR_BASE_VTABLE_CLASS if the class is abstract or
// VPTR_BASE_CONCRETE_VTABLE_CLASS if the class is concrete.  In each
// derived class add VPTR_VTABLE_CLASS.  If you end up with compile or
// link errors for an unresolved method called VPtrSize you missed a
// derived class declaration.
//
//
// All classes to be instantiated must be listed in src\inc\vptr_list.h.
//
// Create a typedef for the type with typedef VPTR(type) PTR_type;
// When using a VPTR, replace Class* with PTR_Class.
//
// ----- Specific Macros:
//
// PTR_TO_TADDR(ptr)
// Retrieves the raw target address for a ?PTR.
// See code:dac_cast for the preferred alternative
//
// PTR_HOST_TO_TADDR(host)
// Given a host address of an instance produced by a ?PTR reference,
// return the original target address.  The host address must
// be an exact match for an instance.
// See code:dac_cast for the preferred alternative
//
// PTR_HOST_INT_TO_TADDR(host)
// Given a host address which resides somewhere within an instance
// produced by a ?PTR reference (a host interior pointer) return the
// corresponding target address. This is useful for evaluating
// relative pointers (e.g. RelativePointer<T>) where calculating the
// target address requires knowledge of the target address of the
// relative pointer field itself. This lookup is slower than that for
// a non-interior host pointer so use it sparingly.
//
// VPTR_HOST_VTABLE_TO_TADDR(host)
// Given the host vtable pointer for a known VPTR class, return
// the target vtable pointer.
//
// PTR_HOST_MEMBER_TADDR(type, host, memb)
// Retrieves the target address of a host instance pointer and
// offsets it by the given member's offset within the type.
//
// PTR_HOST_INT_MEMBER_TADDR(type, host, memb)
// As above but will work for interior host pointers (see the
// description of PTR_HOST_INT_TO_TADDR for an explanation of host
// interior pointers).
//
// PTR_READ(addr, size)
// Reads a block of memory from the target and returns a host
// pointer for it.  Useful for reading blocks of data from the target
// whose size is only known at runtime, such as raw code for a jitted
// method.  If the data being read is actually an object, use SPTR
// instead to get better type semantics.
//
// DAC_EMPTY()
// DAC_EMPTY_ERR()
// DAC_EMPTY_RET(retVal)
// DAC_UNEXPECTED()
// Provides an empty method implementation when compiled
// for DACCESS_COMPILE.  For example, use to stub out methods needed
// for vtable entries but otherwise unused.
//
// These macros are designed to turn into normal code when compiled
// without DACCESS_COMPILE.
//
//*****************************************************************************


#ifndef __daccess_h__
#define __daccess_h__

#ifndef NATIVEAOT
#include <stdint.h>

#if !defined(HOST_WINDOWS)
#include <pal_mstypes.h>
#endif

#include "switches.h"
#include "safemath.h"
#include "corerror.h"

// Keep in sync with the definitions in dbgutil.cpp and createdump.h
#define DACCESS_TABLE_SYMBOL "g_dacTable"

#include <type_traits>
#include "crosscomp.h"

#include <dn-u16.h>

// Information stored in the DAC table of interest to the DAC implementation
// Note that this information is shared between all instantiations of ClrDataAccess, so initialize
// it just once in code:ClrDataAccess.GetDacGlobals (rather than use fields in ClrDataAccess);
struct DacTableInfo
{
    // On Windows, the first DWORD is the 32-bit timestamp read out of the runtime dll's debug directory.
    // The remaining 3 DWORDS must all be 0.
    // On Mac, this is the 16-byte UUID of the runtime dll.
    // It is used to validate that mscorwks is the same version as mscordacwks
    DWORD dwID0;
    DWORD dwID1;
    DWORD dwID2;
    DWORD dwID3;
};

// The header of the DAC table.  This includes the number of globals, the number of vptrs, and
// the DacTableInfo structure.  We need the DacTableInfo and DacTableHeader structs outside
// of a DACCESS_COMPILE since soshost walks the Dac table headers to find the UUID of CoreCLR
// in the target process.
struct DacTableHeader
{
    ULONG numGlobals;
    ULONG numVptrs;
    DacTableInfo info;
};

//
// This version of things wraps pointer access in
// templates which understand how to retrieve data
// through an access layer.  In this case no assumptions
// can be made that the current compilation processor or
// pointer types match the target's processor or pointer types.
//

// Define TADDR as a non-pointer value so use of it as a pointer
// will not work properly.  Define it as unsigned so
// pointer comparisons aren't affected by sign.
typedef uintptr_t TADDR;

// TSIZE_T used for counts or ranges that need to span the size of a
// target pointer.  For cross-plat, this may be different than SIZE_T
// which reflects the host pointer size.
typedef SIZE_T TSIZE_T;


//
// The following table contains all the global information that data access needs to begin
// operation.  All of the values stored here are RVAs.  DacGlobalBase() returns the current
// base address to combine with to get a full target address.
//

typedef struct _DacGlobals
{
#ifdef _MSC_VER
private:
    const static _DacGlobals s_dacGlobals;
#else
    void InitializeEntries();
#endif
public:
    static void Initialize();

// These will define all of the dac related mscorwks static and global variables
#define DEFINE_DACVAR(size, id, var)                 TADDR id;
#define DEFINE_DACVAR_VOLATILE(size, id, var)        TADDR id;
#define DEFINE_DACVAR_NO_DUMP(size, id, var)         TADDR id;
#include "dacvars.h"
#undef DEFINE_DACVAR_VOLATILE
#undef DEFINE_DACVAR_NODUMP
#undef DEFINE_DACVAR

#define DEFINE_DACGFN(func) TADDR fn__##func;
#define DEFINE_DACGFN_STATIC(class, func) TADDR fn__##class##__##func;
#include "gfunc_list.h"
#undef DEFINE_DACGFN
#undef DEFINE_DACGFN_STATIC

    // Vtable pointer values for all classes that must
    // be instanted using vtable pointers as the identity.
#define VPTR_CLASS(name) TADDR name##__vtAddr;
#include "vptr_list.h"
#undef VPTR_CLASS
} DacGlobals;

#endif // !NATIVEAOT

#ifdef DACCESS_COMPILE

#ifdef __cplusplus
extern "C" {
#endif

// These two functions are largely just for marking code
// that is not fully converted.  DacWarning prints a debug
// message, while DacNotImpl throws a not-implemented exception.
void __cdecl DacWarning(_In_ _In_z_ char* format, ...);
void DacNotImpl(void);

void    DacError(HRESULT err);
void    DECLSPEC_NORETURN DacError_NoRet(HRESULT err);
TADDR   DacGlobalBase(void);
DacGlobals* DacGlobalValues(void);
HRESULT DacReadAll(TADDR addr, PVOID buffer, ULONG32 size, bool throwEx);
HRESULT DacWriteAll(TADDR addr, PVOID buffer, ULONG32 size, bool throwEx);
HRESULT DacAllocVirtual(TADDR addr, ULONG32 size,
                        ULONG32 typeFlags, ULONG32 protectFlags,
                        bool throwEx, TADDR* mem);
HRESULT DacFreeVirtual(TADDR mem, ULONG32 size, ULONG32 typeFlags,
                       bool throwEx);
PVOID   DacInstantiateTypeByAddress(TADDR addr, ULONG32 size, bool throwEx);
PVOID   DacInstantiateTypeByAddressNoReport(TADDR addr, ULONG32 size, bool throwEx);
PVOID   DacInstantiateClassByVTable(TADDR addr, ULONG32 minSize, bool throwEx);

// Copy a null-terminated ascii or unicode string from the target to the host.
// Note that most of the work here is to find the null terminator.  If you know the exact length,
// then you can also just call DacInstantiateTypebyAddress.
PSTR    DacInstantiateStringA(TADDR addr, ULONG32 maxChars, bool throwEx);
PWSTR   DacInstantiateStringW(TADDR addr, ULONG32 maxChars, bool throwEx);

TADDR   DacGetTargetAddrForHostAddr(LPCVOID ptr, bool throwEx);
TADDR   DacGetTargetAddrForHostInteriorAddr(LPCVOID ptr, bool throwEx);
TADDR   DacGetTargetVtForHostVt(LPCVOID vtHost, bool throwEx);
PWSTR   DacGetVtNameW(TADDR targetVtable);

// Report a region of memory to the debugger
bool    DacEnumMemoryRegion(TADDR addr, TSIZE_T size, bool fExpectSuccess = true);

// Report a region of memory to the debugger
bool DacUpdateMemoryRegion(TADDR addr, TSIZE_T bufferSize, BYTE* buffer);

HRESULT DacWriteHostInstance(PVOID host, bool throwEx);

// This is meant to mimic the RethrowTerminalExceptions/
// SwallowAllExceptions/RethrowTransientExceptions macros to allow minidump
// gathering cancelation for details see
// code:ClrDataAccess.EnumMemoryRegionsWrapper

extern void DacLogMessage(LPCSTR format, ...);

// This is usable in EX_TRY exactly how RethrowTerminalExceptions et cetera
#define RethrowCancelExceptions                                         \
    if (GET_EXCEPTION()->GetHR() == COR_E_OPERATIONCANCELED)            \
    {                                                                   \
        EX_RETHROW;                                                     \
    }                                                                   \
    DacLogMessage("DAC exception caught at %s:%d\n", __FILE__, __LINE__);

// Occasionally it's necessary to allocate some host memory for
// instance data that's created on the fly and so doesn't directly
// correspond to target memory.  These are held and freed on flush
// like other instances but can't be looked up by address.
PVOID DacAllocHostOnlyInstance(ULONG32 size, bool throwEx);

// Determines whether ASSERTs should be raised when inconsistencies in the target are detected
bool DacTargetConsistencyAssertsEnabled();

// Sets whether ASSERTs should be raised when then fail.
// Returns the previous value
bool DacSetEnableDacAssertsUnconditionally(bool enable);

class DacAssertsEnabledHolder
{
#ifdef _DEBUG
    bool m_fOldValue;
public:
    DacAssertsEnabledHolder()
    {
        m_fOldValue = DacSetEnableDacAssertsUnconditionally(true);
    }

    ~DacAssertsEnabledHolder()
    {
        DacSetEnableDacAssertsUnconditionally(m_fOldValue);
    }
#endif // _DEBUG
};

// Host instances can be marked as they are enumerated in
// order to break cycles.  This function returns true if
// the instance is already marked, otherwise it marks the
// instance and returns false.
bool DacHostPtrHasEnumMark(LPCVOID host);

// Determines if EnumMemoryRegions has been called on a method descriptor.
// This helps perf for minidumps of apps with large managed stacks.
bool DacHasMethodDescBeenEnumerated(LPCVOID pMD);

// Sets a flag indicating that EnumMemoryRegions on a method desciptor
// has been successfully called. The function returns true if
// this flag had been previously set.
bool DacSetMethodDescEnumerated(LPCVOID pMD);

// Determines if a method descriptor is valid
BOOL DacValidateMD(LPCVOID pMD);

// Enumerate the instructions around a call site to help debugger stack walking heuristics
void DacEnumCodeForStackwalk(TADDR taCallEnd);

// Given the address and the size of a memory range which is stored in the buffer, replace all the patches
// in the buffer with the real opcodes.  This is especially important on X64 where the unwinder needs to
// disassemble the native instructions.
class MemoryRange;
HRESULT DacReplacePatchesInHostMemory(MemoryRange range, PVOID pBuffer);

//
// Convenience macros for EnumMemoryRegions implementations.
//

// Enumerate the given host instance and return
// true if the instance hasn't already been enumerated.
#define DacEnumHostDPtrMem(host) \
    (!DacHostPtrHasEnumMark(host) ? \
     (DacEnumMemoryRegion(PTR_HOST_TO_TADDR(host), sizeof(*host)), \
      true) : false)
#define DacEnumHostSPtrMem(host, type) \
    (!DacHostPtrHasEnumMark(host) ? \
     (DacEnumMemoryRegion(PTR_HOST_TO_TADDR(host), \
                          type::DacSize(PTR_HOST_TO_TADDR(host))), \
      true) : false)
#define DacEnumHostVPtrMem(host) \
    (!DacHostPtrHasEnumMark(host) ? \
     (DacEnumMemoryRegion(PTR_HOST_TO_TADDR(host), (host)->VPtrSize()), \
      true) : false)

// Check enumeration of 'this' and return if this has already been
// enumerated.  Making this the first line of an object's EnumMemoryRegions
// method will prevent cycles.
#define DAC_CHECK_ENUM_THIS() \
    if (DacHostPtrHasEnumMark(this)) return
#define DAC_ENUM_DTHIS() \
    if (!DacEnumHostDPtrMem(this)) return
#define DAC_ENUM_STHIS(type) \
    if (!DacEnumHostSPtrMem(this, type)) return
#define DAC_ENUM_VTHIS() \
    if (!DacEnumHostVPtrMem(this)) return

#ifdef __cplusplus
}
class ReflectionModule;
interface IMDInternalImport* DacGetMDImport(const class PEAssembly* pPEAssembly,
                                            bool throwEx);
interface IMDInternalImport* DacGetMDImport(const ReflectionModule* reflectionModule,
                                            bool throwEx);

int DacGetIlMethodSize(TADDR methAddr);
struct COR_ILMETHOD* DacGetIlMethod(TADDR methAddr);
#ifdef FEATURE_EH_FUNCLETS
struct _UNWIND_INFO * DacGetUnwindInfo(TADDR taUnwindInfo);

// virtually unwind a CONTEXT out-of-process
BOOL DacUnwindStackFrame(T_CONTEXT * pContext, T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers);
#endif // FEATURE_EH_FUNCLETS

#if defined(TARGET_UNIX)
// call back through data target to unwind out-of-process
HRESULT DacVirtualUnwind(ULONG32 threadId, PT_CONTEXT context, PT_KNONVOLATILE_CONTEXT_POINTERS contextPointers);
#endif // TARGET_UNIX

#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
class SString;
void DacMdCacheAddEEName(TADDR taEE, const SString& ssEEName);
bool DacMdCacheGetEEName(TADDR taEE, SString & ssEEName);
#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS

//
// Computes (taBase + (dwIndex * dwElementSize()), with overflow checks.
//
// Arguments:
//     taBase          the base TADDR value
//     dwIndex         the index of the offset
//     dwElementSize   the size of each element (to multiply the offset by)
//
// Return value:
//     The resulting TADDR, or throws CORDB_E_TARGET_INCONSISTENT on overlow.
//
// Notes:
//     The idea here is that overflows during address arithmetic suggest that we're operating on corrupt
//     pointers.  It helps to improve reliability to detect the cases we can (like overflow) and fail.  Note
//     that this is just a heuristic, not a security measure.  We can't trust target data regardless -
//     failing on overflow is just one easy case of corruption to detect.  There is no need to use checked
//     arithmetic everywhere in the DAC infrastructure, this is intended just for the places most likely to
//     help catch bugs (eg. __DPtr::operator[]).
//
inline TADDR DacTAddrOffset( TADDR taBase, TSIZE_T dwIndex, TSIZE_T dwElementSize )
{
    ClrSafeInt<TADDR> t(taBase);
    t += ClrSafeInt<TSIZE_T>(dwIndex) * ClrSafeInt<TSIZE_T>(dwElementSize);
    if( t.IsOverflow() )
    {
        // Pointer arithmetic overflow - probably due to corrupt target data
        DacError(CORDBG_E_TARGET_INCONSISTENT);
    }
    return t.Value();
}


// Base pointer wrapper which provides common behavior.
class __TPtrBase
{
public:
    __TPtrBase()
    {
        // Make uninitialized pointers obvious.
        m_addr = (TADDR)-1;
    }
    __TPtrBase(TADDR addr)
    {
        m_addr = addr;
    }

    // We use this delayed check to avoid ambiguous overload issues with TADDR
    // on platforms where NULL is defined as anything other than a uintptr_t constant
    // or nullptr_t exactly.
    // Without this, any valid "null pointer constant" that is not directly either type
    // will be implicitly convertible to both TADDR and std::nullptr_t, causing ambiguity.
    // With this, this constructor (and all similarly declared operators) drop out of
    // consideration when used with NULL (and not nullptr_t).
    // With this workaround, we get identical behavior between the DAC and non-DAC builds for assigning NULL
    // to DACized pointer types.
    template<typename T, typename = typename std::enable_if<std::is_same<T, std::nullptr_t>::value>::type>
    __TPtrBase(T)
    {
        m_addr = 0;
    }

    __TPtrBase& operator=(TADDR addr)
    {
        m_addr = addr;
        return *this;
    }

    template<typename T, typename = typename std::enable_if<std::is_same<T, std::nullptr_t>::value>::type>
    __TPtrBase& operator=(T)
    {
        m_addr = 0;
        return *this;
    }

    bool operator!() const
    {
        return m_addr == 0;
    }

    // We'd like to have an explicit conversion to bool here since the C++
    // standard says all pointer types are implicitly converted to bool.
    // Unfortunately, that would cause ambiguous overload errors for uses
    // of operator== and operator!= with NULL on MSVC (where NULL is a 32-bit int on all platforms).
    // Instead callers will have to compare directly against NULL.

    bool operator==(TADDR addr) const
    {
        return m_addr == addr;
    }
    bool operator!=(TADDR addr) const
    {
        return m_addr != addr;
    }

    template<typename T, typename = typename std::enable_if<std::is_same<T, std::nullptr_t>::value>::type>
    bool operator==(T) const
    {
        return m_addr == 0;
    }

    template<typename T, typename = typename std::enable_if<std::is_same<T, std::nullptr_t>::value>::type>
    bool operator!=(T) const
    {
        return m_addr != 0;
    }
    bool operator<(TADDR addr) const
    {
        return m_addr < addr;
    }
    bool operator>(TADDR addr) const
    {
        return m_addr > addr;
    }
    bool operator<=(TADDR addr) const
    {
        return m_addr <= addr;
    }
    bool operator>=(TADDR addr) const
    {
        return m_addr >= addr;
    }

    TADDR GetAddr(void) const
    {
        return m_addr;
    }
    TADDR SetAddr(TADDR addr)
    {
        m_addr = addr;
        return addr;
    }

protected:
    TADDR m_addr;
};

// Pointer wrapper base class for various forms of normal data.
// This has the common functionality between __DPtr and __ArrayDPtr.
// The DPtrType type parameter is the actual derived type in use.  This is necessary so that
// inhereted functions preserve exact return types.
template<typename type, template<typename> class DPtrTemplate>
class __DPtrBase : public __TPtrBase
{
public:
    typedef type _Type;
    typedef type* _Ptr;
    using DPtrType = DPtrTemplate<type>;

    using __TPtrBase::__TPtrBase;

    __DPtrBase() = default;

    explicit __DPtrBase(__TPtrBase ptr) : __TPtrBase(ptr.GetAddr()) {}
    
    // construct const from non-const
    __DPtrBase(__DPtrBase<typename std::remove_const<type>::type, DPtrTemplate> const & rhs) : __DPtrBase(rhs.GetAddr()) {}

    explicit __DPtrBase(type const * host)
    {
        m_addr = DacGetTargetAddrForHostAddr(host, true);
    }

public:
    using __TPtrBase::operator=;

    DPtrType& operator=(const __TPtrBase& ptr)
    {
        m_addr = ptr.GetAddr();
        return DPtrType(m_addr);
    }

    type& operator*(void) const
    {
        return *(type*)DacInstantiateTypeByAddress(m_addr, sizeof(type), true);
    }

    using __TPtrBase::operator==;
    using __TPtrBase::operator!=;

    bool operator==(const DPtrType& ptr) const
    {
        return m_addr == ptr.GetAddr();
    }

    bool operator!=(const DPtrType& ptr) const
    {
        return !operator==(ptr);
    }

    bool operator<(const DPtrType& ptr) const
    {
        return m_addr < ptr.GetAddr();
    }
    bool operator>(const DPtrType& ptr) const
    {
        return m_addr > ptr.GetAddr();
    }
    bool operator<=(const DPtrType& ptr) const
    {
        return m_addr <= ptr.GetAddr();
    }
    bool operator>=(const DPtrType& ptr) const
    {
        return m_addr >= ptr.GetAddr();
    }

    // Array index operator
    // we want an operator[] for all possible numeric types (rather than rely on
    // implicit numeric conversions on the argument) to prevent ambiguity with
    // DPtr's implicit conversion to type* and the built-in operator[].
    // @dbgtodo : we could also use this technique to simplify other operators below.
    template<typename indexType>
    type& operator[](indexType index)
    {
        // Compute the address of the element.
        TADDR elementAddr;
        if( index >= 0 )
        {
            elementAddr = DacTAddrOffset(m_addr, index, sizeof(type));
        }
        else
        {
            // Don't bother trying to do overflow checking for negative indexes - they are rare compared to
            // positive ones.  ClrSafeInt doesn't support signed datatypes yet (although we should be able to add it
            // pretty easily).
            elementAddr = m_addr + index * sizeof(type);
        }

        // Marshal over a single instance and return a reference to it.
        return *(type*) DacInstantiateTypeByAddress(elementAddr, sizeof(type), true);
    }

    template<typename indexType>
    type const & operator[](indexType index) const
    {
        return (*const_cast<__DPtrBase*>(this))[index];
    }

    //-------------------------------------------------------------------------
    // operator+

    DPtrType operator+(unsigned short val)
    {
        return DPtrType(DacTAddrOffset(m_addr, val, sizeof(type)));
    }
#if defined(HOST_UNIX) && defined(HOST_64BIT)
    DPtrType operator+(unsigned long long val)
    {
        return DPtrType(DacTAddrOffset(m_addr, val, sizeof(type)));
    }
#endif // HOST_UNIX && HOST_BIT64
    DPtrType operator+(short val)
    {
        return DPtrType(m_addr + val * sizeof(type));
    }
    // size_t is unsigned int on Win32, so we need
    // to ifdef here to make sure the unsigned int
    // and size_t overloads don't collide.  size_t
    // is marked __w64 so a simple unsigned int
    // will not work on Win32, it has to be size_t.
    DPtrType operator+(size_t val)
    {
        return DPtrType(DacTAddrOffset(m_addr, val, sizeof(type)));
    }
#if defined (HOST_64BIT)
    DPtrType operator+(unsigned int val)
    {
        return DPtrType(DacTAddrOffset(m_addr, val, sizeof(type)));
    }
#endif
    DPtrType operator+(int val)
    {
        return DPtrType(m_addr + val * sizeof(type));
    }
    // Because of the size difference between long and int on non MS compilers,
    // we only need to define these operators on Windows. These provide compatible
    // overloads for DWORD addition operations.
#ifdef _MSC_VER
    DPtrType operator+(unsigned long val)
    {
        return DPtrType(DacTAddrOffset(m_addr, val, sizeof(type)));
    }
    DPtrType operator+(long val)
    {
        return DPtrType(m_addr + val * sizeof(type));
    }
#endif

    //-------------------------------------------------------------------------
    // operator-

    DPtrType operator-(unsigned short val)
    {
        return DPtrType(m_addr - val * sizeof(type));
    }
    DPtrType operator-(short val)
    {
        return DPtrType(m_addr - val * sizeof(type));
    }
    // size_t is unsigned int on Win32, so we need
    // to ifdef here to make sure the unsigned int
    // and size_t overloads don't collide.  size_t
    // is marked __w64 so a simple unsigned int
    // will not work on Win32, it has to be size_t.
    DPtrType operator-(size_t val)
    {
        return DPtrType(m_addr - val * sizeof(type));
    }
#ifdef HOST_64BIT
    DPtrType operator-(unsigned int val)
    {
        return DPtrType(m_addr - val * sizeof(type));
    }
#endif
    DPtrType operator-(int val)
    {
        return DPtrType(m_addr - val * sizeof(type));
    }
    // Because of the size difference between long and int on non MS compilers,
    // we only need to define these operators on Windows. These provide compatible
    // overloads for DWORD addition operations.
#ifdef _MSC_VER // for now, everything else is 32 bit
    DPtrType operator-(unsigned long val)
    {
        return DPtrType(m_addr - val * sizeof(type));
    }
    DPtrType operator-(long val)
    {
        return DPtrType(m_addr - val * sizeof(type));
    }
#endif
    size_t operator-(const DPtrType& val)
    {
        return (m_addr - val.m_addr) / sizeof(type);
    }

    //-------------------------------------------------------------------------

    DPtrType& operator+=(size_t val)
    {
        m_addr += val * sizeof(type);
        return static_cast<DPtrType&>(*this);
    }
    DPtrType& operator-=(size_t val)
    {
        m_addr -= val * sizeof(type);
        return static_cast<DPtrType&>(*this);
    }

    DPtrType& operator++()
    {
        m_addr += sizeof(type);
        return static_cast<DPtrType&>(*this);
    }
    DPtrType& operator--()
    {
        m_addr -= sizeof(type);
        return static_cast<DPtrType&>(*this);
    }
    DPtrType operator++(int postfix)
    {
        DPtrType orig = DPtrType(*this);
        m_addr += sizeof(type);
        return orig;
    }
    DPtrType operator--(int postfix)
    {
        DPtrType orig = DPtrType(*this);
        m_addr -= sizeof(type);
        return orig;
    }

    bool IsValid(void) const
    {
        return m_addr &&
            DacInstantiateTypeByAddress(m_addr, sizeof(type),
                                        false) != NULL;
    }
    void EnumMem(void) const
    {
        DacEnumMemoryRegion(m_addr, sizeof(type));
    }
};

// forward declaration
template<typename acc_type, typename store_type>
class __GlobalPtr;

// Pointer wrapper for objects which are just plain data
// and need no special handling.
template<typename type>
class __DPtr : public __DPtrBase<type,__DPtr>
{
public:
    using __DPtrBase<type,__DPtr>::__DPtrBase;

    __DPtr() = default;

    // construct from GlobalPtr
    explicit __DPtr(__GlobalPtr< type*, __DPtr< type > > globalPtr) :
        __DPtrBase<type,__DPtr>(globalPtr.GetAddr()) {}

    operator type*() const
    {
        return (type*)DacInstantiateTypeByAddress(this->m_addr, sizeof(type), true);
    }

    type* operator->() const
    {
        return (type*)(*this);
    }
};

#define DPTR(type) __DPtr< type >

// A restricted form of DPtr that doesn't have any conversions to pointer types.
// This is useful for pointer types that almost always represent arrays, as opposed
// to pointers to single instances (eg. PTR_BYTE).  In these cases, allowing implicit
// conversions to (for eg.) BYTE* would usually result in incorrect usage (eg. pointer
// arithmetic and array indexing), since only a single instance has been marshalled to the host.
// If you really must marshal a single instance (eg. converting T* to PTR_T is too painful for now),
// then use code:DacUnsafeMarshalSingleElement so we can identify such unsafe code.
template<typename type>
class __ArrayDPtr : public __DPtrBase<type,__ArrayDPtr>
{
public:
    using __DPtrBase<type,__ArrayDPtr>::__DPtrBase;

    __ArrayDPtr() = default;

    // We delete the base type's constructor from host pointer.
    // Going this direction is less problematic, but often still represents risky coding.
    explicit __ArrayDPtr(type const * host) = delete;
};

#define ArrayDPTR(type) __ArrayDPtr< type >


// Pointer wrapper for objects which are just plain data
// but whose size is not the same as the base type size.
// This can be used for prefetching data for arrays or
// for cases where an object has a variable size.
template<typename type>
class __SPtr : public __TPtrBase
{
public:
    typedef type _Type;
    typedef type* _Ptr;

    using __TPtrBase::__TPtrBase;

    __SPtr() = default;

    explicit __SPtr(__TPtrBase ptr) : __TPtrBase(ptr.GetAddr()) {}

    explicit __SPtr(type* host)
    {
        m_addr = DacGetTargetAddrForHostAddr(host, true);
    }

    using __TPtrBase::operator=;

    __SPtr& operator=(const __TPtrBase& ptr)
    {
        m_addr = ptr.GetAddr();
        return *this;
    }

    operator type*() const
    {
        if (m_addr)
        {
            return (type*)DacInstantiateTypeByAddress(m_addr,
                                                      type::DacSize(m_addr),
                                                      true);
        }
        else
        {
            return (type*)NULL;
        }
    }
    type* operator->() const
    {
        if (m_addr)
        {
            return (type*)DacInstantiateTypeByAddress(m_addr,
                                                      type::DacSize(m_addr),
                                                      true);
        }
        else
        {
            return (type*)NULL;
        }
    }
    type& operator*(void) const
    {
        if (!m_addr)
        {
            DacError(E_INVALIDARG);
        }

        return *(type*)DacInstantiateTypeByAddress(m_addr,
                                                   type::DacSize(m_addr),
                                                   true);
    }

    bool IsValid(void) const
    {
        return m_addr &&
            DacInstantiateTypeByAddress(m_addr, type::DacSize(m_addr),
                                        false) != NULL;
    }
    void EnumMem(void) const
    {
        if (m_addr)
        {
            DacEnumMemoryRegion(m_addr, type::DacSize(m_addr));
        }
    }
};

#define SPTR(type) __SPtr< type >

// Pointer wrapper for objects which have a single leading
// vtable, such as objects in a single-inheritance tree.
// The base class of all such trees must have use
// VPTR_BASE_VTABLE_CLASS in their declaration and all
// instantiable members of the tree must be listed in vptr_list.h.
template<class type>
class __VPtr : public __TPtrBase
{
public:
    // VPtr::_Type has to be a pointer as
    // often the type is an abstract class.
    // This type is not expected to be used anyway.
    typedef type* _Type;
    typedef type* _Ptr;

    using __TPtrBase::__TPtrBase;

    __VPtr() = default;

    explicit __VPtr(__TPtrBase ptr) : __TPtrBase(ptr.GetAddr()) {}

    explicit __VPtr(type* host)
    {
        m_addr = DacGetTargetAddrForHostAddr(host, true);
    }

    using __TPtrBase::operator=;

    __VPtr& operator=(const __TPtrBase& ptr)
    {
        m_addr = ptr.GetAddr();
        return *this;
    }

    operator type*() const
    {
        return (type*)DacInstantiateClassByVTable(m_addr, sizeof(type), true);
    }
    type* operator->() const
    {
        return (type*)DacInstantiateClassByVTable(m_addr, sizeof(type), true);
    }

    using __TPtrBase::operator==;
    using __TPtrBase::operator!=;

    bool operator==(const __VPtr& ptr) const
    {
        return m_addr == ptr.m_addr;
    }

    bool operator!=(const __VPtr& ptr) const
    {
        return !operator==(ptr);
    }

    bool IsValid(void) const
    {
        return m_addr &&
            DacInstantiateClassByVTable(m_addr, sizeof(type), false) != NULL;
    }
    void EnumMem(void) const
    {
        if (IsValid())
        {
            DacEnumMemoryRegion(m_addr, (operator->())->VPtrSize());
        }
    }
};

#define VPTR(type) __VPtr< type >

// Pointer wrapper for 8-bit strings.
template<typename type, ULONG32 maxChars = 32760>
class __Str8Ptr : public __DPtr<char>
{
public:
    typedef type _Type;
    typedef type* _Ptr;

    using __DPtr<char>::__DPtr;

    __Str8Ptr() = default;

    explicit __Str8Ptr(type* host)
    {
        m_addr = DacGetTargetAddrForHostAddr(host, true);
    }

    using __TPtrBase::operator=;

    __Str8Ptr& operator=(const __TPtrBase& ptr)
    {
        m_addr = ptr.GetAddr();
        return *this;
    }

    operator type*() const
    {
        return (type*)DacInstantiateStringA(m_addr, maxChars, true);
    }

    bool IsValid(void) const
    {
        return m_addr &&
            DacInstantiateStringA(m_addr, maxChars, false) != NULL;
    }
    void EnumMem(void) const
    {
        char* str = DacInstantiateStringA(m_addr, maxChars, false);
        if (str)
        {
            DacEnumMemoryRegion(m_addr, strlen(str) + 1);
        }
    }
};

#define S8PTR(type) __Str8Ptr< type >
#define S8PTRMAX(type, maxChars) __Str8Ptr< type, maxChars >

// Pointer wrapper for 16-bit strings.
template<typename type, ULONG32 maxChars = 32760>
class __Str16Ptr : public __DPtr<WCHAR>
{
public:
    typedef type _Type;
    typedef type* _Ptr;

    using __DPtr<WCHAR>::__DPtr;

    __Str16Ptr() = default;

    explicit __Str16Ptr(type* host)
    {
        m_addr = DacGetTargetAddrForHostAddr(host, true);
    }

    using __TPtrBase::operator=;

    __Str16Ptr& operator=(const __TPtrBase& ptr)
    {
        m_addr = ptr.GetAddr();
        return *this;
    }

    operator type*() const
    {
        return (type*)DacInstantiateStringW(m_addr, maxChars, true);
    }

    bool IsValid(void) const
    {
        return m_addr &&
            DacInstantiateStringW(m_addr, maxChars, false) != NULL;
    }
    void EnumMem(void) const
    {
        WCHAR* str = DacInstantiateStringW(m_addr, maxChars, false);
        if (str)
        {
            DacEnumMemoryRegion(m_addr, u16_strlen(str) + 1);
        }
    }
};

#define S16PTR(type) __Str16Ptr< type >
#define S16PTRMAX(type, maxChars) __Str16Ptr< type, maxChars >

template<typename type>
class __GlobalVal
{
public:
    __GlobalVal(TADDR DacGlobals::* ptr)
    {
        m_ptr = ptr;
    }

    operator type() const
    {
        return (type)*__DPtr< type >(DacGlobalValues()->*m_ptr);
    }

    __DPtr< type > operator&() const
    {
        return __DPtr< type >(DacGlobalValues()->*m_ptr);
    }

    // @dbgtodo  dac support: This updates values in the host.  This seems extremely dangerous
    // to do silently.  I'd prefer that a specific (searchable) write function
    // was used.  Try disabling this and see what fails...
    __GlobalVal<type> & operator=(const type & val)
    {
        type* ptr = __DPtr< type >(DacGlobalValues()->*m_ptr);
        // Update the host copy;
        *ptr = val;
        // Write back to the target.
        DacWriteHostInstance(ptr, true);
        return *this;
    }

    bool IsValid(void) const
    {
        return __DPtr< type >(DacGlobalValues()->*m_ptr).IsValid();
    }
    void EnumMem(void) const
    {
        TADDR p = DacGlobalValues()->*m_ptr;
        __DPtr< type >(p).EnumMem();
    }

private:
    TADDR DacGlobals::* m_ptr;
};

template<typename type, size_t size>
class __GlobalArray
{
public:
    __GlobalArray(TADDR DacGlobals::* ptr)
    {
        m_ptr = ptr;
    }

    __DPtr< type > operator&() const
    {
        return __DPtr< type >(DacGlobalValues()->*m_ptr);
    }

    type& operator[](unsigned int index) const
    {
        return __DPtr< type >(DacGlobalValues()->*m_ptr)[index];
    }

    bool IsValid(void) const
    {
        // Only validates the base pointer, not the full array range.
        return __DPtr< type >(DacGlobalValues()->*m_ptr).IsValid();
    }
    void EnumMem(void) const
    {
        DacEnumMemoryRegion(DacGlobalValues()->*m_ptr, sizeof(type) * size);
    }

private:
    TADDR DacGlobals::* m_ptr;
};

template<typename acc_type, typename store_type>
class __GlobalPtr
{
    using DPtr = __DPtr<store_type>;
public:
    __GlobalPtr(TADDR DacGlobals::* ptr)
    {
        m_ptr = ptr;
    }

    DPtr operator&() const
    {
        return DPtr(DacGlobalValues()->*m_ptr);
    }

    store_type& operator=(store_type & val)
    {
        store_type* ptr = DPtr(DacGlobalValues()->*m_ptr);
        // Update the host copy;
        *ptr = val;
        // Write back to the target.
        DacWriteHostInstance(ptr, true);
        return val;
    }

    acc_type operator->() const
    {
        return (acc_type)*DPtr(DacGlobalValues()->*m_ptr);
    }
    operator acc_type() const
    {
        return (acc_type)*DPtr(DacGlobalValues()->*m_ptr);
    }
    operator store_type() const
    {
        return *DPtr(DacGlobalValues()->*m_ptr);
    }
    bool operator!() const
    {
        return !*DPtr(DacGlobalValues()->*m_ptr);
    }

    typename store_type::_Type& operator[](int index)
    {
        return (*DPtr(DacGlobalValues()->*m_ptr))[index];
    }

    typename store_type::_Type& operator[](unsigned int index)
    {
        return (*DPtr(DacGlobalValues()->*m_ptr))[index];
    }

    TADDR GetAddr() const
    {
        return (*DPtr(DacGlobalValues()->*m_ptr)).GetAddr();
    }

    TADDR GetAddrRaw () const
    {
        return DacGlobalValues()->*m_ptr;
    }

    // This is only testing the pointer memory is available but does not verify
    // the memory that it points to.
    //
    bool IsValidPtr(void) const
    {
        return DPtr(DacGlobalValues()->*m_ptr).IsValid();
    }

    bool IsValid(void) const
    {
        return DPtr(DacGlobalValues()->*m_ptr).IsValid() &&
            (*DPtr(DacGlobalValues()->*m_ptr)).IsValid();
    }
    void EnumMem(void) const
    {
        DPtr ptr(DacGlobalValues()->*m_ptr);
        ptr.EnumMem();
        if (ptr.IsValid())
        {
            (*ptr).EnumMem();
        }
    }

    TADDR DacGlobals::* m_ptr;
};

template<typename acc_type, typename store_type>
inline bool operator==(const __GlobalPtr<acc_type, store_type>& gptr,
                       acc_type host)
{
    return DacGetTargetAddrForHostAddr(host, true) ==
        *__DPtr< TADDR >(DacGlobalValues()->*gptr.m_ptr);
}
template<typename acc_type, typename store_type>
inline bool operator!=(const __GlobalPtr<acc_type, store_type>& gptr,
                       acc_type host)
{
    return !operator==(gptr, host);
}

template<typename acc_type, typename store_type>
inline bool operator==(acc_type host,
                       const __GlobalPtr<acc_type, store_type>& gptr)
{
    return DacGetTargetAddrForHostAddr(host, true) ==
        *__DPtr< TADDR >(DacGlobalValues()->*gptr.m_ptr);
}
template<typename acc_type, typename store_type>
inline bool operator!=(acc_type host,
                       const __GlobalPtr<acc_type, store_type>& gptr)
{
    return !operator==(host, gptr);
}


//
// __VoidPtr is a type that behaves like void* but for target pointers.
// Behavior of PTR_VOID:
// * has void* semantics. Will compile to void* in non-DAC builds (just like
//     other PTR types. Unlike TADDR, we want pointer semantics.
// * NOT assignable from host pointer types or convertible to host pointer
//     types - ensures we can't confuse host and target pointers (we'll get
//     compiler errors if we try and cast between them).
// * like void*, no pointer arithmetic or dereferencing is allowed
// * like TADDR, can be used to construct any __DPtr / __VPtr instance
// * representation is the same as a void* (for marshalling / casting)
//
// One way in which __VoidPtr is unlike void* is that it can't be cast to
// pointer or integer types. On the one hand, this is a good thing as it forces
// us to keep target pointers separate from other data types. On the other hand
// in practice this means we have to use dac_cast<TADDR> in places where we used
// to use a (TADDR) cast. Unfortunately C++ provides us no way to allow the
// explicit cast to primitive types without also allowing implicit conversions.
//
// This is very similar in spirit to TADDR. The primary difference is that
// PTR_VOID has pointer semantics, where TADDR has integer semantics. When
// dacizing uses of void* to TADDR, casts must be inserted everywhere back to
// pointer types. If we switch a use of TADDR to PTR_VOID, those casts in
// DACCESS_COMPILE regions no longer compile (see above). Also, TADDR supports
// pointer arithmetic, but that might not be necessary (could use PTR_BYTE
// instead etc.). Ideally we'd probably have just one type for this purpose
// (named TADDR but with the semantics of PTR_VOID), but outright conversion
// would require too much work.
//
class __VoidPtr : public __TPtrBase
{
public:
    using __TPtrBase::__TPtrBase;

    __VoidPtr() = default;

    // Note, unlike __DPtr, this ctor form is not explicit.  We allow implicit
    // conversions from any pointer type (just like for void*).
    __VoidPtr(__TPtrBase addr)
    {
        m_addr = addr.GetAddr();
    }

    // Like TPtrBase, VoidPtrs can also be created impicitly from all GlobalPtrs
    template<typename acc_type, typename store_type>
    __VoidPtr(__GlobalPtr<acc_type, store_type> globalPtr)
    {
        m_addr = globalPtr.GetAddr();
    }

    // Note, unlike __DPtr, there is no explicit conversion from host pointer
    // types.  Since void* cannot be marshalled, there is no such thing as
    // a void* DAC instance in the host.

    // Also, we don't want an implicit conversion to TADDR because then the
    // compiler will allow pointer arithmetic (which it wouldn't allow for
    // void*).  Instead, callers can use dac_cast<TADDR> if they want.

    // Note, unlike __DPtr, any pointer type can be assigned to a __VoidPtr
    // This is to mirror the assignability of any pointer type to a void*
    using __TPtrBase::operator=;

    __VoidPtr& operator=(const __TPtrBase& ptr)
    {
        m_addr = ptr.GetAddr();
        return *this;
    }

    // note, no marshalling operators (type* conversion, operator ->, operator*)
    // A void* can't be marshalled because we don't know how much to copy

    // PTR_Void can be compared to any other pointer type (because conceptually,
    // any other pointer type should be implicitly convertible to void*)

    using __TPtrBase::operator==;
    using __TPtrBase::operator!=;

    bool operator==(const __TPtrBase& ptr) const
    {
        return m_addr == ptr.GetAddr();
    }
    bool operator!=(const __TPtrBase& ptr) const
    {
        return !operator==(ptr);
    }
    bool operator<(const __TPtrBase& ptr) const
    {
        return m_addr < ptr.GetAddr();
    }
    bool operator>(const __TPtrBase& ptr) const
    {
        return m_addr > ptr.GetAddr();
    }
    bool operator<=(const __TPtrBase& ptr) const
    {
        return m_addr <= ptr.GetAddr();
    }
    bool operator>=(const __TPtrBase& ptr) const
    {
        return m_addr >= ptr.GetAddr();
    }
};

typedef __VoidPtr PTR_VOID;
typedef DPTR(PTR_VOID) PTR_PTR_VOID;

// For now we treat pointers to const and non-const void the same in DAC
// builds. In general, DAC is read-only anyway and so there isn't a danger of
// writing to these pointers. Also, the non-dac builds will ensure
// const-correctness. However, if we wanted to support true void* / const void*
// behavior, we could probably build the follow functionality by templating
// __VoidPtr:
//  * A PTR_VOID would be implicitly convertible to PTR_CVOID
//  * An explicit coercion (ideally const_cast) would be required to convert a
//      PTR_CVOID to a PTR_VOID
//  * Similarily, an explicit coercion would be required to convert a cost PTR
//      type (eg. PTR_CBYTE) to a PTR_VOID.
typedef __VoidPtr PTR_CVOID;


// The special empty ctor declared here allows the whole
// class hierarchy to be instantiated easily by the
// external access code.  The actual class body will be
// read externally so no members should be initialized.

//
// VPTR_ANY_CLASS_METHODS - Defines the following methods for all VPTR classes
//
// VPtrSize
//     Returns the size of the dynamic type of the object (as opposed to sizeof
//     which is based only on the static type).
//
// VPtrHostVTable
//     Returns the address of the vtable for this type.
//     We create a temporary instance of this type in order to read it's vtable pointer
//     (at offset 0).  For this temporary instance, we do not want to initialize any fields,
//     so we use the marshalling ctor.  Since we didn't initialize any fields, we also don't
//     wan't to run the dtor (marshaled data structures don't normally expect their destructor
//     or non-DAC constructors to be called in DAC builds anyway).  So, rather than create a
//     normal stack object, or put the object on the heap, we create the temporary object
//     on the stack using placement-new and alloca, and don't destruct it.
//
#define VPTR_ANY_CLASS_METHODS(name)                            \
        virtual ULONG32 VPtrSize(void) { SUPPORTS_DAC; return sizeof(name); } \
        static PVOID VPtrHostVTable() {                         \
            void * pBuf = _alloca(sizeof(name));                \
            name * dummy = new (pBuf) name((TADDR)0, (TADDR)0); \
            return *((PVOID*)dummy); }

#define VPTR_CLASS_METHODS(name)                                \
        VPTR_ANY_CLASS_METHODS(name)                            \
        static TADDR VPtrTargetVTable() {                       \
            SUPPORTS_DAC;                                       \
            return DacGlobalValues()->name##__vtAddr; }

#define VPTR_VTABLE_CLASS(name, base)                           \
public: name(TADDR addr, TADDR vtAddr) : base(addr, vtAddr) {}  \
        VPTR_CLASS_METHODS(name)

#define VPTR_VTABLE_CLASS_AND_CTOR(name, base)                  \
        VPTR_VTABLE_CLASS(name, base)

// Used for base classes that can be instantiated directly.
// The fake vfn is still used to force a vtable even when
// all the normal vfns are ifdef'ed out.
#define VPTR_BASE_CONCRETE_VTABLE_CLASS(name)                   \
public: name(TADDR addr, TADDR vtAddr) {}                       \
        VPTR_CLASS_METHODS(name)

#define VPTR_BASE_CONCRETE_VTABLE_CLASS_NO_CTOR_BODY(name)      \
public: name(TADDR addr, TADDR vtAddr);                         \
        VPTR_CLASS_METHODS(name)

// The pure virtual method forces all derivations to use
// VPTR_VTABLE_CLASS to compile.
#define VPTR_BASE_VTABLE_CLASS(name)                            \
public: name(TADDR addr, TADDR vtAddr) {}                       \
        virtual ULONG32 VPtrSize(void) = 0;

#define VPTR_BASE_VTABLE_CLASS_AND_CTOR(name)                   \
        VPTR_BASE_VTABLE_CLASS(name)

#define VPTR_BASE_VTABLE_CLASS_NO_CTOR_BODY(name)               \
public: name(TADDR addr, TADDR vtAddr);                         \
        virtual ULONG32 VPtrSize(void) = 0;

#define VPTR_ABSTRACT_VTABLE_CLASS(name, base)                  \
public: name(TADDR addr, TADDR vtAddr) : base(addr, vtAddr) {}

#define VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(name, base) \
        VPTR_ABSTRACT_VTABLE_CLASS(name, base)

#define VPTR_ABSTRACT_VTABLE_CLASS_NO_CTOR_BODY(name, base)     \
public: name(TADDR addr, TADDR vtAddr);

// helper macro to make the vtables unique for DAC
#define VPTR_UNIQUE(unique)

// Safe access for retrieving the target address of a PTR.
#define PTR_TO_TADDR(ptr) ((ptr).GetAddr())

#define GFN_TADDR(name) (DacGlobalValues()->fn__ ## name)

#define GVAL_ADDR(g) \
    ((g).operator&())

//
// References to class static and global data.
// These all need to be redirected through the global
// data table.
//

#define _SPTR_DECL(acc_type, store_type, var) \
    static __GlobalPtr< acc_type, store_type > var
#define _SPTR_IMPL(acc_type, store_type, cls, var) \
    __GlobalPtr< acc_type, store_type > cls::var(&DacGlobals::cls##__##var)
#define _SPTR_IMPL_INIT(acc_type, store_type, cls, var, init) \
    __GlobalPtr< acc_type, store_type > cls::var(&DacGlobals::cls##__##var)
#define _SPTR_IMPL_NS(acc_type, store_type, ns, cls, var) \
    __GlobalPtr< acc_type, store_type > cls::var(&DacGlobals::ns##__##cls##__##var)
#define _SPTR_IMPL_NS_INIT(acc_type, store_type, ns, cls, var, init) \
    __GlobalPtr< acc_type, store_type > cls::var(&DacGlobals::ns##__##cls##__##var)

#define VOLATILE_SPTR_DECL(type, var) SPTR_DECL(type, var)
#define VOLATILE_SPTR_IMPL(type, cls, var) SPTR_IMPL(type, cls, var)
#define VOLATILE_SPTR_IMPL_INIT(type, cls, var, init) SPTR_IMPL_INIT(type, cls, var, init)

#define _GPTR_DECL(acc_type, store_type, var) \
    extern __GlobalPtr< acc_type, store_type > var
#define _GPTR_IMPL(acc_type, store_type, var) \
    __GlobalPtr< acc_type, store_type > var(&DacGlobals::dac__##var)
#define _GPTR_IMPL_INIT(acc_type, store_type, var, init) \
    __GlobalPtr< acc_type, store_type > var(&DacGlobals::dac__##var)

#define SVAL_DECL(type, var) \
    static __GlobalVal< type > var
#define SVAL_IMPL(type, cls, var) \
    __GlobalVal< type > cls::var(&DacGlobals::cls##__##var)
#define SVAL_IMPL_INIT(type, cls, var, init) \
    __GlobalVal< type > cls::var(&DacGlobals::cls##__##var)
#define SVAL_IMPL_NS(type, ns, cls, var) \
    __GlobalVal< type > cls::var(&DacGlobals::ns##__##cls##__##var)
#define SVAL_IMPL_NS_INIT(type, ns, cls, var, init) \
    __GlobalVal< type > cls::var(&DacGlobals::ns##__##cls##__##var)

#define VOLATILE_SVAL_DECL(type, var) SVAL_DECL(type, var)
#define VOLATILE_SVAL_IMPL(type, cls, var) SVAL_IMPL(type, cls, var)
#define VOLATILE_SVAL_IMPL_INIT(type, cls, var, init) SVAL_IMPL_INIT(type, cls, var, init)

#define GVAL_DECL(type, var) \
    extern __GlobalVal< type > var
#define GVAL_IMPL(type, var) \
    __GlobalVal< type > var(&DacGlobals::dac__##var)
#define GVAL_IMPL_INIT(type, var, init) \
    __GlobalVal< type > var(&DacGlobals::dac__##var)

#define GARY_DECL(type, var, size) \
    extern __GlobalArray< type, size > var
#define GARY_IMPL(type, var, size) \
    __GlobalArray< type, size > var(&DacGlobals::dac__##var)

// Translation from a host pointer back to the target address
// that was used to retrieve the data for the host pointer.
#define PTR_HOST_TO_TADDR(host) DacGetTargetAddrForHostAddr(host, true)
// Translation from a host interior pointer back to the corresponding
// target address. The host address must reside within a previously
// retrieved instance.
#define PTR_HOST_INT_TO_TADDR(host) DacGetTargetAddrForHostInteriorAddr(host, true)
// Translation from a host vtable pointer to a target vtable pointer.
#define VPTR_HOST_VTABLE_TO_TADDR(host) DacGetTargetVtForHostVt(host, true)

// Construct a pointer to a member of the given type.
#define PTR_HOST_MEMBER_TADDR(type, host, memb) \
    (PTR_HOST_TO_TADDR(host) + (TADDR)offsetof(type, memb))

// Construct a pointer to a member of the given type given an interior
// host address.
#define PTR_HOST_INT_MEMBER_TADDR(type, host, memb) \
    (PTR_HOST_INT_TO_TADDR(host) + (TADDR)offsetof(type, memb))

#define PTR_TO_MEMBER_TADDR(type, ptr, memb) \
    (PTR_TO_TADDR(ptr) + (TADDR)offsetof(type, memb))

// Constructs an arbitrary data instance for a piece of
// memory in the target.
#define PTR_READ(addr, size) \
    DacInstantiateTypeByAddress(addr, size, true)

// This value is used to intiailize target pointers to NULL.  We want this to be TADDR type
// (as opposed to, say, __TPtrBase) so that it can be used in the non-explicit ctor overloads,
// eg. as an argument default value.
// We can't always just use NULL because that's 0 which (in C++) can be any integer or pointer
// type (causing an ambiguous overload compiler error when used in explicit ctor forms).
#define PTR_NULL ((TADDR)0)

// Provides an empty method implementation when compiled
// for DACCESS_COMPILE.  For example, use to stub out methods needed
// for vtable entries but otherwise unused.
// Note that these functions are explicitly NOT marked SUPPORTS_DAC so that we'll get a
// DacCop warning if any calls to them are detected.
// @dbgtodo : It's probably almost always wrong to call any such function, so
// we should probably throw a better error (DacNotImpl), and ideally mark the function
// DECLSPEC_NORETURN so we don't have to deal with fabricating return values and we can
// get compiler warnings (unreachable code) anytime functions marked this way are called.
#define DAC_EMPTY() { LIMITED_METHOD_CONTRACT; }
#define DAC_EMPTY_ERR() { LIMITED_METHOD_CONTRACT; DacError(E_UNEXPECTED); }
#define DAC_EMPTY_RET(retVal) { LIMITED_METHOD_CONTRACT; DacError(E_UNEXPECTED); return retVal; }
#define DAC_UNEXPECTED() { LIMITED_METHOD_CONTRACT; DacError_NoRet(E_UNEXPECTED); }

#endif // #ifdef __cplusplus

// Implementation details for dac_cast, should never be accessed directly.
// See code:dac_cast for details and discussion.
namespace dac_imp
{
    // Helper functions to get the target address of specific types
    inline TADDR getTaddr(TADDR addr) { return addr; }
    inline TADDR getTaddr(__TPtrBase const &tptr) { return PTR_TO_TADDR(tptr); }
    inline TADDR getTaddr(void const * host) { return PTR_HOST_TO_TADDR((void *)host); }
    template<typename acc_type, typename store_type>
    inline TADDR getTaddr(__GlobalPtr<acc_type, store_type> const &gptr) { return PTR_TO_TADDR(gptr); }

    // It is an error to try dac_cast on a __GlobalVal or a __GlobalArray. Declare
    // but do not define the methods so that a compile-time error results.
    template<typename type>
    TADDR getTaddr(__GlobalVal<type> const &gval);
    template<typename type, size_t size>
    TADDR getTaddr(__GlobalArray<type, size> const &garr);

    // Helper class to instantiate DAC instances from a TADDR
    // The default implementation assumes we want to create an instance of a PTR type
    template<typename T> struct makeDacInst
    {
        static inline T fromTaddr(TADDR addr)
        {
            static_assert((std::is_base_of<__TPtrBase, T>::value), "is_base_of constraint violation");
            return T(addr);
        }
    };

    // Partial specialization for creating TADDRs
    // This is the only other way to create a DAC type instance other than PTR types (above)
    template<> struct makeDacInst<TADDR>
    {
        static inline TADDR fromTaddr(TADDR addr) { return addr; }
    };
} // namespace dac_imp


// DacCop in-line exclusion mechanism

// Warnings - official home is DacCop\Shared\Warnings.cs, but we want a way for users to indicate
// warning codes in a way that is descriptive to readers (not just code numbers).  The names here
// don't matter - DacCop just looks at the value
enum DacCopWarningCode
{
    // General Rules
    FieldAccess = 1,
    PointerArith = 2,
    PointerComparison = 3,
    InconsistentMarshalling = 4,
    CastBetweenAddressSpaces = 5,
    CastOfMarshalledType = 6,
    VirtualCallToNonVPtr = 7,
    UndacizedGlobalVariable = 8,

    // Function graph related
    CallUnknown = 701,
    CallNonDac = 702,
    CallVirtualUnknown = 704,
    CallVirtualNonDac = 705,
};

// DACCOP_IGNORE is a mechanism to suppress DacCop violations from within the source-code.
// See the DacCop wiki for guidance on how best to use this: http://mswikis/clr/dev/Pages/DacCop.aspx
//
// DACCOP_IGNORE will suppress a DacCop violation for the following (non-compound) statement.
// For example:
//      // The "dual-mode DAC problem" occurs in a few places where a class is used both
//      // in the host, and marshalled from the target ... <further details>
//      DACCOP_IGNORE(CastBetweenAddressSpaces,"SBuffer has the dual-mode DAC problem");
//      TADDR bufAddr = (TADDR)m_buffer;
//
// A call to DACCOP_IGNORE must occur as it's own statement, and can apply only to following
// single-statements (not to compound statement blocks).  Occasionally it is necessary to hoist
// violation-inducing code out to its own statement (e.g., if it occurs in the conditional of an
// if).
//
// Arguments:
//   code: a literal value from DacCopWarningCode indicating which violation should be suppressed.
//   szReasonString: a short description of why this exclusion is necessary.  This is intended just
//        to help readers of the code understand the source of the problem, and what would be required
//        to fix it.  More details can be provided in comments if desired.
//
inline void DACCOP_IGNORE(DacCopWarningCode code, const char * szReasonString)
{
    // DacCop detects calls to this function.  No implementation is necessary.
}

#else // #ifdef DACCESS_COMPILE

//
// This version of the macros turns into normal pointers
// for unmodified in-proc compilation.

// *******************************************************
// !!!!!!!!!!!!!!!!!!!!!!!!!NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// Please search this file for the type name to find the
// DAC versions of these definitions
//
// !!!!!!!!!!!!!!!!!!!!!!!!!NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!
// *******************************************************


// Declare TADDR as a non-pointer type so that arithmetic
// can be done on it directly, as with the DACCESS_COMPILE definition.
// This also helps expose pointer usage that may need to be changed.
typedef uintptr_t TADDR;

typedef void* PTR_VOID;
typedef LPVOID* PTR_PTR_VOID;
typedef const void* PTR_CVOID;

#define DPTR(type) type*
#define ArrayDPTR(type) type*
#define SPTR(type) type*
#define VPTR(type) type*
#define S8PTR(type) type*
#define S8PTRMAX(type, maxChars) type*
#define S16PTR(type) type*
#define S16PTRMAX(type, maxChars) type*

#if defined(TARGET_UNIX)

#define VPTR_VTABLE_CLASS(name, base) \
        friend struct _DacGlobals; \
public: name(int dummy) : base(dummy) {}

#define VPTR_VTABLE_CLASS_AND_CTOR(name, base) \
        VPTR_VTABLE_CLASS(name, base) \
        name() : base() {}

#define VPTR_BASE_CONCRETE_VTABLE_CLASS(name) \
        friend struct _DacGlobals; \
public: name(int dummy) {}

#define VPTR_BASE_VTABLE_CLASS(name) \
        friend struct _DacGlobals; \
public: name(int dummy) {}

#define VPTR_BASE_VTABLE_CLASS_AND_CTOR(name) \
        VPTR_BASE_VTABLE_CLASS(name) \
        name() {}

#define VPTR_ABSTRACT_VTABLE_CLASS(name, base) \
        friend struct _DacGlobals; \
public: name(int dummy) : base(dummy) {}

#define VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(name, base) \
        VPTR_ABSTRACT_VTABLE_CLASS(name, base) \
        name() : base() {}

#else // TARGET_UNIX

#define VPTR_VTABLE_CLASS(name, base) friend struct _DacGlobals;
#define VPTR_VTABLE_CLASS_AND_CTOR(name, base)
#define VPTR_BASE_CONCRETE_VTABLE_CLASS(name) friend struct _DacGlobals;
#define VPTR_BASE_VTABLE_CLASS(name) friend struct _DacGlobals;
#define VPTR_BASE_VTABLE_CLASS_AND_CTOR(name)
#define VPTR_ABSTRACT_VTABLE_CLASS(name, base) friend struct _DacGlobals;
#define VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(name, base)

#endif // TARGET_UNIX

// helper macro to make the vtables unique for DAC
#define VPTR_UNIQUE(unique) virtual int MakeVTableUniqueForDAC() { return unique; }
#define VPTR_UNIQUE_BaseDomain                          (100000)
#define VPTR_UNIQUE_SystemDomain                        (VPTR_UNIQUE_BaseDomain + 1)
#define VPTR_UNIQUE_ComMethodFrame                      (VPTR_UNIQUE_SystemDomain + 1)
#define VPTR_UNIQUE_RedirectedThreadFrame               (VPTR_UNIQUE_ComMethodFrame + 1)
#define VPTR_UNIQUE_HijackFrame                         (VPTR_UNIQUE_RedirectedThreadFrame + 1)

#define PTR_TO_TADDR(ptr) ((TADDR)(ptr))
#define GFN_TADDR(name) ((TADDR)(name))

#define GVAL_ADDR(g) (&(g))
#define _SPTR_DECL(acc_type, store_type, var) \
    static store_type var
#define _SPTR_IMPL(acc_type, store_type, cls, var) \
    store_type cls::var
#define _SPTR_IMPL_INIT(acc_type, store_type, cls, var, init) \
    store_type cls::var = init
#define _SPTR_IMPL_NS(acc_type, store_type, ns, cls, var) \
    store_type cls::var
#define _SPTR_IMPL_NS_INIT(acc_type, store_type, ns, cls, var, init) \
    store_type cls::var = init
#define VOLATILE_SPTR_DECL(type, var) _SPTR_DECL(type*, Volatile<PTR_##type>, var)
#define VOLATILE_SPTR_IMPL(type, cls, var) _SPTR_IMPL(type*, Volatile<PTR_##type>, cls, var)
#define VOLATILE_SPTR_IMPL_INIT(type, cls, var, init) _SPTR_IMPL_INIT(type*, Volatile<PTR_##type>, cls, var, init)
#define _GPTR_DECL(acc_type, store_type, var) \
    extern store_type var
#define _GPTR_IMPL(acc_type, store_type, var) \
    store_type var
#define _GPTR_IMPL_INIT(acc_type, store_type, var, init) \
    store_type var = init
#define SVAL_DECL(type, var) \
    static type var
#define SVAL_IMPL(type, cls, var) \
    type cls::var
#define SVAL_IMPL_INIT(type, cls, var, init) \
    type cls::var = init
#define VOLATILE_SVAL_DECL(type, var) \
    static Volatile<type> var
#define VOLATILE_SVAL_IMPL(type, cls, var) \
    Volatile<type> cls::var
#define VOLATILE_SVAL_IMPL_INIT(type, cls, var, init) \
    Volatile<type> cls::var = init
#define SVAL_IMPL_NS(type, ns, cls, var) \
    type cls::var
#define SVAL_IMPL_NS_INIT(type, ns, cls, var, init) \
    type cls::var = init
#define GVAL_DECL(type, var) \
    extern type var
#define GVAL_IMPL(type, var) \
    type var
#define GVAL_IMPL_INIT(type, var, init) \
    type var = init
#define GARY_DECL(type, var, size) \
    extern type var[size]
#define GARY_IMPL(type, var, size) \
    type var[size]
#define PTR_HOST_TO_TADDR(host) ((TADDR)(host))
#define PTR_HOST_INT_TO_TADDR(host) ((TADDR)(host))
#define VPTR_HOST_VTABLE_TO_TADDR(host) ((TADDR)(host))
#define PTR_HOST_MEMBER_TADDR(type, host, memb) ((TADDR)&(host)->memb)
#define PTR_HOST_INT_MEMBER_TADDR(type, host, memb) ((TADDR)&(host)->memb)
#define PTR_TO_MEMBER_TADDR(type, ptr, memb) ((TADDR)&((ptr)->memb))
#define PTR_READ(addr, size) ((PVOID)(addr))

#define PTR_NULL NULL

#define DAC_EMPTY()
#define DAC_EMPTY_ERR()
#define DAC_EMPTY_RET(retVal)
#define DAC_UNEXPECTED()

#define DACCOP_IGNORE(warningCode, reasonString)

#endif // #ifdef DACCESS_COMPILE

//----------------------------------------------------------------------------
// dac_cast
// Casting utility, to be used for casting one class pointer type to another.
// Use as you would use static_cast
//
// dac_cast is designed to act just as static_cast does when
// dealing with pointers and their DAC abstractions. Specifically,
// it handles these coversions:
//
//      dac_cast<TargetType>(SourceTypeVal)
//
// where TargetType <- SourceTypeVal are
//
//      ?PTR(Tgt) <- TADDR     - Create PTR type (DPtr etc.) from TADDR
//      ?PTR(Tgt) <- ?PTR(Src) - Convert one PTR type to another
//      ?PTR(Tgt) <- Src *     - Create PTR type from dac host object instance
//      TADDR <- ?PTR(Src)     - Get TADDR of PTR object (DPtr etc.)
//      TADDR <- Src *         - Get TADDR of dac host object instance
//
// Note that there is no direct conversion to other host-pointer types (because we don't
// know if you want a DPTR or VPTR etc.).  However, due to the implicit DAC conversions,
// you can just use dac_cast<PTR_Foo> and assign that to a Foo*.
//
// The beauty of this syntax is that it is consistent regardless
// of source and target casting types. You just use dac_cast
// and the partial template specialization will do the right thing.
//
// One important thing to realise is that all "Foo *" types are
// assumed to be pointers to host instances that were marshalled by DAC.  This should
// fail at runtime if it's not the case.
//
// Some examples would be:
//
//   - Host pointer of one type to a related host pointer of another
//     type, i.e., MethodDesc * <-> InstantiatedMethodDesc *
//     Syntax: with MethodDesc *pMD, InstantiatedMethodDesc *pInstMD
//             pInstMd = dac_cast<PTR_InstantiatedMethodDesc>(pMD)
//             pMD = dac_cast<PTR_MethodDesc>(pInstMD)
//
//   - (D|V)PTR of one encapsulated pointer type to a (D|V)PTR of
//     another type, i.e., PTR_AppDomain <-> PTR_BaseDomain
//     Syntax: with PTR_AppDomain pAD, PTR_BaseDomain pBD
//             dac_cast<PTR_AppDomain>(pBD)
//             dac_cast<PTR_BaseDomain>(pAD)
//
// Example comparisons of some old and new syntax, where
//    h is a host pointer, such as "Foo *h;"
//    p is a DPTR, such as "PTR_Foo p;"
//
//      PTR_HOST_TO_TADDR(h)           ==> dac_cast<TADDR>(h)
//      PTR_TO_TADDR(p)                ==> dac_cast<TADDR>(p)
//      PTR_Foo(PTR_HOST_TO_TADDR(h))  ==> dac_cast<PTR_Foo>(h)
//
//----------------------------------------------------------------------------
template <typename Tgt, typename Src>
inline Tgt dac_cast(Src src)
{
#ifdef DACCESS_COMPILE
    // In DAC builds, first get a TADDR for the source, then create the
    // appropriate destination instance.
    TADDR addr = dac_imp::getTaddr(src);
    return dac_imp::makeDacInst<Tgt>::fromTaddr(addr);
#else
    // In non-DAC builds, dac_cast is the same as a C-style cast because we need to support:
    //  - casting away const
    //  - conversions between pointers and TADDR
    // Perhaps we should more precisely restrict it's usage, but we get the precise
    // restrictions in DAC builds, so it wouldn't buy us much.
    return (Tgt)(src);
#endif
}

//----------------------------------------------------------------------------
//
// Convenience macros which work for either mode.
//
//----------------------------------------------------------------------------

#define SPTR_DECL(type, var) _SPTR_DECL(type*, PTR_##type, var)
#define SPTR_IMPL(type, cls, var) _SPTR_IMPL(type*, PTR_##type, cls, var)
#define SPTR_IMPL_INIT(type, cls, var, init) _SPTR_IMPL_INIT(type*, PTR_##type, cls, var, init)
#define SPTR_IMPL_NS(type, ns, cls, var) _SPTR_IMPL_NS(type*, PTR_##type, ns, cls, var)
#define SPTR_IMPL_NS_INIT(type, ns, cls, var, init) _SPTR_IMPL_NS_INIT(type*, PTR_##type, ns, cls, var, init)
#define GPTR_DECL(type, var) _GPTR_DECL(type*, PTR_##type, var)
#define GPTR_IMPL(type, var) _GPTR_IMPL(type*, PTR_##type, var)
#define GPTR_IMPL_INIT(type, var, init) _GPTR_IMPL_INIT(type*, PTR_##type, var, init)


// If you want to marshal a single instance of an ArrayDPtr over to the host and
// return a pointer to it, you can use this function.  However, this is unsafe because
// users of value may assume they can do pointer arithmetic on it.  This is exactly
// the bugs ArrayDPtr is designed to prevent.  See code:__ArrayDPtr for details.
template<typename type>
inline type* DacUnsafeMarshalSingleElement( ArrayDPTR(type) arrayPtr )
{
    return (DPTR(type))(arrayPtr);
}

//----------------------------------------------------------------------------
//
// Forward typedefs for system types.  This is a convenient place
// to declare things for system types, plus it gives us a central
// place to look at when deciding what types may cause issues for
// cross-platform compilation.
//
//----------------------------------------------------------------------------

typedef DPTR(size_t)       PTR_size_t;
typedef ArrayDPTR(uint8_t) PTR_uint8_t;
typedef DPTR(PTR_uint8_t)  PTR_PTR_uint8_t;
typedef DPTR(int32_t)      PTR_int32_t;
typedef DPTR(uint32_t)     PTR_uint32_t;
typedef DPTR(uint64_t)     PTR_uint64_t;
typedef DPTR(uintptr_t)    PTR_uintptr_t;
typedef DPTR(TADDR)        PTR_TADDR;

#ifndef NATIVEAOT
typedef ArrayDPTR(BYTE)    PTR_BYTE;
typedef DPTR(PTR_BYTE) PTR_PTR_BYTE;
typedef DPTR(PTR_PTR_BYTE) PTR_PTR_PTR_BYTE;
typedef ArrayDPTR(signed char) PTR_SBYTE;
typedef ArrayDPTR(const BYTE) PTR_CBYTE;
typedef DPTR(INT8)    PTR_INT8;
typedef DPTR(INT16)   PTR_INT16;
typedef DPTR(UINT16)  PTR_UINT16;
typedef DPTR(WORD)    PTR_WORD;
typedef DPTR(USHORT)  PTR_USHORT;
typedef DPTR(DWORD)   PTR_DWORD;
typedef DPTR(LONG)    PTR_LONG;
typedef DPTR(ULONG)   PTR_ULONG;
typedef DPTR(INT32)   PTR_INT32;
typedef DPTR(UINT32)  PTR_UINT32;
typedef DPTR(ULONG64) PTR_ULONG64;
typedef DPTR(INT64)   PTR_INT64;
typedef DPTR(UINT64)  PTR_UINT64;
typedef DPTR(SIZE_T)  PTR_SIZE_T;
typedef DPTR(int)     PTR_int;
typedef DPTR(BOOL)    PTR_BOOL;
typedef DPTR(unsigned) PTR_unsigned;

typedef S8PTR(char)           PTR_STR;
typedef S8PTR(const char)     PTR_CSTR;
typedef S8PTR(char)           PTR_UTF8;
typedef S8PTR(const char)     PTR_CUTF8;
typedef S16PTR(WCHAR)         PTR_WSTR;
typedef S16PTR(const WCHAR)   PTR_CWSTR;

typedef DPTR(T_CONTEXT)                  PTR_CONTEXT;
typedef DPTR(PTR_CONTEXT)                PTR_PTR_CONTEXT;
typedef DPTR(struct _EXCEPTION_POINTERS) PTR_EXCEPTION_POINTERS;
typedef DPTR(struct _EXCEPTION_RECORD)   PTR_EXCEPTION_RECORD;

typedef DPTR(struct _EXCEPTION_REGISTRATION_RECORD) PTR_EXCEPTION_REGISTRATION_RECORD;

typedef DPTR(struct IMAGE_COR_VTABLEFIXUP) PTR_IMAGE_COR_VTABLEFIXUP;
typedef DPTR(IMAGE_DATA_DIRECTORY)  PTR_IMAGE_DATA_DIRECTORY;
typedef DPTR(IMAGE_DEBUG_DIRECTORY)  PTR_IMAGE_DEBUG_DIRECTORY;
typedef DPTR(IMAGE_DOS_HEADER)      PTR_IMAGE_DOS_HEADER;
typedef DPTR(IMAGE_NT_HEADERS)      PTR_IMAGE_NT_HEADERS;
typedef DPTR(IMAGE_NT_HEADERS32)    PTR_IMAGE_NT_HEADERS32;
typedef DPTR(IMAGE_NT_HEADERS64)    PTR_IMAGE_NT_HEADERS64;
typedef DPTR(IMAGE_SECTION_HEADER)  PTR_IMAGE_SECTION_HEADER;
typedef DPTR(IMAGE_EXPORT_DIRECTORY)  PTR_IMAGE_EXPORT_DIRECTORY;
typedef DPTR(IMAGE_TLS_DIRECTORY)   PTR_IMAGE_TLS_DIRECTORY;
#endif

#if defined(DACCESS_COMPILE)
#include <corhdr.h>
#include <clrdata.h>
#include <xclrdata.h>
#endif

#ifndef NATIVEAOT
#if defined(TARGET_X86) && defined(FEATURE_EH_FUNCLETS)
typedef DPTR(struct _UNWIND_INFO)      PTR_UNWIND_INFO;
#endif

#ifdef TARGET_64BIT
typedef DPTR(T_RUNTIME_FUNCTION) PTR_RUNTIME_FUNCTION;
typedef DPTR(struct _UNWIND_INFO)      PTR_UNWIND_INFO;
#if defined(TARGET_AMD64)
typedef DPTR(union _UNWIND_CODE)       PTR_UNWIND_CODE;
#endif // TARGET_AMD64
#endif // TARGET_64BIT

#ifdef TARGET_ARM
typedef DPTR(T_RUNTIME_FUNCTION) PTR_RUNTIME_FUNCTION;
#endif
#endif

//----------------------------------------------------------------------------
//
// A PCODE is a valid PC/IP value -- a pointer to an instruction, possibly including some processor mode bits.
// (On ARM, for example, a PCODE value should have the low-order THUMB_CODE bit set if the code should
// be executed in that mode.)
//
typedef TADDR PCODE;
typedef DPTR(PCODE) PTR_PCODE;
typedef DPTR(PTR_PCODE) PTR_PTR_PCODE;

// There is another concept we should have, "pointer to the start of an instruction" -- a PCODE with any mode bits masked off.
// Attempts to introduce this concept, and classify uses of PCODE as one or the other,
// turned out to be too hard: either name choice required *many* code changes, and decisions in unfamiliar code.  So despite the
// the comment above, the PCODE is currently sometimes used for the PINSTR concept.

// See PCODEToPINSTR in utilcode.h for conversion from PCODE to PINSTR.

//----------------------------------------------------------------------------
//
// The access code compile must compile data structures that exactly
// match the real structures for access to work.  The access code
// doesn't want all of the debugging validation code, though, so
// distinguish between _DEBUG, for declaring general debugging data
// and always-on debug code, and _DEBUG_IMPL, for debugging code
// which will be disabled when compiling for external access.
//
//----------------------------------------------------------------------------

#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
#define _DEBUG_IMPL 1
#endif

// Helper macro for tracking EnumMemoryRegions progress.
#if 0
#define EMEM_OUT(args) DacLogMessage args
#else
#define EMEM_OUT(args)
#endif

// Macros like MAIN_CLR_MODULE_NAME* for the DAC module
#define MAIN_DAC_MODULE_NAME_W  W("mscordaccore")
#define MAIN_DAC_MODULE_DLL_NAME_W  W("mscordaccore.dll")

// TARGET_CONSISTENCY_CHECK represents a condition that should not fail unless the DAC target is corrupt.
// This is in contrast to ASSERTs in DAC infrastructure code which shouldn't fail regardless of the memory
// read from the target.  At the moment we treat these the same, but in the future we will want a mechanism
// for disabling just the target consistency checks (eg. for tests that intentionally use corrupted targets).
// @dbgtodo : Separating asserts and target consistency checks is tracked by DevDiv Bugs 31674
#define TARGET_CONSISTENCY_CHECK(expr,msg) _ASSERTE_MSG(expr,msg)

// For cross compilation, controlling type layout is important
// We add a simple macro here which defines DAC_ALIGNAS to the C++11 alignas operator
// This helps force the alignment of the next member
// For most cross compilation cases the layout of types simply works
// There are a few cases (where this macro is helpful) which are not consistent across platforms:
// - Base class whose size is padded to its align size.  On Linux the gcc/clang
//   layouts will reuse this padding in the derived class for the first member
// - Class with an vtable pointer and an alignment greater than the pointer size.
//   The Windows compilers will align the first member to the alignment size of the
//   class.  Linux will align the first member to its natural alignment
#define DAC_ALIGNAS(a) alignas(a)

#endif // #ifndef __daccess_h__
