278 lines
7.2 KiB
C#
278 lines
7.2 KiB
C#
|
|
using System;
|
||
|
|
using System.Reflection;
|
||
|
|
using Mono.Debugger;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
|
||
|
|
|
||
|
|
#if ENABLE_CECIL
|
||
|
|
using Mono.Cecil;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
namespace Mono.Debugger.Soft
|
||
|
|
{
|
||
|
|
public class AssemblyMirror : Mirror
|
||
|
|
{
|
||
|
|
string location;
|
||
|
|
MethodMirror entry_point;
|
||
|
|
bool entry_point_set;
|
||
|
|
ModuleMirror main_module;
|
||
|
|
AssemblyName aname;
|
||
|
|
AppDomainMirror domain;
|
||
|
|
byte[] metadata_blob;
|
||
|
|
bool? isDynamic;
|
||
|
|
byte[] pdb_blob;
|
||
|
|
bool? has_debug_info;
|
||
|
|
Dictionary<string, long> typeCacheIgnoreCase = new Dictionary<string, long> (StringComparer.InvariantCultureIgnoreCase);
|
||
|
|
Dictionary<string, long> typeCache = new Dictionary<string, long> ();
|
||
|
|
Dictionary<uint, long> tokenTypeCache = new Dictionary<uint, long> ();
|
||
|
|
Dictionary<uint, long> tokenMethodCache = new Dictionary<uint, long> ();
|
||
|
|
|
||
|
|
#if ENABLE_CECIL
|
||
|
|
Mono.Cecil.AssemblyDefinition meta;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
internal AssemblyMirror (VirtualMachine vm, long id) : base (vm, id) {
|
||
|
|
}
|
||
|
|
|
||
|
|
public string Location {
|
||
|
|
get {
|
||
|
|
if (location == null)
|
||
|
|
location = vm.conn.Assembly_GetLocation (id);
|
||
|
|
return location;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public MethodMirror EntryPoint {
|
||
|
|
get {
|
||
|
|
if (!entry_point_set) {
|
||
|
|
long mid = vm.conn.Assembly_GetEntryPoint (id);
|
||
|
|
|
||
|
|
if (mid != 0)
|
||
|
|
entry_point = vm.GetMethod (mid);
|
||
|
|
entry_point_set = true;
|
||
|
|
}
|
||
|
|
return entry_point;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public ModuleMirror ManifestModule {
|
||
|
|
get {
|
||
|
|
if (main_module == null) {
|
||
|
|
main_module = vm.GetModule (vm.conn.Assembly_GetManifestModule (id));
|
||
|
|
}
|
||
|
|
return main_module;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Since Protocol version 2.45
|
||
|
|
public AppDomainMirror Domain {
|
||
|
|
get {
|
||
|
|
if (domain == null) {
|
||
|
|
vm.CheckProtocolVersion (2, 45);
|
||
|
|
domain = vm.GetDomain (vm.conn.Assembly_GetIdDomain (id));
|
||
|
|
}
|
||
|
|
return domain;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public virtual AssemblyName GetName () {
|
||
|
|
if (aname == null) {
|
||
|
|
string name = vm.conn.Assembly_GetName (id);
|
||
|
|
aname = new AssemblyName (name);
|
||
|
|
}
|
||
|
|
return aname;
|
||
|
|
}
|
||
|
|
|
||
|
|
public ObjectMirror GetAssemblyObject () {
|
||
|
|
return vm.GetObject (vm.conn.Assembly_GetObject (id));
|
||
|
|
}
|
||
|
|
|
||
|
|
public TypeMirror GetType (string name, bool throwOnError, bool ignoreCase)
|
||
|
|
{
|
||
|
|
if (name == null)
|
||
|
|
throw new ArgumentNullException ("name");
|
||
|
|
if (name.Length == 0)
|
||
|
|
throw new ArgumentException ("name", "Name cannot be empty");
|
||
|
|
|
||
|
|
if (throwOnError)
|
||
|
|
throw new NotImplementedException ();
|
||
|
|
long typeId;
|
||
|
|
if (ignoreCase) {
|
||
|
|
if (!typeCacheIgnoreCase.TryGetValue (name, out typeId)) {
|
||
|
|
typeId = vm.conn.Assembly_GetType (id, name, ignoreCase);
|
||
|
|
typeCacheIgnoreCase.Add (name, typeId);
|
||
|
|
var type = vm.GetType (typeId);
|
||
|
|
if (type != null) {
|
||
|
|
typeCache.Add (type.FullName, typeId);
|
||
|
|
}
|
||
|
|
return type;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (!typeCache.TryGetValue (name, out typeId)) {
|
||
|
|
typeId = vm.conn.Assembly_GetType (id, name, ignoreCase);
|
||
|
|
typeCache.Add (name, typeId);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return vm.GetType (typeId);
|
||
|
|
}
|
||
|
|
|
||
|
|
public TypeMirror GetType (String name, Boolean throwOnError)
|
||
|
|
{
|
||
|
|
return GetType (name, throwOnError, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
public TypeMirror GetType (String name) {
|
||
|
|
return GetType (name, false, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
#if ENABLE_CECIL
|
||
|
|
/*
|
||
|
|
* An optional Cecil assembly which could be used to access metadata instead
|
||
|
|
* of reading it from the debuggee.
|
||
|
|
*/
|
||
|
|
public Mono.Cecil.AssemblyDefinition Metadata {
|
||
|
|
get {
|
||
|
|
if (meta != null)
|
||
|
|
return meta;
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
set {
|
||
|
|
if (value.MainModule.Name != ManifestModule.Name)
|
||
|
|
throw new ArgumentException ("The supplied assembly is named '" + value.MainModule.Name + "', while the assembly in the debuggee is named '" + ManifestModule.Name + "'.");
|
||
|
|
if (value.MainModule.Mvid != ManifestModule.ModuleVersionId)
|
||
|
|
throw new ArgumentException ("The supplied assembly's main module has guid '" + value.MainModule.Mvid + ", while the assembly in the debuggee has guid '" + ManifestModule.ModuleVersionId + "'.", "value");
|
||
|
|
meta = value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Read assembly metadata from the debuggee
|
||
|
|
// Since protocol version 2.47
|
||
|
|
public Mono.Cecil.AssemblyDefinition GetMetadata () {
|
||
|
|
if (IsDynamic)
|
||
|
|
throw new NotSupportedException ();
|
||
|
|
|
||
|
|
using (var ms = new MemoryStream (GetMetadataBlob ()))
|
||
|
|
return meta = Mono.Cecil.AssemblyDefinition.ReadAssembly (ms);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
public byte[] GetMetadataBlob () {
|
||
|
|
if (metadata_blob != null)
|
||
|
|
return metadata_blob;
|
||
|
|
|
||
|
|
vm.CheckProtocolVersion (2, 47);
|
||
|
|
|
||
|
|
return metadata_blob = vm.conn.Assembly_GetMetadataBlob (id);
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool IsDynamic {
|
||
|
|
get {
|
||
|
|
if (isDynamic.HasValue)
|
||
|
|
return isDynamic.Value;
|
||
|
|
|
||
|
|
vm.CheckProtocolVersion (2, 47);
|
||
|
|
|
||
|
|
isDynamic = vm.conn.Assembly_IsDynamic (id);
|
||
|
|
return isDynamic.Value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool HasPdb {
|
||
|
|
get {
|
||
|
|
return pdb_blob != null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool HasFetchedPdb { get; private set; }
|
||
|
|
|
||
|
|
public byte[] GetPdbBlob () {
|
||
|
|
if (HasFetchedPdb)
|
||
|
|
return pdb_blob;
|
||
|
|
|
||
|
|
if (!vm.Version.AtLeast (2, 47))
|
||
|
|
return null;
|
||
|
|
|
||
|
|
var blob = vm.conn.Assembly_GetPdbBlob (id);
|
||
|
|
if (blob != null && blob.Length > 0) {
|
||
|
|
pdb_blob = blob;
|
||
|
|
}
|
||
|
|
HasFetchedPdb = true;
|
||
|
|
return pdb_blob;
|
||
|
|
}
|
||
|
|
|
||
|
|
public TypeMirror GetType (uint token) {
|
||
|
|
vm.CheckProtocolVersion (2, 47);
|
||
|
|
if (IsDynamic)
|
||
|
|
throw new NotSupportedException ();
|
||
|
|
|
||
|
|
long typeId;
|
||
|
|
if (!tokenTypeCache.TryGetValue (token, out typeId)) {
|
||
|
|
typeId = vm.conn.Assembly_GetType (id, token);
|
||
|
|
tokenTypeCache.Add (token, typeId);
|
||
|
|
}
|
||
|
|
return vm.GetType (typeId);
|
||
|
|
}
|
||
|
|
|
||
|
|
public MethodMirror GetMethod (uint token) {
|
||
|
|
vm.CheckProtocolVersion (2, 47);
|
||
|
|
if (IsDynamic)
|
||
|
|
throw new NotSupportedException ();
|
||
|
|
|
||
|
|
long methodId;
|
||
|
|
if (!tokenMethodCache.TryGetValue (token, out methodId)) {
|
||
|
|
methodId = vm.conn.Assembly_GetMethod (id, token);
|
||
|
|
tokenMethodCache.Add (token, methodId);
|
||
|
|
}
|
||
|
|
return vm.GetMethod (methodId);
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool HasDebugInfo {
|
||
|
|
get {
|
||
|
|
if (has_debug_info.HasValue)
|
||
|
|
return has_debug_info.Value;
|
||
|
|
|
||
|
|
vm.CheckProtocolVersion (2, 51);
|
||
|
|
|
||
|
|
has_debug_info = vm.conn.Assembly_HasDebugInfo (id);
|
||
|
|
return has_debug_info.Value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public void ApplyChanges_DebugInformation (byte[] metadataDelta, byte[] pdbDelta)
|
||
|
|
{
|
||
|
|
/*var asmStream = new MemoryStream (metadataDelta);
|
||
|
|
MetadataReader asmMetadataReaderParm = MetadataReaderProvider.FromMetadataStream (asmStream).GetMetadataReader ();
|
||
|
|
var pdbStream = new MemoryStream (pdbDelta);
|
||
|
|
MetadataReader pdbMetadataReaderParm = MetadataReaderProvider.FromPortablePdbStream (pdbStream).GetMetadataReader ();
|
||
|
|
|
||
|
|
TypeInfo typeInfo = null;
|
||
|
|
int methodIdxAsm = 1;
|
||
|
|
foreach (var entry in asmMetadataReaderParm.GetEditAndContinueLogEntries ()) {
|
||
|
|
if (entry.Operation == EditAndContinueOperation.AddField) {
|
||
|
|
var typeHandle = (TypeDefinitionHandle)entry.Handle;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
GetType ((uint)MetadataTokens.GetToken (asmMetadataReaderParm, typeHandle)).ClearCachedDebugInfo ();
|
||
|
|
}
|
||
|
|
catch (Exception) {
|
||
|
|
//type does not exist yet
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach (var entry in pdbMetadataReaderParm.GetEditAndContinueMapEntries ()) {
|
||
|
|
if (entry.Kind == HandleKind.MethodDebugInformation) {
|
||
|
|
try {
|
||
|
|
var methodToken = (pdbMetadataReaderParm.GetRowNumber (entry) << 24) | (6);
|
||
|
|
this.GetMethod ((uint)methodToken).SetUpdatedByEnC ();
|
||
|
|
}
|
||
|
|
catch (Exception) {
|
||
|
|
//method does not exist yet
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}*/
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|