Browse Source

Attach/detach to running process

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
a69f8fe1c0
  1. 1
      Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs
  2. 4
      Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs
  3. 21
      Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj
  4. 120
      Debugger/ILSpy.Debugger/Models/TreeModel/ArrayRangeNode.cs
  5. 153
      Debugger/ILSpy.Debugger/Models/TreeModel/ChildNodesOfObject.cs
  6. 420
      Debugger/ILSpy.Debugger/Models/TreeModel/ExpressionNode.cs
  7. 153
      Debugger/ILSpy.Debugger/Models/TreeModel/ICorDebug.cs
  8. 29
      Debugger/ILSpy.Debugger/Models/TreeModel/IEnumerableNode.cs
  9. 25
      Debugger/ILSpy.Debugger/Models/TreeModel/IListNode.cs
  10. 13
      Debugger/ILSpy.Debugger/Models/TreeModel/ISetText.cs
  11. 2
      Debugger/ILSpy.Debugger/Models/TreeModel/ITreeNode.cs
  12. 2
      Debugger/ILSpy.Debugger/Models/TreeModel/IVisualizerCommand.cs
  13. 26
      Debugger/ILSpy.Debugger/Models/TreeModel/SavedTreeNode.cs
  14. 47
      Debugger/ILSpy.Debugger/Models/TreeModel/StackFrameNode.cs
  15. 94
      Debugger/ILSpy.Debugger/Models/TreeModel/TreeNode.cs
  16. 66
      Debugger/ILSpy.Debugger/Models/TreeModel/Utils.cs
  17. 111
      Debugger/ILSpy.Debugger/Services/Debugger/DebuggerHelper.cs
  18. 33
      Debugger/ILSpy.Debugger/Services/Debugger/ListHelper.cs
  19. 81
      Debugger/ILSpy.Debugger/Services/Debugger/RemotingConfigurationHelpper.cs
  20. 82
      Debugger/ILSpy.Debugger/Services/Debugger/TypeResolverExtension.cs
  21. 727
      Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs
  22. 6
      Debugger/ILSpy.Debugger/Services/ImageService/ImageService.cs
  23. 10
      Debugger/ILSpy.Debugger/UI/AttachToProcessWindow.xaml.cs
  24. 3
      ILSpy/Commands/RoutedUICommands.cs
  25. 10
      ILSpy/MainWindow.xaml
  26. 14
      ILSpy/MainWindow.xaml.cs

1
Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs

@ -26,7 +26,6 @@ using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.AvalonEdit.Utils;
using ILSpy.Debugger.Bookmarks; using ILSpy.Debugger.Bookmarks;
using ILSpy.Debugger.Debugging;
using ILSpy.Debugger.Services; using ILSpy.Debugger.Services;
namespace ILSpy.Debugger.AvalonEdit namespace ILSpy.Debugger.AvalonEdit

4
Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs

@ -28,8 +28,8 @@ namespace ILSpy.Debugger.Bookmarks
public enum BreakpointAction public enum BreakpointAction
{ {
Break, Break,
// Trace, Trace,
// Condition Condition
} }
public class BreakpointBookmark : BookmarkBase public class BreakpointBookmark : BookmarkBase

21
Debugger/ILSpy.Debugger/ILSpy.Debugger.csproj

@ -63,11 +63,27 @@
<Compile Include="Bookmarks\BreakpointBookmarkEventArgs.cs" /> <Compile Include="Bookmarks\BreakpointBookmarkEventArgs.cs" />
<Compile Include="Bookmarks\CurrentLineBookmark.cs" /> <Compile Include="Bookmarks\CurrentLineBookmark.cs" />
<Compile Include="Bookmarks\IBookmark.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\DebuggerService.cs" />
<Compile Include="Services\Debugger\DefaultDebugger.cs" /> <Compile Include="Services\Debugger\DefaultDebugger.cs" />
<Compile Include="Services\Debugger\IDebugger.cs" /> <Compile Include="Services\Debugger\IDebugger.cs" />
<Compile Include="Services\Debugger\Tooltips\ITreeNode.cs" /> <Compile Include="Services\Debugger\ListHelper.cs" />
<Compile Include="Services\Debugger\Tooltips\IVisualizerCommand.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="Services\ImageService\ImageService.cs" />
<Compile Include="Models\RunningProcess.cs" /> <Compile Include="Models\RunningProcess.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
@ -80,6 +96,7 @@
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Models\TreeModel" />
<Folder Include="Services\Debugger\Tooltips" /> <Folder Include="Services\Debugger\Tooltips" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

120
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
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;
}
}
}
}
}

420
Debugger/ILSpy.Debugger/Models/TreeModel/ExpressionNode.cs

@ -0,0 +1,420 @@
// 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.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Media;
using Debugger;
using Debugger.Interop.CorDebug;
using Debugger.MetaData;
using ICSharpCode.NRefactory.Ast;
using ILSpy.Debugger.Services;
using ILSpy.Debugger.Services.Debugger;
namespace ILSpy.Debugger.Models.TreeModel
{
public class ExpressionNode: TreeNode, ISetText, INotifyPropertyChanged
{
bool evaluated;
Expression expression;
bool canSetText;
GetValueException error;
string fullText;
public bool Evaluated {
get { return evaluated; }
set { evaluated = value; }
}
public Expression Expression {
get { return expression; }
}
public override bool CanSetText {
get {
if (!evaluated) EvaluateExpression();
return canSetText;
}
}
public GetValueException Error {
get {
if (!evaluated) EvaluateExpression();
return error;
}
}
public string FullText {
get { return fullText; }
}
public override string Text {
get {
if (!evaluated) EvaluateExpression();
return base.Text;
}
set {
if (value != base.Text) {
base.Text = value;
NotifyPropertyChanged("Text");
}
}
}
public override string FullName {
get {
if (!evaluated) EvaluateExpression();
return this.expression.PrettyPrint() ?? Name.Trim();
}
}
public override string Type {
get {
if (!evaluated) EvaluateExpression();
return base.Type;
}
}
public override IEnumerable<TreeNode> ChildNodes {
get {
if (!evaluated) EvaluateExpression();
return base.ChildNodes;
}
}
public override bool HasChildNodes {
get {
if (!evaluated) EvaluateExpression();
return base.HasChildNodes;
}
}
/// <summary> Used to determine available VisualizerCommands </summary>
private DebugType expressionType;
/// <summary> Used to determine available VisualizerCommands </summary>
private bool valueIsNull = true;
private IEnumerable<IVisualizerCommand> visualizerCommands;
public override IEnumerable<IVisualizerCommand> VisualizerCommands {
get {
if (visualizerCommands == null) {
visualizerCommands = getAvailableVisualizerCommands();
}
return visualizerCommands;
}
}
private IEnumerable<IVisualizerCommand> getAvailableVisualizerCommands()
{
if (!evaluated) EvaluateExpression();
if (this.expressionType == null) {
// no visualizers if EvaluateExpression failed
yield break;
}
if (this.valueIsNull) {
// no visualizers if evaluated value is null
yield break;
}
/*if (this.expressionType.IsPrimitive || this.expressionType.IsSystemDotObject() || this.expressionType.IsEnum()) {
// no visualizers for primitive types
yield break;
}*/
yield break;
// foreach (var descriptor in VisualizerDescriptors.GetAllDescriptors()) {
// if (descriptor.IsVisualizerAvailable(this.expressionType)) {
// yield return descriptor.CreateVisualizerCommand(this.Expression);
// }
// }
}
public ExpressionNode(ImageSource image, string name, Expression expression)
{
this.ImageSource = image;
this.Name = name;
this.expression = expression;
}
void EvaluateExpression()
{
evaluated = true;
Value val;
try {
val = expression.Evaluate(WindowsDebugger.DebuggedProcess);
} catch (GetValueException e) {
error = e;
this.Text = e.Message;
return;
}
this.canSetText = val.Type.IsPrimitive;
this.expressionType = val.Type;
this.Type = val.Type.Name;
this.valueIsNull = val.IsNull;
// Note that these return enumerators so they are lazy-evaluated
if (val.IsNull) {
} else if (val.Type.IsPrimitive || val.Type.FullName == typeof(string).FullName) { // Must be before IsClass
} else if (val.Type.IsArray) { // Must be before IsClass
if (val.ArrayLength > 0)
this.ChildNodes = Utils.LazyGetChildNodesOfArray(this.Expression, val.ArrayDimensions);
} else if (val.Type.IsClass || val.Type.IsValueType) {
if (val.Type.FullNameWithoutGenericArguments == typeof(List<>).FullName) {
if ((int)val.GetMemberValue("_size").PrimitiveValue > 0)
this.ChildNodes = Utils.LazyGetItemsOfIList(this.expression);
} else {
this.ChildNodes = Utils.LazyGetChildNodesOfObject(this.Expression, val.Type);
}
} else if (val.Type.IsPointer) {
Value deRef = val.Dereference();
if (deRef != null) {
this.ChildNodes = new ExpressionNode [] { new ExpressionNode(this.ImageSource, "*" + this.Name, this.Expression.AppendDereference()) };
}
}
if (true) {
TreeNode info = ICorDebug.GetDebugInfoRoot(val.AppDomain, val.CorValue);
this.ChildNodes = Utils.PrependNode(info, this.ChildNodes);
}
// Do last since it may expire the object
if (val.Type.IsInteger) {
fullText = FormatInteger(val.PrimitiveValue);
} else if (val.Type.IsPointer) {
fullText = String.Format("0x{0:X}", val.PointerAddress);
} else if ((val.Type.FullName == typeof(string).FullName ||
val.Type.FullName == typeof(char).FullName) && !val.IsNull) {
try {
fullText = '"' + Escape(val.InvokeToString()) + '"';
} catch (GetValueException e) {
error = e;
fullText = e.Message;
return;
}
} else if ((val.Type.IsClass || val.Type.IsValueType) && !val.IsNull) {
try {
fullText = val.InvokeToString();
} catch (GetValueException e) {
error = e;
fullText = e.Message;
return;
}
} else {
fullText = val.AsString();
}
this.Text = (fullText.Length > 256) ? fullText.Substring(0, 256) + "..." : fullText;
}
string Escape(string source)
{
return source.Replace("\n", "\\n")
.Replace("\t", "\\t")
.Replace("\r", "\\r")
.Replace("\0", "\\0")
.Replace("\b", "\\b")
.Replace("\a", "\\a")
.Replace("\f", "\\f")
.Replace("\v", "\\v")
.Replace("\"", "\\\"");
}
string FormatInteger(object i)
{
if (true)
return i.ToString();
string hex = null;
for(int len = 1;; len *= 2) {
hex = string.Format("{0:X" + len + "}", i);
if (hex.Length == len)
break;
}
if (true) {
return "0x" + hex;
} else {
if (ShowAsHex(i)) {
return String.Format("{0} (0x{1})", i, hex);
} else {
return i.ToString();
}
}
}
bool ShowAsHex(object i)
{
ulong val;
if (i is sbyte || i is short || i is int || i is long) {
unchecked { val = (ulong)Convert.ToInt64(i); }
if (val > (ulong)long.MaxValue)
val = ~val + 1;
} else {
val = Convert.ToUInt64(i);
}
if (val >= 0x10000)
return true;
int ones = 0; // How many 1s there is
int runs = 0; // How many runs of 1s there is
int size = 0; // Size of the integer in bits
while(val != 0) { // There is at least one 1
while((val & 1) == 0) { // Skip 0s
val = val >> 1;
size++;
}
while((val & 1) == 1) { // Skip 1s
val = val >> 1;
size++;
ones++;
}
runs++;
}
return size >= 7 && runs <= (size + 7) / 8;
}
public override bool SetText(string newText)
{
string fullName = FullName;
Value val = null;
try {
val = this.Expression.Evaluate(WindowsDebugger.DebuggedProcess);
if (val.Type.IsInteger && newText.StartsWith("0x")) {
try {
val.PrimitiveValue = long.Parse(newText.Substring(2), NumberStyles.HexNumber);
} catch (FormatException) {
throw new NotSupportedException();
} catch (OverflowException) {
throw new NotSupportedException();
}
} else {
val.PrimitiveValue = newText;
}
this.Text = newText;
return true;
} catch (NotSupportedException) {
string format = "Can not convert {0} to {1}";
string msg = string.Format(format, newText, val.Type.PrimitiveType);
System.Windows.MessageBox.Show(msg);
} catch (COMException) {
// COMException (0x80131330): Cannot perfrom SetValue on non-leaf frames.
// Happens if trying to set value after exception is breaked
System.Windows.MessageBox.Show("UnknownError");
}
return false;
}
public static ImageSource GetImageForThis(out string imageName)
{
imageName = "Icons.16x16.Parameter";
return ImageService.GetImage(imageName);
}
public static ImageSource GetImageForParameter(out string imageName)
{
imageName = "Icons.16x16.Parameter";
return ImageService.GetImage(imageName);
}
public static ImageSource GetImageForLocalVariable(out string imageName)
{
imageName = "Icons.16x16.Local";
return ImageService.GetImage(imageName);
}
public static ImageSource GetImageForArrayIndexer(out string imageName)
{
imageName = "Icons.16x16.Field";
return ImageService.GetImage(imageName);
}
public static ImageSource GetImageForMember(IDebugMemberInfo memberInfo, out string imageName)
{
string name = string.Empty;
if (memberInfo.IsPublic) {
} else if (memberInfo.IsAssembly) {
name += "Internal";
} else if (memberInfo.IsFamily) {
name += "Protected";
} else if (memberInfo.IsPrivate) {
name += "Private";
}
if (memberInfo is FieldInfo) {
name += "Field";
} else if (memberInfo is PropertyInfo) {
name += "Property";
} else if (memberInfo is MethodInfo) {
name += "Method";
} else {
throw new DebuggerException("Unknown member type " + memberInfo.GetType().FullName);
}
imageName = "Icons.16x16." + name;
return ImageService.GetImage(imageName);
}
// public ContextMenuStrip GetContextMenu()
// {
// if (this.Error != null) return GetErrorContextMenu();
//
// ContextMenuStrip menu = new ContextMenuStrip();
//
// ToolStripMenuItem copyItem;
// copyItem = new ToolStripMenuItem();
// copyItem.Text = ResourceService.GetString("MainWindow.Windows.Debug.LocalVariables.CopyToClipboard");
// copyItem.Checked = false;
// copyItem.Click += delegate {
// ClipboardWrapper.SetText(fullText);
// };
// ToolStripMenuItem hexView;
// hexView = new ToolStripMenuItem();
// hexView.Text = ResourceService.GetString("MainWindow.Windows.Debug.LocalVariables.ShowInHexadecimal");
// hexView.Checked = DebuggingOptions.Instance.ShowValuesInHexadecimal;
// hexView.Click += delegate {
// // refresh all pads that use ValueNode for display
// DebuggingOptions.Instance.ShowValuesInHexadecimal = !DebuggingOptions.Instance.ShowValuesInHexadecimal;
// // always check if instance is null, might be null if pad is not opened
// if (LocalVarPad.Instance != null)
// LocalVarPad.Instance.RefreshPad();
// if (WatchPad.Instance != null)
// WatchPad.Instance.RefreshPad();
// };
// menu.Items.AddRange(new ToolStripItem[] {
// copyItem,
// //hexView
// });
//
// return menu;
// }
public static WindowsDebugger WindowsDebugger {
get {
return (WindowsDebugger)DebuggerService.CurrentDebugger;
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(info));
}
}
}
}

153
Debugger/ILSpy.Debugger/Models/TreeModel/ICorDebug.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.Generic;
using Debugger.Interop.CorDebug;
using Debugger.MetaData;
using Debugger;
namespace ILSpy.Debugger.Models.TreeModel
{
public class ICorDebug
{
public class InfoNode: TreeNode
{
List<TreeNode> children;
public InfoNode(string name, string text): this(name, text, null)
{
}
public InfoNode(string name, string text, List<TreeNode> children)
{
this.Name = name;
this.Text = text;
this.ChildNodes = children;
this.children = children;
}
public void AddChild(string name, string text)
{
if (children == null) {
children = new List<TreeNode>();
this.ChildNodes = children;
}
children.Add(new InfoNode(name, text));
}
public void AddChild(string name, string text, List<TreeNode> subChildren)
{
if (children == null) {
children = new List<TreeNode>();
this.ChildNodes = children;
}
children.Add(new InfoNode(name, text, subChildren));
}
}
public static InfoNode GetDebugInfoRoot(AppDomain appDomain, ICorDebugValue corValue)
{
return new InfoNode("ICorDebug", "", GetDebugInfo(appDomain, corValue));
}
public static List<TreeNode> GetDebugInfo(AppDomain appDomain, ICorDebugValue corValue)
{
List<TreeNode> items = new List<TreeNode>();
if (corValue is ICorDebugValue) {
InfoNode info = new InfoNode("ICorDebugValue", "");
info.AddChild("Address", corValue.GetAddress().ToString("X8"));
info.AddChild("Type", ((CorElementType)corValue.GetTheType()).ToString());
info.AddChild("Size", corValue.GetSize().ToString());
items.Add(info);
}
if (corValue is ICorDebugValue2) {
InfoNode info = new InfoNode("ICorDebugValue2", "");
ICorDebugValue2 corValue2 = (ICorDebugValue2)corValue;
string fullname;
try {
fullname = DebugType.CreateFromCorType(appDomain, corValue2.GetExactType()).FullName;
} catch (DebuggerException e) {
fullname = e.Message;
}
info.AddChild("ExactType", fullname);
items.Add(info);
}
if (corValue is ICorDebugGenericValue) {
InfoNode info = new InfoNode("ICorDebugGenericValue", "");
try {
byte[] bytes = ((ICorDebugGenericValue)corValue).GetRawValue();
for(int i = 0; i < bytes.Length; i += 8) {
string val = "";
for(int j = i; j < bytes.Length && j < i + 8; j++) {
val += bytes[j].ToString("X2") + " ";
}
info.AddChild("Value" + i.ToString("X2"), val);
}
} catch (System.ArgumentException) {
info.AddChild("Value", "N/A");
}
items.Add(info);
}
if (corValue is ICorDebugReferenceValue) {
InfoNode info = new InfoNode("ICorDebugReferenceValue", "");
ICorDebugReferenceValue refValue = (ICorDebugReferenceValue)corValue;
info.AddChild("IsNull", (refValue.IsNull() != 0).ToString());
if (refValue.IsNull() == 0) {
info.AddChild("Value", refValue.GetValue().ToString("X8"));
if (refValue.Dereference() != null) {
info.AddChild("Dereference", "", GetDebugInfo(appDomain, refValue.Dereference()));
} else {
info.AddChild("Dereference", "N/A");
}
}
items.Add(info);
}
if (corValue is ICorDebugHeapValue) {
InfoNode info = new InfoNode("ICorDebugHeapValue", "");
items.Add(info);
}
if (corValue is ICorDebugHeapValue2) {
InfoNode info = new InfoNode("ICorDebugHeapValue2", "");
items.Add(info);
}
if (corValue is ICorDebugObjectValue) {
InfoNode info = new InfoNode("ICorDebugObjectValue", "");
ICorDebugObjectValue objValue = (ICorDebugObjectValue)corValue;
info.AddChild("Class", objValue.GetClass().GetToken().ToString("X8"));
info.AddChild("IsValueClass", (objValue.IsValueClass() != 0).ToString());
items.Add(info);
}
if (corValue is ICorDebugObjectValue2) {
InfoNode info = new InfoNode("ICorDebugObjectValue2", "");
items.Add(info);
}
if (corValue is ICorDebugBoxValue) {
InfoNode info = new InfoNode("ICorDebugBoxValue", "");
ICorDebugBoxValue boxValue = (ICorDebugBoxValue)corValue;
info.AddChild("Object", "", GetDebugInfo(appDomain, boxValue.GetObject()));
items.Add(info);
}
if (corValue is ICorDebugStringValue) {
InfoNode info = new InfoNode("ICorDebugStringValue", "");
ICorDebugStringValue stringValue = (ICorDebugStringValue)corValue;
info.AddChild("Length", stringValue.GetLength().ToString());
info.AddChild("String", stringValue.GetString());
items.Add(info);
}
if (corValue is ICorDebugArrayValue) {
InfoNode info = new InfoNode("ICorDebugArrayValue", "");
info.AddChild("...", "...");
items.Add(info);
}
if (corValue is ICorDebugHandleValue) {
InfoNode info = new InfoNode("ICorDebugHandleValue", "");
ICorDebugHandleValue handleValue = (ICorDebugHandleValue)corValue;
info.AddChild("HandleType", handleValue.GetHandleType().ToString());
items.Add(info);
}
return items;
}
}
}

29
Debugger/ILSpy.Debugger/Models/TreeModel/IEnumerableNode.cs

@ -0,0 +1,29 @@
// 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 Debugger.MetaData;
using ICSharpCode.NRefactory.Ast;
using ILSpy.Debugger.Services.Debugger;
namespace ILSpy.Debugger.Models.TreeModel
{
/// <summary>
/// IEnumerable node in the variable tree.
/// </summary>
public class IEnumerableNode : TreeNode
{
Expression targetObject;
Expression debugListExpression;
public IEnumerableNode(Expression targetObject, DebugType itemType)
{
this.targetObject = targetObject;
this.Name = "IEnumerable";
this.Text = "Expanding will enumerate the IEnumerable";
DebugType debugListType;
this.debugListExpression = DebuggerHelpers.CreateDebugListExpression(targetObject, itemType, out debugListType);
this.ChildNodes = Utils.LazyGetItemsOfIList(this.debugListExpression);
}
}
}

25
Debugger/ILSpy.Debugger/Models/TreeModel/IListNode.cs

@ -0,0 +1,25 @@
// 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 ICSharpCode.NRefactory.Ast;
namespace ILSpy.Debugger.Models.TreeModel
{
public class IListNode : TreeNode
{
Expression targetObject;
int count;
public IListNode(Expression targetObject)
{
this.targetObject = targetObject;
this.Name = "IList";
this.count = Utils.GetIListCount(this.targetObject);
this.ChildNodes = Utils.LazyGetItemsOfIList(this.targetObject);
}
public override bool HasChildNodes {
get { return this.count > 0; }
}
}
}

13
Debugger/ILSpy.Debugger/Models/TreeModel/ISetText.cs

@ -0,0 +1,13 @@
// 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;
namespace ILSpy.Debugger.Models.TreeModel
{
public interface ISetText
{
bool CanSetText { get; }
bool SetText(string text);
}
}

2
Debugger/ILSpy.Debugger/Services/Debugger/Tooltips/ITreeNode.cs → Debugger/ILSpy.Debugger/Models/TreeModel/ITreeNode.cs

@ -5,7 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows.Media; using System.Windows.Media;
namespace ILSpy.Debugger.Debugging namespace ILSpy.Debugger.Models.TreeModel
{ {
/// <summary> /// <summary>
/// Node that can be bound to <see cref="DebuggerTooltipControl" />. /// Node that can be bound to <see cref="DebuggerTooltipControl" />.

2
Debugger/ILSpy.Debugger/Services/Debugger/Tooltips/IVisualizerCommand.cs → Debugger/ILSpy.Debugger/Models/TreeModel/IVisualizerCommand.cs

@ -5,7 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace ILSpy.Debugger.Debugging namespace ILSpy.Debugger.Models.TreeModel
{ {
/// <summary> /// <summary>
/// Command called from <see cref="VisualizerPicker"/>. /// Command called from <see cref="VisualizerPicker"/>.

26
Debugger/ILSpy.Debugger/Models/TreeModel/SavedTreeNode.cs

@ -0,0 +1,26 @@
// 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.Windows.Media;
namespace ILSpy.Debugger.Models.TreeModel
{
public class SavedTreeNode : TreeNode
{
public override bool CanSetText {
get { return true; }
}
public SavedTreeNode(ImageSource image, string fullname, string text)
{
base.ImageSource = image;
FullName = fullname;
Text = text;
}
public override bool SetText(string newValue) {
Text = newValue;
return false;
}
}
}

47
Debugger/ILSpy.Debugger/Models/TreeModel/StackFrameNode.cs

@ -0,0 +1,47 @@
// 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.Generic;
using Debugger;
using Debugger.MetaData;
using ICSharpCode.NRefactory.Ast;
namespace ILSpy.Debugger.Models.TreeModel
{
public class StackFrameNode: TreeNode
{
StackFrame stackFrame;
public StackFrame StackFrame {
get { return stackFrame; }
}
public StackFrameNode(StackFrame stackFrame)
{
this.stackFrame = stackFrame;
this.Name = stackFrame.MethodInfo.Name;
this.ChildNodes = LazyGetChildNodes();
}
IEnumerable<TreeNode> LazyGetChildNodes()
{
foreach(DebugParameterInfo par in stackFrame.MethodInfo.GetParameters()) {
string imageName;
var image = ExpressionNode.GetImageForParameter(out imageName);
var expression = new ExpressionNode(image, par.Name, par.GetExpression());
expression.ImageName = imageName;
yield return expression;
}
foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables(this.StackFrame.IP)) {
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
var expression = new ExpressionNode(image, locVar.Name, locVar.GetExpression());
expression.ImageName = imageName;
yield return expression;
}
if (stackFrame.Thread.CurrentException != null) {
yield return new ExpressionNode(null, "__exception", new IdentifierExpression("__exception"));
}
}
}
}

94
Debugger/ILSpy.Debugger/Models/TreeModel/TreeNode.cs

@ -0,0 +1,94 @@
// 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.ComponentModel;
using System.Linq;
using System.Windows.Media;
namespace ILSpy.Debugger.Models.TreeModel
{
/// <summary>
/// A node in the variable tree.
/// The node is imutable.
/// </summary>
public class TreeNode : ITreeNode
{
string text = string.Empty;
IEnumerable<TreeNode> childNodes = null;
public ImageSource ImageSource { get; protected set; }
public string Name { get; set; }
public string ImageName { get; set; }
public virtual string FullName {
get { return Name; }
set { Name = value; }
}
public virtual string Text
{
get { return text; }
set { text = value; }
}
public virtual string Type { get; protected set; }
public virtual IEnumerable<TreeNode> ChildNodes {
get { return childNodes; }
protected set { childNodes = value; }
}
IEnumerable<ITreeNode> ITreeNode.ChildNodes {
get { return childNodes; }
}
public virtual bool HasChildNodes {
get { return childNodes != null; }
}
public virtual bool CanSetText {
get { return false; }
}
public virtual IEnumerable<IVisualizerCommand> VisualizerCommands {
get {
return null;
}
}
public virtual bool HasVisualizerCommands {
get {
return (VisualizerCommands != null) && (VisualizerCommands.Count() > 0);
}
}
public bool IsPinned { get; set; }
public TreeNode()
{
}
public TreeNode(ImageSource iconImage, string name, string text, string type, IEnumerable<TreeNode> childNodes)
{
this.ImageSource = iconImage;
this.Name = name;
this.text = text;
this.Type = type;
this.childNodes = childNodes;
}
public int CompareTo(ITreeNode other)
{
return this.FullName.CompareTo(other.FullName);
}
public virtual bool SetText(string newValue) {
return false;
}
}
}

66
Debugger/ILSpy.Debugger/Models/TreeModel/Utils.cs

@ -0,0 +1,66 @@
// 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.Windows.Threading;
using Debugger;
namespace ILSpy.Debugger.Models.TreeModel
{
public static partial class Utils
{
/// <param name="process">Process on which to track debuggee state</param>
public static void DoEvents(Process process)
{
if (process == null) return;
DebuggeeState oldState = process.DebuggeeState;
WpfDoEvents();
DebuggeeState newState = process.DebuggeeState;
if (oldState != newState) {
//LoggingService.Info("Aborted because debuggee resumed");
throw new AbortedBecauseDebuggeeResumedException();
}
}
public static void WpfDoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => frame.Continue = false));
Dispatcher.PushFrame(frame);
}
}
public class AbortedBecauseDebuggeeResumedException: System.Exception
{
public AbortedBecauseDebuggeeResumedException(): base()
{
}
}
public class PrintTimes: PrintTime
{
public PrintTimes(string text): base(text + " - end")
{
//LoggingService.InfoFormatted("{0} - start", text);
}
}
public class PrintTime: IDisposable
{
string text;
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
public PrintTime(string text)
{
this.text = text;
stopwatch.Start();
}
public void Dispose()
{
stopwatch.Stop();
//LoggingService.InfoFormatted("{0} ({1} ms)", text, stopwatch.ElapsedMilliseconds);
}
}
}

111
Debugger/ILSpy.Debugger/Services/Debugger/DebuggerHelper.cs

@ -0,0 +1,111 @@
// 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 Debugger.Interop.CorDebug;
using System;
using System.Collections.Generic;
using System.Reflection;
using Debugger;
using Debugger.MetaData;
using ICSharpCode.NRefactory.Ast;
namespace ILSpy.Debugger.Services.Debugger
{
public static class DebuggerHelpers
{
/// <summary>
/// Creates an expression which, when evaluated, creates a List&lt;T&gt; in the debugee
/// filled with contents of IEnumerable&lt;T&gt; from the debugee.
/// </summary>
/// <param name="iEnumerableVariable">Expression for IEnumerable variable in the debugee.</param>
/// <param name="itemType">
/// The generic argument of IEnumerable&lt;T&gt; that <paramref name="iEnumerableVariable"/> implements.</param>
public static Expression CreateDebugListExpression(Expression iEnumerableVariable, DebugType itemType, out DebugType listType)
{
// is using itemType.AppDomain ok?
listType = DebugType.CreateFromType(itemType.AppDomain, typeof(System.Collections.Generic.List<>), itemType);
var iEnumerableType = DebugType.CreateFromType(itemType.AppDomain, typeof(IEnumerable<>), itemType);
// explicitely cast the variable to IEnumerable<T>, where T is itemType
Expression iEnumerableVariableExplicitCast = new CastExpression(iEnumerableType.GetTypeReference() , iEnumerableVariable, CastType.Cast);
return new ObjectCreateExpression(listType.GetTypeReference(), iEnumerableVariableExplicitCast.ToList());
}
/// <summary>
/// Gets underlying address of object in the debuggee.
/// </summary>
public static ulong GetObjectAddress(this Value val)
{
if (val.IsNull) return 0;
ICorDebugReferenceValue refVal = val.CorReferenceValue;
return refVal.GetValue();
}
/// <summary>
/// Returns true if this type is enum.
/// </summary>
public static bool IsEnum(this DebugType type)
{
return (type.BaseType != null) && (type.BaseType.FullName == "System.Enum");
}
/// <summary>
/// Returns true is this type is just System.Object.
/// </summary>
public static bool IsSystemDotObject(this DebugType type)
{
return type.FullName == "System.Object";
}
/// <summary>
/// Evaluates expression and gets underlying address of object in the debuggee.
/// </summary>
public static ulong GetObjectAddress(this Expression expr)
{
return expr.Evaluate(WindowsDebugger.CurrentProcess).GetObjectAddress();
}
/// <summary>
/// System.Runtime.CompilerServices.GetHashCode method, for obtaining non-overriden hash codes from debuggee.
/// </summary>
private static DebugMethodInfo hashCodeMethod;
/// <summary>
/// Invokes RuntimeHelpers.GetHashCode on given value, that is a default hashCode ignoring user overrides.
/// </summary>
/// <param name="value">Valid value.</param>
/// <returns>Hash code of the object in the debugee.</returns>
public static int InvokeDefaultGetHashCode(this Value value)
{
if (hashCodeMethod == null || hashCodeMethod.Process.HasExited) {
DebugType typeRuntimeHelpers = DebugType.CreateFromType(value.AppDomain, typeof(System.Runtime.CompilerServices.RuntimeHelpers));
hashCodeMethod = (DebugMethodInfo)typeRuntimeHelpers.GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Static);
if (hashCodeMethod == null) {
throw new DebuggerException("Cannot obtain method System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode");
}
}
// David: I had hard time finding out how to invoke static method.
// value.InvokeMethod is nice for instance methods.
// what about MethodInfo.Invoke() ?
// also, there could be an overload that takes 1 parameter instead of array
Value defaultHashCode = Eval.InvokeMethod(DebuggerHelpers.hashCodeMethod, null, new Value[]{value});
//MethodInfo method = value.Type.GetMember("GetHashCode", BindingFlags.Method | BindingFlags.IncludeSuperType) as MethodInfo;
//string hashCode = value.InvokeMethod(method, null).AsString;
return (int)defaultHashCode.PrimitiveValue;
}
public static Value EvalPermanentReference(this Expression expr)
{
return expr.Evaluate(WindowsDebugger.CurrentProcess).GetPermanentReference();
}
public static bool IsNull(this Expression expr)
{
return expr.Evaluate(WindowsDebugger.CurrentProcess).IsNull;
}
public static DebugType GetType(this Expression expr)
{
return expr.Evaluate(WindowsDebugger.CurrentProcess).Type;
}
}
}

33
Debugger/ILSpy.Debugger/Services/Debugger/ListHelper.cs

@ -0,0 +1,33 @@
// 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;
namespace ILSpy.Debugger.Services.Debugger
{
/// <summary>
/// ListHelper wraps System.Collection.Generic.List methods to return the original list,
/// instead of returning 'void', so we can write eg. list.Sorted().First()
/// </summary>
public static class ListHelper
{
public static List<T> Sorted<T>(this List<T> list, IComparer<T> comparer)
{
list.Sort(comparer);
return list;
}
public static List<T> Sorted<T>(this List<T> list)
{
list.Sort();
return list;
}
public static List<T> ToList<T>(this T singleItem)
{
var newList = new List<T>();
newList.Add(singleItem);
return newList;
}
}
}

81
Debugger/ILSpy.Debugger/Services/Debugger/RemotingConfigurationHelpper.cs

@ -0,0 +1,81 @@
// 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 System.Reflection;
using System.Runtime.Remoting;
using System.Security.Policy;
namespace ILSpy.Debugger.Services.Debugger
{
[Serializable]
class RemotingConfigurationHelpper
{
public string path;
public RemotingConfigurationHelpper(string path)
{
this.path = path;
}
public static string GetLoadedAssemblyPath(string assemblyName)
{
string path = null;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) {
try {
string fullFilename = assembly.Location;
if (Path.GetFileName(fullFilename).Equals(assemblyName, StringComparison.OrdinalIgnoreCase)) {
path = Path.GetDirectoryName(fullFilename);
break;
}
} catch (NotSupportedException) {
// assembly.Location throws NotSupportedException for assemblies emitted using
// Reflection.Emit by custom controls used in the forms designer
}
}
if (path == null) {
throw new Exception("Assembly " + assemblyName + " is not loaded");
}
return path;
}
public void Configure()
{
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
RemotingConfiguration.Configure(Path.Combine(path, "Client.config"), false);
string baseDir = Directory.GetDirectoryRoot(AppDomain.CurrentDomain.BaseDirectory);
string relDirs = AppDomain.CurrentDomain.BaseDirectory + ";" + path;
AppDomain serverAppDomain = AppDomain.CreateDomain("Debugging server",
new Evidence(AppDomain.CurrentDomain.Evidence),
baseDir,
relDirs,
AppDomain.CurrentDomain.ShadowCopyFiles);
serverAppDomain.DoCallBack(new CrossAppDomainDelegate(ConfigureServer));
}
private void ConfigureServer()
{
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
RemotingConfiguration.Configure(Path.Combine(path, "Server.config"), false);
}
Assembly AssemblyResolve(object sender, ResolveEventArgs args)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) {
try {
string fullFilename = assembly.Location;
if (Path.GetFileNameWithoutExtension(fullFilename).Equals(args.Name, StringComparison.OrdinalIgnoreCase) ||
assembly.FullName == args.Name) {
return assembly;
}
} catch (NotSupportedException) {
// assembly.Location throws NotSupportedException for assemblies emitted using
// Reflection.Emit by custom controls used in the forms designer
}
}
return null;
}
}
}

82
Debugger/ILSpy.Debugger/Services/Debugger/TypeResolverExtension.cs

@ -0,0 +1,82 @@
// 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;
using Debugger.MetaData;
using System.Collections.Generic;
using System.Linq;
namespace ILSpy.Debugger.Services.Debugger
{
/// <summary>
/// Helper for obtaining information about DebugType.
/// </summary>
public static class TypeResolverExtension
{
/// <summary>
/// Gets generic interface this type implements.
/// The generic argument of the interface does not have to be specified.
/// If you know the generic argument, use DebugType.GetInterface.
/// </summary>
/// <param name="fullNamePrefix">Eg. "System.Collections.Generic.IList"</param>
public static DebugType GetGenericInterface(this DebugType type, string fullNamePrefix)
{
foreach(DebugType inter in type.GetInterfaces()) {
if (inter.FullName.StartsWith(fullNamePrefix) && inter.GetGenericArguments().Length > 0) {
return inter;
}
}
// not found, search BaseType
return type.BaseType == null ? null : (DebugType)type.BaseType.GetInterface(fullNamePrefix);
}
/// <summary>
/// Resolves implementation of System.Collections.Generic.IList on this type.
/// </summary>
/// <param name="iListType">Result found implementation of System.Collections.Generic.IList.</param>
/// <param name="itemType">The only generic argument of <paramref name="implementation"/></param>
/// <returns>True if found, false otherwise.</returns>
public static bool ResolveIListImplementation(this DebugType type, out DebugType iListType, out DebugType itemType)
{
return type.ResolveGenericInterfaceImplementation(
"System.Collections.Generic.IList", out iListType, out itemType);
}
/// <summary>
/// Resolves implementation of System.Collections.Generic.IEnumerable on this type.
/// </summary>
/// <param name="iEnumerableType">Result found implementation of System.Collections.Generic.IEnumerable.</param>
/// <param name="itemType">The only generic argument of <paramref name="implementation"/></param>
/// <returns>True if found, false otherwise.</returns>
public static bool ResolveIEnumerableImplementation(this DebugType type, out DebugType iEnumerableType, out DebugType itemType)
{
return type.ResolveGenericInterfaceImplementation(
"System.Collections.Generic.IEnumerable", out iEnumerableType, out itemType);
}
/// <summary>
/// Resolves implementation of a single-generic-argument interface on this type.
/// </summary>
/// <param name="fullNamePrefix">Interface name to search for (eg. "System.Collections.Generic.IList")</param>
/// <param name="implementation">Result found implementation.</param>
/// <param name="itemType">The only generic argument of <paramref name="implementation"/></param>
/// <returns>True if found, false otherwise.</returns>
public static bool ResolveGenericInterfaceImplementation(this DebugType type, string fullNamePrefix, out DebugType implementation, out DebugType itemType)
{
if (type == null)
throw new ArgumentNullException("type");
implementation = null;
itemType = null;
implementation = type.GetGenericInterface(fullNamePrefix);
if (implementation != null) {
if (implementation.GetGenericArguments().Length == 1) {
itemType = (DebugType)implementation.GetGenericArguments()[0];
return true;
}
}
return false;
}
}
}

727
Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs

@ -0,0 +1,727 @@
// 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.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Media;
using Debugger;
using Debugger.Interop.CorPublish;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
using ILSpy.Debugger.Bookmarks;
using ILSpy.Debugger.Models.TreeModel;
using ILSpy.Debugger.Services.Debugger;
using CorDbg = Debugger;
using Process = Debugger.Process;
namespace ILSpy.Debugger.Services
{
public class WindowsDebugger : IDebugger
{
enum StopAttachedProcessDialogResult {
Detach = 0,
Terminate = 1,
Cancel = 2
}
bool useRemotingForThreadInterop = false;
bool attached;
NDebugger debugger;
ICorPublish corPublish;
Process debuggedProcess;
//DynamicTreeDebuggerRow currentTooltipRow;
//Expression currentTooltipExpression;
public event EventHandler<ProcessEventArgs> ProcessSelected;
public NDebugger DebuggerCore {
get {
return debugger;
}
}
public Process DebuggedProcess {
get {
return debuggedProcess;
}
}
public static Process CurrentProcess {
get {
WindowsDebugger dbgr = DebuggerService.CurrentDebugger as WindowsDebugger;
if (dbgr != null && dbgr.DebuggedProcess != null) {
return dbgr.DebuggedProcess;
} else {
return null;
}
}
}
/// <inheritdoc/>
public bool BreakAtBeginning {
get;
set;
}
protected virtual void OnProcessSelected(ProcessEventArgs e)
{
if (ProcessSelected != null) {
ProcessSelected(this, e);
}
}
public bool ServiceInitialized {
get {
return debugger != null;
}
}
public WindowsDebugger()
{
}
#region IDebugger Members
string errorDebugging = "Error.Debugging";
string errorNotDebugging = "Error.NotDebugging";
string errorProcessRunning = "Error.ProcessRunning";
string errorProcessPaused = "Error.ProcessPaused";
string errorCannotStepNoActiveFunction = "Threads.CannotStepNoActiveFunction";
public bool IsDebugging {
get {
return ServiceInitialized && debuggedProcess != null;
}
}
public bool IsAttached {
get {
return ServiceInitialized && attached;
}
}
public bool IsProcessRunning {
get {
return IsDebugging && debuggedProcess.IsRunning;
}
}
public void Start(ProcessStartInfo processStartInfo)
{
if (IsDebugging) {
MessageBox.Show(errorDebugging);
return;
}
if (!ServiceInitialized) {
InitializeService();
}
string version = debugger.GetProgramVersion(processStartInfo.FileName);
if (version.StartsWith("v1.0")) {
MessageBox.Show("Net10NotSupported");
} else if (version.StartsWith("v1.1")) {
MessageBox.Show("Net1.1NotSupported");
// } else if (string.IsNullOrEmpty(version)) {
// // Not a managed assembly
// MessageBox.Show(".Error.BadAssembly}");
} else if (debugger.IsKernelDebuggerEnabled) {
MessageBox.Show("KernelDebuggerEnabled");
} else {
attached = false;
if (DebugStarting != null)
DebugStarting(this, EventArgs.Empty);
try {
Process process = debugger.Start(processStartInfo.FileName,
processStartInfo.WorkingDirectory,
processStartInfo.Arguments);
SelectProcess(process);
} catch (System.Exception e) {
// COMException: The request is not supported. (Exception from HRESULT: 0x80070032)
// COMException: The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log for more detail. (Exception from HRESULT: 0x800736B1)
// COMException: The requested operation requires elevation. (Exception from HRESULT: 0x800702E4)
// COMException: The directory name is invalid. (Exception from HRESULT: 0x8007010B)
// BadImageFormatException: is not a valid Win32 application. (Exception from HRESULT: 0x800700C1)
// UnauthorizedAccessException: Отказано в доступе. (Исключение из HRESULT: 0x80070005 (E_ACCESSDENIED))
if (e is COMException || e is BadImageFormatException || e is UnauthorizedAccessException) {
string msg = "CannotStartProcess";
msg += " " + e.Message;
// TODO: Remove
if (e is COMException && ((uint)((COMException)e).ErrorCode == 0x80070032)) {
msg += Environment.NewLine + Environment.NewLine;
msg += "64-bit debugging is not supported. Please set Project -> Project Options... -> Compiling -> Target CPU to 32bit.";
}
MessageBox.Show(msg);
if (DebugStopped != null)
DebugStopped(this, EventArgs.Empty);
} else {
throw;
}
}
}
}
public void Attach(System.Diagnostics.Process existingProcess)
{
if (existingProcess == null)
return;
if (IsDebugging) {
MessageBox.Show(errorDebugging);
return;
}
if (!ServiceInitialized) {
InitializeService();
}
string version = debugger.GetProgramVersion(existingProcess.MainModule.FileName);
if (version.StartsWith("v1.0")) {
MessageBox.Show("Net10NotSupported");
} else {
if (DebugStarting != null)
DebugStarting(this, EventArgs.Empty);
try {
Process process = debugger.Attach(existingProcess);
attached = true;
SelectProcess(process);
} catch (System.Exception e) {
// CORDBG_E_DEBUGGER_ALREADY_ATTACHED
if (e is COMException || e is UnauthorizedAccessException) {
string msg = "CannotAttachToProcess";
MessageBox.Show(msg + " " + e.Message);
if (DebugStopped != null)
DebugStopped(this, EventArgs.Empty);
} else {
throw;
}
}
}
}
public void Detach()
{
if (debuggedProcess == null)
return;
debugger.Detach();
}
public void StartWithoutDebugging(ProcessStartInfo processStartInfo)
{
System.Diagnostics.Process.Start(processStartInfo);
}
public void Stop()
{
if (!IsDebugging) {
MessageBox.Show(errorNotDebugging, "Stop");
return;
}
if (IsAttached) {
Detach();
} else {
debuggedProcess.Terminate();
}
}
// ExecutionControl:
public void Break()
{
if (!IsDebugging) {
MessageBox.Show(errorNotDebugging, "Break");
return;
}
if (!IsProcessRunning) {
MessageBox.Show(errorProcessPaused, "Break");
return;
}
debuggedProcess.Break();
}
public void Continue()
{
if (!IsDebugging) {
MessageBox.Show(errorNotDebugging, "Continue");
return;
}
if (IsProcessRunning) {
MessageBox.Show(errorProcessRunning, "Continue");
return;
}
debuggedProcess.AsyncContinue();
}
// Stepping:
public void StepInto()
{
if (!IsDebugging) {
MessageBox.Show(errorNotDebugging, "StepInto");
return;
}
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) {
MessageBox.Show(errorCannotStepNoActiveFunction, "StepInto");
} else {
debuggedProcess.SelectedStackFrame.AsyncStepInto();
}
}
public void StepOver()
{
if (!IsDebugging) {
MessageBox.Show(errorNotDebugging, "StepOver");
return;
}
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) {
MessageBox.Show(errorCannotStepNoActiveFunction, "StepOver");
} else {
debuggedProcess.SelectedStackFrame.AsyncStepOver();
}
}
public void StepOut()
{
if (!IsDebugging) {
MessageBox.Show(errorNotDebugging, "StepOut");
return;
}
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) {
MessageBox.Show(errorCannotStepNoActiveFunction, "StepOut");
} else {
debuggedProcess.SelectedStackFrame.AsyncStepOut();
}
}
public event EventHandler DebugStarting;
public event EventHandler DebugStarted;
public event EventHandler DebugStopped;
public event EventHandler IsProcessRunningChanged;
protected virtual void OnIsProcessRunningChanged(EventArgs e)
{
if (IsProcessRunningChanged != null) {
IsProcessRunningChanged(this, e);
}
}
/// <summary>
/// Gets variable of given name.
/// Returns null if unsuccessful. Can throw GetValueException.
/// <exception cref="GetValueException">Thrown when evaluation fails. Exception message explains reason.</exception>
/// </summary>
public Value GetValueFromName(string variableName)
{
if (!CanEvaluate) {
return null;
}
return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, debuggedProcess.SelectedStackFrame);
}
/// <summary>
/// Gets Expression for given variable. Can throw GetValueException.
/// <exception cref="GetValueException">Thrown when getting expression fails. Exception message explains reason.</exception>
/// </summary>
public ICSharpCode.NRefactory.Ast.Expression GetExpression(string variableName)
{
if (!CanEvaluate) {
throw new GetValueException("Cannot evaluate now - debugged process is either null or running or has no selected stack frame");
}
return ExpressionEvaluator.ParseExpression(variableName, SupportedLanguage.CSharp);
}
public bool IsManaged(int processId)
{
corPublish = new CorpubPublishClass();
CorDbg.Interop.TrackedComObjects.Track(corPublish);
ICorPublishProcess process = corPublish.GetProcess((uint)processId);
if (process != null) {
return process.IsManaged() != 0;
}
return false;
}
/// <summary>
/// Gets the current value of the variable as string that can be displayed in tooltips.
/// Returns null if unsuccessful.
/// </summary>
public string GetValueAsString(string variableName)
{
try {
Value val = GetValueFromName(variableName);
if (val == null) return null;
return val.AsString();
} catch (GetValueException) {
return null;
}
}
bool CanEvaluate
{
get {
return debuggedProcess != null && !debuggedProcess.IsRunning && debuggedProcess.SelectedStackFrame != null;
}
}
/// <summary>
/// Gets the tooltip control that shows the value of given variable.
/// Return null if no tooltip is available.
/// </summary>
public object GetTooltipControl(Location logicalPosition, string variableName)
{
try {
var tooltipExpression = GetExpression(variableName);
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
ExpressionNode expressionNode = new ExpressionNode(image, variableName, tooltipExpression);
expressionNode.ImageName = imageName;
return null;
// return new DebuggerTooltipControl(logicalPosition, expressionNode);
} catch (GetValueException) {
return null;
}
}
public ITreeNode GetNode(string variable, string currentImageName = null)
{
try {
var expression = GetExpression(variable);
string imageName;
ImageSource image;
if (string.IsNullOrEmpty(currentImageName)) {
image = ExpressionNode.GetImageForLocalVariable(out imageName);
}
else {
image = ImageService.GetImage(currentImageName);
imageName = currentImageName;
}
ExpressionNode expressionNode = new ExpressionNode(image, variable, expression);
expressionNode.ImageName = imageName;
return expressionNode;
} catch (GetValueException) {
return null;
}
}
public bool CanSetInstructionPointer(string filename, int line, int column)
{
if (debuggedProcess != null && debuggedProcess.IsPaused && debuggedProcess.SelectedStackFrame != null) {
SourcecodeSegment seg = debuggedProcess.SelectedStackFrame.CanSetIP(filename, line, column);
return seg != null;
} else {
return false;
}
}
public bool SetInstructionPointer(string filename, int line, int column)
{
if (CanSetInstructionPointer(filename, line, column)) {
SourcecodeSegment seg = debuggedProcess.SelectedStackFrame.SetIP(filename, line, column);
return seg != null;
} else {
return false;
}
}
public void Dispose()
{
Stop();
}
#endregion
public event EventHandler Initialize;
public void InitializeService()
{
if (useRemotingForThreadInterop) {
// This needs to be called before instance of NDebugger is created
string path = RemotingConfigurationHelpper.GetLoadedAssemblyPath("Debugger.Core.dll");
new RemotingConfigurationHelpper(path).Configure();
}
debugger = new NDebugger();
//debugger.Options = DebuggingOptions.Instance;
debugger.DebuggerTraceMessage += debugger_TraceMessage;
debugger.Processes.Added += debugger_ProcessStarted;
debugger.Processes.Removed += debugger_ProcessExited;
DebuggerService.BreakPointAdded += delegate (object sender, BreakpointBookmarkEventArgs e) {
AddBreakpoint(e.BreakpointBookmark);
};
foreach (BreakpointBookmark b in DebuggerService.Breakpoints) {
AddBreakpoint(b);
}
if (Initialize != null) {
Initialize(this, null);
}
}
bool Compare(byte[] a, byte[] b)
{
if (a.Length != b.Length) return false;
for(int i = 0; i < a.Length; i++) {
if (a[i] != b[i]) return false;
}
return true;
}
void AddBreakpoint(BreakpointBookmark bookmark)
{
Breakpoint breakpoint = debugger.Breakpoints.Add(bookmark.TypeName, null, bookmark.LineNumber, 0, bookmark.IsEnabled);
// Action setBookmarkColor = delegate {
// if (debugger.Processes.Count == 0) {
// bookmark.IsHealthy = true;
// bookmark.Tooltip = null;
// } else if (!breakpoint.IsSet) {
// bookmark.IsHealthy = false;
// bookmark.Tooltip = "Breakpoint was not found in any loaded modules";
// } else if (breakpoint.OriginalLocation.CheckSum == null) {
// bookmark.IsHealthy = true;
// bookmark.Tooltip = null;
// } else {
// byte[] fileMD5;
// IEditable file = FileService.GetOpenFile(bookmark.FileName) as IEditable;
// if (file != null) {
// byte[] fileContent = Encoding.UTF8.GetBytesWithPreamble(file.Text);
// fileMD5 = new MD5CryptoServiceProvider().ComputeHash(fileContent);
// } else {
// fileMD5 = new MD5CryptoServiceProvider().ComputeHash(File.ReadAllBytes(bookmark.FileName));
// }
// if (Compare(fileMD5, breakpoint.OriginalLocation.CheckSum)) {
// bookmark.IsHealthy = true;
// bookmark.Tooltip = null;
// } else {
// bookmark.IsHealthy = false;
// bookmark.Tooltip = "Check sum or file does not match to the original";
// }
// }
// };
// event handlers on bookmark and breakpoint don't need deregistration
bookmark.IsEnabledChanged += delegate {
breakpoint.Enabled = bookmark.IsEnabled;
};
breakpoint.Set += delegate {
//setBookmarkColor();
};
//setBookmarkColor();
EventHandler<CollectionItemEventArgs<Process>> bp_debugger_ProcessStarted = (sender, e) => {
//setBookmarkColor();
// User can change line number by inserting or deleting lines
breakpoint.Line = bookmark.LineNumber;
};
EventHandler<CollectionItemEventArgs<Process>> bp_debugger_ProcessExited = (sender, e) => {
//setBookmarkColor();
};
EventHandler<BreakpointEventArgs> bp_debugger_BreakpointHit =
new EventHandler<BreakpointEventArgs>(
delegate(object sender, BreakpointEventArgs e)
{
//LoggingService.Debug(bookmark.Action + " " + bookmark.ScriptLanguage + " " + bookmark.Condition);
switch (bookmark.Action) {
case BreakpointAction.Break:
break;
case BreakpointAction.Condition:
// if (Evaluate(bookmark.Condition, bookmark.ScriptLanguage))
// DebuggerService.PrintDebugMessage(string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.BreakpointHitAtBecause}") + "\n", bookmark.LineNumber, bookmark.FileName, bookmark.Condition));
// else
// this.debuggedProcess.AsyncContinue();
break;
case BreakpointAction.Trace:
//DebuggerService.PrintDebugMessage(string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.BreakpointHitAt}") + "\n", bookmark.LineNumber, bookmark.FileName));
break;
}
});
BookmarkEventHandler bp_bookmarkManager_Removed = null;
bp_bookmarkManager_Removed = (sender, e) => {
if (bookmark == e.Bookmark) {
debugger.Breakpoints.Remove(breakpoint);
// unregister the events
debugger.Processes.Added -= bp_debugger_ProcessStarted;
debugger.Processes.Removed -= bp_debugger_ProcessExited;
breakpoint.Hit -= bp_debugger_BreakpointHit;
BookmarkManager.Removed -= bp_bookmarkManager_Removed;
}
};
// register the events
debugger.Processes.Added += bp_debugger_ProcessStarted;
debugger.Processes.Removed += bp_debugger_ProcessExited;
breakpoint.Hit += bp_debugger_BreakpointHit;
BookmarkManager.Removed += bp_bookmarkManager_Removed;
}
bool Evaluate(string code, string language)
{
try {
SupportedLanguage supportedLanguage = (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), language, true);
Value val = ExpressionEvaluator.Evaluate(code, supportedLanguage, debuggedProcess.SelectedStackFrame);
if (val != null && val.Type.IsPrimitive && val.PrimitiveValue is bool)
return (bool)val.PrimitiveValue;
else
return false;
} catch (GetValueException e) {
string errorMessage = "Error while evaluating breakpoint condition " + code + ":\n" + e.Message + "\n";
//DebuggerService.PrintDebugMessage(errorMessage);
//WorkbenchSingleton.SafeThreadAsyncCall(MessageService.ShowWarning, errorMessage);
return true;
}
}
void LogMessage(object sender, MessageEventArgs e)
{
//DebuggerService.PrintDebugMessage(e.Message);
}
void debugger_TraceMessage(object sender, MessageEventArgs e)
{
//LoggingService.Debug("Debugger: " + e.Message);
}
void debugger_ProcessStarted(object sender, CollectionItemEventArgs<Process> e)
{
if (debugger.Processes.Count == 1) {
if (DebugStarted != null) {
DebugStarted(this, EventArgs.Empty);
}
}
e.Item.LogMessage += LogMessage;
}
void debugger_ProcessExited(object sender, CollectionItemEventArgs<Process> e)
{
if (debugger.Processes.Count == 0) {
if (DebugStopped != null) {
DebugStopped(this, e);
}
SelectProcess(null);
} else {
SelectProcess(debugger.Processes[0]);
}
}
public void SelectProcess(Process process)
{
if (debuggedProcess != null) {
debuggedProcess.Paused -= debuggedProcess_DebuggingPaused;
debuggedProcess.ExceptionThrown -= debuggedProcess_ExceptionThrown;
debuggedProcess.Resumed -= debuggedProcess_DebuggingResumed;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Paused += debuggedProcess_DebuggingPaused;
debuggedProcess.ExceptionThrown += debuggedProcess_ExceptionThrown;
debuggedProcess.Resumed += debuggedProcess_DebuggingResumed;
debuggedProcess.BreakAtBeginning = BreakAtBeginning;
}
// reset
BreakAtBeginning = false;
JumpToCurrentLine();
OnProcessSelected(new ProcessEventArgs(process));
}
void debuggedProcess_DebuggingPaused(object sender, ProcessEventArgs e)
{
OnIsProcessRunningChanged(EventArgs.Empty);
//using(new PrintTimes("Jump to current line")) {
JumpToCurrentLine();
//}
// TODO update tooltip
/*if (currentTooltipRow != null && currentTooltipRow.IsShown) {
using(new PrintTimes("Update tooltip")) {
try {
Utils.DoEvents(debuggedProcess);
AbstractNode updatedNode = ValueNode.Create(currentTooltipExpression);
currentTooltipRow.SetContentRecursive(updatedNode);
} catch (AbortedBecauseDebuggeeResumedException) {
}
}
}*/
}
void debuggedProcess_DebuggingResumed(object sender, CorDbg.ProcessEventArgs e)
{
OnIsProcessRunningChanged(EventArgs.Empty);
DebuggerService.RemoveCurrentLineMarker();
}
void debuggedProcess_ExceptionThrown(object sender, CorDbg.ExceptionEventArgs e)
{
if (!e.IsUnhandled) {
// Ignore the exception
e.Process.AsyncContinue();
return;
}
JumpToCurrentLine();
StringBuilder stacktraceBuilder = new StringBuilder();
// Need to intercept now so that we can evaluate properties
if (e.Process.SelectedThread.InterceptCurrentException()) {
stacktraceBuilder.AppendLine(e.Exception.ToString());
string stackTrace;
try {
stackTrace = e.Exception.GetStackTrace("--- End of inner exception stack trace ---");
} catch (GetValueException) {
stackTrace = e.Process.SelectedThread.GetStackTrace("at {0} in {1}:line {2}", "at {0}");
}
stacktraceBuilder.Append(stackTrace);
} else {
// For example, happens on stack overflow
stacktraceBuilder.AppendLine("CannotInterceptException");
stacktraceBuilder.AppendLine(e.Exception.ToString());
stacktraceBuilder.Append(e.Process.SelectedThread.GetStackTrace("at {0} in {1}:line {2}", "at {0}"));
}
string title = e.IsUnhandled ? "Unhandled" : "Handled";
string message = string.Format("Message {0} {1}", e.Exception.Type, e.Exception.Message);
MessageBox.Show(message + stacktraceBuilder.ToString(), title);
}
public void JumpToCurrentLine()
{
DebuggerService.RemoveCurrentLineMarker();
if (debuggedProcess != null) {
SourcecodeSegment nextStatement = debuggedProcess.NextStatement;
if (nextStatement != null) {
DebuggerService.JumpToCurrentLine(nextStatement.Filename, nextStatement.StartLine, nextStatement.StartColumn, nextStatement.EndLine, nextStatement.EndColumn);
}
}
}
public void ShowAttachDialog()
{
throw new NotImplementedException();
}
}
}

6
Debugger/ILSpy.Debugger/Services/ImageService/ImageService.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
namespace ILSpy.Debugger.Services namespace ILSpy.Debugger.Services
@ -32,5 +33,10 @@ namespace ILSpy.Debugger.Services
public static readonly BitmapImage Breakpoint = LoadBitmap("Breakpoint"); public static readonly BitmapImage Breakpoint = LoadBitmap("Breakpoint");
public static readonly BitmapImage CurrentLine = LoadBitmap("CurrentLine"); public static readonly BitmapImage CurrentLine = LoadBitmap("CurrentLine");
public static ImageSource GetImage(string imageName)
{
return LoadBitmap(imageName);
}
} }
} }

10
Debugger/ILSpy.Debugger/UI/AttachToProcessWindow.xaml.cs

@ -25,6 +25,7 @@ using System.Linq;
using System.Windows; using System.Windows;
using ILSpy.Debugger.Models; using ILSpy.Debugger.Models;
using ILSpy.Debugger.Services;
namespace ILSpy.Debugger.UI namespace ILSpy.Debugger.UI
{ {
@ -33,6 +34,13 @@ namespace ILSpy.Debugger.UI
/// </summary> /// </summary>
public partial class AttachToProcessWindow : Window public partial class AttachToProcessWindow : Window
{ {
public static IDebugger Debugger { get; private set; }
static AttachToProcessWindow()
{
Debugger = new WindowsDebugger();
}
public AttachToProcessWindow() public AttachToProcessWindow()
{ {
InitializeComponent(); InitializeComponent();
@ -89,6 +97,8 @@ namespace ILSpy.Debugger.UI
// start attaching // start attaching
var process = ((RunningProcess)this.RunningProcesses.SelectedItem).Process; var process = ((RunningProcess)this.RunningProcesses.SelectedItem).Process;
Debugger.Attach(process);
this.DialogResult = true;
} }
void CancelButton_Click(object sender, RoutedEventArgs e) void CancelButton_Click(object sender, RoutedEventArgs e)

3
ILSpy/Commands/RoutedUICommands.cs

@ -26,8 +26,11 @@ namespace ICSharpCode.ILSpy.Commands
static RoutedUICommands() static RoutedUICommands()
{ {
AttachToProcess = new RoutedUICommand("Attach to running process...", "AttachToProcess", typeof(RoutedUICommands)); AttachToProcess = new RoutedUICommand("Attach to running process...", "AttachToProcess", typeof(RoutedUICommands));
DetachFromProcess = new RoutedUICommand("Detach from process...", "DetachFromProcess", typeof(RoutedUICommands));
} }
public static RoutedUICommand AttachToProcess { get; private set; } public static RoutedUICommand AttachToProcess { get; private set; }
public static RoutedUICommand DetachFromProcess { get; private set; }
} }
} }

10
ILSpy/MainWindow.xaml

@ -24,6 +24,9 @@
<CommandBinding <CommandBinding
Command="routedCommands:RoutedUICommands.AttachToProcess" Command="routedCommands:RoutedUICommands.AttachToProcess"
Executed="AttachToProcessExecuted" /> Executed="AttachToProcessExecuted" />
<CommandBinding
Command="routedCommands:RoutedUICommands.DetachFromProcess"
Executed="DetachFromProcessExecuted" />
<CommandBinding <CommandBinding
Command="Open" Command="Open"
Executed="OpenCommandExecuted" /> Executed="OpenCommandExecuted" />
@ -63,11 +66,12 @@
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>
<MenuItem Header="_Debugger"> <MenuItem Header="_Debugger">
<MenuItem Header="Attach to _running application" Command="routedCommands:RoutedUICommands.AttachToProcess"> <MenuItem x:Name="AttachMenuItem" Header="Attach to _running application" Command="routedCommands:RoutedUICommands.AttachToProcess">
<MenuItem.Icon> <MenuItem.Icon>
<Image Width="16" Height="16" Source="Images/bug.png" /> <Image Width="16" Height="16" Source="Images/bug.png" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem x:Name="DetachMenuItem" IsEnabled="False" Header="Detach from running application" Command="routedCommands:RoutedUICommands.DetachFromProcess"/>
</MenuItem> </MenuItem>
<MenuItem Header="_Help"> <MenuItem Header="_Help">
<MenuItem Header="_About" Click="AboutClick" /> <MenuItem Header="_About" Click="AboutClick" />
@ -104,9 +108,9 @@
ItemsSource="{x:Static local:Languages.AllLanguages}" ItemsSource="{x:Static local:Languages.AllLanguages}"
SelectedItem="{Binding FilterSettings.Language}" /> SelectedItem="{Binding FilterSettings.Language}" />
<Separator /> <Separator />
<Button Command="routedCommands:RoutedUICommands.AttachToProcess" ToolTip="Attach to running process..."> <Button x:Name="AttachButton" Command="routedCommands:RoutedUICommands.AttachToProcess" ToolTip="Attach to running process...">
<Image Width="16" Height="16" Source="Images/bug.png" /> <Image Width="16" Height="16" Source="Images/bug.png" />
</Button> </Button>
</ToolBar> </ToolBar>
<!-- Main grid separating left pane (treeView) from main pane (textEditor) --> <!-- Main grid separating left pane (treeView) from main pane (textEditor) -->
<Grid> <Grid>

14
ILSpy/MainWindow.xaml.cs

@ -334,7 +334,19 @@ namespace ICSharpCode.ILSpy
{ {
var window = new AttachToProcessWindow(); var window = new AttachToProcessWindow();
window.Owner = this; window.Owner = this;
window.ShowDialog(); if (window.ShowDialog() == true)
{
AttachMenuItem.IsEnabled = AttachButton.IsEnabled = false;
DetachMenuItem.IsEnabled = true;
}
}
void DetachFromProcessExecuted(object sender, ExecutedRoutedEventArgs e)
{
AttachToProcessWindow.Debugger.Detach();
AttachMenuItem.IsEnabled = AttachButton.IsEnabled = true;
DetachMenuItem.IsEnabled = false;
} }
void ExitClick(object sender, RoutedEventArgs e) void ExitClick(object sender, RoutedEventArgs e)

Loading…
Cancel
Save