From 61d67819c3b503932a99d3da61b96c4829b4d1fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Mon, 12 Jul 2010 21:13:53 +0000 Subject: [PATCH] In .NET 4.0, we use the LoadClass callback to load dynamic modules because it always works - UpdateModuleSymbols does not. - Simple dynamic code generation seems to trigger both callbacks. - IronPython for some reason causes just the LoadClass callback so we choose to rely on it out of the two. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@6111 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Debugger.AddIn/Pads/LoadedModulesPad.cs | 6 +- .../Debugger/Debugger.Core/AppDomain.cs | 2 +- .../Debugger/Debugger.Core/ManagedCallback.cs | 25 ++-- src/AddIns/Debugger/Debugger.Core/Module.cs | 130 ++++++++++++------ .../Debugger.Core/ModuleCollection.cs | 3 +- .../Debugger/Debugger.Core/NDebugger.cs | 2 +- .../Debugger.Core/SourcecodeSegment.cs | 4 +- .../Debugger.Tests/DebuggerTestsBase.cs | 2 +- 8 files changed, 118 insertions(+), 56 deletions(-) diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/LoadedModulesPad.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/LoadedModulesPad.cs index 1ea3f1cd8b..edfcebc481 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/LoadedModulesPad.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/LoadedModulesPad.cs @@ -141,7 +141,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads ListViewItem newItem = new ListViewItem(); newItem.Tag = module; RefreshItem(newItem); - module.SymbolsLoaded += delegate { RefreshItem(newItem); }; + module.SymbolsUpdated += delegate { RefreshItem(newItem); }; loadedModulesList.Items.Add(newItem); } @@ -151,9 +151,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads item.SubItems.Clear(); item.SubItems.AddRange( new string[] { - module.Filename, + module.Name, String.Format("{0:X8}", module.BaseAdress), - module.FullPath, + module.IsDynamic ? "(dynamic)" : module.IsInMemory ? "(in memory)" : module.FullPath, module.OrderOfLoading.ToString(), "", "", diff --git a/src/AddIns/Debugger/Debugger.Core/AppDomain.cs b/src/AddIns/Debugger/Debugger.Core/AppDomain.cs index 9f2cd8c5a2..401465a00b 100644 --- a/src/AddIns/Debugger/Debugger.Core/AppDomain.cs +++ b/src/AddIns/Debugger/Debugger.Core/AppDomain.cs @@ -36,7 +36,7 @@ namespace Debugger get { if (mscorlib != null) return mscorlib; foreach(Module m in Process.Modules) { - if (m.Filename == "mscorlib.dll" && + if (m.Name == "mscorlib.dll" && m.AppDomain == this) { mscorlib = m; return mscorlib; diff --git a/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs b/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs index e5b92eb54a..71a260f2a8 100644 --- a/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs +++ b/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs @@ -300,13 +300,16 @@ namespace Debugger { EnterCallback(PausedReason.Other, "UpdateModuleSymbols", pAppDomain); - foreach (Module module in process.Modules) { - if (module.CorModule == pModule) { - process.TraceMessage("UpdateModuleSymbols: Found module: " + pModule.GetName()); - module.UpdateSymbolsFromStream(pSymbolStream); - process.Debugger.Breakpoints.SetInModule(module); - break; - } + Module module = process.Modules[pModule]; + if (module.CorModule is ICorDebugModule3 && module.IsDynamic) { + // In .NET 4.0, we use the LoadClass callback to load dynamic modules + // because it always works - UpdateModuleSymbols does not. + // - Simple dynamic code generation seems to trigger both callbacks. + // - IronPython for some reason causes just the LoadClass callback + // so we choose to rely on it out of the two. + } else { + // In .NET 2.0, this is the the only method and it works fine + module.LoadSymbolsFromMemory(pSymbolStream); } ExitCallback(); @@ -346,7 +349,8 @@ namespace Debugger { EnterCallback(PausedReason.Other, "LoadModule " + pModule.GetName(), pAppDomain); - process.Modules.Add(new Module(process.AppDomains[pAppDomain], pModule)); + Module module = new Module(process.AppDomains[pAppDomain], pModule); + process.Modules.Add(module); ExitCallback(); } @@ -390,6 +394,11 @@ namespace Debugger { EnterCallback(PausedReason.Other, "LoadClass", pAppDomain); + Module module = process.Modules[c.GetModule()]; + + // Dynamic module has been extended - reload symbols to inlude new class + module.LoadSymbolsDynamic(); + ExitCallback(); } diff --git a/src/AddIns/Debugger/Debugger.Core/Module.cs b/src/AddIns/Debugger/Debugger.Core/Module.cs index 5f2c81a833..89650542db 100644 --- a/src/AddIns/Debugger/Debugger.Core/Module.cs +++ b/src/AddIns/Debugger/Debugger.Core/Module.cs @@ -23,7 +23,8 @@ namespace Debugger Process process; bool unloaded = false; - string fullPath; + string name; + string fullPath = string.Empty; int orderOfLoading = 0; ICorDebugModule corModule; @@ -32,14 +33,10 @@ namespace Debugger internal Dictionary LoadedDebugTypes = new Dictionary(); - public event EventHandler SymbolsLoaded; - - protected virtual void OnSymbolsLoaded(ModuleEventArgs e) - { - if (SymbolsLoaded != null) { - SymbolsLoaded(this, e); - } - } + /// + /// Occurs when symbols are loaded or unloaded (for memory modules) + /// + public event EventHandler SymbolsUpdated; public AppDomain AppDomain { get { return appDomain; } @@ -120,6 +117,12 @@ namespace Debugger } } + public string Name { + get { + return name; + } + } + [Debugger.Tests.Ignore] public string FullPath { get { @@ -127,13 +130,6 @@ namespace Debugger } } - public string Filename { - get { - if (IsDynamic || IsInMemory) return String.Empty; - return System.IO.Path.GetFileName(FullPath); - } - } - [Debugger.Tests.Ignore] public string DirectoryName { get { @@ -188,38 +184,96 @@ namespace Debugger metaData = new MetaDataImport(corModule); - fullPath = corModule.GetName(); - - LoadSymbols(process.Options.SymbolsSearchPaths); + if (IsDynamic || IsInMemory) { + name = corModule.GetName(); + } else { + fullPath = corModule.GetName(); + name = System.IO.Path.GetFileName(FullPath); + } + LoadSymbolsFromDisk(process.Options.SymbolsSearchPaths); ResetJustMyCodeStatus(); } - /// Try to load the debugging symbols (.pdb) from the given path - public void LoadSymbols(string[] searchPath) + public void UnloadSymbols() { - if (symReader == null) { - symReader = metaData.GetSymReader(fullPath, string.Join("; ", searchPath ?? new string[0])); - if (symReader != null) { - OnSymbolsLoaded(new ModuleEventArgs(this)); - - ResetJustMyCodeStatus(); + if (symReader != null) { + ((ISymUnmanagedDispose)symReader).Destroy(); + symReader = null; + } + } + + /// + /// Load symblos for on-disk module + /// + public void LoadSymbolsFromDisk(string[] searchPath) + { + if (!IsDynamic && !IsInMemory) { + if (symReader == null) { + symReader = metaData.GetSymReader(fullPath, string.Join("; ", searchPath ?? new string[0])); + if (symReader != null) { + process.TraceMessage("Loaded symbols from disk for " + this.Name); + OnSymbolsUpdated(); + } } } } - public void UpdateSymbolsFromStream(IStream pSymbolStream) + /// + /// Load symbols for in-memory module + /// + public void LoadSymbolsFromMemory(IStream pSymbolStream) { - if (symReader != null) { - ((ISymUnmanagedDispose)symReader).Destroy(); + if (this.IsInMemory) { + UnloadSymbols(); + + symReader = metaData.GetSymReader(pSymbolStream); + if (symReader != null) { + process.TraceMessage("Loaded symbols from memory for " + this.Name); + } else { + process.TraceMessage("Failed to load symbols from memory"); + } + + OnSymbolsUpdated(); } - - symReader = metaData.GetSymReader(pSymbolStream); - if (symReader != null) { - OnSymbolsLoaded(new ModuleEventArgs(this)); + } + + /// + /// Load symbols for dynamic module + /// (as of .NET 4.0) + /// + public void LoadSymbolsDynamic() + { + if (this.CorModule is ICorDebugModule3 && this.IsDynamic) { + Guid guid = new Guid(0, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 70); + symReader = (ISymUnmanagedReader)((ICorDebugModule3)this.CorModule).CreateReaderForInMemorySymbols(guid); + TrackedComObjects.Track(symReader); + process.TraceMessage("Loaded dynamic symbols for " + this.Name); + OnSymbolsUpdated(); } - + } + + void OnSymbolsUpdated() + { + SetBreakpoints(); ResetJustMyCodeStatus(); + if (SymbolsUpdated != null) { + SymbolsUpdated(this, new ModuleEventArgs(this)); + } + } + + void SetBreakpoints() + { + if (this.HasSymbols) { + // This is in case that the client modifies the collection as a response to set breakpoint + // NB: If client adds new breakpoint, it will be set directly as a result of his call, not here (because module is already loaded) + List collection = new List(); + collection.AddRange(this.Debugger.Breakpoints); + + foreach (Breakpoint b in collection) { + b.SetBreakpoint(this); + } + } } /// Sets all code as being 'my code'. The code will be gradually @@ -251,17 +305,15 @@ namespace Debugger public void Dispose() { + UnloadSymbols(); metaData.Dispose(); - if (symReader != null) { - ((ISymUnmanagedDispose)symReader).Destroy(); - } unloaded = true; } public override string ToString() { - return string.Format("{0}", this.Filename); + return string.Format("{0}", this.Name); } } diff --git a/src/AddIns/Debugger/Debugger.Core/ModuleCollection.cs b/src/AddIns/Debugger/Debugger.Core/ModuleCollection.cs index 51bb1e6193..d3498a5e79 100644 --- a/src/AddIns/Debugger/Debugger.Core/ModuleCollection.cs +++ b/src/AddIns/Debugger/Debugger.Core/ModuleCollection.cs @@ -19,7 +19,7 @@ namespace Debugger public Module this[string filename] { get { foreach(Module module in this) { - if (module.Filename == filename) { + if (module.Name == filename) { return module; } } @@ -42,7 +42,6 @@ namespace Debugger { module.OrderOfLoading = lastAssignedModuleOrderOfLoading; lastAssignedModuleOrderOfLoading++; - this.Debugger.Breakpoints.SetInModule(module); base.OnAdded(module); } diff --git a/src/AddIns/Debugger/Debugger.Core/NDebugger.cs b/src/AddIns/Debugger/Debugger.Core/NDebugger.cs index 832300ef06..4d506e3409 100644 --- a/src/AddIns/Debugger/Debugger.Core/NDebugger.cs +++ b/src/AddIns/Debugger/Debugger.Core/NDebugger.cs @@ -245,7 +245,7 @@ namespace Debugger { foreach(Process process in this.Processes) { foreach(Module module in process.Modules) { - module.LoadSymbols(process.Options.SymbolsSearchPaths); + module.LoadSymbolsFromDisk(process.Options.SymbolsSearchPaths); } } TraceMessage("Reloaded symbols"); diff --git a/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs b/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs index 11ab364a20..1056e679e1 100644 --- a/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs +++ b/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs @@ -123,9 +123,11 @@ namespace Debugger if (!symDoc.GetURL().ToLower().EndsWith(filename)) continue; byte[] symDocCheckSum = symDoc.GetCheckSum(); if (symDocCheckSum.Length != checksum.Length) continue; + bool match = true; for (int i = 0; i < checksum.Length; i++) { - if (symDocCheckSum[i] != checksum[i]) continue; + if (symDocCheckSum[i] != checksum[i]) match = false; } + if (!match) continue; return symDoc; } return null; // Not found diff --git a/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs b/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs index 56681830b8..3d3a158490 100644 --- a/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs +++ b/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs @@ -205,7 +205,7 @@ namespace Debugger.Tests LogEvent("LogMessage", e.Message.Replace("\r",@"\r").Replace("\n",@"\n")); }; process.Modules.Added += delegate(object sender, CollectionItemEventArgs e) { - LogEvent("ModuleLoaded", e.Item.Filename + (e.Item.HasSymbols ? " (Has symbols)" : " (No symbols)")); + LogEvent("ModuleLoaded", e.Item.Name + (e.Item.HasSymbols ? " (Has symbols)" : " (No symbols)")); }; process.Paused += delegate(object sender, ProcessEventArgs e) { LogEvent("DebuggingPaused", e.Process.PauseSession.PausedReason.ToString() + " " + e.Process.SelectedStackFrame.NextStatement.ToString());