From 48db555fda5d97714a947392304cee46804cbb1b Mon Sep 17 00:00:00 2001 From: Lukasz Paczkowski Date: Mon, 10 Aug 2015 14:31:35 +0200 Subject: [PATCH 1/5] SoftDebuggerSession: Make registered types unique across assemblies. Fixes case 717944 --- Mono.Debugging.Soft/SoftDebuggerSession.cs | 43 ++++++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/Mono.Debugging.Soft/SoftDebuggerSession.cs b/Mono.Debugging.Soft/SoftDebuggerSession.cs index 4c4a9a62a..b8c638583 100644 --- a/Mono.Debugging.Soft/SoftDebuggerSession.cs +++ b/Mono.Debugging.Soft/SoftDebuggerSession.cs @@ -521,10 +521,7 @@ public VirtualMachine VirtualMachine { public TypeMirror GetType (string fullName) { TypeMirror tm; - - if (!types.TryGetValue (fullName, out tm)) - aliases.TryGetValue (fullName, out tm); - + TryGetType(fullName, out tm); return tm; } @@ -926,7 +923,7 @@ protected override BreakEventInfo OnInsertBreakEvent (BreakEvent breakEvent) var cp = (Catchpoint) breakEvent; TypeMirror type; - if (!types.TryGetValue (cp.ExceptionName, out type)) { + if (!TryGetType (cp.ExceptionName, out type)) { // // Same as in FindLocationByFile (), fetch types matching the type name if (vm.Version.AtLeast (2, 9)) { @@ -935,7 +932,7 @@ protected override BreakEventInfo OnInsertBreakEvent (BreakEvent breakEvent) } } - if (types.TryGetValue (cp.ExceptionName, out type)) { + if (TryGetType (cp.ExceptionName, out type)) { InsertCatchpoint (cp, bi, type); bi.SetStatus (BreakEventStatus.Bound, null); } else { @@ -1837,7 +1834,7 @@ where PathComparer.Equals (pair.Value.Assembly.Location, asm.Location) foreach (string typeName in affectedTypes) { TypeMirror tm; - if (types.TryGetValue (typeName, out tm)) { + if (TryGetType (typeName, out tm)) { if (tm.IsNested) aliases.Remove (NestedTypeNameToAlias (typeName)); @@ -1875,7 +1872,7 @@ void HandleTypeLoadEvents (TypeLoadEvent[] events) throw new InvalidOperationException ("Simultaneous TypeLoadEvents for multiple types"); lock (pending_bes) { - if (!types.ContainsKey (type.FullName)) + if (!ContainsType(type)) ResolveBreakpoints (type); } } @@ -2189,18 +2186,40 @@ static string NestedTypeNameToAlias (string typeName) return prefix + suffix; } - - void ProcessType (TypeMirror t) + + string TypeKey(TypeMirror type) + { + return type.Assembly.GetName().Name + ":" + type.FullName; + } + + bool ContainsType(TypeMirror type) + { + string key = TypeKey(type); + return types.ContainsKey(key); + } + + bool TryGetType(string fullName, out TypeMirror tm) + { + if (!types.TryGetValue(fullName, out tm)) + return aliases.TryGetValue(fullName, out tm); + else + return true; + } + + void ProcessType(TypeMirror t) { string typeName = t.FullName; - if (types.ContainsKey (typeName)) + if (ContainsType(t)) return; if (t.IsNested) aliases[NestedTypeNameToAlias (typeName)] = t; - types[typeName] = t; + types[TypeKey(t)] = t; + + // FIXME: There will be a collision if there is a type with the same full name in multiple asssemblies. + aliases[typeName] = t; //get the source file paths //full paths, from GetSourceFiles (true), are only supported by sdb protocol 2.2 and later From a10c48789173b8097e490afc895971dc6e136b84 Mon Sep 17 00:00:00 2001 From: Lukasz Date: Mon, 31 Aug 2015 10:42:03 +0200 Subject: [PATCH 2/5] Revert "SoftDebuggerSession: Make registered types unique across assemblies. Fixes case 717944" This reverts commit 48db555fda5d97714a947392304cee46804cbb1b. --- Mono.Debugging.Soft/SoftDebuggerSession.cs | 43 ++++++---------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/Mono.Debugging.Soft/SoftDebuggerSession.cs b/Mono.Debugging.Soft/SoftDebuggerSession.cs index b8c638583..4c4a9a62a 100644 --- a/Mono.Debugging.Soft/SoftDebuggerSession.cs +++ b/Mono.Debugging.Soft/SoftDebuggerSession.cs @@ -521,7 +521,10 @@ public VirtualMachine VirtualMachine { public TypeMirror GetType (string fullName) { TypeMirror tm; - TryGetType(fullName, out tm); + + if (!types.TryGetValue (fullName, out tm)) + aliases.TryGetValue (fullName, out tm); + return tm; } @@ -923,7 +926,7 @@ protected override BreakEventInfo OnInsertBreakEvent (BreakEvent breakEvent) var cp = (Catchpoint) breakEvent; TypeMirror type; - if (!TryGetType (cp.ExceptionName, out type)) { + if (!types.TryGetValue (cp.ExceptionName, out type)) { // // Same as in FindLocationByFile (), fetch types matching the type name if (vm.Version.AtLeast (2, 9)) { @@ -932,7 +935,7 @@ protected override BreakEventInfo OnInsertBreakEvent (BreakEvent breakEvent) } } - if (TryGetType (cp.ExceptionName, out type)) { + if (types.TryGetValue (cp.ExceptionName, out type)) { InsertCatchpoint (cp, bi, type); bi.SetStatus (BreakEventStatus.Bound, null); } else { @@ -1834,7 +1837,7 @@ where PathComparer.Equals (pair.Value.Assembly.Location, asm.Location) foreach (string typeName in affectedTypes) { TypeMirror tm; - if (TryGetType (typeName, out tm)) { + if (types.TryGetValue (typeName, out tm)) { if (tm.IsNested) aliases.Remove (NestedTypeNameToAlias (typeName)); @@ -1872,7 +1875,7 @@ void HandleTypeLoadEvents (TypeLoadEvent[] events) throw new InvalidOperationException ("Simultaneous TypeLoadEvents for multiple types"); lock (pending_bes) { - if (!ContainsType(type)) + if (!types.ContainsKey (type.FullName)) ResolveBreakpoints (type); } } @@ -2186,40 +2189,18 @@ static string NestedTypeNameToAlias (string typeName) return prefix + suffix; } - - string TypeKey(TypeMirror type) - { - return type.Assembly.GetName().Name + ":" + type.FullName; - } - - bool ContainsType(TypeMirror type) - { - string key = TypeKey(type); - return types.ContainsKey(key); - } - - bool TryGetType(string fullName, out TypeMirror tm) - { - if (!types.TryGetValue(fullName, out tm)) - return aliases.TryGetValue(fullName, out tm); - else - return true; - } - - void ProcessType(TypeMirror t) + + void ProcessType (TypeMirror t) { string typeName = t.FullName; - if (ContainsType(t)) + if (types.ContainsKey (typeName)) return; if (t.IsNested) aliases[NestedTypeNameToAlias (typeName)] = t; - types[TypeKey(t)] = t; - - // FIXME: There will be a collision if there is a type with the same full name in multiple asssemblies. - aliases[typeName] = t; + types[typeName] = t; //get the source file paths //full paths, from GetSourceFiles (true), are only supported by sdb protocol 2.2 and later From 7b05f28240bec329a798c088d67ded9d33c973ea Mon Sep 17 00:00:00 2001 From: Lukasz Paczkowski Date: Thu, 3 Sep 2015 15:12:39 +0200 Subject: [PATCH 3/5] [soft-debugger-session] Maintain list of loaded assemblies for each domain to remove unloaded types correctly on domain unload. --- Mono.Debugging.Soft/SoftDebuggerSession.cs | 77 +++++++++++++++++----- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/Mono.Debugging.Soft/SoftDebuggerSession.cs b/Mono.Debugging.Soft/SoftDebuggerSession.cs index b4c685416..9d75b7761 100644 --- a/Mono.Debugging.Soft/SoftDebuggerSession.cs +++ b/Mono.Debugging.Soft/SoftDebuggerSession.cs @@ -52,6 +52,7 @@ public class SoftDebuggerSession : DebuggerSession { readonly Dictionary, MethodMirror[]> overloadResolveCache = new Dictionary, MethodMirror[]> (); readonly Dictionary> source_to_type = new Dictionary> (PathComparer); + readonly Dictionary domainAssemblies = new Dictionary(); readonly Dictionary activeExceptionsByThread = new Dictionary (); readonly Dictionary breakpoints = new Dictionary (); readonly Dictionary symbolFiles = new Dictionary (); @@ -416,8 +417,8 @@ void ConnectionStarted (VirtualMachine machine) ConnectOutput (machine.StandardError, true); HideConnectionDialog (); - - machine.EnableEvents (EventType.AssemblyLoad, EventType.ThreadStart, EventType.ThreadDeath, + + machine.EnableEvents (EventType.AppDomainCreate, EventType.AppDomainUnload, EventType.AssemblyLoad, EventType.ThreadStart, EventType.ThreadDeath, EventType.AssemblyUnload, EventType.UserBreak, EventType.UserLog); try { unhandledExceptionRequest = machine.CreateExceptionRequest (null, false, true); @@ -1450,6 +1451,12 @@ void HandleEventSet (EventSet es) } switch (type) { + case EventType.AppDomainCreate: + HandleAppDomainCreateEvents (Array.ConvertAll(es.Events, item => (AppDomainCreateEvent)item)); + break; + case EventType.AppDomainUnload: + HandleAppDomainUnloadEvents (Array.ConvertAll(es.Events, item => (AppDomainUnloadEvent)item)); + break; case EventType.AssemblyLoad: HandleAssemblyLoadEvents (Array.ConvertAll (es.Events, item => (AssemblyLoadEvent)item)); break; @@ -1784,6 +1791,51 @@ void HandleBreakEventSet (Event[] es, bool dequeuing) } } + void HandleAppDomainCreateEvents(AppDomainCreateEvent[] events) + { + var domain = events[0].Domain; + if (events.Length > 1) + throw new InvalidOperationException("Simultaneous AppDomainCreateEvent for multiple domains"); + + if(!domainAssemblies.ContainsKey(domain)) + domainAssemblies[domain] = null; + } + + void HandleAppDomainUnloadEvents(AppDomainUnloadEvent[] events) + { + var domain = events[0].Domain; + if (events.Length > 1) + throw new InvalidOperationException("Simultaneous AppDomainUnloadEvent for multiple domains"); + + if (!domainAssemblies.ContainsKey(domain)) + return; + + var assemblies = domainAssemblies[domain]; + + foreach (var asm in assemblies) + { + // Remove affected types from the loaded types list + var affectedTypes = new List(from pair in types + where PathComparer.Equals(pair.Value.Assembly.Location, asm.Location) + select pair.Key); + + foreach (string typeName in affectedTypes) + { + TypeMirror tm; + + if (types.TryGetValue(typeName, out tm)) + { + if (tm.IsNested) + aliases.Remove(NestedTypeNameToAlias(typeName)); + + types.Remove(typeName); + } + } + } + + domainAssemblies.Remove(domain); + } + void HandleAssemblyLoadEvents (AssemblyLoadEvent[] events) { var asm = events [0].Assembly; @@ -1797,6 +1849,11 @@ void HandleAssemblyLoadEvents (AssemblyLoadEvent[] events) string flagExt = isExternal ? " [External]" : ""; OnDebuggerOutput (false, string.Format ("Loaded assembly: {0}{1}\n", asm.Location, flagExt)); + + // Update loaded assemblies for each domain + var domains = new List(domainAssemblies.Keys); + foreach (var domain in domains) + domainAssemblies[domain] = domain.GetAssemblies(); } void HandleAssemblyUnloadEvents (AssemblyUnloadEvent[] events) @@ -1824,22 +1881,6 @@ void HandleAssemblyUnloadEvents (AssemblyUnloadEvent[] events) pending_bes.Add (breakpoint.Value); } - // Remove affected types from the loaded types list - var affectedTypes = new List (from pair in types - where PathComparer.Equals (pair.Value.Assembly.Location, asm.Location) - select pair.Key); - - foreach (string typeName in affectedTypes) { - TypeMirror tm; - - if (types.TryGetValue (typeName, out tm)) { - if (tm.IsNested) - aliases.Remove (NestedTypeNameToAlias (typeName)); - - types.Remove (typeName); - } - } - foreach (var pair in source_to_type) { pair.Value.RemoveAll (m => PathComparer.Equals (m.Assembly.Location, asm.Location)); } From 7e99a05561a2d5c3a51d814c0692af690423f1ed Mon Sep 17 00:00:00 2001 From: Lukasz Paczkowski Date: Fri, 4 Sep 2015 08:09:05 +0200 Subject: [PATCH 4/5] [soft-debugger-session] Also remove types on assembly unload, to match previous logic. --- Mono.Debugging.Soft/SoftDebuggerSession.cs | 43 ++++++++++++---------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/Mono.Debugging.Soft/SoftDebuggerSession.cs b/Mono.Debugging.Soft/SoftDebuggerSession.cs index 9d75b7761..ac04b3bb5 100644 --- a/Mono.Debugging.Soft/SoftDebuggerSession.cs +++ b/Mono.Debugging.Soft/SoftDebuggerSession.cs @@ -1791,6 +1791,27 @@ void HandleBreakEventSet (Event[] es, bool dequeuing) } } + void RemoveUnloadedAssemblyTypes(AssemblyMirror asm) + { + // Remove affected types from the loaded types list + var affectedTypes = new List(from pair in types + where PathComparer.Equals(pair.Value.Assembly.Location, asm.Location) + select pair.Key); + + foreach (string typeName in affectedTypes) + { + TypeMirror tm; + + if (types.TryGetValue(typeName, out tm)) + { + if (tm.IsNested) + aliases.Remove(NestedTypeNameToAlias(typeName)); + + types.Remove(typeName); + } + } + } + void HandleAppDomainCreateEvents(AppDomainCreateEvent[] events) { var domain = events[0].Domain; @@ -1813,25 +1834,7 @@ void HandleAppDomainUnloadEvents(AppDomainUnloadEvent[] events) var assemblies = domainAssemblies[domain]; foreach (var asm in assemblies) - { - // Remove affected types from the loaded types list - var affectedTypes = new List(from pair in types - where PathComparer.Equals(pair.Value.Assembly.Location, asm.Location) - select pair.Key); - - foreach (string typeName in affectedTypes) - { - TypeMirror tm; - - if (types.TryGetValue(typeName, out tm)) - { - if (tm.IsNested) - aliases.Remove(NestedTypeNameToAlias(typeName)); - - types.Remove(typeName); - } - } - } + RemoveUnloadedAssemblyTypes(asm); domainAssemblies.Remove(domain); } @@ -1881,6 +1884,8 @@ void HandleAssemblyUnloadEvents (AssemblyUnloadEvent[] events) pending_bes.Add (breakpoint.Value); } + RemoveUnloadedAssemblyTypes(asm); + foreach (var pair in source_to_type) { pair.Value.RemoveAll (m => PathComparer.Equals (m.Assembly.Location, asm.Location)); } From 3a9e1a57f5c3706d35ee6550fa01a293d96c2e73 Mon Sep 17 00:00:00 2001 From: Lukasz Paczkowski Date: Fri, 4 Sep 2015 08:23:06 +0200 Subject: [PATCH 5/5] [soft-debugger-session] Update source_to_type on domain unload. --- Mono.Debugging.Soft/SoftDebuggerSession.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Mono.Debugging.Soft/SoftDebuggerSession.cs b/Mono.Debugging.Soft/SoftDebuggerSession.cs index ac04b3bb5..25195cedd 100644 --- a/Mono.Debugging.Soft/SoftDebuggerSession.cs +++ b/Mono.Debugging.Soft/SoftDebuggerSession.cs @@ -1810,6 +1810,11 @@ where PathComparer.Equals(pair.Value.Assembly.Location, asm.Location) types.Remove(typeName); } } + + foreach (var pair in source_to_type) + { + pair.Value.RemoveAll(m => PathComparer.Equals(m.Assembly.Location, asm.Location)); + } } void HandleAppDomainCreateEvents(AppDomainCreateEvent[] events) @@ -1885,10 +1890,6 @@ void HandleAssemblyUnloadEvents (AssemblyUnloadEvent[] events) } RemoveUnloadedAssemblyTypes(asm); - - foreach (var pair in source_to_type) { - pair.Value.RemoveAll (m => PathComparer.Equals (m.Assembly.Location, asm.Location)); - } } OnDebuggerOutput (false, string.Format ("Unloaded assembly: {0}\n", asm.Location)); }