/* 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 System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using dndbg.Engine; using dnSpy.Contracts.Debugger; using dnSpy.Contracts.Debugger.CallStack; using dnSpy.Contracts.Debugger.Code; using dnSpy.Contracts.Debugger.DotNet.Code; using dnSpy.Contracts.Debugger.Engine.CallStack; using dnSpy.Debugger.DotNet.CorDebug.Code; using dnSpy.Debugger.DotNet.CorDebug.Impl; using dnSpy.Debugger.DotNet.Metadata; namespace dnSpy.Debugger.DotNet.CorDebug.CallStack { sealed class ILDbgEngineStackFrame : DbgEngineStackFrame { public override DbgCodeLocation? Location { get; } public override DbgModule? Module { get; } public override DbgStackFrameFlags Flags => DbgStackFrameFlags.LocationIsNextStatement; public override uint FunctionOffset { get; } public override uint FunctionToken { get; } internal CorFrame CorFrame { get { if (__corFrame_DONT_USE.IsNeutered) __corFrame_DONT_USE = FindFrame(__corFrame_DONT_USE) ?? __corFrame_DONT_USE; return __corFrame_DONT_USE; } } CorFrame __corFrame_DONT_USE; CorFrame? FindFrame(CorFrame frame) { foreach (var f in dnThread.AllFrames) { if (f.StackStart == frame.StackStart && f.StackEnd == frame.StackEnd) return f; } return null; } readonly DbgEngineImpl engine; readonly DnThread dnThread; public ILDbgEngineStackFrame(DbgEngineImpl engine, DbgModule module, CorFrame corFrame, DnThread dnThread, CorFunction corFunction, Lazy dbgDotNetNativeCodeLocationFactory, Lazy dbgDotNetCodeLocationFactory) { Debug.Assert(!corFrame.IsNeutered); this.engine = engine ?? throw new ArgumentNullException(nameof(engine)); Module = module ?? throw new ArgumentNullException(nameof(module)); __corFrame_DONT_USE = corFrame ?? throw new ArgumentNullException(nameof(corFrame)); this.dnThread = dnThread ?? throw new ArgumentNullException(nameof(dnThread)); FunctionToken = corFunction?.Token ?? throw new ArgumentNullException(nameof(corFunction)); uint functionOffset; DbgILOffsetMapping ilOffsetMapping; Debug.Assert(corFrame.IsILFrame); var ip = corFrame.ILFrameIP; if (ip.IsExact) { functionOffset = ip.Offset; ilOffsetMapping = DbgILOffsetMapping.Exact; } else if (ip.IsApproximate) { functionOffset = ip.Offset; ilOffsetMapping = DbgILOffsetMapping.Approximate; } else if (ip.IsProlog) { Debug.Assert(ip.Offset == 0); functionOffset = ip.Offset;// 0 ilOffsetMapping = DbgILOffsetMapping.Prolog; } else if (ip.IsEpilog) { functionOffset = ip.Offset;// end of method == DebuggerJitInfo.m_lastIL ilOffsetMapping = DbgILOffsetMapping.Epilog; } else if (ip.HasNoInfo) { functionOffset = uint.MaxValue; ilOffsetMapping = DbgILOffsetMapping.NoInfo; } else if (ip.IsUnmappedAddress) { functionOffset = uint.MaxValue; ilOffsetMapping = DbgILOffsetMapping.UnmappedAddress; } else { Debug.Fail($"Unknown mapping: {ip.Mapping}"); functionOffset = uint.MaxValue; ilOffsetMapping = DbgILOffsetMapping.Unknown; } FunctionOffset = functionOffset; var moduleId = engine.TryGetModuleId(corFrame).GetValueOrDefault().ToModuleId(); var nativeCode = corFrame.Code; Debug.Assert(nativeCode?.IsIL == false); if (nativeCode?.IsIL == false) { var corCode = engine.CreateDnDebuggerObjectHolder(nativeCode); Location = dbgDotNetNativeCodeLocationFactory.Value.Create(module, moduleId, FunctionToken, FunctionOffset, ilOffsetMapping, corCode.Object?.Address ?? 0, corFrame.NativeFrameIP, corCode); } else Location = dbgDotNetCodeLocationFactory.Value.Create(moduleId, FunctionToken, FunctionOffset, ilOffsetMapping); } sealed class ILFrameState { public readonly ILDbgEngineStackFrame ILFrame; public ILFrameState(ILDbgEngineStackFrame ilFrame) => ILFrame = ilFrame; } public override void OnFrameCreated(DbgStackFrame frame) => frame.GetOrCreateData(() => new ILFrameState(this)); internal static bool TryGetEngineStackFrame(DbgStackFrame frame, [NotNullWhen(true)] out ILDbgEngineStackFrame? ilFrame) { if (frame.TryGetData(out ILFrameState? data)) { ilFrame = data.ILFrame; return true; } ilFrame = null; return false; } internal DmdModule GetReflectionModule() => Module!.GetReflectionModule() ?? throw new InvalidOperationException(); internal CorAppDomain GetCorAppDomain() => dnThread.AppDomain?.CorAppDomain ?? throw new InvalidOperationException(); internal void GetFrameMethodInfo(out DmdModule? module, out int methodMetadataToken, out IList genericTypeArguments, out IList genericMethodArguments) { engine.VerifyCorDebugThread(); var corFrame = CorFrame; methodMetadataToken = (int)corFrame.Token; var corModule = corFrame.Function?.Module; if (corModule is not null) { module = engine.TryGetModule(corModule)?.GetReflectionModule() ?? throw new InvalidOperationException(); if (!corFrame.GetTypeAndMethodGenericParameters(out var typeGenArgs, out var methGenArgs)) throw new InvalidOperationException(); var reflectionAppDomain = module.AppDomain; genericTypeArguments = Convert(reflectionAppDomain, typeGenArgs); genericMethodArguments = Convert(reflectionAppDomain, methGenArgs); return; } module = null; methodMetadataToken = 0; genericTypeArguments = Array.Empty(); genericMethodArguments = Array.Empty(); } IList Convert(DmdAppDomain reflectionAppDomain, CorType[] typeArgs) { if (typeArgs.Length == 0) return Array.Empty(); var types = new DmdType[typeArgs.Length]; var reflectionTypeCreator = new ReflectionTypeCreator(engine, reflectionAppDomain); for (int i = 0; i < types.Length; i++) types[i] = reflectionTypeCreator.Create(typeArgs[i]); return types; } protected override void CloseCore(DbgDispatcher dispatcher) { } } }