/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using dnSpy.Contracts.Debugger.CallStack; using dnSpy.Contracts.Debugger.DotNet.Disassembly; using dnSpy.Contracts.Debugger.Evaluation; using dnSpy.Contracts.Disassembly; using dnSpy.Contracts.Metadata; using dnSpy.Debugger.DotNet.Metadata; namespace dnSpy.Contracts.Debugger.DotNet.Evaluation { /// /// Implemented by a .NET engine, see /// public interface IDbgDotNetRuntime { /// /// Gets the dispatcher /// DbgDotNetDispatcher Dispatcher { get; } /// /// Gets the feature flags /// DbgDotNetRuntimeFeatures Features { get; } /// /// Gets the module id /// /// Module /// ModuleId GetModuleId(DbgModule module); /// /// Gets the module data or /// /// Module /// DbgDotNetRawModuleBytes GetRawModuleBytes(DbgModule module); /// /// Translates a method token from the original dynamic module's metadata to the saved module metadata used by the expression compiler /// /// Module /// Method token /// New method token /// New method body local variables signature token /// bool TryGetMethodToken(DbgModule module, int methodToken, out int metadataMethodToken, out int metadataLocalVarSigTok); /// /// Gets the current method or null if it's not a normal IL frame /// /// Evaluation info /// DmdMethodBase? GetFrameMethod(DbgEvaluationInfo evalInfo); /// /// Loads the address of an instance or a static field or returns null if it's not supported /// /// Evaluation info /// Instance object or null if it's a static field /// Field /// DbgDotNetValue? LoadFieldAddress(DbgEvaluationInfo evalInfo, DbgDotNetValue? obj, DmdFieldInfo field); /// /// Loads an instance or a static field /// /// Evaluation info /// Instance object or null if it's a static field /// Field /// DbgDotNetValueResult LoadField(DbgEvaluationInfo evalInfo, DbgDotNetValue? obj, DmdFieldInfo field); /// /// Stores a value in a field. Returns null or an error message /// /// Evaluation info /// Instance object or null if it's a static field /// Field /// Value to store: A or a primitive number or a string or arrays of primitive numbers / strings /// string? StoreField(DbgEvaluationInfo evalInfo, DbgDotNetValue? obj, DmdFieldInfo field, object? value); /// /// Calls an instance or a static method /// /// Evaluation info /// Instance object or null if it's a static method /// Method /// Arguments: A or a primitive number or a string or arrays of primitive numbers / strings /// Invoke options /// DbgDotNetValueResult Call(DbgEvaluationInfo evalInfo, DbgDotNetValue? obj, DmdMethodBase method, object?[] arguments, DbgDotNetInvokeOptions invokeOptions); /// /// Creates a new instance of a type by calling its constructor /// /// Evaluation info /// Constructor /// Arguments: A or a primitive number or a string or arrays of primitive numbers / strings /// Invoke options /// DbgDotNetValueResult CreateInstance(DbgEvaluationInfo evalInfo, DmdConstructorInfo ctor, object?[] arguments, DbgDotNetInvokeOptions invokeOptions); /// /// Creates a new instance of a type. All fields are initialized to 0 or null. The constructor isn't called. /// /// Evaluation info /// Type to create /// DbgDotNetValueResult CreateInstanceNoConstructor(DbgEvaluationInfo evalInfo, DmdType type); /// /// Creates an SZ array /// /// Evaluation info /// Element type /// Length of the array /// DbgDotNetValueResult CreateSZArray(DbgEvaluationInfo evalInfo, DmdType elementType, int length); /// /// Creates a multi-dimensional array /// /// Evaluation info /// Element type /// Dimension infos /// DbgDotNetValueResult CreateArray(DbgEvaluationInfo evalInfo, DmdType elementType, DbgDotNetArrayDimensionInfo[] dimensionInfos); /// /// Gets aliases /// /// Evaluation info /// DbgDotNetAliasInfo[] GetAliases(DbgEvaluationInfo evalInfo); /// /// Gets all exceptions /// /// Evaluation info /// DbgDotNetExceptionInfo[] GetExceptions(DbgEvaluationInfo evalInfo); /// /// Gets all return values /// /// Evaluation info /// DbgDotNetReturnValueInfo[] GetReturnValues(DbgEvaluationInfo evalInfo); /// /// Gets an exception or null /// /// Evaluation info /// Exception id, eg. /// DbgDotNetValue? GetException(DbgEvaluationInfo evalInfo, uint id); /// /// Gets a stowed exception or null /// /// Evaluation info /// Stowed exception id, eg. /// DbgDotNetValue? GetStowedException(DbgEvaluationInfo evalInfo, uint id); /// /// Gets a return value or null /// /// Evaluation info /// Return value id, eg. /// DbgDotNetValue? GetReturnValue(DbgEvaluationInfo evalInfo, uint id); /// /// Gets a local value /// /// Evaluation info /// Metadata index of local /// DbgDotNetValueResult GetLocalValue(DbgEvaluationInfo evalInfo, uint index); /// /// Gets a parameter value /// /// Evaluation info /// Metadata index of parameter /// DbgDotNetValueResult GetParameterValue(DbgEvaluationInfo evalInfo, uint index); /// /// Writes a new local value. Returns an error message or null. /// /// Evaluation info /// Metadata index of parameter /// Type of the local /// New value: A or a primitive number or a string or arrays of primitive numbers / strings /// string? SetLocalValue(DbgEvaluationInfo evalInfo, uint index, DmdType targetType, object? value); /// /// Writes a new parameter value. Returns an error message or null. /// /// Evaluation info /// Metadata index of parameter /// Type of the parameter /// New value: A or a primitive number or a string or arrays of primitive numbers / strings /// string? SetParameterValue(DbgEvaluationInfo evalInfo, uint index, DmdType targetType, object? value); /// /// Gets the address of a local value or null if it's not supported /// /// Evaluation info /// Metadata index of local /// Type of the local /// DbgDotNetValue? GetLocalValueAddress(DbgEvaluationInfo evalInfo, uint index, DmdType targetType); /// /// Gets the address of a parameter value or null if it's not supported /// /// Evaluation info /// Metadata index of local /// Type of the parameter /// DbgDotNetValue? GetParameterValueAddress(DbgEvaluationInfo evalInfo, uint index, DmdType targetType); /// /// Creates a simple value (a primitive number or a string, or arrays of those types) /// /// Evaluation info /// A or a primitive number or a string or arrays of primitive numbers / strings /// DbgDotNetValueResult CreateValue(DbgEvaluationInfo evalInfo, object? value); /// /// Boxes the value type /// /// Evaluation info /// Value to box /// DbgDotNetValueResult Box(DbgEvaluationInfo evalInfo, object? value); /// /// Returns true if it's possible to create an object id /// /// Value created by this runtime /// bool CanCreateObjectId(DbgDotNetValue value); /// /// Creates an object id or returns null /// /// Value created by this runtime /// Unique id /// DbgDotNetObjectId? CreateObjectId(DbgDotNetValue value, uint id); /// /// Checks if an object id and a value refer to the same data /// /// Object id created by this class /// Value created by this runtime /// bool Equals(DbgDotNetObjectId objectId, DbgDotNetValue value); /// /// Gets the hash code of an object id /// /// Object id created by this class /// int GetHashCode(DbgDotNetObjectId objectId); /// /// Gets the hash code of a value created by this runtime /// /// Value created by this runtime /// int GetHashCode(DbgDotNetValue value); /// /// Gets an object ID's value or null if there was an error /// /// Evaluation info /// Object id created by this class /// DbgDotNetValue? GetValue(DbgEvaluationInfo evalInfo, DbgDotNetObjectId objectId); /// /// Checks if two values are equal. Returns null if it's unknown. /// /// Value #1 /// Value #2 /// bool? Equals(DbgDotNetValue a, DbgDotNetValue b); /// /// Tries to get the native code /// /// Frame /// Updated with the native code if successful /// bool TryGetNativeCode(DbgStackFrame frame, out DbgDotNetNativeCode nativeCode); /// /// Tries to get the native code /// /// Method /// Updated with the native code if successful /// bool TryGetNativeCode(DmdMethodBase method, out DbgDotNetNativeCode nativeCode); /// /// Tries to get a symbol /// /// Address /// Updated with the symbol if successful /// bool TryGetSymbol(ulong address, out SymbolResolverResult result); } /// /// Invoke options /// [Flags] public enum DbgDotNetInvokeOptions { /// /// No bit is set /// None = 0, /// /// Non-virtual call /// NonVirtual = 0x00000001, } /// /// .NET runtime features /// [Flags] public enum DbgDotNetRuntimeFeatures { /// /// No bit is set /// None = 0, /// /// Object IDs are supported /// ObjectIds = 0x00000001, /// /// Calling generic methods isn't supported /// NoGenericMethods = 0x00000002, /// /// and /// isn't supported for pointers. /// NoDereferencePointers = 0x00000004, /// /// Async step with object ids isn't supported /// NoAsyncStepObjectId = 0x00000008, /// /// It's possible to get the native code of jitted managed methods /// NativeMethodBodies = 0x00000010, } /// /// Constants /// public static class DbgDotNetRuntimeConstants { /// /// Exception ID /// public const uint ExceptionId = 1; /// /// Stowed exception ID /// public const uint StowedExceptionId = 1; /// /// ID of last return value /// public const uint LastReturnValueId = 0; } /// /// Contains .NET module data information /// public readonly struct DbgDotNetRawModuleBytes { /// /// No .NET module data is available /// public static readonly DbgDotNetRawModuleBytes None = default; /// /// true if it's file layout, false if it's memory layout /// public bool IsFileLayout { get; } /// /// Raw bytes of the .NET module /// public byte[] RawBytes { get; } /// /// Constructor /// /// Raw bytes of the .NET module /// true if it's file layout, false if it's memory layout public DbgDotNetRawModuleBytes(byte[] rawBytes, bool isFileLayout) { IsFileLayout = isFileLayout; RawBytes = rawBytes ?? throw new ArgumentNullException(nameof(rawBytes)); } } }