From e152b747ddd56a604480379d5762df7ffc22f398 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 1 Aug 2014 16:57:29 +0200 Subject: [PATCH] fix calculation of sequence points for breakpoints in pdb files --- .../Debugger/Debugger.Core/Breakpoint.cs | 2 +- .../Debugger/Debugger.Core/PdbSymbolSource.cs | 58 +++++++++++++++---- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs b/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs index 2e170818cc..f6b1e8a034 100644 --- a/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs +++ b/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs @@ -84,7 +84,7 @@ namespace Debugger public void SetBreakpoint(Module module) { - foreach(var symbolSource in module.Process.Debugger.SymbolSources) { + foreach (var symbolSource in module.Process.Debugger.SymbolSources) { foreach (var seq in symbolSource.GetSequencePoints(module, this.FileName, this.Line, this.Column)) { ICorDebugFunction corFunction = module.CorModule.GetFunctionFromToken(seq.MethodDefToken); ICorDebugFunctionBreakpoint corBreakpoint = corFunction.GetILCode().CreateBreakpoint((uint)seq.ILOffset); diff --git a/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs b/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs index 5715fa7443..aad518a400 100644 --- a/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs +++ b/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs @@ -48,6 +48,14 @@ namespace Debugger this.StartLine, this.StartColumn, this.EndLine, this.EndColumn); } + + public bool ContainsLocation(int line, int column = 0) + { + if (column == 0) + return line >= StartLine && line <= EndLine; + return (StartLine < line || (StartLine == line && StartColumn <= column)) + && (line < EndLine || (line == EndLine && column <= EndColumn)); + } } public struct ILRange @@ -185,14 +193,14 @@ namespace Debugger var realSeqPoints = sequencePoints.Where(p => p.StartLine != 0xFEEFEE); // Find point for which (ilstart <= iloffset < ilend) or fallback to the next valid sequence point - var sequencePoint = realSeqPoints.FirstOrDefault(p => p.ILRanges.Any(r => r.From <= iloffset && iloffset < r.To)) ?? - realSeqPoints.FirstOrDefault(p => iloffset <= p.ILOffset); + var sequencePoint = realSeqPoints.FirstOrDefault(p => p.ILRanges.Any(r => r.From <= iloffset && iloffset < r.To)) + ?? realSeqPoints.FirstOrDefault(p => iloffset <= p.ILOffset); if (sequencePoint != null) { // VB.NET sometimes produces temporary files which it then deletes // (eg 17d14f5c-a337-4978-8281-53493378c1071.vb) string name = Path.GetFileName(sequencePoint.Filename); - if (name.Length == 40 && name.EndsWith(".vb")) { + if (name.Length == 40 && name.EndsWith(".vb", StringComparison.OrdinalIgnoreCase)) { if (name.Substring(0, name.Length - 3).All(c => ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') || (c == '-'))) { return null; } @@ -232,19 +240,47 @@ namespace Debugger foreach (ISymUnmanagedMethod symMethod in symMethods) { var corFunction = module.CorModule.GetFunctionFromToken(symMethod.GetToken()); - int codesize = (int)corFunction.GetILCode().GetSize(); - var seqPoints = symMethod.GetSequencePoints(codesize).Where(s => s.StartLine != 0xFEEFEE); - SequencePoint seqPoint = null; - if (column != 0) { - seqPoint = seqPoints.FirstOrDefault(s => (s.StartLine < line || (s.StartLine == line && s.StartColumn <= column)) && - (line < s.EndLine || (line == s.EndLine && column <= s.EndColumn))); - } - seqPoint = seqPoint ?? seqPoints.FirstOrDefault(s => line <= s.StartLine); + int codeSize = (int)corFunction.GetILCode().GetSize(); + var seqPoints = symMethod.GetSequencePoints(codeSize).Where(s => s.StartLine != 0xFEEFEE).OrderBy(s => s.StartLine).ToArray(); + SequencePoint seqPoint = FindNearestMatchingSequencePoint(seqPoints, line, column); if (seqPoint != null) yield return seqPoint; } } + SequencePoint FindNearestMatchingSequencePoint(SequencePoint[] seqPoints, int line, int column) + { + // value is nearest offset in lines; + // negative numbers: (Start|End)Line is same as line, value is offset in columns + int nearestOffset = 0; + SequencePoint bestMatch = null; + for (int i = 0; i < seqPoints.Length; i++) { + var s = seqPoints[i]; + if (s.ContainsLocation(line, column)) + return seqPoints[i]; + + if (bestMatch == null) { + bestMatch = s; + nearestOffset = GetOffsetValue(s, line, column); + } else { + int newOffset = GetOffsetValue(s, line, column); + if ((newOffset < 0 && nearestOffset < 0 && newOffset > nearestOffset) || (newOffset < nearestOffset)) { + bestMatch = s; + nearestOffset = newOffset; + } + } + } + + return bestMatch; + } + + static int GetOffsetValue(SequencePoint s, int line, int column) + { + if (line == s.StartLine || s.EndLine == line) + return -Math.Min(Math.Abs(s.StartColumn - column), Math.Abs(s.EndColumn - column)); + return Math.Min(Math.Abs(s.StartLine - line), Math.Abs(s.EndLine - line)); + } + public IEnumerable GetIgnoredILRanges(IMethod method) { var symMethod = method.GetSymMethod();