Browse Source

implement debugger tree node in Class Browser to allow browsing and decompilation of modules currently loaded in the debug session

pull/48/head
Siegfried Pammer 12 years ago
parent
commit
2fd8a237b2
  1. 4
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin
  2. 1
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj
  3. 149
      src/AddIns/Debugger/Debugger.AddIn/Pads/ClassBrowserSupport.cs
  4. 4
      src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs
  5. 12
      src/Main/Base/Project/Dom/ClassBrowser/AssemblyTreeNode.cs
  6. 6
      src/Main/Base/Project/Dom/IAssemblyModel.cs
  7. 4
      src/Main/Base/Project/Dom/ITypeDefinitionModelCollection.cs
  8. 13
      src/Main/SharpDevelop/Dom/AssemblyModel.cs
  9. 58
      src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs

4
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.addin

@ -149,4 +149,8 @@
<Class class="Debugger.AddIn.Visualizers.ObjectGraphVisualizerDescriptor" /> <Class class="Debugger.AddIn.Visualizers.ObjectGraphVisualizerDescriptor" />
<Class class="Debugger.AddIn.Visualizers.GridVisualizerDescriptor" /> <Class class="Debugger.AddIn.Visualizers.GridVisualizerDescriptor" />
</Path> </Path>
<Path name="/SharpDevelop/TreeNodeFactories">
<Class id="DebuggerTreeNodesFactory" class="ICSharpCode.SharpDevelop.Gui.Pads.DebuggerTreeNodesFactory" />
</Path>
</AddIn> </AddIn>

1
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj

@ -111,6 +111,7 @@
<Compile Include="Pads\CallStackPad.cs"> <Compile Include="Pads\CallStackPad.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Pads\ClassBrowserSupport.cs" />
<Compile Include="Pads\WatchPadCommands.cs" /> <Compile Include="Pads\WatchPadCommands.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Options\DebuggingOptions.cs" /> <Compile Include="Options\DebuggingOptions.cs" />

149
src/AddIns/Debugger/Debugger.AddIn/Pads/ClassBrowserSupport.cs

@ -0,0 +1,149 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using Debugger;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.ClassBrowser;
using System.Linq;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
/// <summary>
/// Description of ClassBrowserSupport.
/// </summary>
public static class ClassBrowserSupport
{
public static void Attach(Debugger.Process process)
{
var classBrowser = SD.GetService<IClassBrowser>();
classBrowser.SpecialNodes.Add(new DebuggerProcessTreeNode(process));
}
public static void Detach(Debugger.Process process)
{
var classBrowser = SD.GetService<IClassBrowser>();
var nodes = classBrowser.SpecialNodes
.Where(n => n.Model == process)
.ToArray();
foreach (var node in nodes) {
classBrowser.SpecialNodes.Remove(node);
}
}
}
class DebuggerTreeNodesFactory : ITreeNodeFactory
{
public Type GetSupportedType(object model)
{
if (model is Debugger.Process)
return typeof(Debugger.Process);
if (model is Debugger.Module)
return typeof(Debugger.Module);
return null;
}
public ICSharpCode.TreeView.SharpTreeNode CreateTreeNode(object model)
{
if (model is Debugger.Process)
return new DebuggerProcessTreeNode((Debugger.Process)model);
if (model is Debugger.Module)
return new DebuggerModuleTreeNode((Debugger.Module)model);
return null;
}
}
class DebuggerProcessTreeNode : ModelCollectionTreeNode
{
Debugger.Process process;
IMutableModelCollection<Debugger.Module> modules;
public DebuggerProcessTreeNode(Debugger.Process process)
{
if (process == null)
throw new ArgumentNullException("process");
this.process = process;
this.modules = new SimpleModelCollection<Debugger.Module>(this.process.Modules);
this.process.ModuleLoaded += ModuleLoaded;
this.process.ModuleUnloaded += ModuleUnloaded;
}
void ModuleLoaded(object sender, ModuleEventArgs e)
{
modules.Add(e.Module);
}
void ModuleUnloaded(object sender, ModuleEventArgs e)
{
modules.Remove(e.Module);
}
protected override object GetModel()
{
return process;
}
protected override IModelCollection<object> ModelChildren {
get {
return modules;
}
}
protected override System.Collections.Generic.IComparer<ICSharpCode.TreeView.SharpTreeNode> NodeComparer {
get {
return NodeTextComparer;
}
}
public override object Text {
get {
return Path.GetFileName(process.Filename);
}
}
public override object Icon {
get {
return IconService.GetImageSource("Icons.16x16.Debug.Start");
}
}
}
class DebuggerModuleTreeNode : AssemblyTreeNode
{
Debugger.Module module;
public DebuggerModuleTreeNode(Module module)
: base(CreateAssemblyModel(module))
{
if (module == null)
throw new ArgumentNullException("module");
this.module = module;
}
public override object Icon {
get {
return IconService.GetImageSource("PadIcons.LoadedModules");
}
}
public override object Text {
get {
return module.Name;
}
}
static IAssemblyModel CreateAssemblyModel(Module module)
{
// references??
IEntityModelContext context = new AssemblyEntityModelContext(module.Assembly.UnresolvedAssembly);
IAssemblyModel model = SD.GetRequiredService<IModelFactory>().CreateAssemblyModel(context);
if (model is IUpdateableAssemblyModel) {
((IUpdateableAssemblyModel)model).Update(EmptyList<IUnresolvedTypeDefinition>.Instance, module.Assembly.TopLevelTypeDefinitions.SelectMany(td => td.Parts).ToList());
}
return model;
}
}
}

4
src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs

@ -10,6 +10,7 @@ using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Windows.Forms; using System.Windows.Forms;
using Debugger; using Debugger;
using ICSharpCode.SharpDevelop.Gui.Pads;
using Debugger.AddIn; using Debugger.AddIn;
using Debugger.AddIn.Tooltips; using Debugger.AddIn.Tooltips;
using Debugger.AddIn.TreeModel; using Debugger.AddIn.TreeModel;
@ -232,6 +233,7 @@ namespace ICSharpCode.SharpDevelop.Services
public void Detach() public void Detach()
{ {
ClassBrowserSupport.Detach(CurrentProcess);
CurrentDebugger.Detach(); CurrentDebugger.Detach();
} }
@ -438,6 +440,7 @@ namespace ICSharpCode.SharpDevelop.Services
CurrentProcess.Paused += debuggedProcess_DebuggingPaused; CurrentProcess.Paused += debuggedProcess_DebuggingPaused;
CurrentProcess.Resumed += debuggedProcess_DebuggingResumed; CurrentProcess.Resumed += debuggedProcess_DebuggingResumed;
CurrentProcess.Exited += (s, e) => debugger_ProcessExited(); CurrentProcess.Exited += (s, e) => debugger_ProcessExited();
ClassBrowserSupport.Attach(CurrentProcess);
UpdateBreakpointIcons(); UpdateBreakpointIcons();
} }
@ -448,6 +451,7 @@ namespace ICSharpCode.SharpDevelop.Services
DebugStopped(this, EventArgs.Empty); DebugStopped(this, EventArgs.Empty);
} }
ClassBrowserSupport.Detach(CurrentProcess);
CurrentProcess = null; CurrentProcess = null;
CurrentThread = null; CurrentThread = null;
CurrentStackFrame = null; CurrentStackFrame = null;

12
src/Main/Base/Project/Dom/ClassBrowser/AssemblyTreeNode.cs

@ -34,6 +34,18 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
return model.Namespaces; return model.Namespaces;
} }
} }
public override object Text {
get {
return model.AssemblyName;
}
}
public override object Icon {
get {
return base.Icon;
}
}
} }
} }

6
src/Main/Base/Project/Dom/IAssemblyModel.cs

@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
@ -57,6 +58,11 @@ namespace ICSharpCode.SharpDevelop.Dom
/// </remarks> /// </remarks>
void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile); void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile);
/// <summary>
/// Updates the parse information with the given list of top-level type definitions.
/// </summary>
void Update(IList<IUnresolvedTypeDefinition> oldFile, IList<IUnresolvedTypeDefinition> newFile);
/// <summary> /// <summary>
/// Gets the assembly name (short name). /// Gets the assembly name (short name).
/// </summary> /// </summary>

4
src/Main/Base/Project/Dom/ITypeDefinitionModelCollection.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.SharpDevelop.Dom
/// <summary> /// <summary>
/// Updates the collection when the parse information has changed. /// Updates the collection when the parse information has changed.
/// </summary> /// </summary>
void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile); void Update(IList<IUnresolvedTypeDefinition> oldFile, IList<IUnresolvedTypeDefinition> newFile);
} }
public sealed class EmptyTypeDefinitionModelCollection : ITypeDefinitionModelCollection public sealed class EmptyTypeDefinitionModelCollection : ITypeDefinitionModelCollection
@ -70,7 +70,7 @@ namespace ICSharpCode.SharpDevelop.Dom
return Enumerable.Empty<ITypeDefinitionModel>().GetEnumerator(); return Enumerable.Empty<ITypeDefinitionModel>().GetEnumerator();
} }
void ITypeDefinitionModelCollection.Update(IUnresolvedFile oldFile, IUnresolvedFile newFile) void ITypeDefinitionModelCollection.Update(IList<IUnresolvedTypeDefinition> oldFile, IList<IUnresolvedTypeDefinition> newFile)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }

13
src/Main/SharpDevelop/Dom/AssemblyModel.cs

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Parser; using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Project;
@ -50,6 +51,18 @@ namespace ICSharpCode.SharpDevelop.Dom
} }
public void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile) public void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile)
{
IList<IUnresolvedTypeDefinition> old = EmptyList<IUnresolvedTypeDefinition>.Instance;
IList<IUnresolvedTypeDefinition> @new = EmptyList<IUnresolvedTypeDefinition>.Instance;
if (oldFile != null)
old = oldFile.TopLevelTypeDefinitions;
if (newFile != null)
@new = newFile.TopLevelTypeDefinitions;
typeDeclarations.Update(old, @new);
}
public void Update(IList<IUnresolvedTypeDefinition> oldFile, IList<IUnresolvedTypeDefinition> newFile)
{ {
typeDeclarations.Update(oldFile, newFile); typeDeclarations.Update(oldFile, newFile);
} }

58
src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs

@ -72,49 +72,45 @@ namespace ICSharpCode.SharpDevelop.Dom
/// <summary> /// <summary>
/// Updates the parse information. /// Updates the parse information.
/// </summary> /// </summary>
public void Update(IUnresolvedFile oldFile, IUnresolvedFile newFile) public void Update(IList<IUnresolvedTypeDefinition> oldFile, IList<IUnresolvedTypeDefinition> newFile)
{ {
List<ITypeDefinitionModel> oldModels = null; List<ITypeDefinitionModel> oldModels = null;
List<ITypeDefinitionModel> newModels = null; List<ITypeDefinitionModel> newModels = null;
bool[] oldTypeDefHandled = null; bool[] oldTypeDefHandled = null;
if (oldFile != null) { if (oldFile.Count > 0) {
oldTypeDefHandled = new bool[oldFile.TopLevelTypeDefinitions.Count]; oldTypeDefHandled = new bool[oldFile.Count];
} }
if (newFile != null) { foreach (var newPart in newFile) {
foreach (var newPart in newFile.TopLevelTypeDefinitions) { FullTypeName newFullTypeName = newPart.FullTypeName;
FullTypeName newFullTypeName = newPart.FullTypeName; TypeDefinitionModel model;
TypeDefinitionModel model; if (dict.TryGetValue(newFullTypeName.TopLevelTypeName, out model)) {
if (dict.TryGetValue(newFullTypeName.TopLevelTypeName, out model)) { // Existing type changed
// Existing type changed // Find a matching old part:
// Find a matching old part: IUnresolvedTypeDefinition oldPart = null;
IUnresolvedTypeDefinition oldPart = null; for (int i = 0; i < oldTypeDefHandled.Length; i++) {
if (oldFile != null) { if (oldTypeDefHandled[i])
for (int i = 0; i < oldTypeDefHandled.Length; i++) { continue;
if (oldTypeDefHandled[i]) if (oldFile[i].FullTypeName == newFullTypeName) {
continue; oldTypeDefHandled[i] = true;
if (oldFile.TopLevelTypeDefinitions[i].FullTypeName == newFullTypeName) { oldPart = oldFile[i];
oldTypeDefHandled[i] = true; break;
oldPart = oldFile.TopLevelTypeDefinitions[i];
break;
}
}
} }
model.Update(oldPart, newPart);
} else {
// New type added
model = new TypeDefinitionModel(context, newPart);
dict.Add(newFullTypeName.TopLevelTypeName, model);
if (newModels == null)
newModels = new List<ITypeDefinitionModel>();
newModels.Add(model);
} }
model.Update(oldPart, newPart);
} else {
// New type added
model = new TypeDefinitionModel(context, newPart);
dict.Add(newFullTypeName.TopLevelTypeName, model);
if (newModels == null)
newModels = new List<ITypeDefinitionModel>();
newModels.Add(model);
} }
} }
// Remove all old parts that weren't updated: // Remove all old parts that weren't updated:
if (oldFile != null) { if (oldTypeDefHandled != null) {
for (int i = 0; i < oldTypeDefHandled.Length; i++) { for (int i = 0; i < oldTypeDefHandled.Length; i++) {
if (!oldTypeDefHandled[i]) { if (!oldTypeDefHandled[i]) {
IUnresolvedTypeDefinition oldPart = oldFile.TopLevelTypeDefinitions[i]; IUnresolvedTypeDefinition oldPart = oldFile[i];
TopLevelTypeName topLevelTypeName = oldPart.FullTypeName.TopLevelTypeName; TopLevelTypeName topLevelTypeName = oldPart.FullTypeName.TopLevelTypeName;
TypeDefinitionModel model; TypeDefinitionModel model;
if (dict.TryGetValue(topLevelTypeName, out model)) { if (dict.TryGetValue(topLevelTypeName, out model)) {

Loading…
Cancel
Save