Browse Source

Make breakpoints work in decompiled code.

pull/16/head
Eusebiu Marcu 14 years ago
parent
commit
f993d5a2a4
  1. 93
      src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs
  2. 82
      src/AddIns/Debugger/Debugger.Core/Breakpoint.cs
  3. 16
      src/AddIns/Debugger/Debugger.Core/BreakpointCollection.cs
  4. 8
      src/AddIns/Debugger/Debugger.Core/Module.cs
  5. 6
      src/AddIns/Debugger/Debugger.Core/Process.cs
  6. 2
      src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs
  7. 6
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj
  8. 15
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs
  9. 9
      src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs
  10. 46
      src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/CodeView.cs
  11. 87
      src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs
  12. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  13. 44
      src/Main/Base/Project/Src/Bookmarks/BookmarkConverter.cs
  14. 2
      src/Main/Base/Project/Src/Bookmarks/BookmarkManager.cs
  15. 10
      src/Main/Base/Project/Src/Commands/DebugCommands.cs
  16. 25
      src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs
  17. 56
      src/Main/Base/Project/Src/Services/Debugger/DecompiledBreakpointBookmark.cs
  18. 12
      src/Main/Base/Project/Src/Services/File/FileService.cs
  19. 6
      src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs

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

@ -464,19 +464,22 @@ namespace ICSharpCode.SharpDevelop.Services @@ -464,19 +464,22 @@ namespace ICSharpCode.SharpDevelop.Services
SourceCodeMapping GetCurrentCodeMapping(out bool isMatch)
{
DecompileInformation debugInformation = (DecompileInformation)DebuggerService.ExternalDebugInformation;
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
int typeToken = frame.MethodInfo.DeclaringType.MetadataToken;
int methodToken = frame.MethodInfo.MetadataToken;
DecompileInformation debugInformation = (DecompileInformation)DebuggerService.ExternalDebugInformation[typeToken];
isMatch = false;
if (debugInformation == null)
return null;
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
int token = frame.MethodInfo.MetadataToken;
// get the mapped instruction from the current line marker or the next one
if (!debugInformation.CodeMappings.ContainsKey(token))
if (!debugInformation.CodeMappings.ContainsKey(methodToken))
return null;
var mappings = (List<MemberMapping>)debugInformation.CodeMappings[token];
return mappings.GetInstructionByTokenAndOffset(token, frame.IP, out isMatch);
var mappings = (List<MemberMapping>)debugInformation.CodeMappings[methodToken];
return mappings.GetInstructionByTokenAndOffset(methodToken, frame.IP, out isMatch);
}
Debugger.StackFrame GetStackFrame()
@ -745,7 +748,44 @@ namespace ICSharpCode.SharpDevelop.Services @@ -745,7 +748,44 @@ namespace ICSharpCode.SharpDevelop.Services
void AddBreakpoint(BreakpointBookmark bookmark)
{
Breakpoint breakpoint = debugger.Breakpoints.Add(bookmark.FileName, null, bookmark.LineNumber, 0, bookmark.IsEnabled);
Breakpoint breakpoint = null;
if (bookmark is DecompiledBreakpointBookmark) {
var dbb = (DecompiledBreakpointBookmark)bookmark;
var memberReference = dbb.MemberReference;
if (!DebuggerService.ExternalDebugInformation.ContainsKey(memberReference.MetadataToken.ToInt32()))
return;
// check if the codemappings exists for bookmark line
DecompileInformation data = (DecompileInformation)DebuggerService.ExternalDebugInformation[memberReference.MetadataToken.ToInt32()];
var storage = data.CodeMappings;
int token = 0;
foreach (var key in storage.Keys) {
var instruction = storage[key].GetInstructionByLineNumber(dbb.LineNumber, out token);
if (instruction == null) {
continue;
}
dbb.ILFrom = instruction.ILInstructionOffset.From;
dbb.ILTo = instruction.ILInstructionOffset.To;
breakpoint = new ILBreakpoint(
debugger,
dbb.MemberReference.FullName,
dbb.LineNumber,
memberReference.MetadataToken.ToInt32(),
instruction.MemberMapping.MetadataToken,
dbb.ILFrom,
dbb.IsEnabled);
debugger.Breakpoints.Add(breakpoint);
break;
}
} else {
breakpoint = debugger.Breakpoints.Add(bookmark.FileName, null, bookmark.LineNumber, 0, bookmark.IsEnabled);
}
MethodInvoker setBookmarkColor = delegate {
if (debugger.Processes.Count == 0) {
bookmark.IsHealthy = true;
@ -753,10 +793,13 @@ namespace ICSharpCode.SharpDevelop.Services @@ -753,10 +793,13 @@ namespace ICSharpCode.SharpDevelop.Services
} else if (!breakpoint.IsSet) {
bookmark.IsHealthy = false;
bookmark.Tooltip = "Breakpoint was not found in any loaded modules";
} else if (breakpoint.OriginalLocation.CheckSum == null) {
} else if (breakpoint.OriginalLocation == null || breakpoint.OriginalLocation.CheckSum == null) {
bookmark.IsHealthy = true;
bookmark.Tooltip = null;
} else {
if (!File.Exists(bookmark.FileName))
return;
byte[] fileMD5;
IEditable file = FileService.GetOpenFile(bookmark.FileName) as IEditable;
if (file != null) {
@ -888,12 +931,14 @@ namespace ICSharpCode.SharpDevelop.Services @@ -888,12 +931,14 @@ namespace ICSharpCode.SharpDevelop.Services
debuggedProcess.Paused -= debuggedProcess_DebuggingPaused;
debuggedProcess.ExceptionThrown -= debuggedProcess_ExceptionThrown;
debuggedProcess.Resumed -= debuggedProcess_DebuggingResumed;
debuggedProcess.ModulesAdded -= debuggedProcess_ModulesAdded;
}
debuggedProcess = process;
if (debuggedProcess != null) {
debuggedProcess.Paused += debuggedProcess_DebuggingPaused;
debuggedProcess.ExceptionThrown += debuggedProcess_ExceptionThrown;
debuggedProcess.Resumed += debuggedProcess_DebuggingResumed;
debuggedProcess.ModulesAdded += debuggedProcess_ModulesAdded;
debuggedProcess.BreakAtBeginning = BreakAtBeginning;
}
@ -904,6 +949,23 @@ namespace ICSharpCode.SharpDevelop.Services @@ -904,6 +949,23 @@ namespace ICSharpCode.SharpDevelop.Services
OnProcessSelected(new ProcessEventArgs(process));
}
void debuggedProcess_ModulesAdded(object sender, ModuleEventArgs e)
{
var currentModuleTypes = e.Module.GetNamesOfDefinedTypes();
foreach (var bookmark in DebuggerService.Breakpoints.OfType<DecompiledBreakpointBookmark>()) {
var breakpoint = debugger.Breakpoints.FirstOrDefault(
b => b is ILBreakpoint && b.Line == bookmark.LineNumber &&
((ILBreakpoint)b).MetadataToken == bookmark.MemberReference.MetadataToken.ToInt32());
if (breakpoint == null)
continue;
// set the breakpoint only if the module contains the type
if (!currentModuleTypes.Contains(breakpoint.TypeName))
continue;
breakpoint.SetBreakpoint(e.Module);
}
}
void debuggedProcess_DebuggingPaused(object sender, ProcessEventArgs e)
{
OnIsProcessRunningChanged(EventArgs.Empty);
@ -980,14 +1042,16 @@ namespace ICSharpCode.SharpDevelop.Services @@ -980,14 +1042,16 @@ namespace ICSharpCode.SharpDevelop.Services
DebuggerService.JumpToCurrentLine(nextStatement.Filename, nextStatement.StartLine, nextStatement.StartColumn, nextStatement.EndLine, nextStatement.EndColumn);
}
} else {
DecompileInformation externalData = (DecompileInformation)DebuggerService.ExternalDebugInformation;
// use most recent stack frame because we don't have the symbols
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
if (frame == null)
return;
int typeToken = frame.MethodInfo.DeclaringType.MetadataToken;
// get external data
object data = null;
DebuggerService.ExternalDebugInformation.TryGetValue(typeToken, out data);
DecompileInformation externalData = data as DecompileInformation;
int token = frame.MethodInfo.MetadataToken;
int ilOffset = frame.IP;
int line;
@ -1050,7 +1114,8 @@ namespace ICSharpCode.SharpDevelop.Services @@ -1050,7 +1114,8 @@ namespace ICSharpCode.SharpDevelop.Services
public static object GetLocalVariableIndex(Debugger.StackFrame stackFrame, string variableName)
{
// get the target name
int token = stackFrame.MethodInfo.MetadataToken;
int typeToken = stackFrame.MethodInfo.DeclaringType.MetadataToken;
int methodToken = stackFrame.MethodInfo.MetadataToken;
int index = variableName.IndexOf('.');
string targetName = variableName;
if (index != -1) {
@ -1060,11 +1125,11 @@ namespace ICSharpCode.SharpDevelop.Services @@ -1060,11 +1125,11 @@ namespace ICSharpCode.SharpDevelop.Services
// get local variable index and store it in UserData property - used in evaluator
object data = null;
IEnumerable<ILVariable> list;
DecompileInformation externalData = (DecompileInformation)DebuggerService.ExternalDebugInformation;
DecompileInformation externalData = (DecompileInformation)DebuggerService.ExternalDebugInformation[typeToken];
if (externalData == null)
return null;
if (externalData.LocalVariables.TryGetValue(token, out list)) {
if (externalData.LocalVariables.TryGetValue(methodToken, out list)) {
var variable = list.FirstOrDefault(v => v.Name == targetName);
if (variable != null && variable.OriginalVariable != null) {
data = new[] { variable.OriginalVariable.Index };

82
src/AddIns/Debugger/Debugger.Core/Breakpoint.cs

@ -21,7 +21,7 @@ namespace Debugger @@ -21,7 +21,7 @@ namespace Debugger
SourcecodeSegment originalLocation;
List<ICorDebugFunctionBreakpoint> corBreakpoints = new List<ICorDebugFunctionBreakpoint>();
protected List<ICorDebugFunctionBreakpoint> corBreakpoints = new List<ICorDebugFunctionBreakpoint>();
public event EventHandler<BreakpointEventArgs> Hit;
public event EventHandler<BreakpointEventArgs> Set;
@ -29,6 +29,7 @@ namespace Debugger @@ -29,6 +29,7 @@ namespace Debugger
[Debugger.Tests.Ignore]
public NDebugger Debugger {
get { return debugger; }
protected set { debugger = value; }
}
public string FileName {
@ -68,6 +69,10 @@ namespace Debugger @@ -68,6 +69,10 @@ namespace Debugger
}
}
public string TypeName {
get; protected set;
}
protected virtual void OnHit(BreakpointEventArgs e)
{
if (Hit != null) {
@ -88,6 +93,8 @@ namespace Debugger @@ -88,6 +93,8 @@ namespace Debugger
}
}
public Breakpoint() { }
public Breakpoint(NDebugger debugger, ICorDebugFunctionBreakpoint corBreakpoint)
{
this.debugger = debugger;
@ -116,18 +123,18 @@ namespace Debugger @@ -116,18 +123,18 @@ namespace Debugger
{
foreach(ICorDebugFunctionBreakpoint corBreakpoint in corBreakpoints) {
#if DEBUG
// Get repro
corBreakpoint.Activate(0);
// Get repro
corBreakpoint.Activate(0);
#else
try {
corBreakpoint.Activate(0);
} catch(COMException e) {
// Sometimes happens, but we had not repro yet.
// 0x80131301: Process was terminated.
if ((uint)e.ErrorCode == 0x80131301)
continue;
throw;
}
try {
corBreakpoint.Activate(0);
} catch(COMException e) {
// Sometimes happens, but we had not repro yet.
// 0x80131301: Process was terminated.
if ((uint)e.ErrorCode == 0x80131301)
continue;
throw;
}
#endif
}
corBreakpoints.Clear();
@ -138,7 +145,7 @@ namespace Debugger @@ -138,7 +145,7 @@ namespace Debugger
corBreakpoints.Clear();
}
internal bool SetBreakpoint(Module module)
public virtual bool SetBreakpoint(Module module)
{
if (this.fileName == null)
return false;
@ -165,20 +172,57 @@ namespace Debugger @@ -165,20 +172,57 @@ namespace Debugger
}
}
public class ILBreakpoint : Breakpoint
{
public ILBreakpoint(NDebugger debugger, string typeName, int line, int metadataToken, int memberToken, int offset, bool enabled)
{
this.Debugger = debugger;
this.Line = line;
this.TypeName = typeName;
this.MetadataToken = metadataToken;
this.MemberMetadataToken = memberToken;
this.ILOffset = offset;
this.Enabled = enabled;
}
public int MetadataToken { get; private set; }
public int MemberMetadataToken { get; private set; }
public int ILOffset { get; private set; }
public override bool SetBreakpoint(Module module)
{
SourcecodeSegment segment = SourcecodeSegment.CreateForIL(module, this.Line, MemberMetadataToken, ILOffset);
if (segment == null)
return false;
try {
ICorDebugFunctionBreakpoint corBreakpoint = segment.CorFunction.GetILCode().CreateBreakpoint((uint)segment.ILStart);
corBreakpoint.Activate(Enabled ? 1 : 0);
corBreakpoints.Add(corBreakpoint);
OnSet(new BreakpointEventArgs(this));
return true;
} catch
#if DEBUG
(System.Exception ex)
#endif
{
return false;
}
}
}
[Serializable]
public class BreakpointEventArgs : DebuggerEventArgs
{
Breakpoint breakpoint;
public Breakpoint Breakpoint {
get {
return breakpoint;
}
get; private set;
}
public BreakpointEventArgs(Breakpoint breakpoint): base(breakpoint.Debugger)
{
this.breakpoint = breakpoint;
this.Breakpoint = breakpoint;
}
}
}

16
src/AddIns/Debugger/Debugger.Core/BreakpointCollection.cs

@ -54,6 +54,12 @@ namespace Debugger @@ -54,6 +54,12 @@ namespace Debugger
{
foreach(Process process in this.Debugger.Processes) {
foreach(Module module in process.Modules) {
if (breakpoint is ILBreakpoint) {
var currentModuleTypes = module.GetNamesOfDefinedTypes();
// set the breakpoint only if the module contains the type
if (!currentModuleTypes.Contains(breakpoint.TypeName))
continue;
}
breakpoint.SetBreakpoint(module);
}
}
@ -80,8 +86,16 @@ namespace Debugger @@ -80,8 +86,16 @@ namespace Debugger
List<Breakpoint> collection = new List<Breakpoint>();
collection.AddRange(this);
var currentModuleTypes = module.GetNamesOfDefinedTypes();
foreach (Breakpoint b in collection) {
b.SetBreakpoint(module);
if (b is ILBreakpoint) {
// set the breakpoint only if the module contains the type
if (!currentModuleTypes.Contains(b.TypeName))
continue;
b.SetBreakpoint(module);
} else {
b.SetBreakpoint(module);
}
}
}
}

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

@ -294,7 +294,13 @@ namespace Debugger @@ -294,7 +294,13 @@ namespace Debugger
List<Breakpoint> collection = new List<Breakpoint>();
collection.AddRange(this.Debugger.Breakpoints);
var currentModuleTypes = this.GetNamesOfDefinedTypes();
foreach (Breakpoint b in collection) {
if (b is ILBreakpoint) {
// set the breakpoint only if the module contains the type
if (!currentModuleTypes.Contains(b.TypeName))
continue;
}
b.SetBreakpoint(this);
}
}
@ -339,7 +345,7 @@ namespace Debugger @@ -339,7 +345,7 @@ namespace Debugger
return;
}
try {
this.CorModule2.SetJMCStatus(1, 0, ref unused);
this.CorModule2.SetJMCStatus(process.Options.EnableJustMyCode ? 1 : 0, 0, ref unused);
} catch (COMException e) {
// Cannot use JMC on this code (likely wrong JIT settings).
if ((uint)e.ErrorCode == 0x80131323) {

6
src/AddIns/Debugger/Debugger.Core/Process.cs

@ -136,6 +136,12 @@ namespace Debugger @@ -136,6 +136,12 @@ namespace Debugger
public bool IsInExternalCode {
get {
if (SelectedStackFrame == null && SelectedThread.MostRecentStackFrame == null)
return true;
if (SelectedStackFrame == null && SelectedThread.MostRecentStackFrame != null)
return true;
return SelectedStackFrame.ToString() != SelectedThread.MostRecentStackFrame.ToString();
}
}

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

@ -346,7 +346,7 @@ namespace Debugger @@ -346,7 +346,7 @@ namespace Debugger
this.startLine, this.startColumn, this.endLine, this.endColumn);
}
#region ILSpy
#region Decompiled breakpoint
public static SourcecodeSegment CreateForIL(Module module, int line, int metadataToken, int iLOffset)
{

6
src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj

@ -43,6 +43,7 @@ @@ -43,6 +43,7 @@
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="PresentationCore">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
@ -191,6 +192,11 @@ @@ -191,6 +192,11 @@
<Name>ICSharpCode.AvalonEdit</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NRefactory\Project\NRefactory.csproj">
<Project>{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}</Project>
<Name>NRefactory</Name>

15
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs

@ -11,7 +11,10 @@ using ICSharpCode.AvalonEdit.Editing; @@ -11,7 +11,10 @@ using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
using Mono.Cecil;
namespace ICSharpCode.AvalonEdit.AddIn
{
@ -232,7 +235,17 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -232,7 +235,17 @@ namespace ICSharpCode.AvalonEdit.AddIn
// no bookmark on the line: create a new breakpoint
ITextEditor textEditor = TextView.Services.GetService(typeof(ITextEditor)) as ITextEditor;
if (textEditor != null) {
ICSharpCode.SharpDevelop.Debugging.DebuggerService.ToggleBreakpointAt(textEditor, line);
DebuggerService.ToggleBreakpointAt(textEditor, line);
return;
}
// create breakpoint for the decompiled content
dynamic viewContent = WorkbenchSingleton.Workbench.ActiveContent;
if (viewContent is AbstractViewContentWithoutFile) {
dynamic codeView = ((AbstractViewContentWithoutFile)viewContent).Control;
var editor = codeView.TextEditor as ITextEditor;
var memberReference = viewContent.MemberReference as MemberReference;
if (editor != null && !string.IsNullOrEmpty(editor.FileName))
DebuggerService.ToggleBreakpointAt(memberReference, editor, line);
}
}
}

9
src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs

@ -5,9 +5,7 @@ using System; @@ -5,9 +5,7 @@ using System;
using System.IO;
using System.Linq;
using ICSharpCode.Core.Services;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
@ -60,7 +58,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -60,7 +58,7 @@ namespace ICSharpCode.ILSpyAddIn
WorkbenchSingleton.Workbench.ShowView(new DecompiledViewContent(assemblyFile, typeName, entityTag));
}
public bool NavigateToMember(string assemblyFile, string typeName, string entityTag)
public bool NavigateToMember(string assemblyFile, string typeName, string entityTag, int lineNumber)
{
//close the window if exists - this is a workaround
foreach (var vc in WorkbenchSingleton.Workbench.ViewContentCollection.OfType<DecompiledViewContent>()) {
@ -69,7 +67,10 @@ namespace ICSharpCode.ILSpyAddIn @@ -69,7 +67,10 @@ namespace ICSharpCode.ILSpyAddIn
break;
}
}
WorkbenchSingleton.Workbench.ShowView(new DecompiledViewContent(assemblyFile, typeName, entityTag));
var view = new DecompiledViewContent(assemblyFile, typeName, entityTag);
view.DecompilationFinished += delegate { view.JumpTo(lineNumber); };
WorkbenchSingleton.Workbench.ShowView(view);
return true;
}
}

46
src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/CodeView.cs

@ -14,11 +14,24 @@ using ICSharpCode.AvalonEdit.Document; @@ -14,11 +14,24 @@ using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.AvalonEdit;
namespace ICSharpCode.ILSpyAddIn.ViewContent
{
class DecompiledTextEditorAdapter : AvalonEditTextEditorAdapter
{
public DecompiledTextEditorAdapter(TextEditor textEditor) : base(textEditor)
{}
public string DecompiledFullTypeName { get; set; }
public override ICSharpCode.Core.FileName FileName {
get { return ICSharpCode.Core.FileName.Create(DecompiledFullTypeName); }
}
}
/// <summary>
/// Equivalent to AE.AddIn CodeEditor, but without editing capabilities.
/// </summary>
@ -26,26 +39,31 @@ namespace ICSharpCode.ILSpyAddIn.ViewContent @@ -26,26 +39,31 @@ namespace ICSharpCode.ILSpyAddIn.ViewContent
{
public event EventHandler DocumentChanged;
readonly AvalonEditTextEditorAdapter adapter = new AvalonEditTextEditorAdapter(new SharpDevelopTextEditor { IsReadOnly = true });
readonly DecompiledTextEditorAdapter adapter;
readonly IconBarManager iconBarManager;
readonly IconBarMargin iconMargin;
readonly TextMarkerService textMarkerService;
public CodeView()
public CodeView(string decompiledFullTypeName)
{
DecompiledFullTypeName = decompiledFullTypeName;
this.adapter = new DecompiledTextEditorAdapter(new SharpDevelopTextEditor { IsReadOnly = true }) {
DecompiledFullTypeName = decompiledFullTypeName
};
this.Children.Add(adapter.TextEditor);
adapter.TextEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
// add margin
iconMargin = new IconBarMargin(iconBarManager = new IconBarManager());
adapter.TextEditor.TextArea.LeftMargins.Insert(0, iconMargin);
adapter.TextEditor.TextArea.TextView.VisualLinesChanged += delegate { iconMargin.InvalidateVisual(); };
this.iconMargin = new IconBarMargin(iconBarManager = new IconBarManager());
this.adapter.TextEditor.TextArea.LeftMargins.Insert(0, iconMargin);
this.adapter.TextEditor.TextArea.TextView.VisualLinesChanged += delegate { iconMargin.InvalidateVisual(); };
// add marker service
textMarkerService = new TextMarkerService(this);
adapter.TextEditor.TextArea.TextView.BackgroundRenderers.Add(textMarkerService);
adapter.TextEditor.TextArea.TextView.LineTransformers.Add(textMarkerService);
adapter.TextEditor.TextArea.TextView.Services.AddService(typeof(ITextMarkerService), textMarkerService);
this.textMarkerService = new TextMarkerService(this);
this.adapter.TextEditor.TextArea.TextView.BackgroundRenderers.Add(textMarkerService);
this.adapter.TextEditor.TextArea.TextView.LineTransformers.Add(textMarkerService);
this.adapter.TextEditor.TextArea.TextView.Services.AddService(typeof(ITextMarkerService), textMarkerService);
this.adapter.TextEditor.TextArea.TextView.Services.AddService(typeof(IBookmarkMargin), iconBarManager);
// add events
this.adapter.TextEditor.MouseHover += TextEditorMouseHover;
@ -212,6 +230,16 @@ namespace ICSharpCode.ILSpyAddIn.ViewContent @@ -212,6 +230,16 @@ namespace ICSharpCode.ILSpyAddIn.ViewContent
get { return iconBarManager; }
}
public AvalonEditTextEditorAdapter Adapter {
get {
return adapter;
}
}
public string DecompiledFullTypeName {
get; private set;
}
public void Dispose()
{
}

87
src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs

@ -2,25 +2,19 @@ @@ -2,25 +2,19 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.Core;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.ILSpyAddIn.ViewContent;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using Mono.Cecil;
@ -41,12 +35,13 @@ namespace ICSharpCode.ILSpyAddIn @@ -41,12 +35,13 @@ namespace ICSharpCode.ILSpyAddIn
bool decompilationFinished;
readonly CodeView codeView = new CodeView();
readonly CodeView codeView;
readonly CancellationTokenSource cancellation = new CancellationTokenSource();
#region Constructor
public DecompiledViewContent(string assemblyFile, string fullTypeName, string entityTag)
{
codeView = new CodeView(string.Format("{0},{1}", assemblyFile, fullTypeName));
this.assemblyFile = assemblyFile;
this.fullTypeName = fullTypeName;
this.jumpToEntityTagWhenDecompilationFinished = entityTag;
@ -57,9 +52,10 @@ namespace ICSharpCode.ILSpyAddIn @@ -57,9 +52,10 @@ namespace ICSharpCode.ILSpyAddIn
Thread thread = new Thread(DecompilationThread);
thread.Name = "Decompiler (" + shortTypeName + ")";
thread.Start();
BookmarkManager.Removed += BookmarkManager_Removed;
BookmarkManager.Added += BookmarkManager_Added;
}
#endregion
#region Properties
@ -78,6 +74,11 @@ namespace ICSharpCode.ILSpyAddIn @@ -78,6 +74,11 @@ namespace ICSharpCode.ILSpyAddIn
public override bool IsReadOnly {
get { return true; }
}
public MemberReference MemberReference {
get; private set;
}
#endregion
#region Dispose
@ -85,6 +86,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -85,6 +86,7 @@ namespace ICSharpCode.ILSpyAddIn
{
cancellation.Cancel();
codeView.Dispose();
BookmarkManager.Added -= BookmarkManager_Added;
BookmarkManager.Removed -= BookmarkManager_Removed;
base.Dispose();
}
@ -141,7 +143,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -141,7 +143,7 @@ namespace ICSharpCode.ILSpyAddIn
}
}
static void RunDecompiler(string assemblyFile, string fullTypeName, ITextOutput textOutput, CancellationToken cancellationToken)
void RunDecompiler(string assemblyFile, string fullTypeName, ITextOutput textOutput, CancellationToken cancellationToken)
{
ReaderParameters readerParameters = new ReaderParameters();
// Use new assembly resolver instance so that the AssemblyDefinitions can be garbage-collected
@ -162,12 +164,23 @@ namespace ICSharpCode.ILSpyAddIn @@ -162,12 +164,23 @@ namespace ICSharpCode.ILSpyAddIn
var nodes = TreeTraversal
.PreOrder((AstNode)astBuilder.CompilationUnit, n => n.Children)
.Where(n => n is AttributedNode && n.Annotation<Tuple<int, int>>() != null);
DebuggerService.ExternalDebugInformation = new DecompileInformation {
CodeMappings = astBuilder.CodeMappings,
LocalVariables = astBuilder.LocalVariables,
DecompiledMemberReferences = astBuilder.DecompiledMemberReferences,
AstNodes = nodes
};
MemberReference = typeDefinition;
int token = MemberReference.MetadataToken.ToInt32();
if (!DebuggerService.ExternalDebugInformation.ContainsKey(token)) {
DebuggerService.ExternalDebugInformation.Add(token, new DecompileInformation {
CodeMappings = astBuilder.CodeMappings,
LocalVariables = astBuilder.LocalVariables,
DecompiledMemberReferences = astBuilder.DecompiledMemberReferences,
AstNodes = nodes
});
} else {
DebuggerService.ExternalDebugInformation[token] = new DecompileInformation {
CodeMappings = astBuilder.CodeMappings,
LocalVariables = astBuilder.LocalVariables,
DecompiledMemberReferences = astBuilder.DecompiledMemberReferences,
AstNodes = nodes
};
}
}
void OnDecompilationFinished(StringWriter output)
@ -183,6 +196,9 @@ namespace ICSharpCode.ILSpyAddIn @@ -183,6 +196,9 @@ namespace ICSharpCode.ILSpyAddIn
// update UI
UpdateIconMargin(output.ToString());
UpdateDebuggingUI();
// fire event
OnDecompilationFinished(EventArgs.Empty);
}
#endregion
@ -192,6 +208,12 @@ namespace ICSharpCode.ILSpyAddIn @@ -192,6 +208,12 @@ namespace ICSharpCode.ILSpyAddIn
string tempFileName = string.Format("decompiled/{0}.cs", fullTypeName);
codeView.IconBarManager.UpdateClassMemberBookmarks(ParserService.ParseFile(tempFileName, new StringTextBuffer(text)));
// load bookmarks
foreach (SDBookmark bookmark in BookmarkManager.GetBookmarks(codeView.Adapter.FileName)) {
bookmark.Document = codeView.Adapter.Document;
codeView.IconBarManager.Bookmarks.Add(bookmark);
}
}
void UpdateDebuggingUI()
@ -201,12 +223,12 @@ namespace ICSharpCode.ILSpyAddIn @@ -201,12 +223,12 @@ namespace ICSharpCode.ILSpyAddIn
if (DebuggerService.DebugStepInformation != null) {
// get debugging information
DecompileInformation debugInformation = (DecompileInformation)DebuggerService.ExternalDebugInformation;
DecompileInformation debugInformation = (DecompileInformation)DebuggerService.ExternalDebugInformation[MemberReference.MetadataToken.ToInt32()];
int token = DebuggerService.DebugStepInformation.Item1;
int ilOffset = DebuggerService.DebugStepInformation.Item2;
int line;
MemberReference member;
if (!debugInformation.CodeMappings.ContainsKey(token))
if (debugInformation.CodeMappings == null || !debugInformation.CodeMappings.ContainsKey(token))
return;
debugInformation.CodeMappings[token].GetInstructionByTokenAndOffset(token, ilOffset, out member, out line);
@ -216,6 +238,17 @@ namespace ICSharpCode.ILSpyAddIn @@ -216,6 +238,17 @@ namespace ICSharpCode.ILSpyAddIn
CurrentLineBookmark.SetPosition(this, line, 0, line, 0);
}
}
public void JumpTo(int lineNumber)
{
if (lineNumber <= 0)
return;
if (codeView == null)
return;
codeView.UnfoldAndScroll(lineNumber);
}
#endregion
#region Bookmarks
@ -227,6 +260,26 @@ namespace ICSharpCode.ILSpyAddIn @@ -227,6 +260,26 @@ namespace ICSharpCode.ILSpyAddIn
mark.Document = null;
}
}
void BookmarkManager_Added(object sender, BookmarkEventArgs e)
{
var mark = e.Bookmark;
if (mark != null && mark is BreakpointBookmark && mark.FileName == codeView.DecompiledFullTypeName) {
codeView.IconBarManager.Bookmarks.Add(mark);
mark.Document = codeView.Adapter.Document;
}
}
#endregion
#region Events
public event EventHandler DecompilationFinished;
protected virtual void OnDecompilationFinished(EventArgs e)
{
if (DecompilationFinished != null) {
DecompilationFinished(this, e);
}
}
#endregion
}
}

1
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -315,6 +315,7 @@ @@ -315,6 +315,7 @@
<Compile Include="Src\Project\TargetFramework.cs" />
<Compile Include="Src\Services\Debugger\BreakpointBookmark.cs" />
<Compile Include="Src\Services\Debugger\BreakpointBookmarkEventArgs.cs" />
<Compile Include="Src\Services\Debugger\DecompiledBreakpointBookmark.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\IPinDebuggerControl.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\ITreeNode.cs" />
<Compile Include="Src\Services\Debugger\Tooltips\IVisualizerCommand.cs" />

44
src/Main/Base/Project/Src/Bookmarks/BookmarkConverter.cs

@ -52,15 +52,29 @@ namespace ICSharpCode.SharpDevelop.Bookmarks @@ -52,15 +52,29 @@ namespace ICSharpCode.SharpDevelop.Bookmarks
bbm.Condition = script;
bookmark = bbm;
break;
case "DecompiledBreakpointBookmark":
action = (Debugging.BreakpointAction)Enum.Parse(typeof(Debugging.BreakpointAction), v[5]);
scriptLanguage = v[6];
script = v[7];
int ilfrom = Convert.ToInt32(v[8]);
int ilto = Convert.ToInt32(v[9]);
bbm = new DecompiledBreakpointBookmark(null, ilfrom, ilto, fileName, new Location(columnNumber, lineNumber), action, scriptLanguage, script);
bbm.IsEnabled = bool.Parse(v[4]);
bbm.Action = action;
bbm.ScriptLanguage = scriptLanguage;
bbm.Condition = script;
bookmark = bbm;
break;
case "PinBookmark":
var pin = new PinBookmark(fileName, new Location(columnNumber, lineNumber));
pin.Comment = v[4];
pin.PinPosition =
new Point
{
X = double.Parse(v[5], culture),
Y = double.Parse(v[6], culture)
};
{
X = double.Parse(v[5], culture),
Y = double.Parse(v[6], culture)
};
// pop-up nodes
pin.SavedNodes = new System.Collections.Generic.List<Tuple<string, string, string>>();
@ -85,7 +99,9 @@ namespace ICSharpCode.SharpDevelop.Bookmarks @@ -85,7 +99,9 @@ namespace ICSharpCode.SharpDevelop.Bookmarks
SDBookmark bookmark = value as SDBookmark;
if (destinationType == typeof(string) && bookmark != null) {
StringBuilder b = new StringBuilder();
if (bookmark is Debugging.BreakpointBookmark) {
if (bookmark is DecompiledBreakpointBookmark) {
b.Append("DecompiledBreakpointBookmark");
} else if (bookmark is Debugging.BreakpointBookmark) {
b.Append("Breakpoint");
} else {
if (bookmark is PinBookmark)
@ -100,8 +116,22 @@ namespace ICSharpCode.SharpDevelop.Bookmarks @@ -100,8 +116,22 @@ namespace ICSharpCode.SharpDevelop.Bookmarks
b.Append('|');
b.Append(bookmark.ColumnNumber);
if (bookmark is Debugging.BreakpointBookmark) {
Debugging.BreakpointBookmark bbm = (Debugging.BreakpointBookmark)bookmark;
if (bookmark is DecompiledBreakpointBookmark) {
var bbm = (DecompiledBreakpointBookmark)bookmark;
b.Append('|');
b.Append(bbm.IsEnabled.ToString());
b.Append('|');
b.Append(bbm.Action.ToString());
b.Append('|');
b.Append(bbm.ScriptLanguage);
b.Append('|');
b.Append(bbm.Condition);
b.Append('|');
b.Append(bbm.ILFrom);
b.Append('|');
b.Append(bbm.ILTo);
} else if (bookmark is Debugging.BreakpointBookmark) {
var bbm = (Debugging.BreakpointBookmark)bookmark;
b.Append('|');
b.Append(bbm.IsEnabled.ToString());
b.Append('|');

2
src/Main/Base/Project/Src/Bookmarks/BookmarkManager.cs

@ -98,7 +98,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks @@ -98,7 +98,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks
{
List<SDBookmark> projectBookmarks = new List<SDBookmark>();
foreach (SDBookmark mark in bookmarks) {
if (mark.IsSaved && mark.FileName != null && project.IsFileInProject(mark.FileName)) {
if (mark.IsSaved && mark.FileName != null) {
projectBookmarks.Add(mark);
}
}

10
src/Main/Base/Project/Src/Commands/DebugCommands.cs

@ -119,13 +119,21 @@ namespace ICSharpCode.SharpDevelop.Project.Commands @@ -119,13 +119,21 @@ namespace ICSharpCode.SharpDevelop.Project.Commands
{
public override void Run()
{
ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveContent as ITextEditorProvider;
var viewContent = WorkbenchSingleton.Workbench.ActiveContent;
ITextEditorProvider provider = viewContent as ITextEditorProvider;
if (provider != null) {
ITextEditor editor = provider.TextEditor;
if (!string.IsNullOrEmpty(editor.FileName)) {
DebuggerService.ToggleBreakpointAt(editor, editor.Caret.Line);
}
} else {
if (viewContent is AbstractViewContentWithoutFile) {
dynamic codeView = ((AbstractViewContentWithoutFile)viewContent).Control;
var editor = codeView.TextEditor as ITextEditor;
if (editor != null && !string.IsNullOrEmpty(editor.FileName))
DebuggerService.ToggleBreakpointAt(editor, editor.Caret.Line);
}
}
}
}

25
src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs

@ -5,6 +5,7 @@ using System; @@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using ICSharpCode.Core;
@ -33,6 +34,8 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -33,6 +34,8 @@ namespace ICSharpCode.SharpDevelop.Debugging
BookmarkManager.Added += BookmarkAdded;
BookmarkManager.Removed += BookmarkRemoved;
ExternalDebugInformation = new Dictionary<int, object>();
}
static void GetDescriptors()
@ -107,7 +110,7 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -107,7 +110,7 @@ namespace ICSharpCode.SharpDevelop.Debugging
/// Gets or sets the external debug information.
/// <summary>This constains the code mappings and local variables.</summary>
/// </summary>
public static object ExternalDebugInformation { get; set; }
public static Dictionary<int, object> ExternalDebugInformation { get; set; }
/// <summary>
/// Gets or sets the current token and IL offset. Used for step in/out.
@ -248,6 +251,16 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -248,6 +251,16 @@ namespace ICSharpCode.SharpDevelop.Debugging
location => new BreakpointBookmark(editor.FileName, location, BreakpointAction.Break, "", ""));
}
public static void ToggleBreakpointAt(MemberReference memberReference, ITextEditor editor, int lineNumber)
{
// no bookmark on the line: create a new breakpoint
BookmarkManager.ToggleBookmark(
editor, lineNumber,
b => b.CanToggle,
location => new DecompiledBreakpointBookmark(
memberReference, 0, 0, editor.FileName, location, BreakpointAction.Break, "", ""));
}
/* TODO: reimplement this stuff
static void ViewContentOpened(object sender, ViewContentEventArgs e)
{
@ -261,12 +274,12 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -261,12 +274,12 @@ namespace ICSharpCode.SharpDevelop.Debugging
CurrentLineBookmark.Remove();
}
public static void JumpToCurrentLine(string SourceFullFilename, int StartLine, int StartColumn, int EndLine, int EndColumn)
public static void JumpToCurrentLine(string sourceFullFilename, int startLine, int startColumn, int endLine, int endColumn)
{
IViewContent viewContent = FileService.OpenFile(SourceFullFilename);
IViewContent viewContent = FileService.OpenFile(sourceFullFilename);
if (viewContent is ITextEditorProvider)
((ITextEditorProvider)viewContent).TextEditor.JumpTo(StartLine, StartColumn);
CurrentLineBookmark.SetPosition(viewContent, StartLine, StartColumn, EndLine, EndColumn);
((ITextEditorProvider)viewContent).TextEditor.JumpTo(startLine, startColumn);
CurrentLineBookmark.SetPosition(viewContent, startLine, startColumn, endLine, endColumn);
}
#region Tool tips
@ -283,7 +296,7 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -283,7 +296,7 @@ namespace ICSharpCode.SharpDevelop.Debugging
Location logicPos = e.LogicalPosition;
var doc = e.Editor.Document;
string fileName;
if (string.IsNullOrEmpty(e.Editor.FileName)) {
if (!File.Exists(e.Editor.FileName)) {
dynamic viewContent = WorkbenchSingleton.Workbench.ActiveViewContent;
fileName = string.Format("decompiled/{0}.cs", viewContent.FullTypeName);
} else {

56
src/Main/Base/Project/Src/Services/Debugger/DecompiledBreakpointBookmark.cs

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// 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 ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop.Debugging;
using Mono.Cecil;
namespace ICSharpCode.SharpDevelop.Bookmarks
{
public class DecompiledBreakpointBookmark : BreakpointBookmark
{
public DecompiledBreakpointBookmark(MemberReference member, int ilFrom, int ilTo, FileName fileName, Location location, BreakpointAction action, string scriptLanguage, string script) : base(fileName, location, action, scriptLanguage, script)
{
this.MemberReference = member;
this.ILFrom = ilFrom;
this.ILTo = ILTo;
}
public int ILFrom {
get; set;
}
public int ILTo {
get; set;
}
MemberReference memberReference;
public MemberReference MemberReference {
get {
if (memberReference != null)
return memberReference;
// reload from filename
ReaderParameters readerParameters = new ReaderParameters();
// Use new assembly resolver instance so that the AssemblyDefinitions can be garbage-collected
// once the code is decompiled.
readerParameters.AssemblyResolver = new DefaultAssemblyResolver();
string fileName = FileName.ToString();
int index = fileName.IndexOf(",");
string assemblyFile = fileName.Substring(0, index);
string fullTypeName = fileName.Substring(index + 1, fileName.Length - index - 1);
ModuleDefinition module = ModuleDefinition.ReadModule(assemblyFile, readerParameters);
TypeDefinition typeDefinition = module.GetType(fullTypeName);
if (typeDefinition == null)
throw new InvalidOperationException("Could not find type");
memberReference = typeDefinition;
return memberReference;
}
private set { memberReference = value; }
}
}
}

12
src/Main/Base/Project/Src/Services/File/FileService.cs

@ -533,6 +533,14 @@ namespace ICSharpCode.SharpDevelop @@ -533,6 +533,14 @@ namespace ICSharpCode.SharpDevelop
bool loggingResumed = false;
try {
// jump to decompiled type from filename
if (fileName.Contains(",")) {
int index = fileName.IndexOf(",");
string assemblyName = fileName.Substring(0, index);
string typeName = fileName.Substring(index + 1, fileName.Length - index - 1);
NavigationService.NavigateTo(assemblyName, typeName, string.Empty, line);
return null;
}
IViewContent content = OpenFile(fileName);
if (content is IPositionable) {
@ -547,11 +555,11 @@ namespace ICSharpCode.SharpDevelop @@ -547,11 +555,11 @@ namespace ICSharpCode.SharpDevelop
NavigationService.Log(content);
}
LoggingService.InfoFormatted("FileService\n\tJumped to File Position: [{0} : {1}x{2}]", fileName, line, column);
return content;
} finally {
LoggingService.InfoFormatted("FileService\n\tJumped to File Position: [{0} : {1}x{2}]", fileName, line, column);
if (!loggingResumed) {
NavigationService.ResumeLogging();
}

6
src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs

@ -475,7 +475,7 @@ namespace ICSharpCode.SharpDevelop @@ -475,7 +475,7 @@ namespace ICSharpCode.SharpDevelop
#region Navigate to Member
public static bool NavigateTo(string assemblyFile, string typeName, string entityTag)
public static bool NavigateTo(string assemblyFile, string typeName, string entityTag, int lineNumber = 0)
{
if (string.IsNullOrEmpty(assemblyFile))
throw new ArgumentException("assemblyFile is null or empty");
@ -484,7 +484,7 @@ namespace ICSharpCode.SharpDevelop @@ -484,7 +484,7 @@ namespace ICSharpCode.SharpDevelop
throw new ArgumentException("typeName is null or empty");
foreach (var item in AddInTree.BuildItems<INavigateToMemberService>("/SharpDevelop/Services/NavigateToEntityService", null, false)) {
if (item.NavigateToMember(assemblyFile, typeName, entityTag))
if (item.NavigateToMember(assemblyFile, typeName, entityTag, lineNumber))
return true;
}
return false;
@ -512,6 +512,6 @@ namespace ICSharpCode.SharpDevelop @@ -512,6 +512,6 @@ namespace ICSharpCode.SharpDevelop
/// </remarks>
public interface INavigateToMemberService
{
bool NavigateToMember(string assemblyFile, string typeName, string entityTag);
bool NavigateToMember(string assemblyFile, string typeName, string entityTag, int lineNumber);
}
}

Loading…
Cancel
Save