diff --git a/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs b/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs index 05b0c5ed99..f7be6faa83 100644 --- a/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs +++ b/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs @@ -70,8 +70,7 @@ namespace Debugger public void SetBreakpoint(Module module) { foreach(var symbolSource in module.Process.Debugger.SymbolSources) { - var seq = symbolSource.GetSequencePoint(module, this.FileName, this.Line, this.Column); - if (seq != null) { + 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); corBreakpoint.Activate(enabled ? 1 : 0); diff --git a/src/AddIns/Debugger/Debugger.Core/Interop/CorSym.cs b/src/AddIns/Debugger/Debugger.Core/Interop/CorSym.cs index 738bcd4ffb..4d3ae9c3f3 100644 --- a/src/AddIns/Debugger/Debugger.Core/Interop/CorSym.cs +++ b/src/AddIns/Debugger/Debugger.Core/Interop/CorSym.cs @@ -77,7 +77,7 @@ namespace Debugger.Interop.CorSym public virtual extern ISymUnmanagedMethod __GetMethodFromDocumentPosition([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedDocument document, [In] uint line, [In] uint column); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] - public virtual extern void __GetMethodsFromDocumentPosition([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedDocument document, [In] uint line, [In] uint column, [In] uint cMethod, out uint pcMethod, [Out] IntPtr pRetVal); + public virtual extern void __GetMethodsFromDocumentPosition([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedDocument document, [In] uint line, [In] uint column, [In] uint cMethod, out uint pcMethod, [Out, MarshalAs(UnmanagedType.LPArray)] ISymUnmanagedMethod[] pRetVal); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] public virtual extern void __GetMethodVersion([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedMethod pMethod, out int version); @@ -332,7 +332,7 @@ namespace Debugger.Interop.CorSym [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] void __GetSymbolStoreFileName([In] uint cchName, out uint pcchName, [Out] IntPtr szName); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] - void __GetMethodsFromDocumentPosition([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedDocument document, [In] uint line, [In] uint column, [In] uint cMethod, out uint pcMethod, [Out] IntPtr pRetVal); + void __GetMethodsFromDocumentPosition([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedDocument document, [In] uint line, [In] uint column, [In] uint cMethod, out uint pcMethod, [Out, MarshalAs(UnmanagedType.LPArray)] ISymUnmanagedMethod[] pRetVal); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] void __GetDocumentVersion([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedDocument pDoc, out int version, out int pbCurrent); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] diff --git a/src/AddIns/Debugger/Debugger.Core/Interop/CorSymExtensionMethods.generated.cs b/src/AddIns/Debugger/Debugger.Core/Interop/CorSymExtensionMethods.generated.cs index 137e8dd2ee..48e610beca 100644 --- a/src/AddIns/Debugger/Debugger.Core/Interop/CorSymExtensionMethods.generated.cs +++ b/src/AddIns/Debugger/Debugger.Core/Interop/CorSymExtensionMethods.generated.cs @@ -67,9 +67,14 @@ namespace Debugger.Interop.CorSym return returnValue; } - public static void GetMethodsFromDocumentPosition(this CorSymReader_SxSClass instance, ISymUnmanagedDocument document, uint line, uint column, uint cMethod, out uint pcMethod, IntPtr pRetVal) + public static ISymUnmanagedMethod[] GetMethodsFromDocumentPosition(this CorSymReader_SxSClass instance, ISymUnmanagedDocument document, uint line, uint column) { - instance.__GetMethodsFromDocumentPosition(document, line, column, cMethod, out pcMethod, pRetVal); + uint count; + instance.__GetMethodsFromDocumentPosition(document, line, column, 0, out count, new ISymUnmanagedMethod[0]); + var methods = new ISymUnmanagedMethod[count]; + instance.__GetMethodsFromDocumentPosition(document, line, column, count, out count, methods); + ProcessOutParameter(methods); + return methods; } public static int GetMethodVersion(this CorSymReader_SxSClass instance, ISymUnmanagedMethod pMethod) @@ -485,9 +490,14 @@ namespace Debugger.Interop.CorSym instance.__GetSymbolStoreFileName(cchName, out pcchName, szName); } - public static void GetMethodsFromDocumentPosition(this ISymUnmanagedReader instance, ISymUnmanagedDocument document, uint line, uint column, uint cMethod, out uint pcMethod, IntPtr pRetVal) + public static ISymUnmanagedMethod[] GetMethodsFromDocumentPosition(this ISymUnmanagedReader instance, ISymUnmanagedDocument document, uint line, uint column) { - instance.__GetMethodsFromDocumentPosition(document, line, column, cMethod, out pcMethod, pRetVal); + uint count; + instance.__GetMethodsFromDocumentPosition(document, line, column, 0, out count, new ISymUnmanagedMethod[0]); + var methods = new ISymUnmanagedMethod[count]; + instance.__GetMethodsFromDocumentPosition(document, line, column, count, out count, methods); + ProcessOutParameter(methods); + return methods; } public static void GetDocumentVersion(this ISymUnmanagedReader instance, ISymUnmanagedDocument pDoc, out int version, out int pbCurrent) diff --git a/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs b/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs index c8d7aa7fa4..e70eaf9fe6 100644 --- a/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs +++ b/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs @@ -72,9 +72,9 @@ namespace Debugger /// Find sequence point by IL offset SequencePoint GetSequencePoint(IMethod method, int iloffset); - /// Find sequence point by source code location + /// Find sequence points by source code location. Might find multiple methods at one location (lambda expressions, etc.) /// Only source files corresponding to the given module are searched - SequencePoint GetSequencePoint(Module module, string filename, int line, int column); + IEnumerable GetSequencePoints(Module module, string filename, int line, int column); /// Get IL ranges that should be always stepped over by the debugger /// This is used for compiler generated code @@ -190,14 +190,14 @@ namespace Debugger return sequencePoint; } - public SequencePoint GetSequencePoint(Module module, string filename, int line, int column) + public IEnumerable GetSequencePoints(Module module, string filename, int line, int column) { // Do not use ISymUnmanagedReader.GetDocument! It is broken if two files have the same name // Do not use ISymUnmanagedMethod.GetOffset! It sometimes returns negative offset ISymUnmanagedReader symReader = module.SymReader; if (symReader == null) - return null; // No symbols + yield break; // No symbols // Find ISymUnmanagedDocument which excactly matches the filename. var symDoc = module.SymDocuments.FirstOrDefault(d => string.Equals(filename, d.GetURL(), StringComparison.OrdinalIgnoreCase)); @@ -205,26 +205,31 @@ namespace Debugger // Find the file even if the symbol is relative or if the file was moved var symDocs = module.SymDocuments.Where(d => string.Equals(Path.GetFileName(filename), Path.GetFileName(d.GetURL()), StringComparison.OrdinalIgnoreCase)); symDoc = symDoc ?? symDocs.FirstOrDefault(d => string.Equals(GetSourceCodePath(module.Process, d.GetURL()), filename, StringComparison.OrdinalIgnoreCase)); - if (symDoc == null) return null; // Document not found + if (symDoc == null) yield break; // Document not found - ISymUnmanagedMethod symMethod; + ISymUnmanagedMethod symMethod2; + ISymUnmanagedMethod[] symMethods; try { uint validLine = symDoc.FindClosestLine((uint)line); - symMethod = symReader.GetMethodFromDocumentPosition(symDoc, (uint)validLine, (uint)column); + symMethods = symReader.GetMethodsFromDocumentPosition(symDoc, validLine, (uint)column); + symMethod2 = symReader.GetMethodFromDocumentPosition(symDoc, (uint)validLine, (uint)column); } catch { - return null; //Not found + yield break; //Not found } - 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))); + 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); + if (seqPoint != null) + yield return seqPoint; } - seqPoint = seqPoint ?? seqPoints.FirstOrDefault(s => line <= s.StartLine); - return seqPoint; } public IEnumerable GetIgnoredILRanges(IMethod method) diff --git a/src/AddIns/Debugger/Debugger.Core/Process.cs b/src/AddIns/Debugger/Debugger.Core/Process.cs index ba27dccff5..934481da01 100644 --- a/src/AddIns/Debugger/Debugger.Core/Process.cs +++ b/src/AddIns/Debugger/Debugger.Core/Process.cs @@ -436,8 +436,7 @@ namespace Debugger foreach(var symbolSource in this.Debugger.SymbolSources) { foreach(Module module in this.Modules) { // Note the we might get multiple matches - SequencePoint seq = symbolSource.GetSequencePoint(module, fileName, line, column); - if (seq != null) { + foreach (SequencePoint seq in symbolSource.GetSequencePoints(module, fileName, line, column)) { ICorDebugFunction corFunction = module.CorModule.GetFunctionFromToken(seq.MethodDefToken); ICorDebugFunctionBreakpoint corBreakpoint = corFunction.GetILCode().CreateBreakpoint((uint)seq.ILOffset); corBreakpoint.Activate(1); diff --git a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs index 298553d136..7f1732183e 100644 --- a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs +++ b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs @@ -198,21 +198,22 @@ namespace Debugger this.Process.AssertPaused(); foreach(var symbolSource in this.Process.Debugger.SymbolSources) { - var seq = symbolSource.GetSequencePoint(this.Module, filename, line, column); - if (seq != null && seq.MethodDefToken == this.MethodInfo.GetMetadataToken()) { - try { - if (dryRun) { - CorILFrame.CanSetIP((uint)seq.ILOffset); - } else { - CorILFrame.SetIP((uint)seq.ILOffset); - // Invalidates all frames and chains for the current thread - this.Process.NotifyResumed(DebuggeeStateAction.Keep); - this.Process.NotifyPaused(); + foreach (var seq in symbolSource.GetSequencePoints(this.Module, filename, line, column)) { + if (seq.MethodDefToken == this.MethodInfo.GetMetadataToken()) { + try { + if (dryRun) { + CorILFrame.CanSetIP((uint)seq.ILOffset); + } else { + CorILFrame.SetIP((uint)seq.ILOffset); + // Invalidates all frames and chains for the current thread + this.Process.NotifyResumed(DebuggeeStateAction.Keep); + this.Process.NotifyPaused(); + } + } catch { + return false; } - } catch { - return false; + return true; } - return true; } } return false; diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs index 738666b64d..5c82063f83 100644 --- a/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs +++ b/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -57,13 +58,13 @@ namespace ICSharpCode.ILSpyAddIn return null; } - public Debugger.SequencePoint GetSequencePoint(Module module, string filename, int line, int column) + public IEnumerable GetSequencePoints(Module module, string filename, int line, int column) { var content = DecompiledViewContent.Get(new FileName(filename)); if (content == null) - return null; + yield break; if (!FileUtility.IsEqualFileName(module.FullPath, content.AssemblyFile)) - return null; + yield break; TextLocation loc = new TextLocation(line, column); foreach(var symbols in content.DebugSymbols.Values.Where(s => s.StartLocation <= loc && loc <= s.EndLocation)) { @@ -73,9 +74,8 @@ namespace ICSharpCode.ILSpyAddIn if (seq == null) seq = symbols.SequencePoints.FirstOrDefault(p => line <= p.StartLocation.Line); if (seq != null) - return seq.ToDebugger(symbols, content.VirtualFileName); + yield return seq.ToDebugger(symbols, content.VirtualFileName); } - return null; } public IEnumerable GetIgnoredILRanges(IMethod method)