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. 20
      src/Main/SharpDevelop/Dom/TopLevelTypeDefinitionModelCollection.cs

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

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

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

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

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

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

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

@ -34,6 +34,18 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser @@ -34,6 +34,18 @@ namespace ICSharpCode.SharpDevelop.Dom.ClassBrowser
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 @@ @@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
@ -57,6 +58,11 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -57,6 +58,11 @@ namespace ICSharpCode.SharpDevelop.Dom
/// </remarks>
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>
/// Gets the assembly name (short name).
/// </summary>

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

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

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

@ -5,6 +5,7 @@ using System; @@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
@ -50,6 +51,18 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -50,6 +51,18 @@ namespace ICSharpCode.SharpDevelop.Dom
}
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);
}

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

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

Loading…
Cancel
Save