/* 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.ComponentModel.Composition; using System.Threading; using System.Threading.Tasks; using dnSpy.Contracts.Debugger; using dnSpy.Contracts.Debugger.DotNet.Code; using dnSpy.Contracts.Debugger.DotNet.Metadata; using dnSpy.Contracts.Decompiler; using dnSpy.Contracts.Documents.Tabs; using dnSpy.Contracts.Documents.Tabs.DocViewer; using dnSpy.Contracts.Metadata; using dnSpy.Debugger.DotNet.Metadata; using dnSpy.Debugger.DotNet.UI; namespace dnSpy.Debugger.DotNet.Code { abstract class DbgDotNetDebugInfoService { public abstract Task GetMethodDebugInfoAsync(DbgModule module, uint token); } [Export(typeof(DbgDotNetDebugInfoService))] sealed class DbgDotNetDebugInfoServiceImpl : DbgDotNetDebugInfoService { readonly UIDispatcher uiDispatcher; readonly DbgModuleIdProviderService dbgModuleIdProviderService; readonly DbgMetadataService dbgMetadataService; readonly Lazy documentTabService; readonly Lazy dbgMethodDebugInfoProvider; readonly Lazy decompilerService; [ImportingConstructor] DbgDotNetDebugInfoServiceImpl(UIDispatcher uiDispatcher, DbgModuleIdProviderService dbgModuleIdProviderService, DbgMetadataService dbgMetadataService, Lazy documentTabService, Lazy dbgMethodDebugInfoProvider, Lazy decompilerService) { this.uiDispatcher = uiDispatcher; this.dbgModuleIdProviderService = dbgModuleIdProviderService; this.dbgMetadataService = dbgMetadataService; this.documentTabService = documentTabService; this.dbgMethodDebugInfoProvider = dbgMethodDebugInfoProvider; this.decompilerService = decompilerService; } void UI(Action callback) => uiDispatcher.UI(callback); public override Task GetMethodDebugInfoAsync(DbgModule module, uint token) { if (module is null) throw new ArgumentNullException(nameof(module)); var tcs = new TaskCompletionSource(); UI(() => GetMethodDebugInfo_UI(module, token, tcs)); return tcs.Task; } void GetMethodDebugInfo_UI(DbgModule module, uint token, TaskCompletionSource tcs) { uiDispatcher.VerifyAccess(); try { var info = TryGetMethodDebugInfo_UI(module, token); tcs.SetResult(info); } catch (Exception ex) { tcs.SetException(ex); } } MethodDebugInfoResult TryGetMethodDebugInfo_UI(DbgModule module, uint token) { uiDispatcher.VerifyAccess(); var tab = documentTabService.Value.GetOrCreateActiveTab(); var documentViewer = tab.TryGetDocumentViewer(); var methodDebugService = documentViewer.GetMethodDebugService(); var moduleId = dbgModuleIdProviderService.GetModuleId(module); if (moduleId is null) return default; var key = new ModuleTokenId(moduleId.Value, token); var decompilerDebugInfo = methodDebugService.TryGetMethodDebugInfo(key); DbgMethodDebugInfo? debugInfo; DbgMethodDebugInfo? stateMachineDebugInfo = null; int methodVersion; if (decompilerDebugInfo is not null) { methodVersion = 1; debugInfo = DbgMethodDebugInfoUtils.ToDbgMethodDebugInfo(decompilerDebugInfo); } else { var cancellationToken = CancellationToken.None; var result = dbgMethodDebugInfoProvider.Value.GetMethodDebugInfo(decompilerService.Value.Decompiler, module, token, cancellationToken); methodVersion = result.MethodVersion; debugInfo = result.DebugInfo; stateMachineDebugInfo = result.StateMachineDebugInfo; } return new MethodDebugInfoResult(methodVersion, debugInfo, stateMachineDebugInfo); } } }