2021-09-20 18:20:01 +02:00

445 lines
16 KiB
C#

/*
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 <http://www.gnu.org/licenses/>.
*/
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 {
/// <summary>
/// Implemented by a .NET engine, see <see cref="DbgRuntime.InternalRuntime"/>
/// </summary>
public interface IDbgDotNetRuntime {
/// <summary>
/// Gets the dispatcher
/// </summary>
DbgDotNetDispatcher Dispatcher { get; }
/// <summary>
/// Gets the feature flags
/// </summary>
DbgDotNetRuntimeFeatures Features { get; }
/// <summary>
/// Gets the module id
/// </summary>
/// <param name="module">Module</param>
/// <returns></returns>
ModuleId GetModuleId(DbgModule module);
/// <summary>
/// Gets the module data or <see cref="DbgDotNetRawModuleBytes.None"/>
/// </summary>
/// <param name="module">Module</param>
/// <returns></returns>
DbgDotNetRawModuleBytes GetRawModuleBytes(DbgModule module);
/// <summary>
/// Translates a method token from the original dynamic module's metadata to the saved module metadata used by the expression compiler
/// </summary>
/// <param name="module">Module</param>
/// <param name="methodToken">Method token</param>
/// <param name="metadataMethodToken">New method token</param>
/// <param name="metadataLocalVarSigTok">New method body local variables signature token</param>
/// <returns></returns>
bool TryGetMethodToken(DbgModule module, int methodToken, out int metadataMethodToken, out int metadataLocalVarSigTok);
/// <summary>
/// Gets the current method or null if it's not a normal IL frame
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <returns></returns>
DmdMethodBase? GetFrameMethod(DbgEvaluationInfo evalInfo);
/// <summary>
/// Loads the address of an instance or a static field or returns null if it's not supported
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="obj">Instance object or null if it's a static field</param>
/// <param name="field">Field</param>
/// <returns></returns>
DbgDotNetValue? LoadFieldAddress(DbgEvaluationInfo evalInfo, DbgDotNetValue? obj, DmdFieldInfo field);
/// <summary>
/// Loads an instance or a static field
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="obj">Instance object or null if it's a static field</param>
/// <param name="field">Field</param>
/// <returns></returns>
DbgDotNetValueResult LoadField(DbgEvaluationInfo evalInfo, DbgDotNetValue? obj, DmdFieldInfo field);
/// <summary>
/// Stores a value in a field. Returns null or an error message
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="obj">Instance object or null if it's a static field</param>
/// <param name="field">Field</param>
/// <param name="value">Value to store: A <see cref="DbgDotNetValue"/> or a primitive number or a string or arrays of primitive numbers / strings</param>
/// <returns></returns>
string? StoreField(DbgEvaluationInfo evalInfo, DbgDotNetValue? obj, DmdFieldInfo field, object? value);
/// <summary>
/// Calls an instance or a static method
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="obj">Instance object or null if it's a static method</param>
/// <param name="method">Method</param>
/// <param name="arguments">Arguments: A <see cref="DbgDotNetValue"/> or a primitive number or a string or arrays of primitive numbers / strings</param>
/// <param name="invokeOptions">Invoke options</param>
/// <returns></returns>
DbgDotNetValueResult Call(DbgEvaluationInfo evalInfo, DbgDotNetValue? obj, DmdMethodBase method, object?[] arguments, DbgDotNetInvokeOptions invokeOptions);
/// <summary>
/// Creates a new instance of a type by calling its constructor
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="ctor">Constructor</param>
/// <param name="arguments">Arguments: A <see cref="DbgDotNetValue"/> or a primitive number or a string or arrays of primitive numbers / strings</param>
/// <param name="invokeOptions">Invoke options</param>
/// <returns></returns>
DbgDotNetValueResult CreateInstance(DbgEvaluationInfo evalInfo, DmdConstructorInfo ctor, object?[] arguments, DbgDotNetInvokeOptions invokeOptions);
/// <summary>
/// Creates a new instance of a type. All fields are initialized to 0 or null. The constructor isn't called.
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="type">Type to create</param>
/// <returns></returns>
DbgDotNetValueResult CreateInstanceNoConstructor(DbgEvaluationInfo evalInfo, DmdType type);
/// <summary>
/// Creates an SZ array
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="elementType">Element type</param>
/// <param name="length">Length of the array</param>
/// <returns></returns>
DbgDotNetValueResult CreateSZArray(DbgEvaluationInfo evalInfo, DmdType elementType, int length);
/// <summary>
/// Creates a multi-dimensional array
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="elementType">Element type</param>
/// <param name="dimensionInfos">Dimension infos</param>
/// <returns></returns>
DbgDotNetValueResult CreateArray(DbgEvaluationInfo evalInfo, DmdType elementType, DbgDotNetArrayDimensionInfo[] dimensionInfos);
/// <summary>
/// Gets aliases
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <returns></returns>
DbgDotNetAliasInfo[] GetAliases(DbgEvaluationInfo evalInfo);
/// <summary>
/// Gets all exceptions
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <returns></returns>
DbgDotNetExceptionInfo[] GetExceptions(DbgEvaluationInfo evalInfo);
/// <summary>
/// Gets all return values
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <returns></returns>
DbgDotNetReturnValueInfo[] GetReturnValues(DbgEvaluationInfo evalInfo);
/// <summary>
/// Gets an exception or null
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="id">Exception id, eg. <see cref="DbgDotNetRuntimeConstants.ExceptionId"/></param>
/// <returns></returns>
DbgDotNetValue? GetException(DbgEvaluationInfo evalInfo, uint id);
/// <summary>
/// Gets a stowed exception or null
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="id">Stowed exception id, eg. <see cref="DbgDotNetRuntimeConstants.StowedExceptionId"/></param>
/// <returns></returns>
DbgDotNetValue? GetStowedException(DbgEvaluationInfo evalInfo, uint id);
/// <summary>
/// Gets a return value or null
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="id">Return value id, eg. <see cref="DbgDotNetRuntimeConstants.LastReturnValueId"/></param>
/// <returns></returns>
DbgDotNetValue? GetReturnValue(DbgEvaluationInfo evalInfo, uint id);
/// <summary>
/// Gets a local value
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="index">Metadata index of local</param>
/// <returns></returns>
DbgDotNetValueResult GetLocalValue(DbgEvaluationInfo evalInfo, uint index);
/// <summary>
/// Gets a parameter value
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="index">Metadata index of parameter</param>
/// <returns></returns>
DbgDotNetValueResult GetParameterValue(DbgEvaluationInfo evalInfo, uint index);
/// <summary>
/// Writes a new local value. Returns an error message or null.
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="index">Metadata index of parameter</param>
/// <param name="targetType">Type of the local</param>
/// <param name="value">New value: A <see cref="DbgDotNetValue"/> or a primitive number or a string or arrays of primitive numbers / strings</param>
/// <returns></returns>
string? SetLocalValue(DbgEvaluationInfo evalInfo, uint index, DmdType targetType, object? value);
/// <summary>
/// Writes a new parameter value. Returns an error message or null.
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="index">Metadata index of parameter</param>
/// <param name="targetType">Type of the parameter</param>
/// <param name="value">New value: A <see cref="DbgDotNetValue"/> or a primitive number or a string or arrays of primitive numbers / strings</param>
/// <returns></returns>
string? SetParameterValue(DbgEvaluationInfo evalInfo, uint index, DmdType targetType, object? value);
/// <summary>
/// Gets the address of a local value or null if it's not supported
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="index">Metadata index of local</param>
/// <param name="targetType">Type of the local</param>
/// <returns></returns>
DbgDotNetValue? GetLocalValueAddress(DbgEvaluationInfo evalInfo, uint index, DmdType targetType);
/// <summary>
/// Gets the address of a parameter value or null if it's not supported
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="index">Metadata index of local</param>
/// <param name="targetType">Type of the parameter</param>
/// <returns></returns>
DbgDotNetValue? GetParameterValueAddress(DbgEvaluationInfo evalInfo, uint index, DmdType targetType);
/// <summary>
/// Creates a simple value (a primitive number or a string, or arrays of those types)
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="value">A <see cref="DbgDotNetValue"/> or a primitive number or a string or arrays of primitive numbers / strings</param>
/// <returns></returns>
DbgDotNetValueResult CreateValue(DbgEvaluationInfo evalInfo, object? value);
/// <summary>
/// Boxes the value type
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="value">Value to box</param>
/// <returns></returns>
DbgDotNetValueResult Box(DbgEvaluationInfo evalInfo, object? value);
/// <summary>
/// Returns true if it's possible to create an object id
/// </summary>
/// <param name="value">Value created by this runtime</param>
/// <returns></returns>
bool CanCreateObjectId(DbgDotNetValue value);
/// <summary>
/// Creates an object id or returns null
/// </summary>
/// <param name="value">Value created by this runtime</param>
/// <param name="id">Unique id</param>
/// <returns></returns>
DbgDotNetObjectId? CreateObjectId(DbgDotNetValue value, uint id);
/// <summary>
/// Checks if an object id and a value refer to the same data
/// </summary>
/// <param name="objectId">Object id created by this class</param>
/// <param name="value">Value created by this runtime</param>
/// <returns></returns>
bool Equals(DbgDotNetObjectId objectId, DbgDotNetValue value);
/// <summary>
/// Gets the hash code of an object id
/// </summary>
/// <param name="objectId">Object id created by this class</param>
/// <returns></returns>
int GetHashCode(DbgDotNetObjectId objectId);
/// <summary>
/// Gets the hash code of a value created by this runtime
/// </summary>
/// <param name="value">Value created by this runtime</param>
/// <returns></returns>
int GetHashCode(DbgDotNetValue value);
/// <summary>
/// Gets an object ID's value or null if there was an error
/// </summary>
/// <param name="evalInfo">Evaluation info</param>
/// <param name="objectId">Object id created by this class</param>
/// <returns></returns>
DbgDotNetValue? GetValue(DbgEvaluationInfo evalInfo, DbgDotNetObjectId objectId);
/// <summary>
/// Checks if two values are equal. Returns null if it's unknown.
/// </summary>
/// <param name="a">Value #1</param>
/// <param name="b">Value #2</param>
/// <returns></returns>
bool? Equals(DbgDotNetValue a, DbgDotNetValue b);
/// <summary>
/// Tries to get the native code
/// </summary>
/// <param name="frame">Frame</param>
/// <param name="nativeCode">Updated with the native code if successful</param>
/// <returns></returns>
bool TryGetNativeCode(DbgStackFrame frame, out DbgDotNetNativeCode nativeCode);
/// <summary>
/// Tries to get the native code
/// </summary>
/// <param name="method">Method</param>
/// <param name="nativeCode">Updated with the native code if successful</param>
/// <returns></returns>
bool TryGetNativeCode(DmdMethodBase method, out DbgDotNetNativeCode nativeCode);
/// <summary>
/// Tries to get a symbol
/// </summary>
/// <param name="address">Address</param>
/// <param name="result">Updated with the symbol if successful</param>
/// <returns></returns>
bool TryGetSymbol(ulong address, out SymbolResolverResult result);
}
/// <summary>
/// Invoke options
/// </summary>
[Flags]
public enum DbgDotNetInvokeOptions {
/// <summary>
/// No bit is set
/// </summary>
None = 0,
/// <summary>
/// Non-virtual call
/// </summary>
NonVirtual = 0x00000001,
}
/// <summary>
/// .NET runtime features
/// </summary>
[Flags]
public enum DbgDotNetRuntimeFeatures {
/// <summary>
/// No bit is set
/// </summary>
None = 0,
/// <summary>
/// Object IDs are supported
/// </summary>
ObjectIds = 0x00000001,
/// <summary>
/// Calling generic methods isn't supported
/// </summary>
NoGenericMethods = 0x00000002,
/// <summary>
/// <see cref="DbgDotNetValue.LoadIndirect"/> and <see cref="DbgDotNetValue.StoreIndirect(DbgEvaluationInfo, object)"/>
/// isn't supported for pointers.
/// </summary>
NoDereferencePointers = 0x00000004,
/// <summary>
/// Async step with object ids isn't supported
/// </summary>
NoAsyncStepObjectId = 0x00000008,
/// <summary>
/// It's possible to get the native code of jitted managed methods
/// </summary>
NativeMethodBodies = 0x00000010,
}
/// <summary>
/// Constants
/// </summary>
public static class DbgDotNetRuntimeConstants {
/// <summary>
/// Exception ID
/// </summary>
public const uint ExceptionId = 1;
/// <summary>
/// Stowed exception ID
/// </summary>
public const uint StowedExceptionId = 1;
/// <summary>
/// ID of last return value
/// </summary>
public const uint LastReturnValueId = 0;
}
/// <summary>
/// Contains .NET module data information
/// </summary>
public readonly struct DbgDotNetRawModuleBytes {
/// <summary>
/// No .NET module data is available
/// </summary>
public static readonly DbgDotNetRawModuleBytes None = default;
/// <summary>
/// true if it's file layout, false if it's memory layout
/// </summary>
public bool IsFileLayout { get; }
/// <summary>
/// Raw bytes of the .NET module
/// </summary>
public byte[] RawBytes { get; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="rawBytes">Raw bytes of the .NET module</param>
/// <param name="isFileLayout">true if it's file layout, false if it's memory layout</param>
public DbgDotNetRawModuleBytes(byte[] rawBytes, bool isFileLayout) {
IsFileLayout = isFileLayout;
RawBytes = rawBytes ?? throw new ArgumentNullException(nameof(rawBytes));
}
}
}