From 572c79f097d444604faad5a7bafb6ba1d6ee1260 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Thu, 3 Mar 2011 17:14:23 +0200 Subject: [PATCH] Fix IL Code mappings; Unfold and scroll when hitting a BP. Jump to the type that has a BP when the BP is hit. --- .../AvalonEdit/IconBarMargin.cs | 24 ++--- .../AvalonEdit/TextMarkerService.cs | 7 +- .../ILSpy.Debugger/Bookmarks/BookmarkBase.cs | 7 +- .../Bookmarks/BookmarkManager.cs | 4 +- .../Bookmarks/BreakpointBookmark.cs | 3 +- .../Bookmarks/CurrentLineBookmark.cs | 7 +- .../Bookmarks/MarkerBookmark.cs | 3 +- Debugger/ILSpy.Debugger/DebuggedType.cs | 21 ++-- .../Models/TreeModel/ExpressionNode.cs | 32 +++--- .../Services/Debugger/DebuggerService.cs | 11 +- .../Services/Debugger/IDebugger.cs | 5 - .../Services/Debugger/WindowsDebugger.cs | 62 ++++------- .../UI/AttachToProcessWindow.xaml.cs | 17 +-- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 2 +- ICSharpCode.Decompiler/CodeMappings.cs | 12 +-- .../Disassembler/ReflectionDisassembler.cs | 2 +- ILSpy.sln | 6 +- ILSpy/MainWindow.xaml.cs | 102 +++++++++++++----- ILSpy/TextView/DecompilerTextView.cs | 36 ++++++- ILSpy/TreeNodes/TypeTreeNode.cs | 2 +- 20 files changed, 226 insertions(+), 139 deletions(-) diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs b/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs index f3784859f..c593fdcb1 100644 --- a/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs +++ b/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs @@ -57,10 +57,10 @@ namespace ILSpy.Debugger.AvalonEdit // create a dictionary line number => first bookmark Dictionary bookmarkDict = new Dictionary(); foreach (var bm in BookmarkManager.Bookmarks) { - if (DebuggedType.CurrentType == null || bm.TypeName != DebuggedType.CurrentType.FullName) + if (DebuggedData.CurrentType == null || bm.Type.FullName != DebuggedData.CurrentType.FullName) continue; if (bm is BreakpointBookmark && - ((BreakpointBookmark)bm).Language != DebuggerService.CurrentDebugger.Language) + ((BreakpointBookmark)bm).Language != DebuggedData.Language) continue; int line = bm.LineNumber; @@ -119,8 +119,8 @@ namespace ILSpy.Debugger.AvalonEdit BookmarkBase result = null; foreach (BookmarkBase bm in BookmarkManager.Bookmarks) { if (bm.LineNumber == line && - DebuggedType.CurrentType != null && - bm.TypeName == DebuggedType.CurrentType.FullName) { + DebuggedData.CurrentType != null && + bm.Type.FullName == DebuggedData.CurrentType.FullName) { if (result == null || bm.ZOrder > result.ZOrder) result = bm; } @@ -189,11 +189,11 @@ namespace ILSpy.Debugger.AvalonEdit InvalidateVisual(); } - if (DebuggedType.CurrentType == null) + if (DebuggedData.CurrentType == null) return; BreakpointBookmark bm = BookmarkManager.Bookmarks.Find( - b => b.TypeName == DebuggedType.CurrentType.FullName && + b => b.Type.FullName == DebuggedData.CurrentType.FullName && b.LineNumber == GetLineFromMousePosition(e) && b is BreakpointBookmark) as BreakpointBookmark; @@ -226,24 +226,24 @@ namespace ILSpy.Debugger.AvalonEdit return; } if (e.ChangedButton == MouseButton.Left) { - if (DebuggedType.CurrentType != null) { + if (DebuggedData.CurrentType != null) { // check if the codemappings exists for this line - var storage = CodeMappings.GetStorage(DebuggerService.CurrentDebugger.Language); + var storage = CodeMappings.GetStorage(DebuggedData.Language); uint token; - var instruction = storage.GetInstructionByTypeAndLine(DebuggedType.CurrentType.FullName, line, out token); + var instruction = storage.GetInstructionByTypeAndLine(DebuggedData.CurrentType.FullName, line, out token); if (instruction == null || instruction.ILInstructionOffset.From == 0) { - MessageBox.Show(string.Format("Missing code mappings for {0} at line {1}", DebuggedType.CurrentType.FullName, line), + MessageBox.Show(string.Format("Missing code mappings for {0} at line {1}", DebuggedData.CurrentType.FullName, line), "Code mappings", MessageBoxButton.OK, MessageBoxImage.Information); return; } // no bookmark on the line: create a new breakpoint DebuggerService.ToggleBreakpointAt( - DebuggedType.CurrentType.FullName, + DebuggedData.CurrentType, line, - DebuggerService.CurrentDebugger.Language); + DebuggedData.Language); } } InvalidateVisual(); diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs b/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs index 3f80c867b..baabc11ac 100644 --- a/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs +++ b/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs @@ -45,8 +45,11 @@ namespace ILSpy.Debugger.AvalonEdit { if (e.Bookmark is MarkerBookmark) { var bm = (MarkerBookmark)e.Bookmark; - DocumentLine line = codeEditor.Document.GetLineByNumber(bm.LineNumber); - bm.Marker = bm.CreateMarker(this, line.Offset, line.Length); + if (DebuggedData.CurrentType != null && DebuggedData.CurrentType.FullName.Equals(bm.Type.FullName, StringComparison.OrdinalIgnoreCase)) { + // add bookmark for the current type + DocumentLine line = codeEditor.Document.GetLineByNumber(bm.LineNumber); + bm.Marker = bm.CreateMarker(this, line.Offset, line.Length); + } } } diff --git a/Debugger/ILSpy.Debugger/Bookmarks/BookmarkBase.cs b/Debugger/ILSpy.Debugger/Bookmarks/BookmarkBase.cs index 12fda6741..0f5495f59 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/BookmarkBase.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/BookmarkBase.cs @@ -6,6 +6,7 @@ using System.Windows.Input; using System.Windows.Media; using ICSharpCode.NRefactory.CSharp; +using Mono.Cecil; namespace ILSpy.Debugger.Bookmarks { @@ -40,7 +41,7 @@ namespace ILSpy.Debugger.Bookmarks } - public string TypeName { get; set; } + public TypeDefinition Type { get; set; } public int LineNumber { get { return location.Line; } @@ -63,9 +64,9 @@ namespace ILSpy.Debugger.Bookmarks } } - public BookmarkBase(string typeName, AstLocation location) + public BookmarkBase(TypeDefinition type, AstLocation location) { - this.TypeName = typeName; + this.Type = type; this.Location = location; } diff --git a/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs b/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs index 90a695af1..b69ee9ebe 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs @@ -29,7 +29,7 @@ namespace ILSpy.Debugger.Bookmarks List marks = new List(); foreach (BookmarkBase mark in bookmarks) { - if (typeName == mark.TypeName) { + if (typeName == mark.Type.FullName) { marks.Add(mark); } } @@ -54,7 +54,7 @@ namespace ILSpy.Debugger.Bookmarks return false; if (a.GetType() != b.GetType()) return false; - if (a.TypeName != b.TypeName) + if (a.Type.FullName != b.Type.FullName) return false; return a.LineNumber == b.LineNumber; } diff --git a/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs b/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs index 5e4030853..879f1f6df 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs @@ -8,6 +8,7 @@ using ICSharpCode.Decompiler; using ICSharpCode.NRefactory.CSharp; using ILSpy.Debugger.AvalonEdit; using ILSpy.Debugger.Services; +using Mono.Cecil; namespace ILSpy.Debugger.Bookmarks { @@ -72,7 +73,7 @@ namespace ILSpy.Debugger.Bookmarks set { tooltip = value; } } - public BreakpointBookmark(string typeName, AstLocation location, BreakpointAction action, DecompiledLanguages language) : base(typeName, location) + public BreakpointBookmark(TypeDefinition type, AstLocation location, BreakpointAction action, DecompiledLanguages language) : base(type, location) { this.action = action; this.tooltip = language.ToString(); diff --git a/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs b/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs index dd790a5c6..ceb01076b 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs @@ -6,6 +6,7 @@ using System.Windows.Media; using ICSharpCode.NRefactory.CSharp; using ILSpy.Debugger.AvalonEdit; using ILSpy.Debugger.Services; +using Mono.Cecil; using Mono.CSharp; namespace ILSpy.Debugger.Bookmarks @@ -23,7 +24,7 @@ namespace ILSpy.Debugger.Bookmarks static int endLine; static int endColumn; - public static void SetPosition(string typeName, int makerStartLine, int makerStartColumn, int makerEndLine, int makerEndColumn) + public static void SetPosition(TypeDefinition type, int makerStartLine, int makerStartColumn, int makerEndLine, int makerEndColumn) { Remove(); @@ -32,7 +33,7 @@ namespace ILSpy.Debugger.Bookmarks endLine = makerEndLine; endColumn = makerEndColumn; - instance = new CurrentLineBookmark(typeName, new AstLocation(startLine, startColumn)); + instance = new CurrentLineBookmark(type, new AstLocation(startLine, startColumn)); BookmarkManager.AddMark(instance); } @@ -52,7 +53,7 @@ namespace ILSpy.Debugger.Bookmarks get { return 100; } } - public CurrentLineBookmark(string typeName, AstLocation location) : base(typeName, location) + public CurrentLineBookmark(TypeDefinition type, AstLocation location) : base(type, location) { } diff --git a/Debugger/ILSpy.Debugger/Bookmarks/MarkerBookmark.cs b/Debugger/ILSpy.Debugger/Bookmarks/MarkerBookmark.cs index cf8caf169..ddcde1c55 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/MarkerBookmark.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/MarkerBookmark.cs @@ -4,12 +4,13 @@ using System; using ICSharpCode.NRefactory.CSharp; using ILSpy.Debugger.AvalonEdit; +using Mono.Cecil; namespace ILSpy.Debugger.Bookmarks { public abstract class MarkerBookmark : BookmarkBase { - public MarkerBookmark(string typeName, AstLocation location) : base(typeName, location) + public MarkerBookmark(TypeDefinition type, AstLocation location) : base(type, location) { } diff --git a/Debugger/ILSpy.Debugger/DebuggedType.cs b/Debugger/ILSpy.Debugger/DebuggedType.cs index c0c0cb949..2424e09f5 100644 --- a/Debugger/ILSpy.Debugger/DebuggedType.cs +++ b/Debugger/ILSpy.Debugger/DebuggedType.cs @@ -17,17 +17,24 @@ // DEALINGS IN THE SOFTWARE. using System; +using ICSharpCode.Decompiler; using Mono.Cecil; namespace ILSpy.Debugger { - public static class DebuggedType + /// + /// Contains the data important for debugger from the main application. + /// + public static class DebuggedData { - static TypeDefinition currentTypeName; - - public static TypeDefinition CurrentType { - get { return currentTypeName; } - set { currentTypeName = value; } - } + /// + /// Gets or sets the current debugged type + /// + public static TypeDefinition CurrentType { get; set; } + + /// + /// Gets or sets the decompiled language. + /// + public static DecompiledLanguages Language { get; set; } } } diff --git a/Debugger/ILSpy.Debugger/Models/TreeModel/ExpressionNode.cs b/Debugger/ILSpy.Debugger/Models/TreeModel/ExpressionNode.cs index 59fcc204f..a75e20284 100644 --- a/Debugger/ILSpy.Debugger/Models/TreeModel/ExpressionNode.cs +++ b/Debugger/ILSpy.Debugger/Models/TreeModel/ExpressionNode.cs @@ -257,22 +257,22 @@ namespace ILSpy.Debugger.Models.TreeModel 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(); - } - } +// 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) diff --git a/Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs b/Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs index 121500da3..f934e6797 100644 --- a/Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs +++ b/Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs @@ -8,6 +8,7 @@ using ICSharpCode.Decompiler; using ICSharpCode.NRefactory.CSharp.Resolver; using ILSpy.Debugger.Bookmarks; using ILSpy.Debugger.ToolTips; +using Mono.Cecil; namespace ILSpy.Debugger.Services { @@ -162,12 +163,12 @@ namespace ILSpy.Debugger.Services } } - public static void ToggleBreakpointAt(string typeName, int lineNumber, DecompiledLanguages language) + public static void ToggleBreakpointAt(TypeDefinition type, int lineNumber, DecompiledLanguages language) { BookmarkManager.ToggleBookmark( - typeName, lineNumber, + type.FullName, lineNumber, b => b.CanToggle && b is BreakpointBookmark, - location => new BreakpointBookmark(typeName, location, BreakpointAction.Break, language)); + location => new BreakpointBookmark(type, location, BreakpointAction.Break, language)); } /* TODO: reimplement this stuff @@ -183,9 +184,9 @@ namespace ILSpy.Debugger.Services CurrentLineBookmark.Remove(); } - public static void JumpToCurrentLine(string typeName, int startLine, int startColumn, int endLine, int endColumn) + public static void JumpToCurrentLine(TypeDefinition type, int startLine, int startColumn, int endLine, int endColumn) { - CurrentLineBookmark.SetPosition(typeName, startLine, startColumn, endLine, endColumn); + CurrentLineBookmark.SetPosition(type, startLine, startColumn, endLine, endColumn); } #region Tool tips diff --git a/Debugger/ILSpy.Debugger/Services/Debugger/IDebugger.cs b/Debugger/ILSpy.Debugger/Services/Debugger/IDebugger.cs index c8e46fd32..f529ef59f 100644 --- a/Debugger/ILSpy.Debugger/Services/Debugger/IDebugger.cs +++ b/Debugger/ILSpy.Debugger/Services/Debugger/IDebugger.cs @@ -10,11 +10,6 @@ namespace ILSpy.Debugger.Services { public interface IDebugger : IDisposable { - /// - /// Gets or sets the decompiled language. - /// - DecompiledLanguages Language { get; set; } - /// /// Gets whether the debugger can evaluate the expression. /// diff --git a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs index f2226b18e..dc153584e 100644 --- a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs +++ b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs @@ -20,6 +20,7 @@ using ILSpy.Debugger.Bookmarks; using ILSpy.Debugger.Models.TreeModel; using ILSpy.Debugger.Services.Debugger; using ILSpy.Debugger.Tooltips; +using Mono.Cecil; using CorDbg = Debugger; using Process = Debugger.Process; using StackFrame = Debugger.StackFrame; @@ -48,7 +49,7 @@ namespace ILSpy.Debugger.Services private ConcurrentDictionary> CodeMappingsStorage { get { - return CodeMappings.GetStorage(Language); + return CodeMappings.GetStorage(DebuggedData.Language); } } @@ -109,8 +110,6 @@ namespace ILSpy.Debugger.Services string errorProcessPaused = "Error.ProcessPaused"; string errorCannotStepNoActiveFunction = "Threads.CannotStepNoActiveFunction"; - public DecompiledLanguages Language { get; set; } - public bool IsDebugging { get { return ServiceInitialized && debuggedProcess != null; @@ -289,10 +288,10 @@ namespace ILSpy.Debugger.Services // get the mapped instruction from the current line marker or the next one uint token; var instruction = CodeMappingsStorage.GetInstructionByTypeAndLine( - CurrentLineBookmark.Instance.TypeName, + CurrentLineBookmark.Instance.Type.FullName, CurrentLineBookmark.Instance.LineNumber, out token); - var val = CodeMappingsStorage[CurrentLineBookmark.Instance.TypeName]; + var val = CodeMappingsStorage[CurrentLineBookmark.Instance.Type.FullName]; var mapping = val.Find(m => m.MetadataToken == token); @@ -560,21 +559,19 @@ namespace ILSpy.Debugger.Services { Breakpoint breakpoint = null; - if (Language == bookmark.Language) { - uint token; - SourceCodeMapping map = - CodeMappingsStorage.GetInstructionByTypeAndLine( - bookmark.TypeName, bookmark.LineNumber, out token); - - if (map != null) { - breakpoint = new ILBreakpoint( - debugger, - bookmark.TypeName, - bookmark.LineNumber, - token, - map.ILInstructionOffset.From, - bookmark.IsEnabled); - } + uint token; + SourceCodeMapping map = CodeMappings + .GetStorage(bookmark.Language) + .GetInstructionByTypeAndLine(bookmark.Type.FullName, bookmark.LineNumber, out token); + + if (map != null) { + breakpoint = new ILBreakpoint( + debugger, + bookmark.Type.FullName, + bookmark.LineNumber, + token, + map.ILInstructionOffset.From, + bookmark.IsEnabled); } if (breakpoint == null) @@ -748,7 +745,7 @@ namespace ILSpy.Debugger.Services foreach (var bookmark in DebuggerService.Breakpoints) { var breakpoint = debugger.Breakpoints.FirstOrDefault( - b => b.Line == bookmark.LineNumber && b.TypeName == bookmark.TypeName); + b => b.Line == bookmark.LineNumber && b.TypeName == bookmark.Type.FullName); if (breakpoint == null) continue; @@ -758,22 +755,8 @@ namespace ILSpy.Debugger.Services 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) { - } - } - }*/ + OnIsProcessRunningChanged(EventArgs.Empty); } void debuggedProcess_DebuggingResumed(object sender, CorDbg.ProcessEventArgs e) @@ -832,9 +815,10 @@ namespace ILSpy.Debugger.Services uint token = (uint)frame.MethodInfo.MetadataToken; int ilOffset = frame.IP; int line; - string typeName; - if (CodeMappingsStorage.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out typeName, out line)) - DebuggerService.JumpToCurrentLine(typeName, line, 0, line, 0); + TypeDefinition type; + if (CodeMappingsStorage.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out type, out line)) { + DebuggerService.JumpToCurrentLine(type, line, 0, line, 0); + } } } diff --git a/Debugger/ILSpy.Debugger/UI/AttachToProcessWindow.xaml.cs b/Debugger/ILSpy.Debugger/UI/AttachToProcessWindow.xaml.cs index 533214249..9b37613c5 100644 --- a/Debugger/ILSpy.Debugger/UI/AttachToProcessWindow.xaml.cs +++ b/Debugger/ILSpy.Debugger/UI/AttachToProcessWindow.xaml.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Windows; using ILSpy.Debugger.Models; -using ILSpy.Debugger.Services; namespace ILSpy.Debugger.UI { @@ -25,6 +24,15 @@ namespace ILSpy.Debugger.UI Loaded += OnLoaded; } + + public Process SelectedProcess { + get { + if (this.RunningProcesses.SelectedItem != null) + return ((RunningProcess)this.RunningProcesses.SelectedItem).Process; + + return null; + } + } void RefreshProcessList() { @@ -51,8 +59,8 @@ namespace ILSpy.Debugger.UI FileName = process.MainModule.FileName, WindowTitle = process.MainWindowTitle, Managed = "Managed", - Process = process - }); + Process = process + }); } } } catch (Win32Exception) { @@ -68,9 +76,6 @@ namespace ILSpy.Debugger.UI if (this.RunningProcesses.SelectedItem == null) return; - // start attaching - var process = ((RunningProcess)this.RunningProcesses.SelectedItem).Process; - DebuggerService.CurrentDebugger.Attach(process); this.DialogResult = true; } diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 9ef31e8f3..ee68c872d 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -137,7 +137,7 @@ namespace Decompiler public TypeDeclaration CreateType(TypeDefinition typeDef) { - // create IL code mappings - used for debugger + // create CSharp code mappings - used for debugger if (!CSharpCodeMapping.SourceCodeMappings.ContainsKey(typeDef.FullName)) { CSharpCodeMapping.SourceCodeMappings.TryAdd(typeDef.FullName, new List()); } else { diff --git a/ICSharpCode.Decompiler/CodeMappings.cs b/ICSharpCode.Decompiler/CodeMappings.cs index d420248f1..72f799236 100644 --- a/ICSharpCode.Decompiler/CodeMappings.cs +++ b/ICSharpCode.Decompiler/CodeMappings.cs @@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler /// public sealed class MethodMapping { - public string TypeName { get; set; } + public TypeDefinition Type { get; set; } public uint MetadataToken { get; set; } @@ -100,7 +100,7 @@ namespace ICSharpCode.Decompiler if (mapping.Find(map => (int)map.MetadataToken == method.MetadataToken.ToInt32()) == null) { currentMethodMapping = new MethodMapping() { MetadataToken = (uint)method.MetadataToken.ToInt32(), - TypeName = method.DeclaringType.FullName, + Type = method.DeclaringType, MethodCodeMappings = new List() }; mapping.Add(currentMethodMapping); @@ -153,16 +153,16 @@ namespace ICSharpCode.Decompiler /// Code mappings storage. /// Metadata token. /// IL offset. - /// Type name. + /// Type definition. /// Line number. public static bool GetSourceCodeFromMetadataTokenAndOffset( this ConcurrentDictionary> codeMappings, uint token, int ilOffset, - out string typeName, + out TypeDefinition type, out int line) { - typeName = null; + type = null; line = 0; foreach (var typename in codeMappings.Keys) { @@ -182,7 +182,7 @@ namespace ICSharpCode.Decompiler } - typeName = typename; + type = mapping.Type; line = codeMapping.SourceCodeLine; return true; } diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 6e20cdfa0..ccc5cfa18 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -316,7 +316,7 @@ namespace ICSharpCode.Decompiler.Disassembler if (!ILCodeMapping.SourceCodeMappings.ContainsKey(type.FullName)) { ILCodeMapping.SourceCodeMappings.TryAdd(type.FullName, new List()); } else { - ILCodeMapping.SourceCodeMappings.Clear(); + ILCodeMapping.SourceCodeMappings[type.FullName].Clear(); } // start writing IL diff --git a/ILSpy.sln b/ILSpy.sln index a9faa853c..ff4c88aa1 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -# SharpDevelop 4.1.0.7302-alpha +# SharpDevelop 4.1.0.7322-alpha Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Debugger", "Debugger", "{1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B}" ProjectSection(SolutionItems) = postProject EndProjectSection @@ -108,4 +108,8 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A} = {1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B} + {1D18D788-F7EE-4585-A23B-34DC8EC63CB8} = {1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B} + EndGlobalSection EndGlobal diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index efab51c5d..a5c4c2e55 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -26,12 +26,15 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using System.Windows.Interop; using System.Windows.Media.Imaging; + using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.FlowAnalysis; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes.Analyzer; using ICSharpCode.TreeView; +using ILSpy.Debugger; using ILSpy.Debugger.AvalonEdit; using ILSpy.Debugger.Bookmarks; using ILSpy.Debugger.Services; @@ -304,22 +307,25 @@ namespace ICSharpCode.ILSpy } } - void OpenFiles(string[] fileNames) + void OpenFiles(string[] fileNames, bool focusNode = true) { - treeView.UnselectAll(); - SharpTreeNode lastNode = null; - foreach (string file in fileNames) { - var asm = assemblyList.OpenAssembly(file); - if (asm != null) { - var node = assemblyListTreeNode.FindAssemblyNode(asm); - if (node != null) { - treeView.SelectedItems.Add(node); - lastNode = node; + if (focusNode) { + treeView.UnselectAll(); + + SharpTreeNode lastNode = null; + foreach (string file in fileNames) { + var asm = assemblyList.OpenAssembly(file); + if (asm != null) { + var node = assemblyListTreeNode.FindAssemblyNode(asm); + if (node != null) { + treeView.SelectedItems.Add(node); + lastNode = node; + } } } + if (lastNode != null) + treeView.FocusNode(lastNode); } - if (lastNode != null) - treeView.FocusNode(lastNode); } void OpenFromGac_Click(object sender, RoutedEventArgs e) @@ -345,32 +351,77 @@ namespace ICSharpCode.ILSpy #region Debugger commands + [System.Runtime.InteropServices.DllImport("user32.dll")] + static extern bool SetWindowPos( + IntPtr hWnd, + IntPtr hWndInsertAfter, + int X, + int Y, + int cx, + int cy, + uint uFlags); + + const UInt32 SWP_NOSIZE = 0x0001; + const UInt32 SWP_NOMOVE = 0x0002; + + static readonly IntPtr HWND_BOTTOM = new IntPtr(1); + static readonly IntPtr HWND_TOP = new IntPtr(0); + + static void SendWpfWindowPos(Window window, IntPtr place) + { + var hWnd = new WindowInteropHelper(window).Handle; + SetWindowPos(hWnd, place, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + } + IDebugger CurrentDebugger { get { return DebuggerService.CurrentDebugger; } } + void StartDebugging(Process process) + { + CurrentDebugger.Attach(process); + EnableDebuggerUI(false); + CurrentDebugger.DebugStopped += OnDebugStopped; + CurrentDebugger.IsProcessRunningChanged += CurrentDebugger_IsProcessRunningChanged; + } + + void CurrentDebugger_IsProcessRunningChanged(object sender, EventArgs e) + { + if (CurrentDebugger.IsProcessRunning) { + //SendWpfWindowPos(this, HWND_BOTTOM); + return; + } + + // breakpoint was hit => bring to front the main window + SendWpfWindowPos(this, HWND_TOP); + this.Activate(); + + // jump to type & expand folding + if (CurrentLineBookmark.Instance != null) { + JumpToReference(CurrentLineBookmark.Instance.Type); + decompilerTextView.UnfoldAndScroll(CurrentLineBookmark.Instance.LineNumber); + } + } + void DebugExecutableExecuted(object sender, ExecutedRoutedEventArgs e) { OpenFileDialog dialog = new OpenFileDialog() { - Filter = ".NET Executable (*.exe) | *.exe", - RestoreDirectory = true, - DefaultExt = "exe" + Filter = ".NET Executable (*.exe) | *.exe", + RestoreDirectory = true, + DefaultExt = "exe" }; - var result = dialog.ShowDialog(); - if (result.HasValue && result.Value) { + if (dialog.ShowDialog() == true) { string fileName = dialog.FileName; // add it to references - OpenFiles(new [] { fileName }); + OpenFiles(new [] { fileName }, false); if (!CurrentDebugger.IsDebugging) { // execute the process - CurrentDebugger.Attach(Process.Start(fileName)); - EnableDebuggerUI(false); - CurrentDebugger.DebugStopped += OnDebugStopped; + this.StartDebugging(Process.Start(fileName)); } } } @@ -383,8 +434,7 @@ namespace ICSharpCode.ILSpy if (window.ShowDialog() == true) { if (CurrentDebugger.IsDebugging) { - EnableDebuggerUI(false); - CurrentDebugger.DebugStopped += OnDebugStopped; + this.StartDebugging(window.SelectedProcess); } } } @@ -393,7 +443,8 @@ namespace ICSharpCode.ILSpy void OnDebugStopped(object sender, EventArgs e) { EnableDebuggerUI(true); - DebuggerService.CurrentDebugger.DebugStopped -= OnDebugStopped; + CurrentDebugger.DebugStopped -= OnDebugStopped; + CurrentDebugger.IsProcessRunningChanged -= CurrentDebugger_IsProcessRunningChanged; } void DetachFromProcessExecuted(object sender, ExecutedRoutedEventArgs e) @@ -599,8 +650,7 @@ namespace ICSharpCode.ILSpy void LanguageComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { - DebuggerService.CurrentDebugger.Language = - sessionSettings.FilterSettings.Language.Name.StartsWith("IL") ? DecompiledLanguages.IL : DecompiledLanguages.CSharp; + DebuggedData.Language = sessionSettings.FilterSettings.Language.Name.StartsWith("IL") ? DecompiledLanguages.IL : DecompiledLanguages.CSharp; } } } \ No newline at end of file diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 8713690b5..748af1f36 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -34,6 +34,7 @@ using System.Windows.Threading; using System.Xml; using ICSharpCode.AvalonEdit; +using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Folding; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting.Xshd; @@ -42,6 +43,7 @@ using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.NRefactory.Documentation; using ILSpy.Debugger; using ILSpy.Debugger.AvalonEdit; +using ILSpy.Debugger.Bookmarks; using ILSpy.Debugger.ToolTips; using Microsoft.Win32; using TextEditorWeakEventManager = ILSpy.Debugger.AvalonEdit.TextEditorWeakEventManager; @@ -329,7 +331,7 @@ namespace ICSharpCode.ILSpy.TextView /// public void Decompile(ILSpy.Language language, IEnumerable treeNodes, DecompilationOptions options) { - DebuggedType.CurrentType = null; + DebuggedData.CurrentType = null; // Some actions like loading an assembly list cause several selection changes in the tree view, // and each of those will start a decompilation action. bool isDecompilationScheduled = this.nextDecompilationRun != null; @@ -390,6 +392,16 @@ namespace ICSharpCode.ILSpy.TextView finally { // repaint bookmarks iconMargin.InvalidateVisual(); + + // show the currentline marker + var bm = CurrentLineBookmark.Instance; + if (bm != null && DebuggedData.CurrentType != null) { + if (DebuggedData.CurrentType.FullName.Equals(bm.Type.FullName, StringComparison.OrdinalIgnoreCase)) { + DocumentLine line = textEditor.Document.GetLineByNumber(bm.LineNumber); + bm.Marker = bm.CreateMarker(textMarkerService, line.Offset, line.Length); + UnfoldAndScroll(bm.LineNumber); + } + } } }); } @@ -623,5 +635,27 @@ namespace ICSharpCode.ILSpy.TextView return text; } #endregion + + #region Unfold + public void UnfoldAndScroll(int lineNumber) + { + if (lineNumber <= 0 || lineNumber > textEditor.Document.LineCount) + return; + + var line = textEditor.Document.GetLineByNumber(lineNumber); + + // unfold + var foldings = foldingManager.GetFoldingsContaining(line.Offset); + if (foldings != null) { + foreach (var folding in foldings) { + if (folding.IsFolded) { + folding.IsFolded = false; + } + } + } + // scroll to + textEditor.ScrollTo(lineNumber, 0); + } + #endregion } } diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index 467f022a1..2ccdc337e 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -129,7 +129,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { - DebuggedType.CurrentType = type; + DebuggedData.CurrentType = type; language.DecompileType(type, output, options); }