From c2855d5a65fec1883653f818294a8340dee10e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Sat, 2 Feb 2013 18:46:27 +0000 Subject: [PATCH] Refactored handling of debug symbols --- .../Debugger.AddIn/Service/WindowsDebugger.cs | 13 +- .../Debugger/Debugger.Core/Breakpoint.cs | 28 +- .../Debugger.Core/Debugger.Core.csproj | 2 +- .../Interop/CorSymExtensionMethods.cs | 39 +- .../Debugger/Debugger.Core/LocalVariable.cs | 125 +++---- .../Debugger/Debugger.Core/NDebugger.cs | 2 +- .../Debugger/Debugger.Core/PdbSymbolSource.cs | 256 +++++++++++++ src/AddIns/Debugger/Debugger.Core/Process.cs | 52 +-- .../Debugger.Core/SourcecodeSegment.cs | 339 ------------------ .../Debugger/Debugger.Core/StackFrame.cs | 105 ++---- src/AddIns/Debugger/Debugger.Core/Thread.cs | 2 +- .../Debugger.Core/TypeSystemExtensions.cs | 2 +- .../Debugger.Tests/Tests/Breakpoint_Tests.cs | 24 +- .../Tests/ControlFlow_Stepping.cs | 2 +- .../Debugger.Tests/Tests/StackFrame_SetIP.cs | 8 +- 15 files changed, 422 insertions(+), 577 deletions(-) create mode 100644 src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs delete mode 100644 src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs diff --git a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs index 82c3242a96..ada5eab5dc 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs @@ -338,13 +338,12 @@ namespace ICSharpCode.SharpDevelop.Services public bool SetInstructionPointer(string filename, int line, int column, bool dryRun) { if (CurrentStackFrame != null) { - SourcecodeSegment seg = CurrentStackFrame.SetIP(filename, line, column, dryRun); - WindowsDebugger.RefreshPads(); - JumpToCurrentLine(); - return seg != null; - } else { - return false; + if (CurrentStackFrame.SetIP(filename, line, column, dryRun)) { + WindowsDebugger.RefreshPads(); + JumpToCurrentLine(); + } } + return false; } public void Dispose() @@ -645,7 +644,7 @@ namespace ICSharpCode.SharpDevelop.Services // if (debuggedProcess.IsSelectedFrameForced()) { if (CurrentStackFrame.HasSymbols) { - SourcecodeSegment nextStatement = CurrentStackFrame.NextStatement; + SequencePoint nextStatement = CurrentStackFrame.NextStatement; if (nextStatement != null) { DebuggerService.RemoveCurrentLineMarker(); DebuggerService.JumpToCurrentLine(nextStatement.Filename, nextStatement.StartLine, nextStatement.StartColumn, nextStatement.EndLine, nextStatement.EndColumn); diff --git a/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs b/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs index 704594f92e..b62aba8864 100644 --- a/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs +++ b/src/AddIns/Debugger/Debugger.Core/Breakpoint.cs @@ -12,12 +12,13 @@ namespace Debugger public class Breakpoint: DebuggerObject { bool enabled; - protected List corBreakpoints = new List(); + List corBreakpoints = new List(); + [Tests.Ignore] public string FileName { get; private set; } public int Line { get; set; } public int Column { get; set; } - public SourcecodeSegment OriginalLocation { get; private set; } + public byte[] Checksum { get; private set; } public bool IsEnabled { get { return enabled; } @@ -41,8 +42,6 @@ namespace Debugger get { return corBreakpoints.Count > 0; } } - public string TypeName { get; protected set; } - internal Breakpoint() { } @@ -70,18 +69,15 @@ namespace Debugger public virtual bool SetBreakpoint(Module module) { - SourcecodeSegment segment = SourcecodeSegment.Resolve(module, FileName, Line, Column); - if (segment == null) - return false; - - OriginalLocation = segment; - - ICorDebugFunctionBreakpoint corBreakpoint = segment.CorFunction.GetILCode().CreateBreakpoint((uint)segment.ILStart); - corBreakpoint.Activate(enabled ? 1 : 0); - - corBreakpoints.Add(corBreakpoint); - - return true; + var seq = PDBSymbolSource.GetSequencePoint(module, this.FileName, this.Line, this.Column); + if (seq != null) { + ICorDebugFunction corFuction = module.CorModule.GetFunctionFromToken(seq.MethodDefToken); + ICorDebugFunctionBreakpoint corBreakpoint = corFuction.GetILCode().CreateBreakpoint((uint)seq.ILOffset); + corBreakpoint.Activate(enabled ? 1 : 0); + corBreakpoints.Add(corBreakpoint); + return true; + } + return false; } } /* diff --git a/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj b/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj index 7bd4c94135..b43319bf6b 100644 --- a/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj +++ b/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj @@ -88,7 +88,7 @@ - + diff --git a/src/AddIns/Debugger/Debugger.Core/Interop/CorSymExtensionMethods.cs b/src/AddIns/Debugger/Debugger.Core/Interop/CorSymExtensionMethods.cs index eac10e2c86..d2c93b95fc 100644 --- a/src/AddIns/Debugger/Debugger.Core/Interop/CorSymExtensionMethods.cs +++ b/src/AddIns/Debugger/Debugger.Core/Interop/CorSymExtensionMethods.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Linq; using System.Runtime.InteropServices; namespace Debugger.Interop.CorSym @@ -57,7 +58,7 @@ namespace Debugger.Interop.CorSym // ISymUnmanagedMethod - public static SequencePoint[] GetSequencePoints(this ISymUnmanagedMethod symMethod) + public static SequencePoint[] GetSequencePoints(this ISymUnmanagedMethod symMethod, int codesize) { uint count = symMethod.GetSequencePointCount(); @@ -79,16 +80,21 @@ namespace Debugger.Interop.CorSym endColumns ); - SequencePoint[] sequencePoints = new SequencePoint[count]; + var sequencePoints = new SequencePoint[count]; + var urls = documents.Distinct().ToDictionary(d => d, d => d.GetURL()); + var sums = documents.Distinct().ToDictionary(d => d, d => d.GetCheckSum()); + uint token = symMethod.GetToken(); for(int i = 0; i < count; i++) { sequencePoints[i] = new SequencePoint() { - Document = documents[i], - Offset = offsets[i], - Line = lines[i], - Column = columns[i], - EndLine = endLines[i], - EndColumn = endColumns[i] + MethodDefToken = token, + ILRanges = new [] { new ILRange((int)offsets[i], i + 1 < count ? (int)offsets[i + 1] : codesize) }, + Filename = urls[documents[i]], + FileCheckSum = sums[documents[i]], + StartLine = (int)lines[i], + StartColumn = (int)columns[i], + EndLine = (int)endLines[i], + EndColumn = (int)endColumns[i] }; } @@ -174,21 +180,4 @@ namespace Debugger.Interop.CorSym return namespaces; } } - - public class SequencePoint: IComparable - { - public ISymUnmanagedDocument Document { get; internal set; } - public uint Offset { get; internal set; } - public uint Line { get; internal set; } - public uint Column { get; internal set; } - public uint EndLine { get; internal set; } - public uint EndColumn { get; internal set; } - - public int CompareTo(SequencePoint other) - { - if (this.Line != other.Line) return this.Line.CompareTo(other.Line); - if (this.Column != other.Column) return this.Column.CompareTo(other.Column); - return this.Offset.CompareTo(other.Offset); - } - } } diff --git a/src/AddIns/Debugger/Debugger.Core/LocalVariable.cs b/src/AddIns/Debugger/Debugger.Core/LocalVariable.cs index ffea217267..2b4db11a75 100644 --- a/src/AddIns/Debugger/Debugger.Core/LocalVariable.cs +++ b/src/AddIns/Debugger/Debugger.Core/LocalVariable.cs @@ -3,41 +3,34 @@ using System; using System.Collections.Generic; -using System.Globalization; -using System.Reflection; using System.Runtime.InteropServices; -using System.Text; -using Debugger.Interop.CorDebug; -using Debugger.Interop.CorSym; -using Debugger.Interop.MetaData; using ICSharpCode.NRefactory.TypeSystem; +using Debugger.Interop.CorDebug; namespace Debugger.MetaData { public class LocalVariable { + delegate Value Getter(StackFrame context); + public IMethod Method { get; private set; } /// Index of the local variable in method. -1 for captured variables public int Index { get; private set; } public IType Type { get; private set; } - public string Name { get; internal set; } - /// IL offset of the start of the variable scope (inclusive) - public int StartOffset { get; private set; } - /// IL offset of the end of the variable scope (exclusive) - public int EndOffset { get; private set; } - public bool IsThis { get; internal set; } - public bool IsCaptured { get; internal set; } + public string Name { get; private set; } + public ILRange[] ILRanges { get; private set; } + public bool IsThis { get; private set; } + public bool IsCaptured { get; private set; } - ValueGetter getter { get; set; } + Getter getter { get; set; } - public LocalVariable(IMethod method, int index, IType type, string name, int startOffset, int endOffset, ValueGetter getter) + LocalVariable(IMethod method, int index, IType type, string name, ILRange[] ilranges, Getter getter) { this.Method = method; this.Index = index; this.Type = type; this.Name = name; - this.StartOffset = startOffset; - this.EndOffset = endOffset; + this.ILRanges = ilranges; this.getter = getter; } @@ -53,29 +46,47 @@ namespace Debugger.MetaData public override string ToString() { - string msg = this.Type.Name + " " + this.Name; - if (IsCaptured) - msg += " (captured)"; - return msg; + return this.Type.Name + " " + this.Name + (this.IsCaptured ? " (captured)" : ""); } - public static List GetLocalVariables(IMethod method, ISymUnmanagedMethod symMethod) + public static List GetLocalVariables(IMethod method) { - List localVariables; + if (!PDBSymbolSource.HasSymbols(method)) + return null; - // Generated constructor may not have any symbols - if (symMethod == null) - return new List(); + List localVariables = new List(); - localVariables = GetLocalVariablesInScope(method, symMethod.GetRootScope()); + foreach (ILLocalVariable ilvar in PDBSymbolSource.GetLocalVariables(method)) { + int index = ilvar.Index; + // NB: Display class does not have the compiler-generated flag + if (ilvar.IsCompilerGenerated || ilvar.Name.StartsWith("CS$")) { + // Get display class from local variable + AddCapturedLocalVariables( + localVariables, + method, + ilvar.ILRanges, + context => GetLocalVariableValue(context, index), + ilvar.Type + ); + } else { + LocalVariable locVar = new LocalVariable( + method, + ilvar.Index, + ilvar.Type, + ilvar.Name, + ilvar.ILRanges, + context => GetLocalVariableValue(context, index) + ); + localVariables.Add(locVar); + } + } if (method.DeclaringType.IsDisplayClass()) { - // Get display class from self + // Get display class from 'this' AddCapturedLocalVariables( localVariables, method, - 0, - int.MaxValue, + new [] { new ILRange(0, int.MaxValue) }, context => context.GetThisValue(false), method.DeclaringType ); @@ -85,8 +96,7 @@ namespace Debugger.MetaData AddCapturedLocalVariables( localVariables, method, - 0, - int.MaxValue, + new [] { new ILRange(0, int.MaxValue) }, // TODO: Use eval thread context => context.GetThisValue(false).GetFieldValue(context.Thread, fieldInfoCopy), fieldInfo.Type @@ -100,18 +110,18 @@ namespace Debugger.MetaData -1, method.DeclaringType, "this", - 0, - int.MaxValue, + new [] { new ILRange(0, int.MaxValue) }, context => context.GetThisValue(false) ); thisVar.IsThis = true; localVariables.Add(thisVar); } } + return localVariables; } - static void AddCapturedLocalVariables(List vars, IMethod method, int scopeStartOffset, int scopeEndOffset, ValueGetter getCaptureClass, IType captureClassType) + static void AddCapturedLocalVariables(List vars, IMethod method, ILRange[] ilranges, ValueGetter getCaptureClass, IType captureClassType) { if (captureClassType.IsDisplayClass()) { foreach(IField fieldInfo in captureClassType.GetFields()) { @@ -122,8 +132,7 @@ namespace Debugger.MetaData -1, fieldInfo.Type, fieldInfo.Name, - scopeStartOffset, - scopeEndOffset, + ilranges, // TODO: Use eval thread context => getCaptureClass(context).GetFieldValue(context.Thread, fieldInfoCopy) ); @@ -146,49 +155,11 @@ namespace Debugger.MetaData } } - static List GetLocalVariablesInScope(IMethod method, ISymUnmanagedScope symScope) - { - List vars = new List(); - foreach (ISymUnmanagedVariable symVar in symScope.GetLocals()) { - uint address = (uint)symVar.GetAddressField1(); - IType type = method.GetLocalVariableType((int)address); - // Compiler generated? - // NB: Display class does not have the compiler-generated flag - if ((symVar.GetAttributes() & 1) == 1 || symVar.GetName().StartsWith("CS$")) { - // Get display class from local variable - AddCapturedLocalVariables( - vars, - method, - (int)symScope.GetStartOffset(), - (int)symScope.GetEndOffset(), - context => GetLocalVariableValue(context, address), - type - ); - } else { - LocalVariable locVar = new LocalVariable( - method, - (int)address, - type, - symVar.GetName(), - // symVar also has Get*Offset methods, but the are not implemented - (int)symScope.GetStartOffset(), - (int)symScope.GetEndOffset(), - context => GetLocalVariableValue(context, address) - ); - vars.Add(locVar); - } - } - foreach(ISymUnmanagedScope childScope in symScope.GetChildren()) { - vars.AddRange(GetLocalVariablesInScope(method, childScope)); - } - return vars; - } - - public static Value GetLocalVariableValue(StackFrame context, uint address) + public static Value GetLocalVariableValue(StackFrame context, int index) { context.Process.AssertPaused(); try { - return new Value(context.AppDomain, context.CorILFrame.GetLocalVariable(address)); + return new Value(context.AppDomain, context.CorILFrame.GetLocalVariable((uint)index)); } catch (COMException e) { if ((uint)e.ErrorCode == 0x80131304) throw new GetValueException("Unavailable in optimized code"); throw; diff --git a/src/AddIns/Debugger/Debugger.Core/NDebugger.cs b/src/AddIns/Debugger/Debugger.Core/NDebugger.cs index 949d47e705..95932bddb1 100644 --- a/src/AddIns/Debugger/Debugger.Core/NDebugger.cs +++ b/src/AddIns/Debugger/Debugger.Core/NDebugger.cs @@ -241,7 +241,7 @@ namespace Debugger lock(ProcessIsBeingCreatedLock) { ICorDebugProcess corDebugProcess = corDebug.DebugActiveProcess((uint)existingProcess.Id, 0); // TODO: Can we get the acutal working directory? - Process process = new Process(this, corDebugProcess, Path.GetDirectoryName(mainModule)); + Process process = new Process(this, corDebugProcess, mainModule, Path.GetDirectoryName(mainModule)); this.processes.Add(process); return process; } diff --git a/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs b/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs new file mode 100644 index 0000000000..848db8f057 --- /dev/null +++ b/src/AddIns/Debugger/Debugger.Core/PdbSymbolSource.cs @@ -0,0 +1,256 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using Debugger; +using Debugger.Interop.CorDebug; +using Debugger.Interop.CorSym; +using ICSharpCode.NRefactory.TypeSystem; + +namespace Debugger +{ + public class SequencePoint + { + public uint MethodDefToken { get; set; } + public ILRange[] ILRanges { get; set; } + public int ILOffset { get { return ILRanges.Length > 0 ? ILRanges[0].From : 0; } } + + public string Filename { get; set; } + public byte[] FileCheckSum { get; set; } + public int StartLine { get; set; } + public int StartColumn { get; set; } + public int EndLine { get; set; } + public int EndColumn { get; set; } + + public override string ToString() + { + return string.Format("{0}:{1},{2}-{3},{4}", + Path.GetFileName(this.Filename ?? string.Empty), + this.StartLine, this.StartColumn, + this.EndLine, this.EndColumn); + } + } + + public struct ILRange + { + public int From; + public int To; + + public ILRange(int from, int to) + { + this.From = from; + this.To = to; + } + } + + public class ILLocalVariable + { + public int Index { get; set; } + public IType Type { get; set; } + public string Name { get; set; } + public bool IsCompilerGenerated { get; set; } + public ILRange[] ILRanges { get; set; } + } + + public class PDBSymbolSource + { + /// + /// Get absolute source code path for the specified document. + /// If the file is not found, some effort will be made to locate it. + /// (i.e. to handle case when the directory is moved after compilation) + /// One document maps exactly to one disk file. + /// + /// + /// Be careful to use this in the same way in both mapping directinons so that + /// setting breakpoints (src->IL) and stepping (IL->src) work consistently. + /// + static string GetSourceCodePath(Process process, string origPath) + { + var paths = RelocatePath(process.Filename, origPath).Distinct(); + var path = paths.FirstOrDefault(f => File.Exists(f)); + return path; + } + + /// + /// Suggest posible new locations for original path. + /// + static IEnumerable RelocatePath(string basePath, string origPath) + { + if (!string.IsNullOrEmpty(origPath)) { + if (Path.IsPathRooted(origPath)) { + // Try without relocating + yield return origPath; + + string[] baseParts = basePath.Split('\\'); + string[] origParts = origPath.Split('\\'); + + // Join the paths at some point (joining directry must match) + for (int i = 0; i < baseParts.Length; i++) { + for (int j = 0; j < origParts.Length; j++) { + if (!string.IsNullOrEmpty(baseParts[i]) && string.Equals(baseParts[i], origParts[j], StringComparison.OrdinalIgnoreCase)) { + // Join the paths + string[] joinedDirs = new string[i + (origParts.Length - j)]; + Array.Copy(baseParts, joinedDirs, i); + Array.Copy(origParts, j, joinedDirs, i, origParts.Length - j); + string joined = string.Join(@"\", joinedDirs); + yield return joined; + } + } + } + } else { + if (origPath.StartsWith(@".\")) + origPath = origPath.Substring(2); + if (origPath.StartsWith(@"\")) + origPath = origPath.Substring(1); + + // Try 0, 1 and 2 levels above the base path + string dir = basePath; + for(int i = 0; i <= 2; i++) { + dir = Path.GetDirectoryName(dir); + if (!string.IsNullOrEmpty(dir)) + yield return Path.Combine(dir, origPath); + } + } + } + } + + public static SequencePoint GetSequencePoint(IMethod method, int iloffset) + { + var symMethod = method.GetSymMethod(); + if (symMethod == null) + return null; + + // 0xFEEFEE means "code generated by compiler" + int codeSize = (int)method.ToCorFunction().GetILCode().GetSize(); + var sequencePoints = symMethod.GetSequencePoints(codeSize); + 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); + + // 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.Substring(0, name.Length - 3).All(c => ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') || (c == '-'))) { + return null; + } + } + + if (sequencePoint != null) { + sequencePoint.Filename = GetSourceCodePath(method.ParentAssembly.GetModule().Process, sequencePoint.Filename); + } + + return sequencePoint; + } + + public static SequencePoint GetSequencePoint(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 + + if (filename == null || !Path.IsPathRooted(filename)) + throw new DebuggerException("Invalid filename. Absolute path is required."); + + ISymUnmanagedReader symReader = module.SymReader; + if (symReader == null) + return null; // No symbols + + // Find ISymUnmanagedDocument which excactly matches the filename. + var symDoc = module.SymDocuments.FirstOrDefault(d => string.Equals(filename, d.GetURL(), StringComparison.OrdinalIgnoreCase)); + + // 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 + + ISymUnmanagedMethod symMethod; + try { + uint validLine = symDoc.FindClosestLine((uint)line); + symMethod = symReader.GetMethodFromDocumentPosition(symDoc, (uint)validLine, (uint)column); + } catch { + return null; //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 && line <= s.EndLine); + } else { + 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); + return seqPoint; + } + + public static bool HasSymbols(IMethod method) + { + return method.GetSymMethod() != null; + } + + public static IEnumerable GetIgnoredILRanges(IMethod method) + { + var symMethod = method.GetSymMethod(); + if (symMethod == null) + return null; + + int codeSize = (int)method.ToCorFunction().GetILCode().GetSize(); + return symMethod.GetSequencePoints(codeSize).Where(p => p.StartLine == 0xFEEFEE).SelectMany(p => p.ILRanges).ToList(); + } + + public static IEnumerable GetLocalVariables(IMethod method) + { + var symMethod = method.GetSymMethod(); + if (symMethod == null) + return null; + + List vars = new List(); + Stack scopes = new Stack(); + scopes.Push(symMethod.GetRootScope()); + while(scopes.Count > 0) { + ISymUnmanagedScope scope = scopes.Pop(); + foreach (ISymUnmanagedVariable symVar in scope.GetLocals()) { + int index = (int)symVar.GetAddressField1(); + vars.Add(new ILLocalVariable() { + Index = index, + Type = method.GetLocalVariableType(index), + Name = symVar.GetName(), + IsCompilerGenerated = (symVar.GetAttributes() & 1) == 1, + // symVar also has Get*Offset methods, but the are not implemented + ILRanges = new [] { new ILRange() { From = (int)scope.GetStartOffset(), To = (int)scope.GetEndOffset() } } + }); + } + foreach(ISymUnmanagedScope childScope in scope.GetChildren()) { + scopes.Push(childScope); + } + } + return vars; + } + } + + static class PDBSymbolSourceExtensions + { + public static ISymUnmanagedMethod GetSymMethod(this IMethod method) + { + var module = method.ParentAssembly.GetModule(); + if (module.SymReader == null) { + return null; + } + try { + return module.SymReader.GetMethod(method.GetMetadataToken()); + } catch (System.Runtime.InteropServices.COMException) { + // Can not find the method + // eg. Compiler generated constructors are not in symbol store + return null; + } + } + } +} diff --git a/src/AddIns/Debugger/Debugger.Core/Process.cs b/src/AddIns/Debugger/Debugger.Core/Process.cs index db48e3401b..0ec6a19724 100644 --- a/src/AddIns/Debugger/Debugger.Core/Process.cs +++ b/src/AddIns/Debugger/Debugger.Core/Process.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Runtime.InteropServices; using Debugger.Interop.CorDebug; using Debugger.Interop.CorSym; @@ -106,13 +105,16 @@ namespace Debugger get { return workingDirectory; } } + public string Filename { get; private set; } + public static DebugModeFlag DebugMode { get; set; } - internal Process(NDebugger debugger, ICorDebugProcess corProcess, string workingDirectory) + internal Process(NDebugger debugger, ICorDebugProcess corProcess, string filename, string workingDirectory) { this.debugger = debugger; this.corProcess = corProcess; this.workingDirectory = workingDirectory; + this.Filename = System.IO.Path.GetFullPath(filename); // normalize path this.callbackInterface = new ManagedCallback(this); } @@ -127,7 +129,7 @@ namespace Debugger ICorDebugProcess outProcess; - if (workingDirectory == null || workingDirectory == "") { + if (string.IsNullOrEmpty(workingDirectory)) { workingDirectory = System.IO.Path.GetDirectoryName(filename); } @@ -136,25 +138,26 @@ namespace Debugger secAttr.lpSecurityDescriptor = IntPtr.Zero; secAttr.nLength = (uint)sizeof(_SECURITY_ATTRIBUTES); - fixed (uint* pprocessStartupInfo = processStartupInfo) - fixed (uint* pprocessInfo = processInfo) - outProcess = - debugger.CorDebug.CreateProcess( - filename, // lpApplicationName - // If we do not prepend " ", the first argument migh just get lost - " " + arguments, // lpCommandLine - ref secAttr, // lpProcessAttributes - ref secAttr, // lpThreadAttributes - 1,//TRUE // bInheritHandles - 0x00000010 /*CREATE_NEW_CONSOLE*/, // dwCreationFlags - IntPtr.Zero, // lpEnvironment - workingDirectory, // lpCurrentDirectory - (uint)pprocessStartupInfo, // lpStartupInfo - (uint)pprocessInfo, // lpProcessInformation, - CorDebugCreateProcessFlags.DEBUG_NO_SPECIAL_OPTIONS // debuggingFlags - ); + fixed (uint* pprocessStartupInfo = processStartupInfo) { + fixed (uint* pprocessInfo = processInfo) { + outProcess = debugger.CorDebug.CreateProcess( + filename, // lpApplicationName + // If we do not prepend " ", the first argument migh just get lost + " " + arguments, // lpCommandLine + ref secAttr, // lpProcessAttributes + ref secAttr, // lpThreadAttributes + 1,//TRUE // bInheritHandles + 0x00000010 /*CREATE_NEW_CONSOLE*/, // dwCreationFlags + IntPtr.Zero, // lpEnvironment + workingDirectory, // lpCurrentDirectory + (uint)pprocessStartupInfo, // lpStartupInfo + (uint)pprocessInfo, // lpProcessInformation, + CorDebugCreateProcessFlags.DEBUG_NO_SPECIAL_OPTIONS // debuggingFlags + ); + } + } - return new Process(debugger, outProcess, workingDirectory); + return new Process(debugger, outProcess, filename, workingDirectory); } internal void OnLogMessage(MessageEventArgs arg) @@ -449,9 +452,10 @@ namespace Debugger public void RunTo(string fileName, int line, int column) { foreach(Module module in this.Modules) { - SourcecodeSegment segment = SourcecodeSegment.Resolve(module, fileName, line, column); - if (segment != null) { - ICorDebugFunctionBreakpoint corBreakpoint = segment.CorFunction.GetILCode().CreateBreakpoint((uint)segment.ILStart); + SequencePoint seq = PDBSymbolSource.GetSequencePoint(module, fileName, line, column); + if (seq != null) { + ICorDebugFunction corFunction = module.CorModule.GetFunctionFromToken(seq.MethodDefToken); + ICorDebugFunctionBreakpoint corBreakpoint = corFunction.GetILCode().CreateBreakpoint((uint)seq.ILOffset); corBreakpoint.Activate(1); this.tempBreakpoints.Add(corBreakpoint); } diff --git a/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs b/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs deleted file mode 100644 index 3f1a0af159..0000000000 --- a/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) - -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; - -using Debugger.Interop.CorDebug; -using Debugger.Interop.CorSym; - -namespace Debugger -{ - public class SourcecodeSegment: DebuggerObject - { - public Module Module { get; private set; } - public string Filename { get; private set; } - public string Typename { get; private set; } - public byte[] CheckSum { get; private set; } - public int StartLine { get; private set; } - public int StartColumn { get; private set; } - public int EndLine { get; private set; } - public int EndColumn { get; private set; } - internal ICorDebugFunction CorFunction { get; private set; } - public int ILStart { get; private set; } - public int ILEnd { get; private set; } - public int[] StepRanges { get; private set; } - - private SourcecodeSegment() - { - } - - /// - /// Use the module path to figure out where to look for the source file - /// - static IEnumerable RelocateSymURL(Module module, string symUrl) - { - string modulePath = module.Process.WorkingDirectory; - if (module.IsInMemory || module.IsDynamic) { - // Just use any module with symboles - foreach(Module m in module.Process.Modules) { - if (m.HasSymbols) { - if (!string.IsNullOrEmpty(m.FullPath)) { - modulePath = Path.GetDirectoryName(m.FullPath); - break; - } - } - } - } else { - if (!string.IsNullOrEmpty(module.FullPath)) - modulePath = Path.GetDirectoryName(module.FullPath); - } - if (string.IsNullOrEmpty(modulePath)) { - yield return symUrl; - yield break; - } - - if (Path.IsPathRooted(symUrl)) { - Dictionary returned = new Dictionary(); - - // Try without relocating - returned.Add(symUrl, null); - yield return symUrl; - - // The two paths to combine - string[] moduleDirs = modulePath.Split('\\'); - string[] urlDirs = symUrl.Split('\\'); - - // Join the paths at some point (joining directry must match) - for (int i = 0; i < moduleDirs.Length; i++) { - for (int j = 0; j < urlDirs.Length; j++) { - if (!string.IsNullOrEmpty(moduleDirs[i]) && - !string.IsNullOrEmpty(urlDirs[j]) && - string.Equals(moduleDirs[i], urlDirs[j], StringComparison.OrdinalIgnoreCase)) - { - // Join the paths - string[] joinedDirs = new string[i + (urlDirs.Length - j)]; - Array.Copy(moduleDirs, joinedDirs, i); - Array.Copy(urlDirs, j, joinedDirs, i, urlDirs.Length - j); - string joined = string.Join(@"\", joinedDirs); - - // Return joined path - if (!returned.ContainsKey(joined)) { - returned.Add(joined, null); - yield return joined; - } - } - } - } - } else { - if (symUrl.StartsWith(@".\")) symUrl = symUrl.Substring(2); - if (symUrl.StartsWith(@"\")) symUrl = symUrl.Substring(1); - // Try 0, 1 and 2 levels above the module directory - string dir = modulePath; - if (!string.IsNullOrEmpty(dir)) yield return Path.Combine(dir, symUrl); - dir = Path.GetDirectoryName(dir); - if (!string.IsNullOrEmpty(dir)) yield return Path.Combine(dir, symUrl); - dir = Path.GetDirectoryName(dir); - if (!string.IsNullOrEmpty(dir)) yield return Path.Combine(dir, symUrl); - } - } - - static ISymUnmanagedDocument GetSymDocumentFromFilename(Module module, string filename) - { - if (filename == null) throw new ArgumentNullException("filename"); - - if (Path.IsPathRooted(filename)) { - foreach(ISymUnmanagedDocument symDoc in module.SymDocuments) { - foreach (string url in RelocateSymURL(module, symDoc.GetURL())) { - if (string.Equals(url, filename, StringComparison.OrdinalIgnoreCase)) - return symDoc; - } - } - } else { - foreach(ISymUnmanagedDocument symDoc in module.SymDocuments) { - if (filename.StartsWith(@".\")) filename = filename.Substring(2); - if (filename.StartsWith(@"\")) filename = filename.Substring(1); - if (symDoc.GetURL().ToLowerInvariant().EndsWith(@"\" + filename.ToLowerInvariant())) { - return symDoc; - } - } - } - - return null; - } - - public static SourcecodeSegment Resolve(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 - - if (fileName == null) return null; - - ISymUnmanagedReader symReader = module.SymReader; - if (symReader == null) return null; // No symbols - - ISymUnmanagedDocument symDoc = GetSymDocumentFromFilename(module, fileName); - if (symDoc == null) return null; // Document not found - - ISymUnmanagedMethod symMethod; - try { - uint validLine = symDoc.FindClosestLine((uint)line); - symMethod = symReader.GetMethodFromDocumentPosition(symDoc, (uint)validLine, (uint)column); - } catch { - return null; //Not found - } - - SequencePoint[] seqPoints = symMethod.GetSequencePoints(); - Array.Sort(seqPoints); - if (seqPoints.Length == 0) return null; - if (line < seqPoints[0].Line) return null; - foreach(SequencePoint sqPoint in seqPoints) { - if (sqPoint.Line == 0xFEEFEE) continue; - // If the desired breakpoint position is before the end of the sequence point - if (line < sqPoint.EndLine || (line == sqPoint.EndLine && column < sqPoint.EndColumn)) { - SourcecodeSegment segment = new SourcecodeSegment(); - segment.Module = module; - segment.Filename = symDoc.GetURL(); - segment.CheckSum = symDoc.GetCheckSum(); - segment.StartLine = (int)sqPoint.Line; - segment.StartColumn = (int)sqPoint.Column; - segment.EndLine = (int)sqPoint.EndLine; - segment.EndColumn = (int)sqPoint.EndColumn; - segment.CorFunction = module.CorModule.GetFunctionFromToken(symMethod.GetToken()); - segment.ILStart = (int)sqPoint.Offset; - segment.ILEnd = (int)sqPoint.Offset; - segment.StepRanges = null; - return segment; - } - } - return null; - } - - static string GetFilenameFromSymDocument(Module module, ISymUnmanagedDocument symDoc) - { - foreach (string filename in RelocateSymURL(module, symDoc.GetURL())) { - if (File.Exists(filename)) - return filename; - } - return symDoc.GetURL(); - } - - /// - /// 'ILStart <= ILOffset <= ILEnd' and this range includes at least - /// the returned area of source code. (May incude some extra compiler generated IL too) - /// - internal static SourcecodeSegment Resolve(Module module, ISymUnmanagedMethod symMethod, ICorDebugFunction corFunction, int offset) - { - if (symMethod == null) - return null; - - uint sequencePointCount = symMethod.GetSequencePointCount(); - SequencePoint[] sequencePoints = symMethod.GetSequencePoints(); - - // Get i for which: offsets[i] <= offset < offsets[i + 1] - // or fallback to first element if offset < offsets[0] - for (int i = (int)sequencePointCount - 1; i >= 0; i--) { // backwards - if ((int)sequencePoints[i].Offset <= offset || i == 0) { - // Set inforamtion about current IL range - int codeSize = (int)corFunction.GetILCode().GetSize(); - - int ilStart = (int)sequencePoints[i].Offset; - int ilEnd = (i + 1 < sequencePointCount) ? (int)sequencePoints[i+1].Offset : codeSize; - - // 0xFeeFee means "code generated by compiler" - // If we are in generated sequence use to closest real one instead, - // extend the ILStart and ILEnd to include the 'real' sequence - - // Look ahead for 'real' sequence - while (i + 1 < sequencePointCount && sequencePoints[i].Line == 0xFeeFee) { - i++; - ilEnd = (i + 1 < sequencePointCount) ? (int)sequencePoints[i+1].Offset : codeSize; - } - // Look back for 'real' sequence - while (i - 1 >= 0 && sequencePoints[i].Line == 0xFeeFee) { - i--; - ilStart = (int)sequencePoints[i].Offset; - } - // Wow, there are no 'real' sequences - if (sequencePoints[i].Line == 0xFeeFee) { - return null; - } - - List stepRanges = new List(); - for (int j = 0; j < sequencePointCount; j++) { - // Step over compiler generated sequences and current statement - // 0xFeeFee means "code generated by compiler" - if (sequencePoints[j].Line == 0xFeeFee || j == i) { - // Add start offset or remove last end (to connect two ranges into one) - if (stepRanges.Count > 0 && stepRanges[stepRanges.Count - 1] == sequencePoints[j].Offset) { - stepRanges.RemoveAt(stepRanges.Count - 1); - } else { - stepRanges.Add((int)sequencePoints[j].Offset); - } - // Add end offset | handle last sequence point - if (j + 1 < sequencePointCount) { - stepRanges.Add((int)sequencePoints[j+1].Offset); - } else { - stepRanges.Add(codeSize); - } - } - } - - SourcecodeSegment segment = new SourcecodeSegment(); - segment.Module = module; - segment.Filename = GetFilenameFromSymDocument(module, sequencePoints[i].Document); - segment.CheckSum = sequencePoints[i].Document.GetCheckSum(); - segment.StartLine = (int)sequencePoints[i].Line; - segment.StartColumn = (int)sequencePoints[i].Column; - segment.EndLine = (int)sequencePoints[i].EndLine; - segment.EndColumn = (int)sequencePoints[i].EndColumn; - segment.CorFunction = corFunction; - segment.ILStart = ilStart; - segment.ILEnd = ilEnd; - segment.StepRanges = stepRanges.ToArray(); - - // VB.NET sometimes produces temporary files which it then deletes - // (eg 17d14f5c-a337-4978-8281-53493378c1071.vb) - string filename = Path.GetFileName(segment.Filename); - if (filename.Length == 40 && filename.EndsWith(".vb")) { - bool guidName = true; - foreach(char c in filename.Substring(0, filename.Length - 3)) { - if (('0' <= c && c <= '9') || - ('a' <= c && c <= 'f') || - ('A' <= c && c <= 'F') || - (c == '-')) - { - guidName = true; - } else { - guidName = false; - break; - } - } - if (guidName) - return null; - } - - return segment; - } - } - return null; - } - - public override string ToString() - { - return string.Format("{0}:{1},{2}-{3},{4}", - Path.GetFileName(this.Filename ?? string.Empty), - this.StartLine, this.StartColumn, this.EndLine, this.EndColumn); - } - - #region Decompiled breakpoint - - public static SourcecodeSegment CreateForIL(Module module, int line, int metadataToken, int iLOffset) - { - try { - SourcecodeSegment segment = new SourcecodeSegment(); - segment.Module = module; - segment.Typename = null; - segment.CheckSum = null; - segment.StartLine = line; - segment.StartColumn = 0; - segment.EndLine = line; - segment.EndColumn = 0; - segment.CorFunction = module.CorModule.GetFunctionFromToken((uint)metadataToken); - segment.ILStart = iLOffset; - segment.ILEnd = iLOffset; - segment.StepRanges = null; - - return segment; - } catch { - return null; - } - } - - public static SourcecodeSegment ResolveForIL(Module module, ICorDebugFunction corFunction, int line, int offset, int[] ranges) - { - try { - SourcecodeSegment segment = new SourcecodeSegment(); - segment.Module = module; - segment.Typename = null; - segment.CheckSum = null; - segment.StartLine = line; - segment.StartColumn = 0; - segment.EndLine = line; - segment.EndColumn = 0; - segment.CorFunction = corFunction; - segment.ILStart = offset; - segment.ILEnd = ranges[1]; - segment.StepRanges = ranges; - - return segment; - } catch { - return null; - } - } - - #endregion - } -} diff --git a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs index 786bf63d98..cc1968c5e8 100644 --- a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs +++ b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs @@ -5,11 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; -using Debugger.Interop.CorSym; -using Debugger.MetaData; -using Debugger.Interop.CorDebug; -using Debugger.Interop.MetaData; using ICSharpCode.NRefactory.TypeSystem; +using Debugger.Interop.CorDebug; +using Debugger.MetaData; namespace Debugger { @@ -45,30 +43,14 @@ namespace Debugger internal ICorDebugFunction CorFunction { get; private set; } - /// True if the stack frame has symbols defined. - /// (That is has accesss to the .pdb file) + /// True if the stack frame has symbols defined. public bool HasSymbols { get { - return GetSegmentForOffset(0) != null; + return PDBSymbolSource.HasSymbols(this.MethodInfo); } } - internal ISymUnmanagedMethod SymMethod { - get { - if (this.Module.SymReader == null) { - return null; - } - try { - return this.Module.SymReader.GetMethod(this.CorFunction.GetToken()); - } catch (COMException) { - // Can not find the method - // eg. Compiler generated constructors are not in symbol store - return null; - } - } - } - - /// Returns true is this incance can not be used any more. + /// Returns true if this instance can not be used any more. public bool IsInvalid { get { try { @@ -128,17 +110,6 @@ namespace Debugger } } - public int[] ILRanges { get; set; } - - public int SourceCodeLine { get; set; } - - SourcecodeSegment GetSegmentForOffset(int offset) - { - if (SourceCodeLine != 0) - return SourcecodeSegment.ResolveForIL(this.Module, this.CorFunction, SourceCodeLine, offset, ILRanges); - return SourcecodeSegment.Resolve(this.Module, this.SymMethod, this.CorFunction, offset); - } - /// Step into next instruction public void StepInto() { @@ -182,19 +153,26 @@ namespace Debugger void AsyncStep(bool stepIn) { - int[] stepRanges; - if (ILRanges == null) { - SourcecodeSegment nextSt = NextStatement; - if (nextSt == null) { - throw new DebuggerException("Unable to step. Next statement not aviable"); - } - stepRanges = nextSt.StepRanges; - } else { - stepRanges = ILRanges; + List stepRanges = new List(); + var seq = PDBSymbolSource.GetSequencePoint(this.MethodInfo, this.IP); + if (seq != null) { + stepRanges.AddRange(seq.ILRanges); + stepRanges.AddRange(PDBSymbolSource.GetIgnoredILRanges(this.MethodInfo)); } + // Remove overlapping and connected ranges + List fromToList = new List(); + foreach(var range in stepRanges.OrderBy(r => r.From)) { + if (fromToList.Count > 0 && range.From <= fromToList[fromToList.Count - 1]) { + fromToList[fromToList.Count - 1] = Math.Max(range.To, fromToList[fromToList.Count - 1]); + } else { + fromToList.Add(range.From); + fromToList.Add(range.To); + } + } + if (stepIn) { - Stepper stepInStepper = Stepper.StepIn(this, stepRanges, "normal"); + Stepper stepInStepper = Stepper.StepIn(this, fromToList.ToArray(), "normal"); this.Thread.CurrentStepIn = stepInStepper; Stepper clearCurrentStepIn = Stepper.StepOut(this, "clear current step in"); clearCurrentStepIn.StepComplete += delegate { @@ -204,7 +182,7 @@ namespace Debugger }; clearCurrentStepIn.Ignore = true; } else { - Stepper.StepOver(this, stepRanges, "normal"); + Stepper.StepOver(this, fromToList.ToArray(), "normal"); } this.Process.AsyncContinue(DebuggeeStateAction.Clear); @@ -215,34 +193,33 @@ namespace Debugger /// /// Returns null on error. /// - public SourcecodeSegment NextStatement { + public SequencePoint NextStatement { get { - return GetSegmentForOffset(IP); + return PDBSymbolSource.GetSequencePoint(this.MethodInfo, this.IP); } } - public SourcecodeSegment SetIP(string filename, int line, int column, bool dryRun) + public bool SetIP(string filename, int line, int column, bool dryRun) { this.Process.AssertPaused(); - SourcecodeSegment segment = SourcecodeSegment.Resolve(this.Module, filename, line, column); - - if (segment != null && segment.CorFunction.GetToken() == this.MethodInfo.GetMetadataToken()) { + var seq = PDBSymbolSource.GetSequencePoint(this.Module, filename, line, column); + if (seq != null && seq.MethodDefToken == this.MethodInfo.GetMetadataToken()) { try { if (dryRun) { - CorILFrame.CanSetIP((uint)segment.ILStart); + CorILFrame.CanSetIP((uint)seq.ILOffset); } else { - CorILFrame.SetIP((uint)segment.ILStart); + CorILFrame.SetIP((uint)seq.ILOffset); // Invalidates all frames and chains for the current thread this.Process.NotifyResumed(DebuggeeStateAction.Keep); this.Process.NotifyPaused(); } } catch { - return null; + return false; } - return segment; + return true; } - return null; + return false; } /// Get instance of 'this'. @@ -341,28 +318,24 @@ namespace Debugger /// Get all local variables public IEnumerable GetLocalVariables() { + // Note that the user might load symbols later if (localVariables == null) { - var symMethod = this.SymMethod; - // Note that the user might load symbols later - if (symMethod == null) - return new List(); - - localVariables = LocalVariable.GetLocalVariables(this.MethodInfo, symMethod); + localVariables = LocalVariable.GetLocalVariables(this.MethodInfo); } - return localVariables; + return localVariables ?? new List(); } /// Get local variables valid at the given IL offset public IEnumerable GetLocalVariables(int offset) { - return GetLocalVariables().Where(v => v.StartOffset <= offset && offset < v.EndOffset); + return GetLocalVariables().Where(v => v.ILRanges.Any(r => r.From <= offset && offset < r.To)); } /// Get local variable with given name which is valid at the current IP /// Null if not found public Value GetLocalVariableValue(string name) { - var loc = GetLocalVariables(this.IP).Where(v => v.Name == name).FirstOrDefault(); + var loc = GetLocalVariables(this.IP).FirstOrDefault(v => v.Name == name); if (loc == null) throw new GetValueException("Local variable \"{0}\" not found", name); return loc.GetValue(this); @@ -374,7 +347,7 @@ namespace Debugger Options opt = this.Process.Options; if (opt.StepOverNoSymbols) { - if (this.SymMethod == null) return true; + if (!PDBSymbolSource.HasSymbols(this.MethodInfo)) return true; } if (opt.StepOverDebuggerAttributes) { string[] debuggerAttributes = { diff --git a/src/AddIns/Debugger/Debugger.Core/Thread.cs b/src/AddIns/Debugger/Debugger.Core/Thread.cs index d49142a66e..ca195bb1fd 100644 --- a/src/AddIns/Debugger/Debugger.Core/Thread.cs +++ b/src/AddIns/Debugger/Debugger.Core/Thread.cs @@ -300,7 +300,7 @@ namespace Debugger { StringBuilder stackTrace = new StringBuilder(); foreach(StackFrame stackFrame in this.GetCallstack(100)) { - SourcecodeSegment loc = stackFrame.NextStatement; + SequencePoint loc = stackFrame.NextStatement; stackTrace.Append(" "); if (loc != null) { stackTrace.AppendFormat(formatSymbols, stackFrame.MethodInfo.FullName, loc.Filename, loc.StartLine); diff --git a/src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs b/src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs index 8864a32a09..c7653d0862 100644 --- a/src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs +++ b/src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs @@ -461,7 +461,7 @@ namespace Debugger public static ICorDebugFunction ToCorFunction(this IMethod method) { - Module module = method.DeclaringType.GetDefinition().ParentAssembly.GetModule(); + Module module = method.ParentAssembly.GetModule(); return module.CorModule.GetFunctionFromToken(method.GetMetadataToken()); } diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/Breakpoint_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/Breakpoint_Tests.cs index 366f58621c..13803af366 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Tests/Breakpoint_Tests.cs +++ b/src/AddIns/Debugger/Debugger.Tests/Tests/Breakpoint_Tests.cs @@ -28,11 +28,13 @@ namespace Debugger.Tests { [NUnit.Framework.Test] public void Breakpoint_Tests() { - Breakpoint breakpoint1 = debugger.AddBreakpoint(@"Breakpoint_Tests.cs", 14); - Breakpoint breakpoint2 = debugger.AddBreakpoint(@"Breakpoint_Tests.cs", 15); - StartTest(); + string filename = CurrentStackFrame.NextStatement.Filename; + + Breakpoint breakpoint1 = debugger.AddBreakpoint(filename, 14); + Breakpoint breakpoint2 = debugger.AddBreakpoint(filename, 15); + Assert.IsTrue(breakpoint1.IsSet); Assert.IsTrue(breakpoint2.IsSet); ObjectDump("Breakpoint1", breakpoint1); @@ -64,19 +66,15 @@ namespace Debugger.Tests { Breakpoint_Tests.cs:12,4-12,40 + Line="14" /> + Line="15" /> System.Configuration.dll (No symbols) System.Xml.dll (No symbols) @@ -89,17 +87,13 @@ namespace Debugger.Tests { + Line="14" /> + Line="15" /> diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/ControlFlow_Stepping.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/ControlFlow_Stepping.cs index 458588d2d0..ae793aeaa8 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Tests/ControlFlow_Stepping.cs +++ b/src/AddIns/Debugger/Debugger.Tests/Tests/ControlFlow_Stepping.cs @@ -119,7 +119,7 @@ namespace Debugger.Tests { { StartTest(); - SourcecodeSegment start = this.CurrentStackFrame.NextStatement; + SequencePoint start = this.CurrentStackFrame.NextStatement; foreach (bool jmcEnabled in new bool[] {true, true, false}) { ObjectDump("Log", "Starting run with JMC=" + jmcEnabled.ToString()); diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_SetIP.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_SetIP.cs index 23f9a15278..de02d4a768 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_SetIP.cs +++ b/src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_SetIP.cs @@ -26,9 +26,11 @@ namespace Debugger.Tests { { StartTest(); - Assert.IsNotNull(this.CurrentStackFrame.SetIP("StackFrame_SetIP.cs", 12, 0, true)); - Assert.IsNull(this.CurrentStackFrame.SetIP("StackFrame_SetIP.cs", 100, 0, true)); - this.CurrentStackFrame.SetIP("StackFrame_SetIP.cs", 12, 0, false); + string filename = this.CurrentStackFrame.NextStatement.Filename; + + Assert.IsNotNull(this.CurrentStackFrame.SetIP(filename, 12, 0, true)); + Assert.IsFalse(this.CurrentStackFrame.SetIP(filename, 100, 0, true)); + this.CurrentStackFrame.SetIP(filename, 12, 0, false); process.Continue(); Assert.AreEqual("1\r\n1\r\n", log);