Browse Source

implement GetMethodsFromDocumentPosition and set breakpoints in all methods (lambdas, etc.) in that location

pull/59/merge
Siegfried Pammer 12 years ago
parent
commit
9cce5d9369
  1. 3
      src/AddIns/Debugger/Debugger.Core/Breakpoint.cs
  2. 4
      src/AddIns/Debugger/Debugger.Core/Interop/CorSym.cs
  3. 18
      src/AddIns/Debugger/Debugger.Core/Interop/CorSymExtensionMethods.generated.cs
  4. 39
      src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs
  5. 3
      src/AddIns/Debugger/Debugger.Core/Process.cs
  6. 27
      src/AddIns/Debugger/Debugger.Core/StackFrame.cs
  7. 10
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs

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

@ -70,8 +70,7 @@ namespace Debugger
public void SetBreakpoint(Module module) public void SetBreakpoint(Module module)
{ {
foreach(var symbolSource in module.Process.Debugger.SymbolSources) { foreach(var symbolSource in module.Process.Debugger.SymbolSources) {
var seq = symbolSource.GetSequencePoint(module, this.FileName, this.Line, this.Column); foreach (var seq in symbolSource.GetSequencePoints(module, this.FileName, this.Line, this.Column)) {
if (seq != null) {
ICorDebugFunction corFunction = module.CorModule.GetFunctionFromToken(seq.MethodDefToken); ICorDebugFunction corFunction = module.CorModule.GetFunctionFromToken(seq.MethodDefToken);
ICorDebugFunctionBreakpoint corBreakpoint = corFunction.GetILCode().CreateBreakpoint((uint)seq.ILOffset); ICorDebugFunctionBreakpoint corBreakpoint = corFunction.GetILCode().CreateBreakpoint((uint)seq.ILOffset);
corBreakpoint.Activate(enabled ? 1 : 0); corBreakpoint.Activate(enabled ? 1 : 0);

4
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); public virtual extern ISymUnmanagedMethod __GetMethodFromDocumentPosition([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedDocument document, [In] uint line, [In] uint column);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] [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)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
public virtual extern void __GetMethodVersion([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedMethod pMethod, out int version); 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)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
void __GetSymbolStoreFileName([In] uint cchName, out uint pcchName, [Out] IntPtr szName); void __GetSymbolStoreFileName([In] uint cchName, out uint pcchName, [Out] IntPtr szName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] [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)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
void __GetDocumentVersion([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedDocument pDoc, out int version, out int pbCurrent); void __GetDocumentVersion([In, MarshalAs(UnmanagedType.Interface)] ISymUnmanagedDocument pDoc, out int version, out int pbCurrent);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]

18
src/AddIns/Debugger/Debugger.Core/Interop/CorSymExtensionMethods.generated.cs

@ -67,9 +67,14 @@ namespace Debugger.Interop.CorSym
return returnValue; 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) public static int GetMethodVersion(this CorSymReader_SxSClass instance, ISymUnmanagedMethod pMethod)
@ -485,9 +490,14 @@ namespace Debugger.Interop.CorSym
instance.__GetSymbolStoreFileName(cchName, out pcchName, szName); 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) public static void GetDocumentVersion(this ISymUnmanagedReader instance, ISymUnmanagedDocument pDoc, out int version, out int pbCurrent)

39
src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs

@ -72,9 +72,9 @@ namespace Debugger
/// <summary> Find sequence point by IL offset </summary> /// <summary> Find sequence point by IL offset </summary>
SequencePoint GetSequencePoint(IMethod method, int iloffset); SequencePoint GetSequencePoint(IMethod method, int iloffset);
/// <summary> Find sequence point by source code location </summary> /// <summary> Find sequence points by source code location. Might find multiple methods at one location (lambda expressions, etc.) </summary>
/// <remarks> Only source files corresponding to the given module are searched </remarks> /// <remarks> Only source files corresponding to the given module are searched </remarks>
SequencePoint GetSequencePoint(Module module, string filename, int line, int column); IEnumerable<SequencePoint> GetSequencePoints(Module module, string filename, int line, int column);
/// <summary> Get IL ranges that should be always stepped over by the debugger </summary> /// <summary> Get IL ranges that should be always stepped over by the debugger </summary>
/// <remarks> This is used for compiler generated code </remarks> /// <remarks> This is used for compiler generated code </remarks>
@ -190,14 +190,14 @@ namespace Debugger
return sequencePoint; return sequencePoint;
} }
public SequencePoint GetSequencePoint(Module module, string filename, int line, int column) public IEnumerable<SequencePoint> 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 ISymUnmanagedReader.GetDocument! It is broken if two files have the same name
// Do not use ISymUnmanagedMethod.GetOffset! It sometimes returns negative offset // Do not use ISymUnmanagedMethod.GetOffset! It sometimes returns negative offset
ISymUnmanagedReader symReader = module.SymReader; ISymUnmanagedReader symReader = module.SymReader;
if (symReader == null) if (symReader == null)
return null; // No symbols yield break; // No symbols
// Find ISymUnmanagedDocument which excactly matches the filename. // Find ISymUnmanagedDocument which excactly matches the filename.
var symDoc = module.SymDocuments.FirstOrDefault(d => string.Equals(filename, d.GetURL(), StringComparison.OrdinalIgnoreCase)); 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 // 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)); 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)); 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 { try {
uint validLine = symDoc.FindClosestLine((uint)line); 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 { } catch {
return null; //Not found yield break; //Not found
} }
var corFunction = module.CorModule.GetFunctionFromToken(symMethod.GetToken()); foreach (ISymUnmanagedMethod symMethod in symMethods) {
int codesize = (int)corFunction.GetILCode().GetSize(); var corFunction = module.CorModule.GetFunctionFromToken(symMethod.GetToken());
var seqPoints = symMethod.GetSequencePoints(codesize).Where(s => s.StartLine != 0xFEEFEE); int codesize = (int)corFunction.GetILCode().GetSize();
SequencePoint seqPoint = null; var seqPoints = symMethod.GetSequencePoints(codesize).Where(s => s.StartLine != 0xFEEFEE);
if (column != 0) { SequencePoint seqPoint = null;
seqPoint = seqPoints.FirstOrDefault(s => (s.StartLine < line || (s.StartLine == line && s.StartColumn <= column)) && if (column != 0) {
(line < s.EndLine || (line == s.EndLine && column <= s.EndColumn))); 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<ILRange> GetIgnoredILRanges(IMethod method) public IEnumerable<ILRange> GetIgnoredILRanges(IMethod method)

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

@ -436,8 +436,7 @@ namespace Debugger
foreach(var symbolSource in this.Debugger.SymbolSources) { foreach(var symbolSource in this.Debugger.SymbolSources) {
foreach(Module module in this.Modules) { foreach(Module module in this.Modules) {
// Note the we might get multiple matches // Note the we might get multiple matches
SequencePoint seq = symbolSource.GetSequencePoint(module, fileName, line, column); foreach (SequencePoint seq in symbolSource.GetSequencePoints(module, fileName, line, column)) {
if (seq != null) {
ICorDebugFunction corFunction = module.CorModule.GetFunctionFromToken(seq.MethodDefToken); ICorDebugFunction corFunction = module.CorModule.GetFunctionFromToken(seq.MethodDefToken);
ICorDebugFunctionBreakpoint corBreakpoint = corFunction.GetILCode().CreateBreakpoint((uint)seq.ILOffset); ICorDebugFunctionBreakpoint corBreakpoint = corFunction.GetILCode().CreateBreakpoint((uint)seq.ILOffset);
corBreakpoint.Activate(1); corBreakpoint.Activate(1);

27
src/AddIns/Debugger/Debugger.Core/StackFrame.cs

@ -198,21 +198,22 @@ namespace Debugger
this.Process.AssertPaused(); this.Process.AssertPaused();
foreach(var symbolSource in this.Process.Debugger.SymbolSources) { foreach(var symbolSource in this.Process.Debugger.SymbolSources) {
var seq = symbolSource.GetSequencePoint(this.Module, filename, line, column); foreach (var seq in symbolSource.GetSequencePoints(this.Module, filename, line, column)) {
if (seq != null && seq.MethodDefToken == this.MethodInfo.GetMetadataToken()) { if (seq.MethodDefToken == this.MethodInfo.GetMetadataToken()) {
try { try {
if (dryRun) { if (dryRun) {
CorILFrame.CanSetIP((uint)seq.ILOffset); CorILFrame.CanSetIP((uint)seq.ILOffset);
} else { } else {
CorILFrame.SetIP((uint)seq.ILOffset); CorILFrame.SetIP((uint)seq.ILOffset);
// Invalidates all frames and chains for the current thread // Invalidates all frames and chains for the current thread
this.Process.NotifyResumed(DebuggeeStateAction.Keep); this.Process.NotifyResumed(DebuggeeStateAction.Keep);
this.Process.NotifyPaused(); this.Process.NotifyPaused();
}
} catch {
return false;
} }
} catch { return true;
return false;
} }
return true;
} }
} }
return false; return false;

10
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpySymbolSource.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -57,13 +58,13 @@ namespace ICSharpCode.ILSpyAddIn
return null; return null;
} }
public Debugger.SequencePoint GetSequencePoint(Module module, string filename, int line, int column) public IEnumerable<Debugger.SequencePoint> GetSequencePoints(Module module, string filename, int line, int column)
{ {
var content = DecompiledViewContent.Get(new FileName(filename)); var content = DecompiledViewContent.Get(new FileName(filename));
if (content == null) if (content == null)
return null; yield break;
if (!FileUtility.IsEqualFileName(module.FullPath, content.AssemblyFile)) if (!FileUtility.IsEqualFileName(module.FullPath, content.AssemblyFile))
return null; yield break;
TextLocation loc = new TextLocation(line, column); TextLocation loc = new TextLocation(line, column);
foreach(var symbols in content.DebugSymbols.Values.Where(s => s.StartLocation <= loc && loc <= s.EndLocation)) { 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) if (seq == null)
seq = symbols.SequencePoints.FirstOrDefault(p => line <= p.StartLocation.Line); seq = symbols.SequencePoints.FirstOrDefault(p => line <= p.StartLocation.Line);
if (seq != null) if (seq != null)
return seq.ToDebugger(symbols, content.VirtualFileName); yield return seq.ToDebugger(symbols, content.VirtualFileName);
} }
return null;
} }
public IEnumerable<ILRange> GetIgnoredILRanges(IMethod method) public IEnumerable<ILRange> GetIgnoredILRanges(IMethod method)

Loading…
Cancel
Save