/*
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 dnlib.DotNet;
using dnSpy.Contracts.Debugger.Code;
using dnSpy.Contracts.Debugger.DotNet.Code;
using dnSpy.Contracts.Debugger.DotNet.Metadata;
using dnSpy.Contracts.Metadata;
using dnSpy.Contracts.Settings;
namespace dnSpy.Debugger.DotNet.Code {
[ExportDbgCodeLocationSerializer(PredefinedDbgCodeLocationTypes.DotNet)]
sealed class DbgCodeLocationSerializerImpl : DbgCodeLocationSerializer {
readonly Lazy dbgDotNetCodeLocationFactory;
readonly Lazy dbgMetadataService;
[ImportingConstructor]
DbgCodeLocationSerializerImpl(Lazy dbgDotNetCodeLocationFactory, Lazy dbgMetadataService) {
this.dbgDotNetCodeLocationFactory = dbgDotNetCodeLocationFactory;
this.dbgMetadataService = dbgMetadataService;
}
// PERF: Getting the serialized name of a method is slow if there are lots of assemblies
sealed class SerializedState {
public bool Initialized;
public string? MethodAsString;
}
public override void Serialize(ISettingsSection section, DbgCodeLocation location) {
var loc = (DbgDotNetCodeLocation)location;
section.Attribute("Token", loc.Token);
section.Attribute("Offset", loc.Offset);
section.Attribute("AssemblyFullName", loc.Module.AssemblyFullName);
section.Attribute("ModuleName", loc.Module.ModuleName);
if (loc.Module.IsDynamic)
section.Attribute("IsDynamic", loc.Module.IsDynamic);
if (loc.Module.IsInMemory)
section.Attribute("IsInMemory", loc.Module.IsInMemory);
if (loc.Module.ModuleNameOnly)
section.Attribute("ModuleNameOnly", loc.Module.ModuleNameOnly);
if (!loc.Module.IsInMemory && !loc.Module.IsDynamic) {
var state = location.GetOrCreateData();
if (!state.Initialized) {
state.MethodAsString = GetMethodAsString(loc.Module, loc.Token);
state.Initialized = true;
}
if (state.MethodAsString is not null)
section.Attribute("Method", state.MethodAsString);
}
}
public override DbgCodeLocation? Deserialize(ISettingsSection section) {
var token = section.Attribute("Token");
var offset = section.Attribute("Offset");
var assemblyFullName = section.Attribute("AssemblyFullName");
var moduleName = section.Attribute("ModuleName");
var isDynamic = section.Attribute("IsDynamic") ?? false;
var isInMemory = section.Attribute("IsInMemory") ?? false;
var moduleNameOnly = section.Attribute("ModuleNameOnly") ?? false;
if (token is null || offset is null || assemblyFullName is null || moduleName is null)
return null;
var moduleId = new ModuleId(assemblyFullName, moduleName, isDynamic, isInMemory, moduleNameOnly);
var location = dbgDotNetCodeLocationFactory.Value.Create(moduleId, token.Value, offset.Value);
if (!isInMemory && !isDynamic) {
var s = section.Attribute("Method");
if (!string.IsNullOrEmpty(s) && s != GetMethodAsString(moduleId, token.Value)) {
location.Close();
return null;
}
var state = location.GetOrCreateData();
state.MethodAsString = s;
state.Initialized = true;
}
return location;
}
string? GetMethodAsString(ModuleId moduleId, uint token) {
var module = dbgMetadataService.Value.TryGetMetadata(moduleId, DbgLoadModuleOptions.AutoLoaded);
return (module?.ResolveToken(token) as MethodDef)?.ToString();
}
}
}