summaryrefslogtreecommitdiff
path: root/src/debug/inc/dacdbiinterface.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/debug/inc/dacdbiinterface.h')
-rw-r--r--src/debug/inc/dacdbiinterface.h2726
1 files changed, 2726 insertions, 0 deletions
diff --git a/src/debug/inc/dacdbiinterface.h b/src/debug/inc/dacdbiinterface.h
new file mode 100644
index 0000000000..fe58724fc5
--- /dev/null
+++ b/src/debug/inc/dacdbiinterface.h
@@ -0,0 +1,2726 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//*****************************************************************************
+// DacDbiInterface.h
+//
+
+//
+// Define the interface between the DAC and DBI.
+//*****************************************************************************
+
+#ifndef _DACDBI_INTERFACE_H_
+#define _DACDBI_INTERFACE_H_
+
+#include <metahost.h>
+
+// The DAC/DBI interface can use structures and LSPTR declarations from the
+// existing V2 interfaces
+#include "dbgipcevents.h"
+
+//-----------------------------------------------------------------------------
+// Deallocation function for memory allocated with the global IAllocator object.
+//
+// Arguments:
+// p - pointer to delete. Allocated with IAllocator::Alloc
+//
+// Notes:
+// This should invoke the dtor and then call IAllocator::Free.
+// In the DAC implementation, this will call via IAllocator.
+// In the DBI implementation, this can directly call delete (assuming the IAllocator::Free
+// directly called new).
+template<class T> void DeleteDbiMemory(T *p);
+// Need a class to serve as a tag that we can use to overload New/Delete.
+class forDbiWorker {};
+#define forDbi (*(forDbiWorker *)NULL)
+extern void * operator new(size_t lenBytes, const forDbiWorker &);
+extern void * operator new[](size_t lenBytes, const forDbiWorker &);
+extern void operator delete(void *p, const forDbiWorker &);
+extern void operator delete[](void *p, const forDbiWorker &);
+
+// The dac exposes a way to walk all GC references in the process. This
+// includes both strong references and weak references. This is done
+// through a referece walk.
+typedef void* * RefWalkHandle;
+
+#include "dacdbistructures.h"
+
+// This is the current format of code:DbiVersion. It needs to be rev'ed when we decide to store something
+// else other than the product version of the DBI in DbiVersion (e.g. a timestamp). See
+// code:CordbProcess::CordbProcess#DBIVersionChecking for more information.
+const DWORD kCurrentDbiVersionFormat = 1;
+
+//-----------------------------------------------------------------------------
+// This is a low-level interface between DAC and DBI.
+// The DAC is the raw DAC-ized code from the EE.
+// DBI is the implementation of ICorDebug on top of that.
+//
+// This interface should be:
+// - Stateless: The DAC component should not have any persistent state. It should not have any resources
+// that it needs to clean up. DBI can store all the state (eg, list of of modules).
+// Using IAllocator/IStringHolder interfaces to allocate data to pass back out is ok because DBI owns
+// the resources, not the DAC layer.
+// - blittable: The types on the interface should be blittable. For example, use TIDs instead of OS Thread handles.
+// Passing pointers to be used as out-parameters is ok.
+// - lightweight: it will inevitably have many methods on it and should be very fluid to use.
+// - very descriptive: heavily call out liabilities on the runtime. For example, don't just have a method like
+// "GetName" where Name is ambiguous. Heavily comment exactly what Name is, when it may fail, if it's 0-length,
+// if it's unique, etc. This serves two purposes:
+// a) it helps ensure the right invariants flow up to the public API level.
+// b) it helps ensure that the debugger is making the right assumptions about the runtime's behavior.
+//
+// #Marshaling:
+// This interface should be marshalable such that the caller (the Right Side) can exist in one
+// process, while the implementation of Dac could be on another machine.
+// - All types need to be marshable.
+// - Use OUT and OPTIONAL as defined in windef.h to guide the marshaler. Here are how types are marshaled:
+// T : value-type, copied on input.
+// T* : will be marshaled as non-null by-ref (copy on input, copy on return),
+// const T*: non-null, copy on input only.
+// OUT T*: non-null copy-on-return only.
+// OPTIONAL T*: by-ref, could be null.
+// - The marshaler has special knowledge of IStringHolder and DacDbiArrayList<T>.
+// - You can write custom marshalers for non-blittable structures defined in DacDbiStructures.h.
+// - There is custom handling for marshalling callbacks.
+//
+//
+// Threading: The interface (and the underlying DataTarget) are free-threaded to leverage
+// concurrency.
+//
+// Allocation:
+// This interface can use IAllocator to allocate objects and hand them back. The allocated objects should be:
+// - closed, serializable object graphs.
+// - should have private fields and public accessors
+// - have dtors that free any allocated the memory via calling DeleteDbiMemory.
+// Objects can be declared in a header and shared between both dbi and dac.
+// Consider using DacDbiArrayList<T> instead of custom allocations.
+
+// Error handling:
+// Any call on the interface may fail. For example, the data-target may not have access to the necessary memory.
+// Methods should throw on error.
+//
+// #Enumeration
+// General rules about Enumerations:
+// - Do not assume that enumerations exposed here are in any particular order.
+// - many enumerations also correspond to Load/Unload events. Since load/unload aren't atomic with publishing
+// in an enumeration, this is a Total Ordering of things:
+// a) object shows up in enumeration
+// b) load event.
+// c) ... steady state ...
+// d) object removed from DacDbi enumeration;
+// Any existing handles we get beyond this are explicitly associated with a Cordb* object; which can be
+// neutered on the unload event by Dbi.
+// e) unload event.
+// - Send after it's reachability from other objects is broken. (Eg, For AppDomain unload
+// means no threads left in that appdomain)
+// - Send before it's deleted (so VMPTR is still valid; not yet recycled).
+// - Send early enough that property access can at least gracefully fail. (eg,
+// Module::GetName should either return the name, or fail)
+//
+// Cordb must neuter any Cordb objects that have any pre-existing handles to the object.
+// After this point, gauranteed that nobody can discover the VMPTR any more:
+// - doesn't show up in enumerations (so can't be discoverered implicitly)
+// - object should not be discoverable by other objects in VM.
+// - any Cordb object that already had it would be neutered by Dbi.
+// - Therefore nothing should even be asking Dac for it.
+// f) object deleted.
+// Think of it like this: The event occurs to let you know that the enumeration has been updated.
+//
+// A robust debugger should not rely on events for correctness. For example,
+// a corrupt debuggee may send:
+// 1) multiple load events. (if target repeats due to an issue)
+// 2) no load event and only an unload event. (if target fails inbetween
+// publish (a) and load (b), and then backout code sends the unload).
+// 3) no unload event. (eg, if target is rudely killed)
+// 4) multiple unload events (if target repeats due to bug)
+//
+// This satisfies the following rules:
+// - once you get the load event, you can find the object via enumeration
+// - once an item is discoverable, it must immediately show up in the enumeration.
+// - once you get the unload event, the object is dead and can't be rediscovered via enumeration.
+//
+// This is an issue even for well-behaved targets. Imagine if a debugger attaches right after
+// an unload event is sent. We don't want the debugger to enumerate and re-discover the
+// unloaded object because now that the unload event is already sent, the debugger won't get
+// any further notification of when the object is deleted in the target.
+// Thus it's valuable for the debugger to have debug-only checks after unload events to assert
+// that the object is no longer discoverable.
+//
+//.............................................................................
+// The purpose of this object is to provide EE funcationality back to
+// the debugger. This represents the entire set of EE functions used
+// by the debugger.
+//
+// We will make this interface larger over time to grow the functionality
+// between the EE and the Debugger.
+//
+//
+//-----------------------------------------------------------------------------
+class IDacDbiInterface
+{
+public:
+ class IStringHolder;
+
+ // The following tag tells the DD-marshalling tool to start scanning.
+ // BEGIN_MARSHAL
+
+ //-----------------------------------------------------------------------------
+ // Functions to control the behavior of the DacDbi implementation itself.
+ //-----------------------------------------------------------------------------
+
+ //
+ // Check whether the version of the DBI matches the version of the runtime.
+ // This is only called when we are remote debugging. On Windows, we should have checked all the
+ // versions before we call any API on the IDacDbiInterface. See
+ // code:CordbProcess::CordbProcess#DBIVersionChecking for more information on version checks.
+ //
+ // Return Value:
+ // S_OK on success.
+ //
+ // Notes:
+ // THIS MUST BE THE FIRST API ON THE INTERFACE!
+ //
+ virtual
+ HRESULT CheckDbiVersion(const DbiVersion * pVersion) = 0;
+
+ //
+ // Flush the DAC cache. This should be called when target memory changes.
+ //
+ //
+ // Return Value:
+ // S_OK on success.
+ //
+ // Notes:
+ // If this fails, the interface is in an undefined state.
+ // This must be called anytime target memory changes, else all other functions
+ // (besides Destroy) may yield out-of-date or semantically incorrect results.
+ //
+ virtual
+ HRESULT FlushCache() = 0;
+
+ //
+ // Control DAC's checking of the target's consistency. Specifically, if this is disabled then
+ // ASSERTs in VM code are ignored. The default is disabled, since DAC should do it's best to
+ // return results even with a corrupt or unsyncrhonized target. See
+ // code:ClrDataAccess::TargetConsistencyAssertsEnabled for more details.
+ //
+ // When testing with a non-corrupt and properly syncrhonized target, this should be enabled to
+ // help catch bugs.
+ //
+ // Arguments:
+ // fEnableAsserts - whether ASSERTs should be raised when consistency checks fail (_DEBUG
+ // builds only)
+ //
+ // Notes:
+ // In the future we may want to extend DAC target consistency checks to be retail checks
+ // (exceptions) as well. We'll also need a mechanism for disabling them (eg. when an advanced
+ // user wants to try to get a result anyway even though the target is inconsistent). In that
+ // case we'll want an additional argument here for enabling/disabling the throwing of
+ // consistency failures exceptions (this is independent from asserts - there are legitimate
+ // scenarios for all 4 combinations).
+ //
+ virtual
+ void DacSetTargetConsistencyChecks(bool fEnableAsserts) = 0;
+
+ //
+ // Destroy the interface object. The client should call this when it's done
+ // with the IDacDbiInterface to free up any resources.
+ //
+ // Return Value:
+ // None.
+ //
+ // Notes:
+ // The client should not call anything else on this interface after Destroy.
+ //
+ virtual
+ void Destroy() = 0;
+
+ //-----------------------------------------------------------------------------
+ // General purpose target inspection functions
+ //-----------------------------------------------------------------------------
+
+ //
+ // Query if Left-side is started up?
+ //
+ //
+ // Return Value:
+ // BOOL whether Left-side is intialized.
+ //
+ // Notes:
+ // If the Left-side is not yet started up, then data in the LS is not yet initialized enough
+ // for us to make meaningful queries, but the runtime will fire "Startup Exception" when it is.
+ //
+ // If the left-side is started up, then data is ready. (Although data may be temporarily inconsistent,
+ // see DataSafe). We may still get a Startup Exception in these cases, but it can be ignored.
+ //
+ virtual
+ BOOL IsLeftSideInitialized() = 0;
+
+
+ //
+ // Get an LS Appdomain via an AppDomain unique ID.
+ // Fails if the AD is not found or if the ID is invalid.
+ //
+ // Arguments:
+ // appdomainId - "unique appdomain ID". Must be a valid Id.
+ //
+ // Return Value:
+ // VMPTR_AppDomain for the corresponding AppDomain ID. Else throws.
+ //
+ // Notes:
+ // This query is based off the lifespan of the AppDomain from the VM's perspective.
+ // The AppDomainId is most likely obtained from an AppDomain-Created debug events.
+ // An AppDomainId is unique for the lifetime of the VM.
+ // This is the inverse function of GetAppDomainId().
+ //
+ virtual
+ VMPTR_AppDomain GetAppDomainFromId(ULONG appdomainId) = 0;
+
+
+ //
+ // Get the AppDomain ID for an AppDomain.
+ //
+ // Arguments:
+ // vmAppDomain - VM pointer to the AppDomain object of interest
+ //
+ // Return Value:
+ // AppDomain ID for appdomain. Else throws.
+ //
+ // Notes:
+ // An AppDomainId is unique for the lifetime of the VM. It is non-zero.
+ //
+ virtual
+ ULONG GetAppDomainId(VMPTR_AppDomain vmAppDomain) = 0;
+
+ //
+ // Get the managed AppDomain object for an AppDomain.
+ //
+ // Arguments:
+ // vmAppDomain - VM pointer to the AppDomain object of interest
+ //
+ // Return Value:
+ // objecthandle for the managed app domain object or the Null VMPTR if there is no
+ // object created yet
+ //
+ // Notes:
+ // The AppDomain managed object is lazily constructed on the AppDomain the first time
+ // it is requested. It may be NULL.
+ //
+ virtual
+ VMPTR_OBJECTHANDLE GetAppDomainObject(VMPTR_AppDomain vmAppDomain) = 0;
+
+ //
+ // Determine if the specified AppDomain is the default domain
+ //
+ // Arguments:
+ // vmAppDomain - VM pointer to the AppDomain ojbect of interest
+ //
+ // Return Value:
+ // TRUE if this is the default appdomain, else FALSE.
+ //
+ // Notes:
+ // The default domain is the only one which cannot be unloaded and exists for the life
+ // of the process.
+ // A well behaved target only has 1 default domain.
+ //
+ virtual
+ BOOL IsDefaultDomain(VMPTR_AppDomain vmAppDomain) = 0;
+
+
+ virtual
+ void GetAssemblyFromDomainAssembly(VMPTR_DomainAssembly vmDomainAssembly, OUT VMPTR_Assembly * vmAssembly) = 0;
+
+ //
+ // Determines whether the runtime security system has assigned full-trust to this assembly.
+ //
+ // Arguments:
+ // vmDomainAssembly - VM pointer to the assembly in question.
+ //
+ // Return Value:
+ // Returns trust status for the assembly.
+ // Throws on error.
+ //
+ // Notes:
+ // Of course trusted malicious code in the process could always cause this API to lie. However,
+ // an assembly loaded without full-trust should have no way of causing this API to return true.
+ //
+ virtual
+ BOOL IsAssemblyFullyTrusted(VMPTR_DomainAssembly vmDomainAssembly) = 0;
+
+
+ //
+ // Get the full AD friendly name for the given EE AppDomain.
+ //
+ // Arguments:
+ // vmAppDomain - VM pointer to the AppDomain.
+ // pStrName - required out parameter where the name will be stored.
+ //
+ // Return Value:
+ // None. On success, sets the string via the holder. Throws on error.
+ // This either sets pStrName or Throws. It won't do both.
+ //
+ // Notes:
+ // AD names have an unbounded length. AppDomain friendly names can also change, and
+ // so callers should be prepared to listen for name-change events and requery.
+ // AD names are specified by the user.
+ //
+ virtual
+ void GetAppDomainFullName(
+ VMPTR_AppDomain vmAppDomain,
+ IStringHolder * pStrName) = 0;
+
+
+ //
+ // #ModuleNames
+ //
+ // Modules / Assemblies have many different naming schemes:
+ //
+ // 1) Metadata Scope name: All modules have metadata, and each metadata scope has a name assigned
+ // by the creator of that scope (eg, the compiler). This usually is similar to the filename, but could
+ // be arbitrary.
+ // eg: "Foo"
+ //
+ // 2) FileRecord: the File record entry in the manifest module's metadata (table 0x26) for this module.
+ // eg: "Foo"
+ //
+ // 3) Managed module path: This is path that the image was loaded from. Eg, "c:\foo.dll". For non-file
+ // based modules (like in-memory, dynamic), there is no file path. The specific path is determined by
+ // fusion / loader policy.
+ // eg: "c:\foo.dll"
+ //
+ // 4) GAC path: If the module is loaded from the GAC, this is the path on disk into the gac cache that
+ // the image was pulled from.
+ // eg: "
+ //
+ // 5) Ngen path: If the module was ngenned, this is the path on disk into the ngen cache that the image
+ // was pulled from.
+ // eg:
+ //
+ // 6) Fully Qualified Assembly Name: this is an abstract name, which the CLR (fusion / loader) will
+ // resolve (to a filename for file-based modules). Managed apps may need to deal in terms of FQN,
+ // but the debugging services generally avoid them.
+ // eg: "Foo, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL".
+ //
+
+
+ //
+ // Get the "simple name" of a module. This is a heuristic within the CLR to return a simple,
+ // not-well-specified, but meaningful, name for a module.
+ //
+ // Arguments:
+ // vmModule - module to query
+ // pStrFileName - string holder to get simple name.
+ //
+ // Return Value:
+ // None, but pStrFilename will be initialized upon return.
+ // Throws if there was a problem reading the data with DAC or if there is an OOM exception,
+ // in which case no string was stored into pStrFilename.
+ //
+ // Notes:
+ // See code:#ModuleNames for an overview on module names.
+ //
+ // This is really just using code:Module::GetSimpleName.
+ // This gives back a meaningful name, which is generally some combination of the metadata
+ // name of the FileRecord name. This is important because it's valid even when a module
+ // doesn't have a filename.
+ //
+ // The simple name does not have any meaning. It is not a filename, does not necessarily have any
+ // relationship to the filename, and it's not necesarily the metadata name.
+ // Do not use the simple name for anything other than as a pretty string to give the an end user.
+ //
+ virtual
+ void GetModuleSimpleName(VMPTR_Module vmModule, IStringHolder * pStrFilename) = 0;
+
+
+ //
+ // Get the full path and file name to the assembly's manifest module.
+ //
+ // Arguments:
+ // vmAssembly - VM pointer to the Assembly.
+ // pStrFilename - required out parameter where the filename will be stored.
+ //
+ // Return Value:
+ // TRUE on success, in which case the filename was stored into pStrFilename
+ // FALSE if the assembly has no filename (eg. for in-memory assemblies), in which
+ // case an empty string was stored into pStrFilename.
+ // Throws if there was a problem reading the data with DAC, in which case
+ // no string was stored into pStrFilename.
+ //
+ // Notes:
+ // See code:#ModuleNames for an overview on module names.
+ //
+ // Normally this is just the filename from which the dll containing the assembly was
+ // loaded. In the case of multi-module assemblies, this is the filename for the
+ // manifest module (the one containing the assembly manifest). For in-memory
+ // assemblies (eg. those loaded from a Byte[], and those created by Reflection.Emit
+ // which will not be saved to disk) there is no filename. In that case this API
+ // returns an empty string.
+ //
+ virtual
+ BOOL GetAssemblyPath(VMPTR_Assembly vmAssembly,
+ IStringHolder * pStrFilename) = 0;
+
+
+ // get a type def resolved across modules
+ // Arguments:
+ // input: pTypeRefInfo - domain file and type ref from the referencing module
+ // output: pTargetRefInfo - domain file and type def from the referenced type (this may
+ // come from a module other than the referencing module)
+ // Note: throws
+ virtual
+ void ResolveTypeReference(const TypeRefData * pTypeRefInfo,
+ TypeRefData * pTargetRefInfo) = 0;
+ //
+ // Get the full path and file name to the module (if any).
+ //
+ // Arguments:
+ // vmModule - VM pointer to the module.
+ // pStrFilename - required out parameter where the filename will be stored.
+ //
+ // Return Value:
+ // TRUE on success, in which case the filename was stored into pStrFilename
+ // FALSE the module has no filename (eg. for in-memory assemblies), in which
+ // case an empty string was stored into pStrFilename.
+ // Throws an exception if there was a problem reading the data with DAC, in which case
+ // no string was stored into pStrFilename.
+ //
+ // Notes:
+ // See code:#ModuleNames for an overview on module names.
+ //
+ // Normally this is just the filename from which the module was loaded.
+ // For in-memory module (eg. those loaded from a Byte[], and those created by Reflection.Emit
+ // which will not be saved to disk) there is no filename. In that case this API
+ // returns an empty string. Consider GetModuleSimpleName in those cases.
+ //
+ // We intentionally don't use the function name "GetModuleFileName" here because
+ // winbase #defines that token (along with many others) to have an A or W suffix.
+ //
+ virtual
+ BOOL GetModulePath(VMPTR_Module vmModule,
+ IStringHolder * pStrFilename) = 0;
+
+
+ //
+ // Get the full path and file name to the ngen image for the module (if any).
+ //
+ // Arguments:
+ // vmModule - VM pointer to the module.
+ // pStrFilename - required out parameter where the filename will be stored.
+ //
+ // Return Value:
+ // TRUE on success, in which case the filename was stored into pStrFilename
+ // FALSE the module has no filename (eg. for in-memory assemblies), in which
+ // case an empty string was stored into pStrFilename.
+ // Throws an exception if there was a problem reading the data with DAC, in which case
+ // no string was stored into pStrFilename.
+ //
+ // Notes:
+ // See code:#ModuleNames for an overview on module names.
+ //
+ virtual
+ BOOL GetModuleNGenPath(VMPTR_Module vmModule,
+ IStringHolder * pStrFilename) = 0;
+
+
+
+ // Get the metadata for the target module
+ //
+ // Arguments:
+ // vmModule - target module to get metadata for.
+ // pTargetBuffer - Out parameter to get target-buffer for metadata. Gauranteed to be non-empty on
+ // return. This will throw CORDBG_E_MISSING_METADATA hr if the buffer is empty.
+ // This does not gaurantee that the buffer is readable. For example, in a minidump, buffer's
+ // memory may not be present.
+ //
+ // Notes:
+ // Each module's metadata exists as a raw buffer in the target. This finds that target buffer and
+ // returns it. The host can then use OpenScopeOnMemory to create an instance of the metadata in
+ // the host process space.
+ //
+ // For dynamic modules, the CLR will eagerly serialize the metadata at "debuggable" points. This
+ // could be after each type is loaded; or after a bulk update.
+ // For non-dynamic modules (both in-memory and file-based), the metadata exists in the PEFile's image.
+ //
+ // Failure cases:
+ // This should succeed in normal, live-debugging scenarios. However, common failure paths here would be:
+ //
+ // 1. Data structures are intact, but Unable to even find the TargetBuffer in the target. In this
+ // case Metadata is truly missing. Likely means:
+ // - target is in the middle of generating metadata for a large bulk operation. (For example, attach
+ // to a TypeLibConverter using Ref.Emit to emit a module for a very large .tlb file).
+ // - corrupted target,
+ // - or the target had some error(out-of-memory?) generating the metadata.
+ // This throws CORDBG_E_MISSING_METADATA.
+ //
+ // 2. Target buffer is found, but memory it describes is not present. Likely means a minidump
+ // scenario with missing memory. Client should use alternative metadata location techniques (such as
+ // an ImagePath to locate the original image and then pulling metadata from that file).
+ //
+ virtual
+ void GetMetadata(VMPTR_Module vmModule, OUT TargetBuffer * pTargetBuffer) = 0;
+
+
+ // Definitions for possible symbol formats
+ // This is equivalent to code:ESymbolFormat in the runtime
+ typedef enum
+ {
+ kSymbolFormatNone, // No symbols available
+ kSymbolFormatPDB, // PDB symbol format - use diasymreader.dll
+ kSymbolFormatILDB, // ILDB symbol format - use ildbsymlib
+ } SymbolFormat;
+
+ //
+ // Get the in-memory symbol (PDB/ILDB) buffer in the target if present.
+ //
+ // Arguments:
+ // vmModule- module to query for.
+ // pTargetBuffer - out parameter to get buffer in target of symbols. If no symbols, pTargetBuffer is empty on return.
+ // pSymbolFormat - out parameter to get the format of the symbols.
+ //
+ // Returns:
+ // 1) If there are in-memory symbols for the given module, pTargetBuffer is set to the buffer describing
+ // the symbols and pSymbolFormat is set to indicate PDB or ILDB format. This buffer can then be read,
+ // converted into an IStream, and passed to ISymUnmanagedBinder::CreateReaderForStream.
+ // 2) If the target is valid, but there is no symbols for the module, then pTargetBuffer->IsEmpty() == true
+ // and *pSymbolFormat == kSymbolFormatNone.
+ // 3) Else, throws exception.
+ //
+ //
+ // Notes:
+ // For file-based modules, PDBs are normally on disk and the debugger retreieves them via a symbol
+ // path without any help from ICorDebug.
+ // However, in some cases, the PDB is stored in-memory and so the debugger needs ICorDebug. Common
+ // cases include:
+ // - dynamic modules generated with reflection-emit.
+ // - in-memory modules loaded by Load(Byte[],Byte[]), which provide the PDB as a byte[].
+ // - hosted modules where the host (such as SQL) store the PDB.
+ //
+ // In all cases, this can commonly fail. Executable code does not need to have a PDB.
+ virtual
+ void GetSymbolsBuffer(VMPTR_Module vmModule, OUT TargetBuffer * pTargetBuffer, OUT SymbolFormat * pSymbolFormat) = 0;
+
+ //
+ // Get properties for a module
+ //
+ // Arguments:
+ // vmModule - vm handle to a module
+ // pData - required out parameter which will be filled out with module properties
+ //
+ // Notes:
+ // See definition of DomainFileInfo for more details about what properties
+ // this gives back.
+ virtual
+ void GetModuleData(VMPTR_Module vmModule, OUT ModuleInfo * pData) = 0;
+
+
+ //
+ // Get properties for a DomainFile
+ //
+ // Arguments:
+ // vmDomainFile - vm handle to a DomainFile
+ // pData - required out parameter which will be filled out with module properties
+ //
+ // Notes:
+ // See definition of DomainFileInfo for more details about what properties
+ // this gives back.
+ virtual
+ void GetDomainFileData(VMPTR_DomainFile vmDomainFile, OUT DomainFileInfo * pData) = 0;
+
+ virtual
+ void GetModuleForDomainFile(VMPTR_DomainFile vmDomainFile, OUT VMPTR_Module * pModule) = 0;
+
+ //.........................................................................
+ // These methods were the methods that DBI was calling from IXClrData in V2.
+ // We imported them over to this V3 interface so that we can sever all ties between DBI and the
+ // old IXClrData.
+ //
+ // The exact semantics of these are whatever their V2 IXClrData counterpart did.
+ // We may eventually migrate these to their real V3 replacements.
+ //.........................................................................
+
+ // "types" of addresses. This is taken exactly from the definition, but renamed to match
+ // CLR coding conventions.
+ typedef enum
+ {
+ kAddressUnrecognized,
+ kAddressManagedMethod,
+ kAddressRuntimeManagedCode,
+ kAddressRuntimeUnmanagedCode,
+ kAddressGcData,
+ kAddressRuntimeManagedStub,
+ kAddressRuntimeUnmanagedStub,
+ } AddressType;
+
+ //
+ // Get the "type" of address.
+ //
+ // Arguments:
+ // address - address to query type.
+ //
+ // Return Value:
+ // Type of address. Throws on error.
+ //
+ // Notes:
+ // This is taken exactly from the IXClrData definition.
+ // This is provided for V3 compatibility to support Interop-debugging.
+ // This should eventually be deprecated.
+ //
+ virtual
+ AddressType GetAddressType(CORDB_ADDRESS address) = 0;
+
+
+ //
+ // Query if address is a CLR stub.
+ //
+ // Arguments:
+ // address - Target address to query for.
+ //
+ //
+ // Return Value:
+ // true if the address is a CLR stub.
+ //
+ // Notes:
+ // This is used to implement ICorDebugProcess::IsTransitionStub
+ // This yields true if the address is claimed by a CLR stub manager, or if the IP is in mscorwks.
+ // Conceptually, This should eventually be merged with GetAddressType().
+ //
+ virtual
+ BOOL IsTransitionStub(CORDB_ADDRESS address) = 0;
+
+ //.........................................................................
+ // Get the values of the JIT Optimization and EnC flags.
+ //
+ // Arguments:
+ // vmDomainFile - (input) VM DomainFile (module) for which we are retrieving flags
+ // pfAllowJITOpts - (mandatory output) true iff this is not compiled for debug,
+ // i.e., without optimization
+ // pfEnableEnc - (mandatory output) true iff this module has EnC enabled
+ //
+ // Return Value:
+ // Returns on success. Throws on failure.
+ //
+ // Notes:
+ // This is used to implement both ICorDebugModule2::GetJitCompilerFlags and
+ // ICorDebugCode2::GetCompilerFlags.
+ //.........................................................................
+
+ virtual
+ void GetCompilerFlags(
+ VMPTR_DomainFile vmDomainFile,
+ OUT BOOL * pfAllowJITOpts,
+ OUT BOOL * pfEnableEnC) = 0;
+
+ //.........................................................................
+ // Set the values of the JIT optimization and EnC flags.
+ //
+ // Arguments:
+ // vmDomainFile - (input) VM DomainFile (module) for which we are retrieving flags
+ // pfAllowJITOpts - (input) true iff this should not be compiled for debug,
+ // i.e., without optimization
+ // pfEnableEnc - (input) true iff this module should have EnC enabled. If this is
+ // false, no change is made to the EnC flags. In other words, once EnC is enabled,
+ // there is no way to disable it.
+ //
+ // Return Value:
+ // S_OK on success and all bits were set.
+ // CORDBG_S_NOT_ALL_BITS_SET - if not all bits are set. Must use GetCompileFlags to
+ // determine which bits were set.
+ // CORDBG_E_CANT_CHANGE_JIT_SETTING_FOR_ZAP_MODULE - if module is ngenned.
+ // Throw on other errors.
+ //
+ // Notes:
+ // Caller can only use this at module-load before any methods are jitted.
+ // This may be called multiple times.
+ // This is used to implement both ICorDebugModule2::SetJitCompilerFlags and
+ // ICorDebugModule::EnableJITDebugging.
+ //.........................................................................
+
+ virtual
+ HRESULT SetCompilerFlags(VMPTR_DomainFile vmDomainFile,
+ BOOL fAllowJitOpts,
+ BOOL fEnableEnC) = 0;
+
+ //
+ // Enumerate all AppDomains in the process.
+ //
+ // Arguments:
+ // fpCallback - callback to invoke on each appdomain
+ // pUserData - user data to supply for each callback.
+ //
+ // Return Value:
+ // Returns on success. Throws on error.
+ //
+ // Notes:
+ // Enumerates all appdomains in the process, including the Default-domain.
+ // Appdomains must show up in this list before the AD Load event is sent, and before
+ // that appdomain is discoverable from the debugger.
+ // See enumeration rules for details.
+ //
+ typedef void (*FP_APPDOMAIN_ENUMERATION_CALLBACK)(VMPTR_AppDomain vmAppDomain, CALLBACK_DATA pUserData);
+ virtual
+ void EnumerateAppDomains(FP_APPDOMAIN_ENUMERATION_CALLBACK fpCallback,
+ CALLBACK_DATA pUserData) = 0;
+
+
+ //
+ // Eunmerate all Assemblies in an appdomain. Enumerations is in load-order
+ //
+ // Arguments:
+ // vmAppDomain - domain in which to enumerate
+ // fpCallback - address to query type.
+ // pUserData - required out parameter for type of address.
+ //
+ // Return Value:
+ // Returns on success. Throws on error.
+ //
+ // Notes:
+ // Enumerates all executable assemblies (both shared and unshared) within an appdomain.
+ // This does not include inspection-only assemblies because those are just data and
+ // not executable (eg, they'll never show up on the stack and you can't set a breakpoint in them).
+ // This enumeration needs to be consistent with load/unload events.
+ // See enumeration rules for details.
+ //
+ // The order of the enumeration is the order the assemblies where loaded.
+ // Ultimately, the debugger needs to be able to tell the user the load
+ // order of assemblies (it can do this with native dlls). Since
+ // managed assembliees don't 1:1 correspond to native dlls, debuggers
+ // need this information from the runtime.
+ //
+
+ typedef void (*FP_ASSEMBLY_ENUMERATION_CALLBACK)(VMPTR_DomainAssembly vmDomainAssembly, CALLBACK_DATA pUserData);
+ virtual
+ void EnumerateAssembliesInAppDomain(VMPTR_AppDomain vmAppDomain,
+ FP_ASSEMBLY_ENUMERATION_CALLBACK fpCallback,
+ CALLBACK_DATA pUserData) = 0;
+
+
+
+ //
+ // Callback function for EnumerateModulesInAssembly
+ //
+ // This can throw on error.
+ //
+ // Arguments:
+ // vmModule - new module from the enumeration
+ // pUserData - user data passed to EnumerateModulesInAssembly
+ typedef void (*FP_MODULE_ENUMERATION_CALLBACK)(VMPTR_DomainFile vmModule, CALLBACK_DATA pUserData);
+
+ //
+ // Enumerates all the code Modules in an assembly.
+ //
+ // Arguments:
+ // vmAssembly - assembly to enumerate within
+ // fpCallback - callback function to invoke on each module
+ // pUserData - arbitrary data passed to the callback
+ //
+ // Notes:
+ // This only enumerates "code" modules (ie, modules that have executable code in them). That
+ // includes normal file-based, ngenned, in-memory, and even dynamic modules.
+ // That excludes:
+ // - Resource modules (which have no code or metadata)
+ // - Inspection-only modules. These are viewed as pure data from the debugger's perspective.
+ //
+ virtual
+ void EnumerateModulesInAssembly(
+ VMPTR_DomainAssembly vmAssembly,
+ FP_MODULE_ENUMERATION_CALLBACK fpCallback,
+ CALLBACK_DATA pUserData) = 0;
+
+
+
+ //
+ // When stopped at an event, request a synchronization.
+ //
+ //
+ // Return Value:
+ // Returns on success. Throws on error.
+ //
+ // Notes:
+ // Call this when an event is dispatched (eg, LoadModule) to request the runtime
+ // synchronize. This does a cooperative sync with the LS. This is not an async break
+ // and can not be called at arbitrary points.
+ // This primitive lets the LS always take the V3 codepath and defer decision making to the RS.
+ // The V2 behavior is to call this after every event (Since that's what V2 did).
+ // The V3 behavior is to never call this.
+ //
+ // If this is called, the LS will sync and we will get a SyncComplete.
+ //
+ // This is also like a precursor to "AsyncBreakAllOtherThreads"
+ //
+ virtual
+ void RequestSyncAtEvent() = 0;
+
+ // Sets a flag inside LS.Debugger that indicates that
+ // 1. all "first chance exception" events should not be sent to the debugger
+ // 2. "exception handler found" events for exceptions never crossing JMC frames should not be sent to the debugger
+ //
+ // Arguments:
+ // sendExceptionsOutsideOfJMC - new value for the flag Debugger::m_sendExceptionsOutsideOfJMC.
+ //
+ // Return Value:
+ // Returns error code, never throws.
+ //
+ // Note: This call is used by ICorDebugProcess8.EnableExceptionCallbacksOutsideOfMyCode.
+ virtual
+ HRESULT SetSendExceptionsOutsideOfJMC(BOOL sendExceptionsOutsideOfJMC) = 0;
+
+ //
+ // Notify the debuggee that a debugger atach is pending.
+ //
+ // Arguments:
+ // None
+ //
+ // Return Value:
+ // Returns on success. Throws on error.
+ //
+ // Notes:
+ // Attaching means that CORDebuggerPendingAttach() will now return true.
+ // This doesn't do anything else (eg, no fake events).
+ //
+ // @dbgtodo- still an open Feature-Crew decision how this is exposed publicly.
+ virtual
+ void MarkDebuggerAttachPending() = 0;
+
+ //
+ // Notify the debuggee that a debugger is attached / detached.
+ //
+ // Arguments:
+ // fAttached - true if we're attaching, false if we're detaching.
+ //
+ // Return Value:
+ // Returns on success. Throws on error.
+ //
+ // Notes:
+ // Attaching means that CorDebuggerAttached() will now return true.
+ // This doesn't do anything else (eg, no fake events).
+ // This lets the V3 codepaths invade the LS to subscribe to events.
+ //
+ // @dbgtodo- still an open Feature-Crew decision how this is exposed publicly.
+ virtual
+ void MarkDebuggerAttached(BOOL fAttached) = 0;
+
+
+
+ //
+ // Hijack a thread. This will effectively do a native func-eval of the thread to set the IP
+ // to a hijack stub and push the parameters.
+ //
+ // Arguments:
+ // dwThreadId - OS thread to hijack. This must be consistent with pRecord and pOriginalContext
+ // pRecord - optional pointer to Exception record. Required if this is hijacked at an exception.
+ // NULL if this is hijacked at a managed IP.
+ // pOriginalContext - optional pointer to buffer to receive the context that the thread is hijacked from.
+ // The caller can use this to either restore the hijack or walk the hijack.
+ // cbSizeContext - size in bytes of buffer pointed to by pContext
+ // reason - reason code for the hijack. The hijack stub can then delegate to the proper hijack.
+ // pUserData - arbitrary data passed through to hijack. This is reason-depedendent.
+ // pRemoteContextAddr - If non-NULL this receives the remote address where the CONTEXT was written in the
+ // in the debuggee.
+ //
+ // Assumptions:
+ // Caller must guarantee this is safe.
+ // This is intended to be used at a thread that either just had an exception or is at a managed IP.
+ // If this is hijacked at an exception, client must cancel the exception (gh / DBG_CONTINUE)
+ // so that the OS exception processing doesn't interfere with the hijack.
+ //
+ // Notes:
+ // Hijack is hard, so we want 1 hijack stub that handles all our hijacking needs.
+ // This lets us share:
+ // - assembly stubs (which are very platform specific)
+ // - hijacking / restoration mechanics,
+ // - making the hijack walkable via the stackwalker.
+ //
+ // Hijacking can be used to implement: func-eval, FE abort, Synchronizing,
+ // dispatching Unhandled Exception notifications.
+ //
+ // Nesting: Since Hijacking passes the key state off to the hijacked thread, (such as original
+ // context to be used with restoring the hijack), the raw hijacking nests just like function
+ // calls. However, the client may need to keep additional state to handle nesting. For example,
+ // nested hijacks will require the client to track multiple CONTEXT*.
+ //
+ // If the thread is in jitted code, then the hijack needs to cooperate with the in-process
+ // stackwalker that the GC uses. It must be in cooperative mode, and push a Frame on the
+ // frame chain to protect the managed frames it hijacked from before it goes to preemptive mode.
+
+ virtual
+ void Hijack(
+ VMPTR_Thread vmThread,
+ ULONG32 dwThreadId,
+ const EXCEPTION_RECORD * pRecord,
+ T_CONTEXT * pOriginalContext,
+ ULONG32 cbSizeContext,
+ EHijackReason::EHijackReason reason,
+ void * pUserData,
+ CORDB_ADDRESS * pRemoteContextAddr) = 0;
+
+
+ //
+ // Callback function for connection enumeration.
+ //
+ // Arguments:
+ // id - the connection ID.
+ // pName - the name of the connection.
+ // pUserData - user data supplied to EnumerateConnections
+ typedef void (*FP_CONNECTION_CALLBACK)(DWORD id, LPCWSTR pName, CALLBACK_DATA pUserData);
+
+ //
+ // Enumerate all the Connections in the process.
+ //
+ // Arguments:
+ // fpCallback - callback to invoke for each connection
+ // pUserData - random user data to pass to callback.
+ //
+ // Notes:
+ // This enumerates all the connections. The host notifies the debugger of Connections
+ // via the ICLRDebugManager interface.
+ // ICorDebug has no interest in connections. It's merely the transport between the host and the debugger.
+ // Ideally, that transport would be more general.
+ //
+ // V2 Attach would provide faked up CreateConnection, ChangeConnection events on attach.
+ // This enumeration ability allows V3 to emulate that behavior.
+ //
+#ifdef FEATURE_INCLUDE_ALL_INTERFACES
+ virtual void EnumerateConnections(FP_CONNECTION_CALLBACK fpCallback, CALLBACK_DATA pUserData) = 0;
+#endif //FEATURE_INCLUDE_ALL_INTERFACES
+
+ //
+ // Enumerate all threads in the target.
+ //
+ // Arguments:
+ // fpCallback - callback function to invoke on each thread.
+ // pUserData - arbitrary user data supplied to each callback.
+ //
+ // Notes:
+ // This enumerates the ThreadStore in the target, which is all the Thread* objects.
+ // This includes threads that have entered the runtime. This may include threads
+ // even before that thread has executed IL and after that thread no longer has managed
+ // code on its stack.
+
+ // Callback invoked for each thread.
+ typedef void (*FP_THREAD_ENUMERATION_CALLBACK)(VMPTR_Thread vmThread, CALLBACK_DATA pUserData);
+
+ virtual
+ void EnumerateThreads(FP_THREAD_ENUMERATION_CALLBACK fpCallback, CALLBACK_DATA pUserData) = 0;
+
+
+ // Check if the thread is dead
+ //
+ // Arguments:
+ // vmThread - valid thread to check if it's dead.
+ //
+ // Returns: true if the thread is "dead", which means it can never call managed code again.
+ //
+ // Notes:
+ // #IsThreadMarkedDead
+ // Threads shutdown states are:
+ // 1) Thread is running managed code normally. Thread eventually exits all managed code and
+ // gets to a point where it will never call managed code again.
+ // 2) Thread is marked as dead.
+ // - For threads created outside of the runtime (such as a native thread that wanders into
+ // managed code), this mark can happen in DllMain(ThreadDetach)
+ // - For threads created by the runtime (eg, System.Threading.Thread.Start), this may be done
+ // at the top of the threads stack after it calls the user's Thread-Proc.
+ // 3) MAYBE Native thread exits at this point (or it may not). This would be the common case
+ // for threads created outside the runtime.
+ // 4) Thread exit event is sent.
+ // - For threads created by the runtime, this may be sent at the top of the thread's
+ // stack (or even when we know that the thread will never execute managed code again)
+ // - For threads created outside the runtime, this is more difficult. A thread can
+ // call into managed code and then return, and then call back into managed code at a
+ // later time (The finalizer does this!). So it's not clear when the native thread
+ // actually exits and will never call managed code again. The only hook we have for
+ // this is DllMain(Thread-Detach). We can mark bits in DllMain, but we can't send
+ // debugger notifications (too dangerous from such a restricted context).
+ // So we may mark the thread as dead, but then sweep later (perhaps on the finalizer
+ // thread), and thus send the Exit events later.
+ // 5) Native thread may exit at this point. This is the common case for threads created by
+ // the runtime.
+ //
+ // The underlying native thread may have exited at eitehr #3 or #5. Because of this
+ // flexibility, we don't want to rely on native thread exit events.
+ // This function checks if a Thread is passed state #2 (marked as dead). The key invariant
+ // is that once a thread is marked as dead:
+ // - it can never call managed code again.
+ // - it should not be discoverable by DacDbi enumerations.
+ //
+ // DBI should prefer relying on IsThreadMarkedDead rather than event notifications (either
+ // managed or native) because tracking events requires that DBI maintain state, which means
+ // that attach + dump cases may break. For example, we want a full dump at the ExitThread
+ // event to have the same view as a live process at the ExitThread event.
+ //
+ // We avoid relying on the native thread exit notifications because:
+ // - that's a specific feature of the Win32 debugging API that may not be available on other platforms.
+ // - the only native events the pipeline gets are Exceptions.
+ //
+ // Whether a thread is dead can be inferred from the ICorDebug API. However, we have this
+ // on DacDbi to ensure that this definition is consistent with the other DacDbi methods,
+ // especially the enumeration and discovery rules.
+ virtual
+ bool IsThreadMarkedDead(VMPTR_Thread vmThread) = 0;
+
+
+ //
+ // Return the handle of the specified thread.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ //
+ // Return Value:
+ // the handle of the specified thread
+ //
+ // @dbgtodo- this should go away in V3. This is useless on a dump.
+
+ virtual
+ HANDLE GetThreadHandle(VMPTR_Thread vmThread) = 0;
+
+ //
+ // Return the object handle for the managed Thread object corresponding to the specified thread.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ //
+ // Return Value:
+ // This function returns the object handle for the managed Thread object corresponding to the
+ // specified thread. The return value may be NULL if a managed Thread object has not been created
+ // for the specified thread yet.
+ //
+
+ virtual
+ VMPTR_OBJECTHANDLE GetThreadObject(VMPTR_Thread vmThread) = 0;
+
+ //
+ // Set and reset the TSNC_DebuggerUserSuspend bit on the state of the specified thread
+ // according to the CorDebugThreadState.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ // debugState - the desired CorDebugThreadState
+ //
+
+ virtual
+ void SetDebugState(VMPTR_Thread vmThread,
+ CorDebugThreadState debugState) = 0;
+
+ //
+ // Returns TRUE if this thread has an unhandled exception
+ //
+ // Arguments:
+ // vmThread - the thread to query
+ //
+ // Return Value
+ // TRUE iff this thread has an unhandled exception
+ //
+ virtual
+ BOOL HasUnhandledException(VMPTR_Thread vmThread) = 0;
+
+ //
+ // Return the user state of the specified thread. Most of the state are derived from
+ // the ThreadState of the specified thread, e.g. TS_Background, TS_Unstarted, etc.
+ // The exception is USER_UNSAFE_POINT, which we need to do a one-frame stackwalk to figure out.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ //
+ // Return Value:
+ // the user state of the specified thread
+ //
+
+ virtual
+ CorDebugUserState GetUserState(VMPTR_Thread vmThread) = 0;
+
+
+ //
+ // Returns most of the user state of the specified thread,
+ // i.e. flags which can be derived from the ThreadState:
+ // USER_STOP_REQUESTED, USER_SUSPEND_REQUESTED, USER_BACKGROUND, USER_UNSTARTED
+ // USER_STOPPED, USER_WAIT_SLEEP_JOIN, USER_SUSPENDED, USER_THREADPOOL
+ //
+ // Only USER_UNSAFE_POINT is always set to 0, since it takes additional stackwalk.
+ // If you need USER_UNSAFE_POINT, use GetUserState(VMPTR_Thread);
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ //
+ // Return Value:
+ // the user state of the specified thread
+ //
+ virtual
+ CorDebugUserState GetPartialUserState(VMPTR_Thread vmThread) = 0;
+
+
+ //
+ // Return the connection ID of the specified thread.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ //
+ // Return Value:
+ // the connection ID of the specified thread
+ //
+
+ virtual
+ CONNID GetConnectionID(VMPTR_Thread vmThread) = 0;
+
+ //
+ // Return the task ID of the specified thread.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ //
+ // Return Value:
+ // the task ID of the specified thread
+ //
+
+ virtual
+ TASKID GetTaskID(VMPTR_Thread vmThread) = 0;
+
+ //
+ // Return the OS thread ID of the specified thread
+ //
+ // Arguments:
+ // vmThread - the specified thread; cannot be NULL
+ //
+ // Return Value:
+ // the OS thread ID of the specified thread. Returns 0 if not scheduled.
+ //
+
+ virtual
+ DWORD TryGetVolatileOSThreadID(VMPTR_Thread vmThread) = 0;
+
+ //
+ // Return the unique thread ID of the specified thread. The value used for the thread ID changes
+ // depending on whether the runtime is being hosted. In non-hosted scenarios, a managed thread will
+ // always be associated with the same native thread, and so we can use the OS thread ID as the thread ID
+ // for the managed thread. In hosted scenarios, however, a managed thread may run on multiple native
+ // threads. It may not even have a backing native thread if it's switched out. Therefore, we can't use
+ // the OS thread ID as the thread ID. Instead, we use the internal managed thread ID.
+ //
+ // Arguments:
+ // vmThread - the specified thread; cannot be NULL
+ //
+ // Return Value:
+ // Returns a stable and unique thread ID for the lifetime of the specified managed thread.
+ //
+
+ virtual
+ DWORD GetUniqueThreadID(VMPTR_Thread vmThread) = 0;
+
+ //
+ // Return the object handle to the managed Exception object of the current exception
+ // on the specified thread. The return value could be NULL if there is no current exception.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ //
+ // Return Value:
+ // This function returns the object handle to the managed Exception object of the current exception.
+ // The return value may be NULL if there is no exception being processed, or if the specified thread
+ // is an unmanaged thread which has entered and exited the runtime.
+ //
+
+ virtual
+ VMPTR_OBJECTHANDLE GetCurrentException(VMPTR_Thread vmThread) = 0;
+
+ //
+ // Return the object handle to the managed object for a given CCW pointer.
+ //
+ // Arguments:
+ // ccwPtr - the specified ccw pointer
+ //
+ // Return Value:
+ // This function returns the object handle to the managed object for a given CCW pointer.
+ //
+
+ virtual
+ VMPTR_OBJECTHANDLE GetObjectForCCW(CORDB_ADDRESS ccwPtr) = 0;
+
+ //
+ // Return the object handle to the managed CustomNotification object of the current notification
+ // on the specified thread. The return value could be NULL if there is no current notification.
+ //
+ // Arguments:
+ // vmThread - the specified thread on which the notification occurred
+ //
+ // Return Value:
+ // This function returns the object handle to the managed CustomNotification object of the current notification.
+ // The return value may be NULL if there is no current notification.
+ //
+
+ virtual
+ VMPTR_OBJECTHANDLE GetCurrentCustomDebuggerNotification(VMPTR_Thread vmThread) = 0;
+
+
+ //
+ // Return the current appdomain the specified thread is in.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ //
+ // Return Value:
+ // the current appdomain of the specified thread
+ //
+ // Notes:
+ // This function throws if the current appdomain is NULL for whatever reason.
+ //
+
+ virtual
+ VMPTR_AppDomain GetCurrentAppDomain(VMPTR_Thread vmThread) = 0;
+
+
+ //
+ // Resolve an assembly
+ //
+ // Arguments:
+ // vmScope - module containing metadata that the token is scoped to.
+ // tkAssemblyRef - assembly ref token to lookup.
+ //
+ // Returns:
+ // Assembly that the loader/fusion has bound to the given assembly ref.
+ // Returns NULL if the assembly has not yet been loaded (a common case).
+ // Throws on error.
+ //
+ // Notes:
+ // A single module has metadata that specifies references via tokens. The
+ // loader/fusion goes through tremendous and random policy hoops to determine
+ // which specific file actually gets bound to the reference. This policy includes
+ // things like config files, registry settings, and many other knobs.
+ //
+ // The debugger can't duplicate this policy with 100% accuracy, and
+ // so we need DAC to lookup the assembly that was actually loaded.
+ virtual
+ VMPTR_DomainAssembly ResolveAssembly(VMPTR_DomainFile vmScope, mdToken tkAssemblyRef) = 0;
+
+ //-----------------------------------------------------------------------------
+ // Interface for initializing the native/IL sequence points and native var info
+ // for a function.
+ // Arguments:
+ // input:
+ // vmMethodDesc MethodDesc of the function
+ // startAddr starting address of the function--this serves to
+ // differentiate various EnC versions of the function
+ // fCodePitched indicates whether code for the function has been pitched
+ // fJitComplete indicates whether the function has been jitted
+ // output:
+ // pNativeVarData space for the native code offset information for locals
+ // pSequencePoints space for the IL/native sequence points
+ // Return value:
+ // none, but may throw an exception
+ // Assumptions:
+ // vmMethodDesc, pNativeVarInfo and pSequencePoints are non-NULL
+
+ // Notes:
+ //-----------------------------------------------------------------------------
+
+ virtual
+ void GetNativeCodeSequencePointsAndVarInfo(VMPTR_MethodDesc vmMethodDesc,
+ CORDB_ADDRESS startAddress,
+ BOOL fCodeAvailabe,
+ OUT NativeVarData * pNativeVarData,
+ OUT SequencePoints * pSequencePoints) = 0;
+
+ //
+ // Return the filter CONTEXT on the LS. Once we move entirely over to the new managed pipeline
+ // built on top of the Win32 debugging API, this won't be necessary.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ //
+ // Return Value:
+ // the filter CONTEXT of the specified thread
+ //
+ // Notes:
+ // This function should go away when everything is moved OOP and
+ // we don't have a filter CONTEXT on the LS anymore.
+ //
+
+ virtual
+ VMPTR_CONTEXT GetManagedStoppedContext(VMPTR_Thread vmThread) = 0;
+
+ typedef enum
+ {
+ kInvalid,
+ kManagedStackFrame,
+ kExplicitFrame,
+ kNativeStackFrame,
+ kNativeRuntimeUnwindableStackFrame,
+ kAtEndOfStack,
+ } FrameType;
+
+ // The stackwalker functions allocate persistent state within DDImpl. Clients can hold onto
+ // this via an opaque StackWalkHandle.
+ typedef void* * StackWalkHandle;
+
+ //
+ // Create a stackwalker on the specified thread and return a handle to it.
+ // Initially, the stackwalker is at the filter CONTEXT if there is one.
+ // Otherwise it is at the leaf CONTEXT. It DOES NOT fast forward to the first frame of interest.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ // pInternalContextBuffer - a CONTEXT buffer for the stackwalker to work with
+ // ppSFIHandle - out parameter; return a handle to the stackwalker
+ //
+ // Notes:
+ // Call DeleteStackWalk() to delete the stackwalk buffer.
+ // This is a special case that violates the 'no state' tenant.
+ //
+
+ virtual
+ void CreateStackWalk(VMPTR_Thread vmThread,
+ DT_CONTEXT * pInternalContextBuffer,
+ OUT StackWalkHandle * ppSFIHandle) = 0;
+
+ // Delete the stackwalk object created from CreateStackWalk.
+ virtual
+ void DeleteStackWalk(StackWalkHandle ppSFIHandle) = 0;
+
+ //
+ // Get the CONTEXT of the current frame where the stackwalker is stopped at.
+ //
+ // Arguments:
+ // pSFIHandle - the handle to the stackwalker
+ // pContext - OUT: the CONTEXT to be filled out. The context control flags are ignored.
+ //
+
+ virtual
+ void GetStackWalkCurrentContext(StackWalkHandle pSFIHandle,
+ DT_CONTEXT * pContext) = 0;
+
+ //
+ // Set the stackwalker to the given CONTEXT. The CorDebugSetContextFlag indicates whether
+ // the CONTEXT is "active", meaning that the IP is point at the current instruction,
+ // not the return address of some function call.
+ //
+ // Arguments:
+ // vmThread - the current thread
+ // pSFIHandle - the handle to the stackwalker
+ // flag - flag to indicate whether the specified CONTEXT is "active"
+ // pContext - the specified CONTEXT. This may make correctional adjustments to the context's IP.
+ //
+
+ virtual
+ void SetStackWalkCurrentContext(VMPTR_Thread vmThread,
+ StackWalkHandle pSFIHandle,
+ CorDebugSetContextFlag flag,
+ DT_CONTEXT * pContext) = 0;
+
+ //
+ // Unwind the stackwalker to the next frame. The next frame could be any actual stack frame,
+ // explicit frame, native marker frame, etc. Call GetStackWalkCurrentFrameInfo() to find out
+ // more about the frame.
+ //
+ // Arguments:
+ // pSFIHandle - the handle to the stackwalker
+ //
+ // Return Value:
+ // Return TRUE if we successfully unwind to the next frame.
+ // Return FALSE if there is no more frames to walk.
+ // Throw on error.
+ //
+
+ virtual
+ BOOL UnwindStackWalkFrame(StackWalkHandle pSFIHandle) = 0;
+
+ //
+ // Check whether the specified CONTEXT is valid. The only check we perform right now is whether the
+ // SP in the specified CONTEXT is in the stack range of the thread.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ // pContext - the CONTEXT to be checked
+ //
+ // Return Value:
+ // Return S_OK if the CONTEXT passes our checks.
+ // Returns CORDBG_E_NON_MATCHING_CONTEXT if the SP in the specified CONTEXT doesn't fall in the stack
+ // range of the thread.
+ // Throws on error.
+ //
+
+ virtual
+ HRESULT CheckContext(VMPTR_Thread vmThread,
+ const DT_CONTEXT * pContext) = 0;
+
+ //
+ // Fill in the DebuggerIPCE_STRData structure with information about the current frame
+ // where the stackwalker is stopped at.
+ //
+ // Arguments:
+ // pSFIHandle - the handle to the stackwalker
+ // pFrameData - the DebuggerIPCE_STRData to be filled out;
+ // it can be NULL if you just want to know the frame type
+ //
+ // Return Value:
+ // Return the type of the current frame
+ //
+
+ virtual
+ FrameType GetStackWalkCurrentFrameInfo(StackWalkHandle pSFIHandle,
+ OPTIONAL DebuggerIPCE_STRData * pFrameData) = 0;
+
+ //
+ // Return the number of internal frames on the specified thread.
+ //
+ // Arguments:
+ // vmThread - the thread whose internal frames are being retrieved
+ //
+ // Return Value:
+ // Return the number of internal frames.
+ //
+ // Notes:
+ // Explicit frames are "marker objects" the runtime pushes on the stack to mark special places, e.g.
+ // appdomain transition, managed-to- unmanaged transition, etc. Internal frames are only a subset of
+ // explicit frames. Explicit frames which are not interesting to the debugger are not exposed (e.g.
+ // GCFrame). Internal frames are interesting to the debugger if they have a CorDebugInternalFrameType
+ // other than STUBFRAME_NONE.
+ //
+ // The user should call this function before code:IDacDbiInterface::EnumerateInternalFrames to figure
+ // out how many interesting internal frames there are.
+ //
+
+ virtual
+ ULONG32 GetCountOfInternalFrames(VMPTR_Thread vmThread) = 0;
+
+ //
+ // Enumerate the internal frames on the specified thread and invoke the provided callback on each of
+ // them. Information about the internal frame is stored in the DebuggerIPCE_STRData.
+ //
+ // Arguments:
+ // vmThread - the thread to be walked fpCallback - callback function invoked on each internal frame
+ // pUserData - user-specified custom data
+ //
+ // Notes:
+ // The user can call code:IDacDbiInterface::GetCountOfInternalFrames to figure out how many internal
+ // frames are on the thread before calling this function. Also, refer to the comment of that function
+ // to find out more about internal frames.
+ //
+
+ typedef void (*FP_INTERNAL_FRAME_ENUMERATION_CALLBACK)(const DebuggerIPCE_STRData * pFrameData, CALLBACK_DATA pUserData);
+
+ virtual
+ void EnumerateInternalFrames(VMPTR_Thread vmThread,
+ FP_INTERNAL_FRAME_ENUMERATION_CALLBACK fpCallback,
+ CALLBACK_DATA pUserData) = 0;
+
+ //
+ // Given the FramePointer of the parent frame and the FramePointer of the current frame,
+ // check if the current frame is the parent frame. fpParent should have been returned
+ // previously by the DacDbiInterface via GetStackWalkCurrentFrameInfo().
+ //
+ // Arguments:
+ // fpToCheck - the FramePointer of the current frame
+ // fpParent - the FramePointer of the parent frame; should have been returned earlier by the DDI
+ //
+ // Return Value:
+ // Return TRUE if the current frame is indeed the parent frame
+ //
+ // Note:
+ // Because of the complexity involved in checking for the parent frame, we should always
+ // ask the ExceptionTracker to do it.
+ //
+
+ virtual
+ BOOL IsMatchingParentFrame(FramePointer fpToCheck, FramePointer fpParent) = 0;
+
+ //
+ // Return the stack parameter size of a given method. This is necessary on x86 for unwinding.
+ //
+ // Arguments:
+ // controlPC - any address in the specified method; you can use the current PC of the stack frame
+ //
+ // Return Value:
+ // Return the size of the stack parameters of the given method.
+ // Return 0 for vararg methods.
+ //
+ // Assumptions:
+ // The callee stack parameter size is constant throughout a method.
+ //
+
+ virtual
+ ULONG32 GetStackParameterSize(CORDB_ADDRESS controlPC) = 0;
+
+ //
+ // Return the FramePointer of the current frame where the stackwalker is stopped at.
+ //
+ // Arguments:
+ // pSFIHandle - the handle to the stackwalker
+ //
+ // Return Value:
+ // the FramePointer of the current frame
+ //
+ // Notes:
+ // The FramePointer of a stack frame is:
+ // the stack address of the return address on x86,
+ // the current SP on AMD64,
+ //
+ // On x86, to get the stack address of the return address, we need to unwind one more frame
+ // and use the SP of the caller frame as the FramePointer of the callee frame. This
+ // function does NOT do that. It just returns the SP. The caller needs to handle the
+ // unwinding.
+ //
+ // The FramePointer of an explicit frame is just the stack address of the explicit frame.
+ //
+
+ virtual
+ FramePointer GetFramePointer(StackWalkHandle pSFIHandle) = 0;
+
+ //
+ // Check whether the specified CONTEXT is the CONTEXT of the leaf frame. This function doesn't care
+ // whether the leaf frame is native or managed.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ // pContext - the CONTEXT to check
+ //
+ // Return Value:
+ // Return TRUE if the specified CONTEXT is the leaf CONTEXT.
+ //
+ // Notes:
+ // Currently we check the specified CONTEXT against the filter CONTEXT first.
+ // This will be deprecated in V3.
+ //
+
+ virtual
+ BOOL IsLeafFrame(VMPTR_Thread vmThread,
+ const DT_CONTEXT * pContext) = 0;
+
+ // Get the context for a particular thread of the target process.
+ // Arguments:
+ // input: vmThread - the thread for which the context is required
+ // output: pContextBuffer - the address of the CONTEXT to be initialized.
+ // The memory for this belongs to the caller. It must not be NULL.
+ // Note: throws
+ virtual
+ void GetContext(VMPTR_Thread vmThread, DT_CONTEXT * pContextBuffer) = 0;
+
+ //
+ // This is a simple helper function to convert a CONTEXT to a DebuggerREGDISPLAY. We need to do this
+ // inside DDI because the RS has no notion of REGDISPLAY.
+ //
+ // Arguments:
+ // pInContext - the CONTEXT to be converted
+ // pOutDRD - the converted DebuggerREGDISPLAY
+ // fActive - Indicate whether the CONTEXT is active or not. An active CONTEXT means that the
+ // IP is the next instruction to be executed, not the return address of a function call.
+ // The opposite of an active CONTEXT is an unwind CONTEXT, which is obtained from
+ // unwinding.
+ //
+
+ virtual
+ void ConvertContextToDebuggerRegDisplay(const DT_CONTEXT * pInContext,
+ DebuggerREGDISPLAY * pOutDRD,
+ BOOL fActive) = 0;
+
+ typedef enum
+ {
+ kNone,
+ kILStub,
+ kLCGMethod,
+ } DynamicMethodType;
+
+ //
+ // Check whether the specified method is an IL stub or an LCG method. This answer determines if we
+ // need to expose the method in a V2-style stackwalk.
+ //
+ // Arguments:
+ // vmMethodDesc - the method to be checked
+ //
+ // Return Value:
+ // Return kNone if the method is neither an IL stub or an LCG method.
+ // Return kILStub if the method is an IL stub.
+ // Return kLCGMethod if the method is an LCG method.
+ //
+
+ virtual
+ DynamicMethodType IsILStubOrLCGMethod(VMPTR_MethodDesc vmMethodDesc) = 0;
+
+ //
+ // Return a TargetBuffer for the raw vararg signature.
+ // Also return the address of the first argument in the vararg signature.
+ //
+ // Arguments:
+ // VASigCookieAddr - the target address of the VASigCookie pointer (double indirection)
+ // pArgBase - out parameter; return the target address of the first word of the arguments
+ //
+ // Return Value:
+ // Return a TargetBuffer for the raw vararg signature.
+ //
+ // Notes:
+ // We can't take a VMPTR here because VASigCookieAddr does not come from the DDI. Instead,
+ // we use the native variable information to figure out which stack slot contains the
+ // VASigCookie pointer. So a remote address is all we have got.
+ //
+ // Ideally we should be able to return just a SigParser, but doing so has a not-so-trivial problem.
+ // The memory used for the signature pointed to by the SigParser cannot be allocated in the DAC cache,
+ // since it'll be used by mscordbi. We don't have a clean way to allocate memory in mscordbi without
+ // breaking the Signature abstraction.
+ //
+ // The other option would be to create a new sub-type like "SignatureCopy" which allocates and frees
+ // its own backing memory. Currently we don't want to share heaps between mscordacwks.dll and
+ // mscordbi.dll, and so we would have to jump through some hoops to allocate with an allocator
+ // in mscordbi.dll.
+ //
+
+ virtual
+ TargetBuffer GetVarArgSig(CORDB_ADDRESS VASigCookieAddr,
+ OUT CORDB_ADDRESS * pArgBase) = 0;
+
+ //
+ // Indicates if the specified type requires 8-byte alignment.
+ //
+ // Arguments:
+ // thExact - the exact TypeHandle of the type to query
+ //
+ // Return Value:
+ // TRUE if the type requires 8-byte alignment.
+ //
+
+ virtual
+ BOOL RequiresAlign8(VMPTR_TypeHandle thExact) = 0;
+
+ //
+ // Resolve the raw generics token to the real generics type token. The resolution is based on the
+ // given index. See Notes below.
+ //
+ // Arguments:
+ // dwExactGenericArgsTokenIndex - the variable index of the generics type token
+ // rawToken - the raw token to be resolved
+ //
+ // Return Value:
+ // Return the actual generics type token.
+ //
+ // Notes:
+ // DDI tells the RS which variable stores the generics type token, but DDI doesn't retrieve the value
+ // of the variable itself. Instead, the RS retrieves the value of the variable. However,
+ // in some cases, the variable value is not the generics type token. In this case, we need to
+ // "resolve" the variable value to the generics type token. The RS should call this API to do that.
+ //
+ // If the index is 0, then the generics type token is the MethodTable of the "this" object.
+ // rawToken will be the address of the "this" object.
+ //
+ // If the index is TYPECTXT_ILNUM, the generics type token is a secret argument.
+ // It could be a MethodDesc or a MethodTable, and in this case no resolution is actually necessary.
+ // rawToken will be the actual secret argument, and this API really is just a nop.
+ //
+ // However, we don't want the RS to know all this logic.
+ //
+
+ virtual
+ GENERICS_TYPE_TOKEN ResolveExactGenericArgsToken(DWORD dwExactGenericArgsTokenIndex,
+ GENERICS_TYPE_TOKEN rawToken) = 0;
+
+ //-----------------------------------------------------------------------------
+ // Functions to get information about code objects
+ //-----------------------------------------------------------------------------
+
+ // GetILCodeAndSig returns the function's ILCode and SigToken given
+ // a module and a token. The info will come from a MethodDesc, if
+ // one exists or from metadata.
+ //
+ // Arguments:
+ // Input:
+ // vmDomainFile - module containing metadata for the method
+ // functionToken - metadata token for the function
+ // Output (required):
+ // codeInfo - start address and size of the IL
+ // pLocalSigToken - signature token for the method
+ virtual
+ void GetILCodeAndSig(VMPTR_DomainFile vmDomainFile,
+ mdToken functionToken,
+ OUT TargetBuffer * pCodeInfo,
+ OUT mdToken * pLocalSigToken) = 0;
+
+ // Gets information about a native code blob:
+ // it's method desc, whether it's an instantiated generic, its EnC version number
+ // and hot and cold region information.
+ // Arguments:
+ // Input:
+ // vmDomainFile - module containing metadata for the method
+ // functionToken - token for the function for which we need code info
+ // Output (required):
+ // pCodeInfo - data structure describing the native code regions.
+ // Notes: If the function is unjitted, the method desc will be NULL and the
+ // output parameter will be invalid. In general, if the native start address
+ // is unavailable for any reason, the output parameter will also be
+ // invalid (i.e., pCodeInfo->IsValid is false).
+
+ virtual
+ void GetNativeCodeInfo(VMPTR_DomainFile vmDomainFile,
+ mdToken functionToken,
+ OUT NativeCodeFunctionData * pCodeInfo) = 0;
+
+ // Gets information about a native code blob:
+ // it's method desc, whether it's an instantiated generic, its EnC version number
+ // and hot and cold region information.
+ // This is similar to function above, just works from a different starting point
+ // Also this version can get info for any particular EnC version instance
+ // because they all have different start addresses whereas the above version gets
+ // the most recent one
+ // Arguments:
+ // Input:
+ // hotCodeStartAddr - the beginning of the code hot code region
+ // Output (required):
+ // pCodeInfo - data structure describing the native code regions.
+
+ virtual
+ void GetNativeCodeInfoForAddr(VMPTR_MethodDesc vmMethodDesc,
+ CORDB_ADDRESS hotCodeStartAddr,
+ NativeCodeFunctionData * pCodeInfo) = 0;
+
+ //-----------------------------------------------------------------------------
+ // Functions to get information about types
+ //-----------------------------------------------------------------------------
+
+ // Determine if a type is a ValueType
+ //
+ // Arguments:
+ // input: vmTypeHandle - the type being checked (works even on unrestored types)
+ //
+ // Return:
+ // TRUE iff the type is a ValueType
+
+ virtual
+ BOOL IsValueType (VMPTR_TypeHandle th) = 0;
+
+ // Determine if a type has generic parameters
+ //
+ // Arguments:
+ // input: vmTypeHandle - the type being checked (works even on unrestored types)
+ //
+ // Return:
+ // TRUE iff the type has generic parameters
+
+ virtual
+ BOOL HasTypeParams (VMPTR_TypeHandle th) = 0;
+
+ // Get type information for a class
+ //
+ // Arguments:
+ // input: vmAppDomain - appdomain where we will fetch field data for the type
+ // thExact - exact type handle for type
+ // output:
+ // pData - structure containing information about the class and its
+ // fields
+
+ virtual
+ void GetClassInfo (VMPTR_AppDomain vmAppDomain,
+ VMPTR_TypeHandle thExact,
+ ClassInfo * pData) = 0;
+
+ // get field information and object size for an instantiated generic
+ //
+ // Arguments:
+ // input: vmDomainFile - module containing metadata for the type
+ // thExact - exact type handle for type (may be NULL)
+ // thApprox - approximate type handle for the type
+ // output:
+ // pFieldList - array of structures containing information about the fields. Clears any previous
+ // contents. Allocated and initialized by this function.
+ // pObjectSize - size of the instantiated object
+ //
+ virtual
+ void GetInstantiationFieldInfo (VMPTR_DomainFile vmDomainFile,
+ VMPTR_TypeHandle vmThExact,
+ VMPTR_TypeHandle vmThApprox,
+ OUT DacDbiArrayList<FieldData> * pFieldList,
+ OUT SIZE_T * pObjectSize) = 0;
+
+ // use a type handle to get the information needed to create the corresponding RS CordbType instance
+ //
+ // Arguments:
+ // input: boxed - indicates what, if anything, is boxed. See code:AreValueTypesBoxed for more
+ // specific information
+ // vmAppDomain - module containing metadata for the type
+ // vmTypeHandle - type handle for the type
+ // output: pTypeInfo - holds information needed to build the corresponding CordbType
+ //
+ virtual
+ void TypeHandleToExpandedTypeInfo(AreValueTypesBoxed boxed,
+ VMPTR_AppDomain vmAppDomain,
+ VMPTR_TypeHandle vmTypeHandle,
+ DebuggerIPCE_ExpandedTypeData * pTypeInfo) = 0;
+
+ virtual
+ void GetObjectExpandedTypeInfo(AreValueTypesBoxed boxed,
+ VMPTR_AppDomain vmAppDomain,
+ CORDB_ADDRESS addr,
+ OUT DebuggerIPCE_ExpandedTypeData * pTypeInfo) = 0;
+
+
+ virtual
+ void GetObjectExpandedTypeInfoFromID(AreValueTypesBoxed boxed,
+ VMPTR_AppDomain vmAppDomain,
+ COR_TYPEID id,
+ OUT DebuggerIPCE_ExpandedTypeData * pTypeInfo) = 0;
+
+
+ // Get type handle for a TypeDef token, if one exists. For generics this returns the open type.
+ // Note there is no guarantee the returned handle will be fully restored (in pre-jit scenarios),
+ // only that it exists. Later functions that use this type handle should fail if they require
+ // information not yet available at the current restoration level
+ //
+ // Arguments:
+ // input: vmModule - the module scope in which to look up the type def
+ // metadataToken - the type definition to retrieve
+ //
+ // Return value: the type handle if it exists or throws CORDBG_E_CLASS_NOT_LOADED if it isn't loaded
+ //
+ virtual
+ VMPTR_TypeHandle GetTypeHandle(VMPTR_Module vmModule,
+ mdTypeDef metadataToken) = 0;
+
+ // Get the approximate type handle for an instantiated type. This may be identical to the exact type handle,
+ // but if we have code sharing for generics, it may differ in that it may have canonical type parameters.
+ // This will occur if we have not yet loaded an exact type but we have loaded the canonical form of the
+ // type.
+ //
+ // Arguments:
+ // input: pTypeData - information needed to get the type handle, this includes a list of type parameters
+ // and the number of entries in the list. Allocated and initialized by the caller.
+ // Return value: the approximate type handle
+ //
+ virtual
+ VMPTR_TypeHandle GetApproxTypeHandle(TypeInfoList * pTypeData) = 0;
+
+ // Get the exact type handle from type data.
+ // Arguments:
+ // input: pTypeData - type information for the type. includes information about
+ // the top-level type as well as information
+ // about the element type for array types, the referent for
+ // pointer types, or actual parameters for generic class or
+ // valuetypes, as appropriate for the top-level type.
+ // pArgInfo - This is preallocated and initialized by the caller and contains two fields:
+ // genericArgsCount - number of type parameters (these may be actual type parameters
+ // for generics or they may represent the element type or referent
+ // type.
+ // pGenericArgData - list of type parameters
+ // vmTypeHandle - the exact type handle derived from the type information
+ // Return Value: an HRESULT indicating the result of the operation
+ virtual
+ HRESULT GetExactTypeHandle(DebuggerIPCE_ExpandedTypeData * pTypeData,
+ ArgInfoList * pArgInfo,
+ VMPTR_TypeHandle& vmTypeHandle) = 0;
+
+ //
+ // Retrieve the generic type params for a given MethodDesc. This function is specifically
+ // for stackwalking because it requires the generic type token on the stack.
+ //
+ // Arguments:
+ // vmAppDomain - the appdomain of the MethodDesc
+ // vmMethodDesc - the method in question
+ // genericsToken - the generic type token in the stack frame owned by the method
+ //
+ // pcGenericClassTypeParams - out parameter; returns the number of type parameters for the class
+ // containing the method in question; must not be NULL
+ // pGenericTypeParams - out parameter; returns an array of type parameters and
+ // the count of the total number of type parameters; must not be NULL
+ //
+ // Notes:
+ // The memory for the array is allocated by this function on the Dbi heap.
+ // The caller is responsible for releasing it.
+ //
+
+ virtual
+ void GetMethodDescParams(VMPTR_AppDomain vmAppDomain,
+ VMPTR_MethodDesc vmMethodDesc,
+ GENERICS_TYPE_TOKEN genericsToken,
+ OUT UINT32 * pcGenericClassTypeParams,
+ OUT TypeParamsList * pGenericTypeParams) = 0;
+
+ // Get the target field address of a context or thread local static.
+ // Arguments:
+ // input: vmField - pointer to the field descriptor for the static field
+ // vmRuntimeThread - thread to which the static field belongs. This must
+ // NOT be NULL
+ // Return Value: The target address of the field if the field is allocated.
+ // NULL if the field storage is not yet allocated.
+ //
+ // Note:
+ // Static field storage is lazily allocated, so this may commonly return NULL.
+ // This is an inspection only method and can not allocate the static storage.
+ // Field storage is constant once allocated, so this value can be cached.
+
+ virtual
+ CORDB_ADDRESS GetThreadOrContextStaticAddress(VMPTR_FieldDesc vmField,
+ VMPTR_Thread vmRuntimeThread) = 0;
+
+ // Get the target field address of a collectible types static.
+ // Arguments:
+ // input: vmField - pointer to the field descriptor for the static field
+ // vmAppDomain - AppDomain to which the static field belongs. This must
+ // NOT be NULL
+ // Return Value: The target address of the field if the field is allocated.
+ // NULL if the field storage is not yet allocated.
+ //
+ // Note:
+ // Static field storage may not exist yet, so this may commonly return NULL.
+ // This is an inspection only method and can not allocate the static storage.
+ // Field storage is not constant once allocated so this value can not be cached
+ // across a Continue
+
+ virtual
+ CORDB_ADDRESS GetCollectibleTypeStaticAddress(VMPTR_FieldDesc vmField,
+ VMPTR_AppDomain vmAppDomain) = 0;
+
+ // Get information about a field added with Edit And Continue.
+ // Arguments:
+ // intput: pEnCFieldInfo - information about the EnC added field including:
+ // object to which it belongs (if this is null the field is static)
+ // the field token
+ // the class token for the class to which the field was added
+ // the offset to the fields
+ // the domain file
+ // an indication of the type: whether it's a class or value type
+ // output: pFieldData - information about the EnC added field
+ // pfStatic - flag to indicate whether the field is static
+ virtual
+ void GetEnCHangingFieldInfo(const EnCHangingFieldInfo * pEnCFieldInfo,
+ OUT FieldData * pFieldData,
+ OUT BOOL * pfStatic) = 0;
+
+
+ // GetTypeHandleParams gets the necessary data for a type handle, i.e. its
+ // type parameters, e.g. "String" and "List<int>" from the type handle
+ // for "Dict<String,List<int>>", and sends it back to the right side.
+ // Arguments:
+ // input: vmAppDomain - app domain to which the type belongs
+ // vmTypeHandle - type handle for the type
+ // output: pParams - list of instances of DebuggerIPCE_ExpandedTypeData,
+ // one for each type parameter. These will be used on the
+ // RS to build up an instantiation which will allow
+ // building an instance of CordbType for the top-level
+ // type. The memory for this list is allocated on the dbi
+ // heap in this function.
+ // This will not fail except for OOM
+
+ virtual
+ void GetTypeHandleParams(VMPTR_AppDomain vmAppDomain,
+ VMPTR_TypeHandle vmTypeHandle,
+ OUT TypeParamsList * pParams) = 0;
+
+ // GetSimpleType
+ // gets the metadata token and domain file corresponding to a simple type
+ // Arguments:
+ // input: vmAppDomain - Appdomain in which simpleType resides
+ // simpleType - CorElementType value corresponding to a simple type
+ // output: pMetadataToken - the metadata token corresponding to simpleType,
+ // in the scope of vmDomainFile.
+ // vmDomainFile - the domainFile for simpleType
+ // Notes:
+ // This is inspection-only. If the type is not yet loaded, it will throw CORDBG_E_CLASS_NOT_LOADED.
+ // It will not try to load a type.
+ // If the type has been loaded, vmDomainFile will be non-null unless the target is somehow corrupted.
+ // In that case, we will throw CORDBG_E_TARGET_INCONSISTENT.
+
+ virtual
+ void GetSimpleType(VMPTR_AppDomain vmAppDomain,
+ CorElementType simpleType,
+ OUT mdTypeDef * pMetadataToken,
+ OUT VMPTR_Module * pVmModule,
+ OUT VMPTR_DomainFile * pVmDomainFile) = 0;
+
+ // for the specified object returns TRUE if the object derives from System.Exception
+ virtual
+ BOOL IsExceptionObject(VMPTR_Object vmObject) = 0;
+
+ // gets the list of raw stack frames for the specified exception object
+ virtual
+ void GetStackFramesFromException(VMPTR_Object vmObject, DacDbiArrayList<DacExceptionCallStackData>& dacStackFrames) = 0;
+
+ // Returns true if the argument is a runtime callable wrapper
+ virtual
+ BOOL IsRcw(VMPTR_Object vmObject) = 0;
+
+ // retrieves the list of COM interfaces implemented by vmObject, as it is known at
+ // the time of the call (the list may change as new interface types become available
+ // in the runtime)
+ virtual
+ void GetRcwCachedInterfaceTypes(
+ VMPTR_Object vmObject,
+ VMPTR_AppDomain vmAppDomain,
+ BOOL bIInspectableOnly,
+ OUT DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pDacInterfaces) = 0;
+
+ // retrieves the list of interfaces pointers implemented by vmObject, as it is known at
+ // the time of the call (the list may change as new interface types become available
+ // in the runtime)
+ virtual
+ void GetRcwCachedInterfacePointers(
+ VMPTR_Object vmObject,
+ BOOL bIInspectableOnly,
+ OUT DacDbiArrayList<CORDB_ADDRESS> * pDacItfPtrs) = 0;
+
+ // retrieves a list of interface types corresponding to the passed in
+ // list of IIDs. the interface types are retrieved from an app domain
+ // IID / Type cache, that is updated as new types are loaded. will
+ // have NULL entries corresponding to unknown IIDs in "iids"
+ virtual
+ void GetCachedWinRTTypesForIIDs(
+ VMPTR_AppDomain vmAppDomain,
+ DacDbiArrayList<GUID> & iids,
+ OUT DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pTypes) = 0;
+
+ // retrieves the whole app domain cache of IID / Type mappings.
+ virtual
+ void GetCachedWinRTTypes(
+ VMPTR_AppDomain vmAppDomain,
+ OUT DacDbiArrayList<GUID> * piids,
+ OUT DacDbiArrayList<DebuggerIPCE_ExpandedTypeData> * pTypes) = 0;
+
+
+ // ----------------------------------------------------------------------------
+ // functions to get information about reference/handle referents for ICDValue
+ // ----------------------------------------------------------------------------
+
+ // Get object information for a TypedByRef object. Initializes the objRef and typedByRefType fields of
+ // pObjectData (type info for the referent).
+ // Arguments:
+ // input: pTypedByRef - pointer to a TypedByRef struct
+ // vmAppDomain - AppDomain for the type of the object referenced
+ // output: pObjectData - information about the object referenced by pTypedByRef
+ // Note: Throws
+ virtual
+ void GetTypedByRefInfo(CORDB_ADDRESS pTypedByRef,
+ VMPTR_AppDomain vmAppDomain,
+ DebuggerIPCE_ObjectData * pObjectData) = 0;
+
+ // Get the string length and offset to string base for a string object
+ // Arguments:
+ // input: objPtr - address of a string object
+ // output: pObjectData - fills in the string fields stringInfo.offsetToStringBase and
+ // stringInfo.length
+ // Note: throws
+ virtual
+ void GetStringData(CORDB_ADDRESS objectAddress, DebuggerIPCE_ObjectData * pObjectData) = 0;
+
+ // Get information for an array type referent of an objRef, including rank, upper and lower bounds,
+ // element size and type, and the number of elements.
+ // Arguments:
+ // input: objectAddress - the address of an array object
+ // output: pObjectData - fills in the array-related fields:
+ // arrayInfo.offsetToArrayBase,
+ // arrayInfo.offsetToLowerBounds,
+ // arrayInfo.offsetToUpperBounds,
+ // arrayInfo.componentCount,
+ // arrayInfo.rank,
+ // arrayInfo.elementSize,
+ // Note: throws
+ virtual
+ void GetArrayData(CORDB_ADDRESS objectAddress, DebuggerIPCE_ObjectData * pObjectData) = 0;
+
+ // Get information about an object for which we have a reference, including the object size and
+ // type information.
+ // Arguments:
+ // input: objectAddress - address of the object for which we want information
+ // type - the basic type of the object (we may find more specific type
+ // information for the object)
+ // vmAppDomain - the appdomain to which the object belong
+ // output: pObjectData - fills in the size and type information fields
+ // Note: throws
+ virtual
+ void GetBasicObjectInfo(CORDB_ADDRESS objectAddress,
+ CorElementType type,
+ VMPTR_AppDomain vmAppDomain,
+ DebuggerIPCE_ObjectData * pObjectData) = 0;
+
+ // --------------------------------------------------------------------------------------------
+#ifdef TEST_DATA_CONSISTENCY
+ // Determine whether a crst is held by the left side. When the DAC is executing VM code that takes a
+ // lock, we want to know whether the LS already holds that lock. If it does, we will assume the locked
+ // data is in an inconsistent state and will throw an exception, rather than relying on this data. This
+ // function is part of a self-test that will ensure we are correctly detecting when the LS holds a lock
+ // on data the RS is trying to inspect.
+ // Argument:
+ // input: vmCrst - the lock to test
+ // output: none
+ // Notes:
+ // Throws
+ // For this code to run, the environment variable TestDataConsistency must be set to 1.
+ virtual
+ void TestCrst(VMPTR_Crst vmCrst) = 0;
+
+ // Determine whether a crst is held by the left side. When the DAC is executing VM code that takes a
+ // lock, we want to know whether the LS already holds that lock. If it does, we will assume the locked
+ // data is in an inconsistent state and will throw an exception, rather than relying on this data. This
+ // function is part of a self-test that will ensure we are correctly detecting when the LS holds a lock
+ // on data the RS is trying to inspect.
+ // Argument:
+ // input: vmRWLock - the lock to test
+ // output: none
+ // Notes:
+ // Throws
+ // For this code to run, the environment variable TestDataConsistency must be set to 1.
+
+ virtual
+ void TestRWLock(VMPTR_SimpleRWLock vmRWLock) = 0;
+#endif
+ // --------------------------------------------------------------------------------------------
+ // Get the address of the Debugger control block on the helper thread. The debugger control block
+ // contains information about the status of the debugger, handles to various events and space to hold
+ // information sent back and forth between the debugger and the debuggee's helper thread.
+ // Arguments: none
+ // Return Value: The remote address of the Debugger control block allocated on the helper thread
+ // if it has been successfully allocated or NULL otherwise.
+ virtual
+ CORDB_ADDRESS GetDebuggerControlBlockAddress() = 0;
+
+ // Creates a VMPTR of an Object. The Object is found by dereferencing ptr
+ // as though it is a target address to an OBJECTREF. This is similar to
+ // GetObject with another level of indirection.
+ //
+ // Arguments:
+ // ptr - A target address pointing to an OBJECTREF
+ //
+ // Return Value:
+ // A VMPTR to the Object which ptr points to
+ //
+ // Notes:
+ // The VMPTR this produces can be deconstructed by GetObjectContents.
+ // This function will throw if given a NULL or otherwise invalid pointer,
+ // but if given a valid address to an invalid pointer, it will produce
+ // a VMPTR_Object which points to invalid memory.
+ virtual
+ VMPTR_Object GetObjectFromRefPtr(CORDB_ADDRESS ptr) = 0;
+
+ // Creates a VMPTR of an Object. The Object is assumed to be at the target
+ // address supplied by ptr
+ //
+ // Arguments:
+ // ptr - A target address to an Object
+ //
+ // Return Value:
+ // A VMPTR to the Object which was at ptr
+ //
+ // Notes:
+ // The VMPTR this produces can be deconstructed by GetObjectContents.
+ // This will produce a VMPTR_Object regardless of whether the pointer is
+ // valid or not.
+ virtual
+ VMPTR_Object GetObject(CORDB_ADDRESS ptr) = 0;
+
+ // Sets state in the native binder.
+ //
+ // Arguments:
+ // ePolicy - the NGEN policy to change
+ //
+ // Return Value:
+ // HRESULT indicating if the state was successfully updated
+ //
+ virtual
+ HRESULT EnableNGENPolicy(CorDebugNGENPolicy ePolicy) = 0;
+
+ // Sets the NGEN compiler flags. This restricts NGEN to only use images with certain
+ // types of pregenerated code. With respect to debugging this is used to specify that
+ // the NGEN image must be debuggable aka non-optimized code. Note that these flags
+ // are merged with other sources of configuration so it is possible that the final
+ // result retrieved from GetDesiredNGENCompilerFlags does not match what was specfied
+ // in this call.
+ //
+ // If an NGEN image of the appropriate type isn't available then one of two things happens:
+ // a) the NGEN image isn't loaded and CLR loads the MSIL image instead
+ // b) the NGEN image is loaded, but we don't use the pregenerated code it contains
+ // and instead use only the MSIL and metadata
+ //
+ // This function is only legal to call at app startup before any decisions have been
+ // made about NGEN image loading. Once we begin loading this configuration is immutable.
+ //
+ //
+ // Arguments:
+ // dwFlags - the new NGEN compiler flags that should go into effect
+ //
+ // Return Value:
+ // HRESULT indicating if the state was successfully updated. On error the
+ // current flags in effect will not have changed.
+ //
+ virtual
+ HRESULT SetNGENCompilerFlags(DWORD dwFlags) = 0;
+
+ // Gets the NGEN compiler flags currently in effect. This accounts for settings that
+ // were caused by SetDesiredNGENCompilerFlags as well as other configuration sources.
+ // See SetDesiredNGENCompilerFlags for more info
+ //
+ // Arguments:
+ // pdwFlags - the NGEN compiler flags currently in effect
+ //
+ // Return Value:
+ // HRESULT indicating if the state was successfully retrieved.
+ //
+ virtual
+ HRESULT GetNGENCompilerFlags(DWORD *pdwFlags) = 0;
+
+ // Create a VMPTR_OBJECTHANDLE from a CORDB_ADDRESS pointing to an object handle
+ //
+ // Arguments:
+ // handle: target address of a GC handle
+ //
+ // ReturnValue:
+ // returns a VMPTR_OBJECTHANDLE with the handle as the m_addr field
+ //
+ // Notes:
+ // This will produce a VMPTR_OBJECTHANDLE regardless of whether handle is
+ // valid.
+ // Ideally we'd be using only strongly-typed variables on the RS, and then this would be unnecessary
+ virtual
+ VMPTR_OBJECTHANDLE GetVmObjectHandle(CORDB_ADDRESS handleAddress) = 0;
+
+ // Validate that the VMPTR_OBJECTHANDLE refers to a legitimate managed object
+ //
+ // Arguments:
+ // handle: the GC handle to be validated
+ //
+ // Return value:
+ // TRUE if the object appears to be valid (its a heuristic), FALSE if it definately is not valid
+ //
+ virtual
+ BOOL IsVmObjectHandleValid(VMPTR_OBJECTHANDLE vmHandle) = 0;
+
+ // indicates if the specified module is a WinRT module
+ //
+ // Arguments:
+ // vmModule: the module to check
+ // isWinRT: out parameter indicating state of module
+ //
+ // Return value:
+ // S_OK indicating that the operation succeeded
+ //
+ virtual
+ HRESULT IsWinRTModule(VMPTR_Module vmModule, BOOL& isWinRT) = 0;
+
+ // Determines the app domain id for the object refered to by a given VMPTR_OBJECTHANDLE
+ //
+ // Arguments:
+ // handle: the GC handle which refers to the object of interest
+ //
+ // Return value:
+ // The app domain id of the object of interest
+ //
+ // This may throw if the object handle is corrupt (it doesn't refer to a managed object)
+ virtual
+ ULONG GetAppDomainIdFromVmObjectHandle(VMPTR_OBJECTHANDLE vmHandle) = 0;
+
+
+ // Get the target address from a VMPTR_OBJECTHANDLE, i.e., the handle address
+ // Arguments:
+ // vmHandle - (input) the VMPTR_OBJECTHANDLE from which we need the target address
+ // Return value: the target address from the VMPTR_OBJECTHANDLE
+ //
+ virtual
+ CORDB_ADDRESS GetHandleAddressFromVmHandle(VMPTR_OBJECTHANDLE vmHandle) = 0;
+
+ // Given a VMPTR to an Object return the target address
+ //
+ // Arguments:
+ // obj - the Object VMPTR to get the address from
+ //
+ // Return Value:
+ // Return the target address which obj is using
+ //
+ // Notes:
+ // The VMPTR this consumes can be reconstructed using GetObject and
+ // providing the address stored in the returned TargetBuffer. This has
+ // undefined behavior for invalid VMPTR_Objects.
+
+ virtual
+ TargetBuffer GetObjectContents(VMPTR_Object obj) = 0;
+
+ // The callback used to enumerate blocking objects
+ typedef void (*FP_BLOCKINGOBJECT_ENUMERATION_CALLBACK)(DacBlockingObject blockingObject,
+ CALLBACK_DATA pUserData);
+
+ //
+ // Enumerate all monitors blocking a thread
+ //
+ // Arguments:
+ // vmThread - the thread to get monitor data for
+ // fpCallback - callback to invoke on the blocking data for each monitor
+ // pUserData - user data to supply for each callback.
+ //
+ // Return Value:
+ // Returns on success. Throws on error.
+ //
+ //
+ virtual
+ void EnumerateBlockingObjects(VMPTR_Thread vmThread,
+ FP_BLOCKINGOBJECT_ENUMERATION_CALLBACK fpCallback,
+ CALLBACK_DATA pUserData) = 0;
+
+
+
+ //
+ // Returns the thread which owns the monitor lock on an object and the acquisition
+ // count
+ //
+ // Arguments:
+ // vmObject - The object to check for ownership
+
+ //
+ // Return Value:
+ // Throws on error. Inside the structure we have:
+ // pVmThread - the owning or thread or VMPTR_Thread::NullPtr() if unowned
+ // pAcquisitionCount - the number of times the lock would need to be released in
+ // order for it to be unowned
+ //
+ virtual
+ MonitorLockInfo GetThreadOwningMonitorLock(VMPTR_Object vmObject) = 0;
+
+ //
+ // Enumerate all threads waiting on the monitor event for an object
+ //
+ // Arguments:
+ // vmObject - the object whose monitor event we are interested in
+ // fpCallback - callback to invoke on each thread in the queue
+ // pUserData - user data to supply for each callback.
+ //
+ // Return Value:
+ // Returns on success. Throws on error.
+ //
+ //
+ virtual
+ void EnumerateMonitorEventWaitList(VMPTR_Object vmObject,
+ FP_THREAD_ENUMERATION_CALLBACK fpCallback,
+ CALLBACK_DATA pUserData) = 0;
+
+ //
+ // Returns the managed debugging flags for the process (a combination
+ // of the CLR_DEBUGGING_PROCESS_FLAGS flags). This function specifies,
+ // beyond whether or not a managed debug event is pending, also if the
+ // event (if one exists) is caused by a Debugger.Launch(). This is
+ // important b/c Debugger.Launch calls should *NOT* cause the debugger
+ // to terminate the process when the attach is canceled.
+ virtual
+ CLR_DEBUGGING_PROCESS_FLAGS GetAttachStateFlags() = 0;
+
+ virtual
+ bool GetMetaDataFileInfoFromPEFile(VMPTR_PEFile vmPEFile,
+ DWORD & dwTimeStamp,
+ DWORD & dwImageSize,
+ bool & isNGEN,
+ IStringHolder* pStrFilename) = 0;
+
+ virtual
+ bool GetILImageInfoFromNgenPEFile(VMPTR_PEFile vmPEFile,
+ DWORD & dwTimeStamp,
+ DWORD & dwSize,
+ IStringHolder* pStrFilename) = 0;
+
+
+ virtual
+ bool IsThreadSuspendedOrHijacked(VMPTR_Thread vmThread) = 0;
+
+
+ typedef void* * HeapWalkHandle;
+
+ // Returns true if it is safe to walk the heap. If this function returns false,
+ // you could still create a heap walk and attempt to walk it, but there's no
+ // telling how much of the heap will be available.
+ virtual
+ bool AreGCStructuresValid() = 0;
+
+ // Creates a HeapWalkHandle which can be used to walk the managed heap with the
+ // WalkHeap function. Note if this function completes successfully you will need
+ // to delete the handle by passing it into DeleteHeapWalk.
+ //
+ // Arguments:
+ // pHandle - the location to store the heap walk handle in
+ //
+ // Returns:
+ // S_OK on success, an error code on failure.
+ virtual
+ HRESULT CreateHeapWalk(OUT HeapWalkHandle * pHandle) = 0;
+
+
+ // Deletes the give HeapWalkHandle. Note you must call this function if
+ // CreateHeapWalk returns success.
+ virtual
+ void DeleteHeapWalk(HeapWalkHandle handle) = 0;
+
+ // Walks the heap using the given heap walk handle, enumerating objects
+ // on the managed heap. Note that walking the heap requires that the GC
+ // data structures be in a valid state, which you can find by calling
+ // AreGCStructuresValid.
+ //
+ // Arguments:
+ // handle - a HeapWalkHandle obtained from CreateHeapWalk
+ // count - the number of object addresses to obtain; pValues must
+ // be at least as large as count
+ // objects - the location to stuff the object addresses found during
+ // the heap walk; this array should be at least "count" in
+ // length; this field must not be null
+ // pFetched - a location to store the actual number of values filled
+ // into pValues; this field must not be null
+ //
+ // Returns:
+ // S_OK on success, a failure HRESULT otherwise.
+ //
+ // Note:
+ // You should iteratively call WalkHeap requesting more values until
+ // *pFetched != count.. This signifies that we have reached the end
+ // of the heap walk.
+ virtual
+ HRESULT WalkHeap(HeapWalkHandle handle,
+ ULONG count,
+ OUT COR_HEAPOBJECT * objects,
+ OUT ULONG * pFetched) = 0;
+
+ virtual
+ HRESULT GetHeapSegments(OUT DacDbiArrayList<COR_SEGMENT> * pSegments) = 0;
+
+ virtual
+ bool IsValidObject(CORDB_ADDRESS obj) = 0;
+
+ virtual
+ bool GetAppDomainForObject(CORDB_ADDRESS obj, OUT VMPTR_AppDomain * pApp,
+ OUT VMPTR_Module * pModule,
+ OUT VMPTR_DomainFile * pDomainFile) = 0;
+
+
+ // Reference Walking.
+
+ // Creates a reference walk.
+ // Parameters:
+ // pHandle - out - the reference walk handle to create
+ // walkStacks - in - whether or not to report stack references
+ // walkFQ - in - whether or not to report references from the finalizer queue
+ // handleWalkMask - in - the types of handles report (see CorGCReferenceType, cordebug.idl)
+ // Returns:
+ // An HRESULT indicating whether it succeded or failed.
+ // Exceptions:
+ // Does not throw, but does not catch exceptions either.
+ virtual
+ HRESULT CreateRefWalk(OUT RefWalkHandle * pHandle, BOOL walkStacks, BOOL walkFQ, UINT32 handleWalkMask) = 0;
+
+ // Deletes a reference walk.
+ // Parameters:
+ // handle - in - the handle of the reference walk to delete
+ // Excecptions:
+ // Does not throw, but does not catch exceptions either.
+ virtual
+ void DeleteRefWalk(RefWalkHandle handle) = 0;
+
+ // Enumerates GC references in the process based on the parameters passed to CreateRefWalk.
+ // Parameters:
+ // handle - in - the RefWalkHandle to enumerate
+ // count - in - the capacity of "refs"
+ // refs - in/out - an array to write the references to
+ // pFetched - out - the number of references written
+ virtual
+ HRESULT WalkRefs(RefWalkHandle handle, ULONG count, OUT DacGcReference * refs, OUT ULONG * pFetched) = 0;
+
+ virtual
+ HRESULT GetTypeID(CORDB_ADDRESS obj, COR_TYPEID * pType) = 0;
+
+ virtual
+ HRESULT GetObjectFields(COR_TYPEID id, ULONG32 celt, OUT COR_FIELD * layout, OUT ULONG32 * pceltFetched) = 0;
+
+ virtual
+ HRESULT GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT * pLayout) = 0;
+
+ virtual
+ HRESULT GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT * pLayout) = 0;
+
+ virtual
+ void GetGCHeapInformation(OUT COR_HEAPINFO * pHeapInfo) = 0;
+
+ // If a PEFile has an RW capable IMDInternalImport, this returns the address of the MDInternalRW
+ // object which implements it.
+ //
+ //
+ // Arguments:
+ // vmPEFile - target PEFile to get metadata MDInternalRW for.
+ // pAddrMDInternalRW - If a PEFile has an RW capable IMDInternalImport, this will be set to the address
+ // of the MDInternalRW object which implements it. Otherwise it will be NULL.
+ //
+ virtual
+ HRESULT GetPEFileMDInternalRW(VMPTR_PEFile vmPEFile, OUT TADDR* pAddrMDInternalRW) = 0;
+
+ // Retrieves the active ReJitInfo for a given module/methodDef, if it exists.
+ // Active is defined as after GetReJitParameters returns from the profiler dll and
+ // no call to Revert has completed yet.
+ //
+ //
+ // Arguments:
+ // vmModule - The module to search in
+ // methodTk - The methodDef token indicates the method within the module to check
+ // pReJitInfo - [out] The RejitInfo request, if any, that is active on this method. If no request
+ // is active this will be pReJitInfo->IsNull() == TRUE.
+ //
+ // Returns:
+ // S_OK regardless of whether a rejit request is active or not, as long as the answer is certain
+ // error HRESULTs such as CORDBG_READ_VIRTUAL_FAILURE are possible
+ //
+ virtual
+ HRESULT GetReJitInfo(VMPTR_Module vmModule, mdMethodDef methodTk, OUT VMPTR_ReJitInfo* pReJitInfo) = 0;
+
+ // Retrieves the active ReJitInfo for a given MethodDesc/code address, if it exists.
+ // Active is defined as after GetReJitParameters returns from the profiler dll and
+ // no call to Revert has completed yet.
+ //
+ //
+ // Arguments:
+ // vmMethod - The method to look for
+ // codeStartAddress - The code start address disambiguates between multiple rejitted instances
+ // of the method.
+ // pReJitInfo - [out] The RejitInfo request, if any, that is active on this method. If no request
+ // is active this will be pReJitInfo->IsNull() == TRUE.
+ //
+ // Returns:
+ // S_OK regardless of whether a rejit request is active or not, as long as the answer is certain
+ // error HRESULTs such as CORDBG_READ_VIRTUAL_FAILURE are possible
+ //
+ virtual
+ HRESULT GetReJitInfo(VMPTR_MethodDesc vmMethod, CORDB_ADDRESS codeStartAddress, OUT VMPTR_ReJitInfo* pReJitInfo) = 0;
+
+
+ // Retrieves the SharedReJitInfo for a given ReJitInfo.
+ //
+ //
+ // Arguments:
+ // vmReJitInfo - The ReJitInfo to inspect
+ // pSharedReJitInfo - [out] The SharedReJitInfo that is pointed to by vmReJitInfo.
+ //
+ // Returns:
+ // S_OK if no error
+ // error HRESULTs such as CORDBG_READ_VIRTUAL_FAILURE are possible
+ //
+ virtual
+ HRESULT GetSharedReJitInfo(VMPTR_ReJitInfo vmReJitInfo, VMPTR_SharedReJitInfo* pSharedReJitInfo) = 0;
+
+ // Retrieves useful data from a SharedReJitInfo such as IL code and IL mapping.
+ //
+ //
+ // Arguments:
+ // sharedReJitInfo - The SharedReJitInfo to inspect
+ // pData - [out] Various properties of the SharedReJitInfo such as IL code and IL mapping.
+ //
+ // Returns:
+ // S_OK if no error
+ // error HRESULTs such as CORDBG_READ_VIRTUAL_FAILURE are possible
+ //
+ virtual
+ HRESULT GetSharedReJitInfoData(VMPTR_SharedReJitInfo sharedReJitInfo, DacSharedReJitInfo* pData) = 0;
+
+ // Retrieves a bit field indicating which defines were in use when clr was built. This only includes
+ // defines that are specified in the Debugger::_Target_Defines enumeration, which is a small subset of
+ // all defines.
+ //
+ //
+ // Arguments:
+ // pDefines - [out] The set of defines clr.dll was built with. Bit offsets are encoded using the
+ // enumeration Debugger::_Target_Defines
+ //
+ // Returns:
+ // S_OK if no error
+ // error HRESULTs such as CORDBG_READ_VIRTUAL_FAILURE are possible
+ //
+ virtual
+ HRESULT GetDefinesBitField(ULONG32 *pDefines) = 0;
+
+ // Retrieves a version number indicating the shape of the data structures used in the Metadata implementation
+ // inside clr.dll. This number changes anytime a datatype layout changes so that they can be correctly
+ // deserialized from out of process
+ //
+ //
+ // Arguments:
+ // pMDStructuresVersion - [out] The layout version number for metadata data structures. See
+ // Debugger::Debugger() in Debug\ee\Debugger.cpp for a description of the options.
+ //
+ // Returns:
+ // S_OK if no error
+ // error HRESULTs such as CORDBG_READ_VIRTUAL_FAILURE are possible
+ //
+ virtual
+ HRESULT GetMDStructuresVersion(ULONG32* pMDStructuresVersion) = 0;
+
+ // The following tag tells the DD-marshalling tool to stop scanning.
+ // END_MARSHAL
+
+ //-----------------------------------------------------------------------------
+ // Utility interface used for passing strings out of these APIs. The caller
+ // provides an implementation of this that uses whatever memory allocation
+ // strategy it desires, and IDacDbiInterface APIs will call AssignCopy in order
+ // to pass back the contents of strings.
+ //
+ // This permits the client and implementation of IDacDbiInterface to be in
+ // different DLLs with their own heap allocation mechanism, while avoiding
+ // the ugly and verbose 2-call C-style string passing API pattern.
+ //-----------------------------------------------------------------------------
+ class IStringHolder
+ {
+ public:
+ //
+ // Store a copy of of the provided string.
+ //
+ // Arguments:
+ // psz - The null-terminated unicode string to copy.
+ //
+ // Return Value:
+ // S_OK on success, typical HRESULT return values on failure.
+ //
+ // Notes:
+ // The underlying object is responsible for allocating and freeing the
+ // memory for this copy. The object must not store the value of psz,
+ // it is no longer valid after this call returns.
+ //
+ virtual
+ HRESULT AssignCopy(const WCHAR * psz) = 0;
+ };
+
+
+ //-----------------------------------------------------------------------------
+ // Interface for allocations
+ // This lets DD allocate buffers to pass back to DBI; and thus avoids
+ // the common 2-step (query size/allocate/query data) pattern.
+ //
+ // Note that mscordacwks.dll and clients cannot share the same heap allocator,
+ // DAC statically links the CRT to avoid run-time dependencies on non-OS libraries.
+ //-----------------------------------------------------------------------------
+ class IAllocator
+ {
+ public:
+ // Allocate
+ // Expected to throw on error.
+ virtual
+ void * Alloc(SIZE_T lenBytes) = 0;
+
+ // Free. This shouldn't throw.
+ virtual
+ void Free(void * p) = 0;
+ };
+
+
+ //-----------------------------------------------------------------------------
+ // Callback interface to provide Metadata lookup.
+ //-----------------------------------------------------------------------------
+ class IMetaDataLookup
+ {
+ public:
+ //
+ // Lookup a metadata importer via PEFile.
+ //
+ // Returns:
+ // A IMDInternalImport used by dac-ized VM code. The object is NOT addref-ed. See lifespan notes below.
+ // Returns NULL if no importer is available.
+ // Throws on exceptional circumstances (eg, detects the debuggee is corrupted).
+ //
+ // Notes:
+ // IMDInternalImport is a property of PEFile. The DAC-ized code uses it as a weak reference,
+ // and so we avoid doing an AddRef() here because that would mean we need to add Release() calls
+ // in DAC-only paths.
+ // The metadata importers are not DAC-ized, and thus we have a local copy in the host.
+ // If it was dac-ized, then DAC would get the importer just like any other field.
+ //
+ // lifespan of returned object:
+ // - DBI owns the metadata importers.
+ // - DBI must not free the importer without calling Flush() on DAC first.
+ // - DAC will only invoke this when in a DD primitive, which was in turn invoked by DBI.
+ // - For performance reasons, we want to allow DAC to cache this between Flush() calls.
+ // - If DAC caches the importer, it will only use it when DBI invokes a DD primitive.
+ // - the reference count of the returned object is not adjusted.
+ //
+ virtual
+ IMDInternalImport * LookupMetaData(VMPTR_PEFile addressPEFile, bool &isILMetaDataForNGENImage) = 0;
+ };
+
+}; // end IDacDbiInterface
+
+
+#endif // _DACDBI_INTERFACE_H_