From 052ea0565f11d418764b645c94e865b58d40d7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Tue, 5 Feb 2013 23:42:02 +0000 Subject: [PATCH 1/4] Make ILRange immutable struct --- .../Ast/AstMethodBodyBuilder.cs | 4 +- .../Ast/TextOutputFormatter.cs | 2 +- .../ICSharpCode.Decompiler/CodeMappings.cs | 8 ++- .../Disassembler/MethodBodyDisassembler.cs | 4 +- .../ILAst/ILAstBuilder.cs | 2 +- .../ILAst/ILAstTypes.cs | 52 +++++++++++-------- 6 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 36066b1a43..fae41f6860 100644 --- a/src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -147,7 +147,7 @@ namespace ICSharpCode.Decompiler.Ast if (node is ILLabel) { yield return new Ast.LabelStatement { Label = ((ILLabel)node).Name }; } else if (node is ILExpression) { - List ilRanges = ILRange.OrderAndJoint(node.GetSelfAndChildrenRecursive().SelectMany(e => e.ILRanges)); + List ilRanges = ILRange.OrderAndJoin(node.GetSelfAndChildrenRecursive().SelectMany(e => e.ILRanges)); AstNode codeExpr = TransformExpression((ILExpression)node); if (codeExpr != null) { codeExpr = codeExpr.WithAnnotation(ilRanges); @@ -253,7 +253,7 @@ namespace ICSharpCode.Decompiler.Ast Expression astExpr = node as Expression; // get IL ranges - used in debugger - List ilRanges = ILRange.OrderAndJoint(expr.GetSelfAndChildrenRecursive().SelectMany(e => e.ILRanges)); + List ilRanges = ILRange.OrderAndJoin(expr.GetSelfAndChildrenRecursive().SelectMany(e => e.ILRanges)); AstNode result; if (astExpr != null) diff --git a/src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs b/src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs index 6fa539280a..7155a67b9e 100644 --- a/src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs +++ b/src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs @@ -307,7 +307,7 @@ namespace ICSharpCode.Decompiler.Ast if (symbolsStack.Count > 0 && ranges != null && ranges.Count > 0) { symbolsStack.Peek().SequencePoints.Add( new SequencePoint() { - ILRanges = ranges, + ILRanges = ILRange.OrderAndJoin(ranges).ToArray(), StartLocation = startLocation, EndLocation = output.Location }); diff --git a/src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs b/src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs index c6c0f06571..b2dcab8621 100644 --- a/src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs +++ b/src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs @@ -44,8 +44,14 @@ namespace ICSharpCode.Decompiler public class SequencePoint { - public List ILRanges { get; set; } + public ILRange[] ILRanges { get; set; } public TextLocation StartLocation { get; set; } public TextLocation EndLocation { get; set; } + public int ILOffset { get { return this.ILRanges[0].From; } } + + public override string ToString() + { + return string.Join(" ", this.ILRanges) + " " + this.StartLocation + "-" + this.EndLocation; + } } } diff --git a/src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs index 52c2772271..a45a718207 100644 --- a/src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs +++ b/src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs @@ -94,7 +94,7 @@ namespace ICSharpCode.Decompiler.Disassembler new SequencePoint() { StartLocation = output.Location, EndLocation = output.Location, - ILRanges = new List() { new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset } } + ILRanges = new ILRange[] { new ILRange(inst.Offset, inst.Next == null ? method.Body.CodeSize : inst.Next.Offset) } }); } @@ -198,7 +198,7 @@ namespace ICSharpCode.Decompiler.Disassembler new SequencePoint() { StartLocation = startLocation, EndLocation = output.Location, - ILRanges = new List() { new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset } } + ILRanges = new ILRange[] { new ILRange(inst.Offset, inst.Next == null ? codeSize : inst.Next.Offset) } }); } diff --git a/src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index cbdc5d771f..da8c6c6beb 100644 --- a/src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ b/src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -743,7 +743,7 @@ namespace ICSharpCode.Decompiler.ILAst // Convert stack-based IL code to ILAst tree foreach(ByteCode byteCode in body) { - ILRange ilRange = new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset }; + ILRange ilRange = new ILRange(byteCode.Offset, byteCode.EndOffset); if (byteCode.StackBefore == null) { // Unreachable code diff --git a/src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs index 4f3930fcdd..9cd42a14fc 100644 --- a/src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs +++ b/src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs @@ -221,37 +221,43 @@ namespace ICSharpCode.Decompiler.ILAst } } - public class ILRange + public struct ILRange { - public int From; - public int To; // Exlusive + public readonly int From; + public readonly int To; // Exlusive + + public ILRange(int @from, int to) + { + this.From = @from; + this.To = to; + } public override string ToString() { - return string.Format("{0}-{1}", From.ToString("X"), To.ToString("X")); + return string.Format("{0:X2}-{1:X2}", From, To); } - public static List OrderAndJoint(IEnumerable input) + public static List OrderAndJoin(IEnumerable input) { if (input == null) throw new ArgumentNullException("Input is null!"); - List ranges = input.Where(r => r != null).OrderBy(r => r.From).ToList(); - for (int i = 0; i < ranges.Count - 1;) { - ILRange curr = ranges[i]; - ILRange next = ranges[i + 1]; - // Merge consequtive ranges if they intersect - if (curr.From <= next.From && next.From <= curr.To) { - curr.To = Math.Max(curr.To, next.To); - ranges.RemoveAt(i + 1); - } else { - i++; + List result = new List(); + foreach(ILRange curr in input.OrderBy(r => r.From)) { + if (result.Count > 0) { + // Merge consequtive ranges if possible + ILRange last = result[result.Count - 1]; + if (curr.From <= last.To) { + result[result.Count - 1] = new ILRange(last.From, Math.Max(last.To, curr.To)); + continue; + } } + result.Add(curr); } - return ranges; + return result; } - public static IEnumerable Invert(IEnumerable input, int codeSize) + public static List Invert(IEnumerable input, int codeSize) { if (input == null) throw new ArgumentNullException("Input is null!"); @@ -259,23 +265,25 @@ namespace ICSharpCode.Decompiler.ILAst if (codeSize <= 0) throw new ArgumentException("Code size must be grater than 0"); - var ordered = OrderAndJoint(input); + List ordered = OrderAndJoin(input); + List result = new List(ordered.Count + 1); if (ordered.Count == 0) { - yield return new ILRange() { From = 0, To = codeSize }; + result.Add(new ILRange(0, codeSize)); } else { // Gap before the first element if (ordered.First().From != 0) - yield return new ILRange() { From = 0, To = ordered.First().From }; + result.Add(new ILRange(0, ordered.First().From)); // Gaps between elements for (int i = 0; i < ordered.Count - 1; i++) - yield return new ILRange() { From = ordered[i].To, To = ordered[i + 1].From }; + result.Add(new ILRange(ordered[i].To, ordered[i + 1].From)); // Gap after the last element Debug.Assert(ordered.Last().To <= codeSize); if (ordered.Last().To != codeSize) - yield return new ILRange() { From = ordered.Last().To, To = codeSize }; + result.Add(new ILRange(ordered.Last().To, codeSize)); } + return result; } } From 333e3644b760060d34d92245b93ed6ce9876de83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Tue, 5 Feb 2013 23:46:10 +0000 Subject: [PATCH 2/4] Slightly improve mapping from IL to source code --- src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs | 10 ++++++++-- src/AddIns/Debugger/Debugger.Core/StackFrame.cs | 1 + .../DisplayBindings/ILSpyAddIn/DebuggerTextOutput.cs | 2 ++ .../DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs | 9 +++++++-- .../ILSpyAddIn/ViewContent/DecompiledViewContent.cs | 4 ++++ 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs b/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs index ebb6468f94..9711582ab7 100644 --- a/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs +++ b/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs @@ -28,10 +28,11 @@ namespace Debugger public override string ToString() { - return string.Format("{0}:{1},{2}-{3},{4}", + return string.Format("{0}:{1},{2}-{3},{4} IL:{5}", Path.GetFileName(this.Filename ?? string.Empty), this.StartLine, this.StartColumn, - this.EndLine, this.EndColumn); + this.EndLine, this.EndColumn, + string.Join(" ", this.ILRanges)); } } @@ -45,6 +46,11 @@ namespace Debugger this.From = from; this.To = to; } + + public override string ToString() + { + return string.Format("{0:X2}-{1:X2}", From, To); + } } public class ILLocalVariable diff --git a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs index 35acdd82e7..105259272e 100644 --- a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs +++ b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs @@ -156,6 +156,7 @@ namespace Debugger List stepRanges = new List(); var seq = this.Module.SymbolSource.GetSequencePoint(this.MethodInfo, this.IP); if (seq != null) { + Process.TraceMessage("Step over: {0}", seq); stepRanges.AddRange(seq.ILRanges); stepRanges.AddRange(this.Module.SymbolSource.GetIgnoredILRanges(this.MethodInfo)); } diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerTextOutput.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerTextOutput.cs index 5dce8fa0b0..a8e99300e5 100644 --- a/src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerTextOutput.cs +++ b/src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerTextOutput.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using ICSharpCode.Core; using ICSharpCode.Decompiler; using Mono.Cecil; @@ -66,6 +67,7 @@ namespace ICSharpCode.ILSpyAddIn public void AddDebugSymbols(MethodDebugSymbols methodDebugSymbols) { var id = XmlDocKeyProvider.GetKey(methodDebugSymbols.CecilMethod); + methodDebugSymbols.SequencePoints = methodDebugSymbols.SequencePoints.OrderBy(s => s.ILOffset).ToList(); this.DebugSymbols.Add(id, methodDebugSymbols); output.AddDebugSymbols(methodDebugSymbols); } diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs index f35d64a4d9..82244b0995 100644 --- a/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs +++ b/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs @@ -15,7 +15,8 @@ namespace ICSharpCode.ILSpyAddIn { public static MethodDebugSymbols GetSymbols(IMethod method) { - var id = IdStringProvider.GetIdString(method); + // Use the non-specialised method definition to look up decompiled symbols + var id = IdStringProvider.GetIdString(method.MemberDefinition); var content = DecompiledViewContent.Get(method); if (content != null && content.DebugSymbols.ContainsKey(id)) { return content.DebugSymbols[id]; @@ -31,7 +32,11 @@ namespace ICSharpCode.ILSpyAddIn var content = DecompiledViewContent.Get(method); var seq = symbols.SequencePoints.FirstOrDefault(p => p.ILRanges.Any(r => r.From <= iloffset && iloffset < r.To)); - return seq.ToDebugger(symbols, content.VirtualFileName); + if (seq == null) + seq = symbols.SequencePoints.FirstOrDefault(p => iloffset <= p.ILOffset); + if (seq != null) + return seq.ToDebugger(symbols, content.VirtualFileName); + return null; } public Debugger.SequencePoint GetSequencePoint(Module module, string filename, int line, int column) diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs index 327d1db451..287d0e57e6 100644 --- a/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs +++ b/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs @@ -13,6 +13,7 @@ using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.Core; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Ast; +using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.NRefactory.Documentation; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.ILSpyAddIn.LaunchILSpy; @@ -235,6 +236,9 @@ namespace ICSharpCode.ILSpyAddIn astBuilder.AddType(typeDefinition); astBuilder.GenerateCode(textOutput); + // ReflectionDisassembler disasm = new ReflectionDisassembler(textOutput, true, cancellationToken); + // disasm.DisassembleType(typeDefinition); + // save decompilation data memberLocations = textOutput.MemberLocations; this.DebugSymbols = textOutput.DebugSymbols; From ea026ca4013f9750ca5b09bfe84be70a21df312c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Tue, 5 Feb 2013 23:48:27 +0000 Subject: [PATCH 3/4] Fix CurrentLineBookmark for whole-line and multi-line sequence points --- .../Src/Services/Debugger/CurrentLineBookmark.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Main/Base/Project/Src/Services/Debugger/CurrentLineBookmark.cs b/src/Main/Base/Project/Src/Services/Debugger/CurrentLineBookmark.cs index c425b17924..24ecebad61 100644 --- a/src/Main/Base/Project/Src/Services/Debugger/CurrentLineBookmark.cs +++ b/src/Main/Base/Project/Src/Services/Debugger/CurrentLineBookmark.cs @@ -52,9 +52,6 @@ namespace ICSharpCode.SharpDevelop.Debugging if (startColumn < 1) startColumn = 1; - IDocumentLine line = document.GetLineByNumber(startLine); - if (endColumn < 1 || endColumn > line.Length) - endColumn = line.Length; instance = new CurrentLineBookmark(); instance.Location = new TextLocation(startLine, startColumn); instance.FileName = fileName; @@ -96,8 +93,11 @@ namespace ICSharpCode.SharpDevelop.Debugging protected override ITextMarker CreateMarker(ITextMarkerService markerService) { - IDocumentLine line = this.Document.GetLineByNumber(startLine); - ITextMarker marker = markerService.Create(line.Offset + startColumn - 1, Math.Max(endColumn - startColumn, 1)); + IDocumentLine sLine = this.Document.GetLineByNumber(startLine); + IDocumentLine eLine = this.Document.GetLineByNumber(endLine); + int sOffset = Math.Min(sLine.Offset + startColumn - 1, sLine.EndOffset); + int eOffset = Math.Min(eLine.Offset + endColumn - 1, eLine.EndOffset); + ITextMarker marker = markerService.Create(sOffset, Math.Max(eOffset - sOffset, 1)); IHighlighter highlighter = this.Document.GetService(typeof(IHighlighter)) as IHighlighter; marker.BackgroundColor = DefaultBackground; marker.ForegroundColor = DefaultForeground; From 1e902d13aca457318a4e3a4813a0659d7031a55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Wed, 6 Feb 2013 00:47:47 +0000 Subject: [PATCH 4/4] Fix unit tests --- src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs | 5 ++--- src/AddIns/Debugger/Debugger.Core/StackFrame.cs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs b/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs index 9711582ab7..578fdc4fe6 100644 --- a/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs +++ b/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs @@ -28,11 +28,10 @@ namespace Debugger public override string ToString() { - return string.Format("{0}:{1},{2}-{3},{4} IL:{5}", + return string.Format("{0}:{1},{2}-{3},{4}", Path.GetFileName(this.Filename ?? string.Empty), this.StartLine, this.StartColumn, - this.EndLine, this.EndColumn, - string.Join(" ", this.ILRanges)); + this.EndLine, this.EndColumn); } } diff --git a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs index 105259272e..4780446a78 100644 --- a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs +++ b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs @@ -156,7 +156,7 @@ namespace Debugger List stepRanges = new List(); var seq = this.Module.SymbolSource.GetSequencePoint(this.MethodInfo, this.IP); if (seq != null) { - Process.TraceMessage("Step over: {0}", seq); + Process.TraceMessage("Step over: {0} IL:{1}", seq, string.Join(" ", seq.ILRanges)); stepRanges.AddRange(seq.ILRanges); stepRanges.AddRange(this.Module.SymbolSource.GetIgnoredILRanges(this.MethodInfo)); }