Skip to content

Commit

Permalink
Attach/detach to running process
Browse files Browse the repository at this point in the history
  • Loading branch information
eusebiu committed Feb 12, 2011
1 parent 42c2c95 commit a69f8fe
Show file tree
Hide file tree
Showing 26 changed files with 2,242 additions and 11 deletions.
1 change: 0 additions & 1 deletion Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs
Expand Up @@ -26,7 +26,6 @@
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
using ILSpy.Debugger.Bookmarks;
using ILSpy.Debugger.Debugging;
using ILSpy.Debugger.Services;

namespace ILSpy.Debugger.AvalonEdit
Expand Down
4 changes: 2 additions & 2 deletions Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs
Expand Up @@ -28,8 +28,8 @@ namespace ILSpy.Debugger.Bookmarks
public enum BreakpointAction
{
Break,
// Trace,
// Condition
Trace,
Condition
}

public class BreakpointBookmark : BookmarkBase
Expand Down
21 changes: 19 additions & 2 deletions Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj
Expand Up @@ -63,11 +63,27 @@
<Compile Include="Bookmarks\BreakpointBookmarkEventArgs.cs" />
<Compile Include="Bookmarks\CurrentLineBookmark.cs" />
<Compile Include="Bookmarks\IBookmark.cs" />
<Compile Include="Models\TreeModel\ArrayRangeNode.cs" />
<Compile Include="Models\TreeModel\ChildNodesOfObject.cs" />
<Compile Include="Models\TreeModel\ExpressionNode.cs" />
<Compile Include="Models\TreeModel\ICorDebug.cs" />
<Compile Include="Models\TreeModel\IEnumerableNode.cs" />
<Compile Include="Models\TreeModel\IListNode.cs" />
<Compile Include="Models\TreeModel\ISetText.cs" />
<Compile Include="Models\TreeModel\ITreeNode.cs" />
<Compile Include="Models\TreeModel\IVisualizerCommand.cs" />
<Compile Include="Models\TreeModel\SavedTreeNode.cs" />
<Compile Include="Models\TreeModel\StackFrameNode.cs" />
<Compile Include="Models\TreeModel\TreeNode.cs" />
<Compile Include="Models\TreeModel\Utils.cs" />
<Compile Include="Services\Debugger\DebuggerHelper.cs" />
<Compile Include="Services\Debugger\DebuggerService.cs" />
<Compile Include="Services\Debugger\DefaultDebugger.cs" />
<Compile Include="Services\Debugger\IDebugger.cs" />
<Compile Include="Services\Debugger\Tooltips\ITreeNode.cs" />
<Compile Include="Services\Debugger\Tooltips\IVisualizerCommand.cs" />
<Compile Include="Services\Debugger\ListHelper.cs" />
<Compile Include="Services\Debugger\RemotingConfigurationHelpper.cs" />
<Compile Include="Services\Debugger\TypeResolverExtension.cs" />
<Compile Include="Services\Debugger\WindowsDebugger.cs" />
<Compile Include="Services\ImageService\ImageService.cs" />
<Compile Include="Models\RunningProcess.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand All @@ -80,6 +96,7 @@
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="Models\TreeModel" />
<Folder Include="Services\Debugger\Tooltips" />
</ItemGroup>
<ItemGroup>
Expand Down
120 changes: 120 additions & 0 deletions Debugger/ILSpy.Debugger/Models/TreeModel/ArrayRangeNode.cs
@@ -0,0 +1,120 @@
// 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.Collections.Generic;
using System.Text;

using Debugger;
using ICSharpCode.NRefactory.Ast;

namespace ILSpy.Debugger.Models.TreeModel
{
public partial class Utils
{
public static IEnumerable<TreeNode> LazyGetChildNodesOfArray(Expression expression, ArrayDimensions dimensions)
{
if (dimensions.TotalElementCount == 0)
return new TreeNode[] { new TreeNode(null, "(empty)", null, null, null) };

return new ArrayRangeNode(expression, dimensions, dimensions).ChildNodes;
}
}

/// <summary> This is a partent node for all elements within a given bounds </summary>
public class ArrayRangeNode: TreeNode
{
const int MaxElementCount = 100;

Expression arrayTarget;
ArrayDimensions bounds;
ArrayDimensions originalBounds;

public ArrayRangeNode(Expression arrayTarget, ArrayDimensions bounds, ArrayDimensions originalBounds)
{
this.arrayTarget = arrayTarget;
this.bounds = bounds;
this.originalBounds = originalBounds;

this.Name = GetName();
this.ChildNodes = LazyGetChildren();
}

string GetName()
{
StringBuilder name = new StringBuilder();
bool isFirst = true;
name.Append("[");
for(int i = 0; i < bounds.Count; i++) {
if (!isFirst) name.Append(", ");
isFirst = false;
ArrayDimension dim = bounds[i];
ArrayDimension originalDim = originalBounds[i];

if (dim.Count == 0) {
throw new DebuggerException("Empty dimension");
} else if (dim.Count == 1) {
name.Append(dim.LowerBound.ToString());
} else if (dim.Equals(originalDim)) {
name.Append("*");
} else {
name.Append(dim.LowerBound);
name.Append("..");
name.Append(dim.UpperBound);
}
}
name.Append("]");
return name.ToString();
}

static string GetName(int[] indices)
{
StringBuilder sb = new StringBuilder(indices.Length * 4);
sb.Append("[");
bool isFirst = true;
foreach(int index in indices) {
if (!isFirst) sb.Append(", ");
sb.Append(index.ToString());
isFirst = false;
}
sb.Append("]");
return sb.ToString();
}

IEnumerable<TreeNode> LazyGetChildren()
{
// The whole array is small - just add all elements as childs
if (bounds.TotalElementCount <= MaxElementCount) {
foreach(int[] indices in bounds.Indices) {
string imageName;
var image = ExpressionNode.GetImageForArrayIndexer(out imageName);
var expression = new ExpressionNode(image, GetName(indices), arrayTarget.AppendIndexer(indices));
expression.ImageName = imageName;
yield return expression;
}
yield break;
}

// Find a dimension of size at least 2
int splitDimensionIndex = bounds.Count - 1;
for(int i = 0; i < bounds.Count; i++) {
if (bounds[i].Count > 1) {
splitDimensionIndex = i;
break;
}
}
ArrayDimension splitDim = bounds[splitDimensionIndex];

// Split the dimension
int elementsPerSegment = 1;
while (splitDim.Count > elementsPerSegment * MaxElementCount) {
elementsPerSegment *= MaxElementCount;
}
for(int i = splitDim.LowerBound; i <= splitDim.UpperBound; i += elementsPerSegment) {
List<ArrayDimension> newDims = new List<ArrayDimension>(bounds);
newDims[splitDimensionIndex] = new ArrayDimension(i, Math.Min(i + elementsPerSegment - 1, splitDim.UpperBound));
yield return new ArrayRangeNode(arrayTarget, new ArrayDimensions(newDims), originalBounds);
}
yield break;
}
}
}
153 changes: 153 additions & 0 deletions Debugger/ILSpy.Debugger/Models/TreeModel/ChildNodesOfObject.cs
@@ -0,0 +1,153 @@
// 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.Collections;
using System.Collections.Generic;
using System.Reflection;

using Debugger;
using Debugger.MetaData;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Ast;
using ILSpy.Debugger.Services;
using ILSpy.Debugger.Services.Debugger;

namespace ILSpy.Debugger.Models.TreeModel
{
public partial class Utils
{
public static IEnumerable<TreeNode> LazyGetChildNodesOfObject(Expression targetObject, DebugType shownType)
{
MemberInfo[] publicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
MemberInfo[] publicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
MemberInfo[] nonPublicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly);
MemberInfo[] nonPublicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

DebugType baseType = (DebugType)shownType.BaseType;
if (baseType != null) {
yield return new TreeNode(
ImageService.GetImage("Icons.16x16.Class"),
"BaseClass",
baseType.Name,
baseType.FullName,
baseType.FullName == "System.Object" ? null : Utils.LazyGetChildNodesOfObject(targetObject, baseType)
);
}

if (nonPublicInstance.Length > 0) {
yield return new TreeNode(
null,
"NonPublicMembers",
string.Empty,
string.Empty,
Utils.LazyGetMembersOfObject(targetObject, nonPublicInstance)
);
}

if (publicStatic.Length > 0 || nonPublicStatic.Length > 0) {
IEnumerable<TreeNode> childs = Utils.LazyGetMembersOfObject(targetObject, publicStatic);
if (nonPublicStatic.Length > 0) {
TreeNode nonPublicStaticNode = new TreeNode(
null,
"NonPublicStaticMembers",
string.Empty,
string.Empty,
Utils.LazyGetMembersOfObject(targetObject, nonPublicStatic)
);
childs = Utils.PrependNode(nonPublicStaticNode, childs);
}
yield return new TreeNode(
null,
"StaticMembers",
string.Empty,
string.Empty,
childs
);
}

DebugType iListType = (DebugType)shownType.GetInterface(typeof(IList).FullName);
if (iListType != null) {
yield return new IListNode(targetObject);
} else {
DebugType iEnumerableType, itemType;
if (shownType.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) {
yield return new IEnumerableNode(targetObject, itemType);
}
}

foreach(TreeNode node in LazyGetMembersOfObject(targetObject, publicInstance)) {
yield return node;
}
}

public static IEnumerable<TreeNode> LazyGetMembersOfObject(Expression expression, MemberInfo[] members)
{
List<TreeNode> nodes = new List<TreeNode>();
foreach(MemberInfo memberInfo in members) {
string imageName;
var image = ExpressionNode.GetImageForMember((IDebugMemberInfo)memberInfo, out imageName);
var exp = new ExpressionNode(image, memberInfo.Name, expression.AppendMemberReference((IDebugMemberInfo)memberInfo));
exp.ImageName = imageName;
nodes.Add(exp);
}
nodes.Sort();
return nodes;
}


public static IEnumerable<TreeNode> LazyGetItemsOfIList(Expression targetObject)
{
// This is needed for expanding IEnumerable<T>
targetObject = new CastExpression(
new TypeReference(typeof(IList).FullName),
targetObject,
CastType.Cast
);
int count = 0;
GetValueException error = null;
try {
count = GetIListCount(targetObject);
} catch (GetValueException e) {
// Cannot yield a value in the body of a catch clause (CS1631)
error = e;
}
if (error != null) {
yield return new TreeNode(null, "(error)", error.Message, null, null);
} else if (count == 0) {
yield return new TreeNode(null, "(empty)", null, null, null);
} else {
for(int i = 0; i < count; i++) {
string imageName;
var image = ExpressionNode.GetImageForArrayIndexer(out imageName);
var expression = new ExpressionNode(image, "[" + i + "]", targetObject.AppendIndexer(i));
expression.ImageName = imageName;
yield return expression;
}
}
}

/// <summary>
/// Evaluates System.Collections.ICollection.Count property on given object.
/// </summary>
/// <exception cref="GetValueException">Evaluating System.Collections.ICollection.Count on targetObject failed.</exception>
public static int GetIListCount(Expression targetObject)
{
Value list = targetObject.Evaluate(WindowsDebugger.CurrentProcess);
var iCollectionInterface = list.Type.GetInterface(typeof(ICollection).FullName);
if (iCollectionInterface == null)
throw new GetValueException(targetObject, targetObject.PrettyPrint() + " does not implement System.Collections.ICollection");
PropertyInfo countProperty = iCollectionInterface.GetProperty("Count");
// Do not get string representation since it can be printed in hex
return (int)list.GetPropertyValue(countProperty).PrimitiveValue;
}

public static IEnumerable<TreeNode> PrependNode(TreeNode node, IEnumerable<TreeNode> rest)
{
yield return node;
if (rest != null) {
foreach(TreeNode absNode in rest) {
yield return absNode;
}
}
}
}
}

0 comments on commit a69f8fe

Please sign in to comment.