Browse Source

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
pull/1/head
David Srbecký 15 years ago
parent
commit
61d67819c3
  1. 6
      src/AddIns/Debugger/Debugger.AddIn/Pads/LoadedModulesPad.cs
  2. 2
      src/AddIns/Debugger/Debugger.Core/AppDomain.cs
  3. 25
      src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs
  4. 114
      src/AddIns/Debugger/Debugger.Core/Module.cs
  5. 3
      src/AddIns/Debugger/Debugger.Core/ModuleCollection.cs
  6. 2
      src/AddIns/Debugger/Debugger.Core/NDebugger.cs
  7. 4
      src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs
  8. 2
      src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs

6
src/AddIns/Debugger/Debugger.AddIn/Pads/LoadedModulesPad.cs

@ -141,7 +141,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
ListViewItem newItem = new ListViewItem(); ListViewItem newItem = new ListViewItem();
newItem.Tag = module; newItem.Tag = module;
RefreshItem(newItem); RefreshItem(newItem);
module.SymbolsLoaded += delegate { RefreshItem(newItem); }; module.SymbolsUpdated += delegate { RefreshItem(newItem); };
loadedModulesList.Items.Add(newItem); loadedModulesList.Items.Add(newItem);
} }
@ -151,9 +151,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
item.SubItems.Clear(); item.SubItems.Clear();
item.SubItems.AddRange( item.SubItems.AddRange(
new string[] { new string[] {
module.Filename, module.Name,
String.Format("{0:X8}", module.BaseAdress), String.Format("{0:X8}", module.BaseAdress),
module.FullPath, module.IsDynamic ? "(dynamic)" : module.IsInMemory ? "(in memory)" : module.FullPath,
module.OrderOfLoading.ToString(), module.OrderOfLoading.ToString(),
"", "",
"", "",

2
src/AddIns/Debugger/Debugger.Core/AppDomain.cs

@ -36,7 +36,7 @@ namespace Debugger
get { get {
if (mscorlib != null) return mscorlib; if (mscorlib != null) return mscorlib;
foreach(Module m in Process.Modules) { foreach(Module m in Process.Modules) {
if (m.Filename == "mscorlib.dll" && if (m.Name == "mscorlib.dll" &&
m.AppDomain == this) { m.AppDomain == this) {
mscorlib = m; mscorlib = m;
return mscorlib; return mscorlib;

25
src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs

@ -300,13 +300,16 @@ namespace Debugger
{ {
EnterCallback(PausedReason.Other, "UpdateModuleSymbols", pAppDomain); EnterCallback(PausedReason.Other, "UpdateModuleSymbols", pAppDomain);
foreach (Module module in process.Modules) { Module module = process.Modules[pModule];
if (module.CorModule == pModule) { if (module.CorModule is ICorDebugModule3 && module.IsDynamic) {
process.TraceMessage("UpdateModuleSymbols: Found module: " + pModule.GetName()); // In .NET 4.0, we use the LoadClass callback to load dynamic modules
module.UpdateSymbolsFromStream(pSymbolStream); // because it always works - UpdateModuleSymbols does not.
process.Debugger.Breakpoints.SetInModule(module); // - Simple dynamic code generation seems to trigger both callbacks.
break; // - 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(); ExitCallback();
@ -346,7 +349,8 @@ namespace Debugger
{ {
EnterCallback(PausedReason.Other, "LoadModule " + pModule.GetName(), pAppDomain); 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(); ExitCallback();
} }
@ -390,6 +394,11 @@ namespace Debugger
{ {
EnterCallback(PausedReason.Other, "LoadClass", pAppDomain); 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(); ExitCallback();
} }

114
src/AddIns/Debugger/Debugger.Core/Module.cs

@ -23,7 +23,8 @@ namespace Debugger
Process process; Process process;
bool unloaded = false; bool unloaded = false;
string fullPath; string name;
string fullPath = string.Empty;
int orderOfLoading = 0; int orderOfLoading = 0;
ICorDebugModule corModule; ICorDebugModule corModule;
@ -32,14 +33,10 @@ namespace Debugger
internal Dictionary<string, DebugType> LoadedDebugTypes = new Dictionary<string, DebugType>(); internal Dictionary<string, DebugType> LoadedDebugTypes = new Dictionary<string, DebugType>();
public event EventHandler<ModuleEventArgs> SymbolsLoaded; /// <summary>
/// Occurs when symbols are loaded or unloaded (for memory modules)
protected virtual void OnSymbolsLoaded(ModuleEventArgs e) /// </summary>
{ public event EventHandler<ModuleEventArgs> SymbolsUpdated;
if (SymbolsLoaded != null) {
SymbolsLoaded(this, e);
}
}
public AppDomain AppDomain { public AppDomain AppDomain {
get { return appDomain; } get { return appDomain; }
@ -120,17 +117,16 @@ namespace Debugger
} }
} }
[Debugger.Tests.Ignore] public string Name {
public string FullPath {
get { get {
return fullPath; return name;
} }
} }
public string Filename { [Debugger.Tests.Ignore]
public string FullPath {
get { get {
if (IsDynamic || IsInMemory) return String.Empty; return fullPath;
return System.IO.Path.GetFileName(FullPath);
} }
} }
@ -188,38 +184,96 @@ namespace Debugger
metaData = new MetaDataImport(corModule); metaData = new MetaDataImport(corModule);
if (IsDynamic || IsInMemory) {
name = corModule.GetName();
} else {
fullPath = corModule.GetName(); fullPath = corModule.GetName();
name = System.IO.Path.GetFileName(FullPath);
}
LoadSymbols(process.Options.SymbolsSearchPaths); LoadSymbolsFromDisk(process.Options.SymbolsSearchPaths);
ResetJustMyCodeStatus(); ResetJustMyCodeStatus();
} }
/// <summary> Try to load the debugging symbols (.pdb) from the given path </summary> public void UnloadSymbols()
public void LoadSymbols(string[] searchPath)
{ {
if (symReader != null) {
((ISymUnmanagedDispose)symReader).Destroy();
symReader = null;
}
}
/// <summary>
/// Load symblos for on-disk module
/// </summary>
public void LoadSymbolsFromDisk(string[] searchPath)
{
if (!IsDynamic && !IsInMemory) {
if (symReader == null) { if (symReader == null) {
symReader = metaData.GetSymReader(fullPath, string.Join("; ", searchPath ?? new string[0])); symReader = metaData.GetSymReader(fullPath, string.Join("; ", searchPath ?? new string[0]));
if (symReader != null) { if (symReader != null) {
OnSymbolsLoaded(new ModuleEventArgs(this)); process.TraceMessage("Loaded symbols from disk for " + this.Name);
OnSymbolsUpdated();
ResetJustMyCodeStatus(); }
} }
} }
} }
public void UpdateSymbolsFromStream(IStream pSymbolStream) /// <summary>
/// Load symbols for in-memory module
/// </summary>
public void LoadSymbolsFromMemory(IStream pSymbolStream)
{ {
if (symReader != null) { if (this.IsInMemory) {
((ISymUnmanagedDispose)symReader).Destroy(); UnloadSymbols();
}
symReader = metaData.GetSymReader(pSymbolStream); symReader = metaData.GetSymReader(pSymbolStream);
if (symReader != null) { if (symReader != null) {
OnSymbolsLoaded(new ModuleEventArgs(this)); process.TraceMessage("Loaded symbols from memory for " + this.Name);
} else {
process.TraceMessage("Failed to load symbols from memory");
}
OnSymbolsUpdated();
}
} }
/// <summary>
/// Load symbols for dynamic module
/// (as of .NET 4.0)
/// </summary>
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(); 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<Breakpoint> collection = new List<Breakpoint>();
collection.AddRange(this.Debugger.Breakpoints);
foreach (Breakpoint b in collection) {
b.SetBreakpoint(this);
}
}
} }
/// <summary> Sets all code as being 'my code'. The code will be gradually /// <summary> Sets all code as being 'my code'. The code will be gradually
@ -251,17 +305,15 @@ namespace Debugger
public void Dispose() public void Dispose()
{ {
UnloadSymbols();
metaData.Dispose(); metaData.Dispose();
if (symReader != null) {
((ISymUnmanagedDispose)symReader).Destroy();
}
unloaded = true; unloaded = true;
} }
public override string ToString() public override string ToString()
{ {
return string.Format("{0}", this.Filename); return string.Format("{0}", this.Name);
} }
} }

3
src/AddIns/Debugger/Debugger.Core/ModuleCollection.cs

@ -19,7 +19,7 @@ namespace Debugger
public Module this[string filename] { public Module this[string filename] {
get { get {
foreach(Module module in this) { foreach(Module module in this) {
if (module.Filename == filename) { if (module.Name == filename) {
return module; return module;
} }
} }
@ -42,7 +42,6 @@ namespace Debugger
{ {
module.OrderOfLoading = lastAssignedModuleOrderOfLoading; module.OrderOfLoading = lastAssignedModuleOrderOfLoading;
lastAssignedModuleOrderOfLoading++; lastAssignedModuleOrderOfLoading++;
this.Debugger.Breakpoints.SetInModule(module);
base.OnAdded(module); base.OnAdded(module);
} }

2
src/AddIns/Debugger/Debugger.Core/NDebugger.cs

@ -245,7 +245,7 @@ namespace Debugger
{ {
foreach(Process process in this.Processes) { foreach(Process process in this.Processes) {
foreach(Module module in process.Modules) { foreach(Module module in process.Modules) {
module.LoadSymbols(process.Options.SymbolsSearchPaths); module.LoadSymbolsFromDisk(process.Options.SymbolsSearchPaths);
} }
} }
TraceMessage("Reloaded symbols"); TraceMessage("Reloaded symbols");

4
src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs

@ -123,9 +123,11 @@ namespace Debugger
if (!symDoc.GetURL().ToLower().EndsWith(filename)) continue; if (!symDoc.GetURL().ToLower().EndsWith(filename)) continue;
byte[] symDocCheckSum = symDoc.GetCheckSum(); byte[] symDocCheckSum = symDoc.GetCheckSum();
if (symDocCheckSum.Length != checksum.Length) continue; if (symDocCheckSum.Length != checksum.Length) continue;
bool match = true;
for (int i = 0; i < checksum.Length; i++) { 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 symDoc;
} }
return null; // Not found return null; // Not found

2
src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs

@ -205,7 +205,7 @@ namespace Debugger.Tests
LogEvent("LogMessage", e.Message.Replace("\r",@"\r").Replace("\n",@"\n")); LogEvent("LogMessage", e.Message.Replace("\r",@"\r").Replace("\n",@"\n"));
}; };
process.Modules.Added += delegate(object sender, CollectionItemEventArgs<Module> e) { process.Modules.Added += delegate(object sender, CollectionItemEventArgs<Module> 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) { process.Paused += delegate(object sender, ProcessEventArgs e) {
LogEvent("DebuggingPaused", e.Process.PauseSession.PausedReason.ToString() + " " + e.Process.SelectedStackFrame.NextStatement.ToString()); LogEvent("DebuggingPaused", e.Process.PauseSession.PausedReason.ToString() + " " + e.Process.SelectedStackFrame.NextStatement.ToString());

Loading…
Cancel
Save