Browse Source

Rewritten Breakpoint and SourcecodeSegment classes. SourcecodeSegment is now immutable.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3137 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 17 years ago
parent
commit
dbba4a13eb
  1. 11
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/WindowsDebugger.cs
  2. 12
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/NDebugger-Breakpoints.cs
  3. 129
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs
  4. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs
  5. 134
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Breakpoint.cs
  6. 346
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/SourcecodeSegment.cs
  7. 17
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorSym/ISymUnmanagedDocument.cs
  8. 30
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Breakpoint.cs
  9. 12
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Callstack.cs
  10. 10
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/FunctionLifetime.cs
  11. 16
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Generics.cs
  12. 2
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/StackOverflow.cs
  13. 18
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Stepping.cs

11
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/WindowsDebugger.cs

@ -395,24 +395,23 @@ namespace ICSharpCode.SharpDevelop.Services @@ -395,24 +395,23 @@ namespace ICSharpCode.SharpDevelop.Services
void AddBreakpoint(BreakpointBookmark bookmark)
{
SourcecodeSegment seg = new SourcecodeSegment(bookmark.FileName, bookmark.LineNumber + 1);
Breakpoint breakpoint = debugger.AddBreakpoint(seg, bookmark.IsEnabled);
Breakpoint breakpoint = debugger.AddBreakpoint(bookmark.FileName, null, bookmark.LineNumber + 1, 0, bookmark.IsEnabled);
MethodInvoker setBookmarkColor = delegate {
bookmark.WillBeHit = breakpoint.HadBeenSet || debugger.Processes.Count == 0;
bookmark.WillBeHit = breakpoint.IsSet || debugger.Processes.Count == 0;
};
// event handlers on bookmark and breakpoint don't need deregistration
bookmark.IsEnabledChanged += delegate {
breakpoint.Enabled = bookmark.IsEnabled;
};
breakpoint.Changed += delegate { setBookmarkColor(); };
breakpoint.Set += delegate { setBookmarkColor(); };
setBookmarkColor();
EventHandler<ProcessEventArgs> bp_debugger_ProcessStarted = (sender, e) => {
setBookmarkColor();
// User can change line number by inserting or deleting lines
breakpoint.SourcecodeSegment.StartLine = bookmark.LineNumber + 1;
breakpoint.Line = bookmark.LineNumber + 1;
};
EventHandler<ProcessEventArgs> bp_debugger_ProcessExited = (sender, e) => {
setBookmarkColor();
@ -559,7 +558,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -559,7 +558,7 @@ namespace ICSharpCode.SharpDevelop.Services
if (debuggedProcess != null) {
SourcecodeSegment nextStatement = debuggedProcess.NextStatement;
if (nextStatement != null) {
DebuggerService.JumpToCurrentLine(nextStatement.SourceFullFilename, nextStatement.StartLine, nextStatement.StartColumn, nextStatement.EndLine, nextStatement.EndColumn);
DebuggerService.JumpToCurrentLine(nextStatement.Filename, nextStatement.StartLine, nextStatement.StartColumn, nextStatement.EndLine, nextStatement.EndColumn);
}
}
}

12
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/NDebugger-Breakpoints.cs

@ -65,7 +65,7 @@ namespace Debugger @@ -65,7 +65,7 @@ namespace Debugger
throw new DebuggerException("Breakpoint is not in collection");
}
internal Breakpoint AddBreakpoint(Breakpoint breakpoint)
public Breakpoint AddBreakpoint(Breakpoint breakpoint)
{
breakpointCollection.Add(breakpoint);
@ -74,7 +74,6 @@ namespace Debugger @@ -74,7 +74,6 @@ namespace Debugger
breakpoint.SetBreakpoint(module);
}
}
breakpoint.Changed += new EventHandler<BreakpointEventArgs>(OnBreakpointStateChanged);
breakpoint.Hit += new EventHandler<BreakpointEventArgs>(OnBreakpointHit);
OnBreakpointAdded(breakpoint);
@ -84,17 +83,16 @@ namespace Debugger @@ -84,17 +83,16 @@ namespace Debugger
public Breakpoint AddBreakpoint(string filename, int line)
{
return AddBreakpoint(new SourcecodeSegment(filename, line), true);
return AddBreakpoint(new Breakpoint(this, filename, null, line, 0, true));
}
public Breakpoint AddBreakpoint(SourcecodeSegment segment, bool breakpointEnabled)
public Breakpoint AddBreakpoint(string fileName, byte[] checkSum, int line, int column, bool enabled)
{
return AddBreakpoint(new Breakpoint(this, segment, breakpointEnabled));
return AddBreakpoint(new Breakpoint(this, fileName, checkSum, line, column, enabled));
}
public void RemoveBreakpoint(Breakpoint breakpoint)
{
breakpoint.Changed -= new EventHandler<BreakpointEventArgs>(OnBreakpointStateChanged);
breakpoint.Hit -= new EventHandler<BreakpointEventArgs>(OnBreakpointHit);
breakpoint.Enabled = false;
@ -112,7 +110,7 @@ namespace Debugger @@ -112,7 +110,7 @@ namespace Debugger
public void DeactivateBreakpoints()
{
foreach (Breakpoint b in breakpointCollection) {
b.Deactivate();
b.Enabled = false;
}
}

129
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs

@ -115,6 +115,11 @@ namespace Debugger @@ -115,6 +115,11 @@ namespace Debugger
}
}
SourcecodeSegment GetSegmentForOffet(uint offset)
{
return SourcecodeSegment.Resolve(this.MethodInfo.Module, corFunction, offset);
}
/// <summary> Step into next instruction </summary>
public void StepInto()
{
@ -190,92 +195,6 @@ namespace Debugger @@ -190,92 +195,6 @@ namespace Debugger
return GetSegmentForOffet(CorInstructionPtr);
}
}
/// <summary>
/// Returns null on error.
///
/// 'ILStart &lt;= ILOffset &lt;= ILEnd' and this range includes at least
/// the returned area of source code. (May incude some extra compiler generated IL too)
/// </summary>
SourcecodeSegment GetSegmentForOffet(uint offset)
{
ISymUnmanagedMethod symMethod = this.MethodInfo.SymMethod;
if (symMethod == null) {
return null;
}
uint sequencePointCount = symMethod.SequencePointCount;
SequencePoint[] sequencePoints = symMethod.SequencePoints;
SourcecodeSegment retVal = new SourcecodeSegment();
// 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 (sequencePoints[i].Offset <= offset || i == 0) {
// Set inforamtion about current IL range
int codeSize = (int)corFunction.ILCode.Size;
retVal.ILOffset = (int)offset;
retVal.ILStart = (int)sequencePoints[i].Offset;
retVal.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++;
retVal.ILEnd = (i + 1 < sequencePointCount) ? (int)sequencePoints[i+1].Offset : codeSize;
}
// Look back for 'real' sequence
while (i - 1 >= 0 && sequencePoints[i].Line == 0xFeeFee) {
i--;
retVal.ILStart = (int)sequencePoints[i].Offset;
}
// Wow, there are no 'real' sequences
if (sequencePoints[i].Line == 0xFeeFee) {
return null;
}
retVal.ModuleFilename = this.MethodInfo.Module.FullPath;
retVal.SourceFullFilename = sequencePoints[i].Document.URL;
retVal.StartLine = (int)sequencePoints[i].Line;
retVal.StartColumn = (int)sequencePoints[i].Column;
retVal.EndLine = (int)sequencePoints[i].EndLine;
retVal.EndColumn = (int)sequencePoints[i].EndColumn;
List<int> stepRanges = new List<int>();
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);
}
}
}
retVal.StepRanges = stepRanges.ToArray();
return retVal;
}
return null;
}
/// <summary>
/// Determine whether the instrustion pointer can be set to given location
@ -299,31 +218,25 @@ namespace Debugger @@ -299,31 +218,25 @@ namespace Debugger
{
process.AssertPaused();
SourcecodeSegment suggestion = new SourcecodeSegment(filename, line, column, column);
ICorDebugFunction corFunction;
int ilOffset;
if (!suggestion.GetFunctionAndOffset(this.MethodInfo.Module, false, out corFunction, out ilOffset)) {
return null;
} else {
if (corFunction.Token != this.MethodInfo.MetadataToken) {
return null;
} else {
try {
if (simulate) {
CorILFrame.CanSetIP((uint)ilOffset);
} else {
// invalidates all frames and chains for the current thread
CorILFrame.SetIP((uint)ilOffset);
process.NotifyResumed(DebuggeeStateAction.Keep);
process.NotifyPaused(PausedReason.SetIP);
process.RaisePausedEvents();
}
} catch {
return null;
SourcecodeSegment segment = SourcecodeSegment.Resolve(this.MethodInfo.Module, filename, null, line, column);
if (segment != null && segment.CorFunction.Token == this.MethodInfo.MetadataToken) {
try {
if (simulate) {
CorILFrame.CanSetIP((uint)segment.ILStart);
} else {
// Invalidates all frames and chains for the current thread
CorILFrame.SetIP((uint)segment.ILStart);
process.NotifyResumed(DebuggeeStateAction.Keep);
process.NotifyPaused(PausedReason.SetIP);
process.RaisePausedEvents();
}
return GetSegmentForOffet((uint)ilOffset);
} catch {
return null;
}
return segment;
}
return null;
}
/// <summary>

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs

@ -308,7 +308,7 @@ namespace Debugger @@ -308,7 +308,7 @@ namespace Debugger
SourcecodeSegment loc = stackFrame.NextStatement;
if (loc != null) {
stackTrace.Append(" ");
stackTrace.AppendFormat(formatSymbols, stackFrame.MethodInfo.FullName, loc.SourceFullFilename, loc.StartLine);
stackTrace.AppendFormat(formatSymbols, stackFrame.MethodInfo.FullName, loc.Filename, loc.StartLine);
stackTrace.AppendLine();
} else {
stackTrace.AppendFormat(formatNoSymbols, stackFrame.MethodInfo.FullName);

134
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Breakpoint.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Collections.Generic;
using Debugger.Wrappers.CorDebug;
namespace Debugger
@ -13,114 +14,113 @@ namespace Debugger @@ -13,114 +14,113 @@ namespace Debugger
public class Breakpoint: DebuggerObject
{
NDebugger debugger;
string fileName;
byte[] checkSum;
int line;
int column;
bool enabled;
SourcecodeSegment sourcecodeSegment;
SourcecodeSegment originalLocation;
List<ICorDebugFunctionBreakpoint> corBreakpoints = new List<ICorDebugFunctionBreakpoint>();
bool hadBeenSet = false;
bool enabled = true;
ICorDebugFunctionBreakpoint corBreakpoint;
public event EventHandler<BreakpointEventArgs> Hit;
public event EventHandler<BreakpointEventArgs> Set;
[Debugger.Tests.Ignore]
public NDebugger Debugger {
get {
return debugger;
}
get { return debugger; }
}
public SourcecodeSegment SourcecodeSegment {
get {
return sourcecodeSegment;
}
public string FileName {
get { return fileName; }
}
public bool HadBeenSet {
get {
return hadBeenSet;
}
internal set {
hadBeenSet = value;
OnChanged();
}
public byte[] CheckSum {
get { return checkSum; }
}
public int Line {
get { return line; }
set { line = value; }
}
public int Column {
get { return column; }
set { column = value; }
}
public bool Enabled {
get {
return enabled;
}
set {
get { return enabled; }
set {
enabled = value;
if (HadBeenSet) {
corBreakpoint.Activate(enabled?1:0);
foreach(ICorDebugFunctionBreakpoint corBreakpoint in corBreakpoints) {
corBreakpoint.Activate(enabled ? 1 : 0);
}
OnChanged();
}
}
public event EventHandler<BreakpointEventArgs> Changed;
protected void OnChanged()
{
if (Changed != null) {
Changed(this, new BreakpointEventArgs(this));
public SourcecodeSegment OriginalLocation {
get { return originalLocation; }
}
public bool IsSet {
get {
return corBreakpoints.Count > 0;
}
}
public event EventHandler<BreakpointEventArgs> Hit;
internal void OnHit()
protected virtual void OnHit(BreakpointEventArgs e)
{
if (Hit != null) {
Hit(this, new BreakpointEventArgs(this));
Hit(this, e);
}
}
internal Breakpoint(NDebugger debugger, SourcecodeSegment sourcecodeSegment, bool enabled)
{
this.debugger = debugger;
this.sourcecodeSegment = sourcecodeSegment;
this.enabled = enabled;
}
internal bool Equals(ICorDebugFunctionBreakpoint obj)
protected virtual void OnSet(BreakpointEventArgs e)
{
return corBreakpoint == obj;
if (Set != null) {
Set(this, e);
}
}
public override bool Equals(object obj)
public Breakpoint(NDebugger debugger, string fileName, byte[] checkSum, int line, int column, bool enabled)
{
return base.Equals(obj) || (corBreakpoint != null && corBreakpoint.Equals(obj));
this.debugger = debugger;
this.fileName = fileName;
this.checkSum = checkSum;
this.line = line;
this.column = column;
this.enabled = enabled;
}
public override int GetHashCode()
internal bool IsOwnerOf(ICorDebugFunctionBreakpoint breakpoint)
{
return base.GetHashCode();
foreach(ICorDebugFunctionBreakpoint corBreakpoint in corBreakpoints) {
if (corBreakpoint == breakpoint) return true;
}
return false;
}
internal void MarkUnset()
{
HadBeenSet = false;
corBreakpoints.Clear();
}
internal void Deactivate()
internal bool SetBreakpoint(Module module)
{
corBreakpoint.Activate(0);
}
public bool SetBreakpoint(Module module)
{
ICorDebugFunction corFunction;
int ilOffset;
if (!sourcecodeSegment.GetFunctionAndOffset(module, false, out corFunction, out ilOffset)) {
return false;
}
SourcecodeSegment segment = SourcecodeSegment.Resolve(module, FileName, CheckSum, Line, Column);
if (segment == null) return false;
originalLocation = segment;
corBreakpoint = corFunction.ILCode.CreateBreakpoint((uint)ilOffset);
ICorDebugFunctionBreakpoint corBreakpoint = segment.CorFunction.ILCode.CreateBreakpoint((uint)segment.ILStart);
corBreakpoint.Activate(enabled ? 1 : 0);
hadBeenSet = true;
corBreakpoint.Activate(enabled?1:0);
corBreakpoints.Add(corBreakpoint);
OnChanged();
OnSet(new BreakpointEventArgs(this));
return true;
}

346
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/SourcecodeSegment.cs

@ -7,221 +7,261 @@ @@ -7,221 +7,261 @@
using System;
using System.Collections.Generic;
using Debugger.Wrappers.CorDebug;
using Debugger.Wrappers.CorSym;
using System.IO;
namespace Debugger
{
[Serializable]
public class SourcecodeSegment
public class SourcecodeSegment: DebuggerObject
{
string moduleFilename;
string sourceFullFilename;
Module module;
string filename;
byte[] checkSum;
int startLine;
int startColumn;
int endLine;
int endColumn;
int ilOffset;
ICorDebugFunction corFunction;
int ilStart;
int ilEnd;
int[] stepRanges;
internal SourcecodeSegment()
{
}
public SourcecodeSegment(string sourceFilename, int line)
{
this.sourceFullFilename = sourceFilename;
this.startLine = line;
this.endLine = line;
}
public SourcecodeSegment(string sourceFilename, int line, int startColumn, int endColumn)
{
this.sourceFullFilename = sourceFilename;
this.startLine = line;
this.endLine = line;
this.startColumn = startColumn;
this.endColumn = endColumn;
}
public SourcecodeSegment(string sourceFilename, int startLine, int endLine, int startColumn, int endColumn)
{
this.sourceFullFilename = sourceFilename;
this.startLine = startLine;
this.endLine = endLine;
this.startColumn = startColumn;
this.endColumn = endColumn;
}
public string ModuleFilename {
get {
return moduleFilename;
}
set {
moduleFilename = value;
}
public Module Module {
get { return module; }
}
public string SourceFullFilename {
get {
return sourceFullFilename;
}
set {
sourceFullFilename = value;
}
public string Filename {
get { return filename; }
}
public string SourceFilename {
get {
return System.IO.Path.GetFileName(sourceFullFilename);
}
public byte[] CheckSum {
get { return checkSum; }
}
public int StartLine {
get {
return startLine;
}
set {
startLine = value;
}
get { return startLine; }
}
public int StartColumn {
get {
return startColumn;
}
set {
startColumn = value;
}
get { return startColumn; }
}
public int EndLine {
get {
return endLine;
}
set {
endLine = value;
}
get { return endLine; }
}
public int EndColumn {
get {
return endColumn;
}
set {
endColumn = value;
}
}
public int[] StepRanges {
get {
return stepRanges;
}
set {
stepRanges = value;
}
get { return endColumn; }
}
public int ILOffset {
get {
return ilOffset;
}
set {
ilOffset = value;
}
internal ICorDebugFunction CorFunction {
get { return corFunction; }
}
public int ILStart {
get {
return ilStart;
}
set {
ilStart = value;
}
get { return ilStart; }
}
public int ILEnd {
get {
return ilEnd;
}
set {
ilEnd = value;
}
get { return ilEnd; }
}
public int[] StepRanges {
get { return stepRanges; }
}
// Returns true if found
internal bool GetFunctionAndOffset(Module module, bool normailize, out ICorDebugFunction function, out int ilOffset)
private SourcecodeSegment()
{
function = null;
ilOffset = 0;
ISymUnmanagedReader symReader = module.SymReader;
if (symReader == null) {
return false; // No symbols
}
// Do not use ISymUnmanagedReader.GetDocument! It is broken if two files have the same name
}
static ISymUnmanagedDocument GetSymDocument(Module module, string filename, byte[] checksum)
{
if (filename == null) throw new ArgumentNullException("filename");
filename = filename.ToLower();
ISymUnmanagedDocument[] symDocs = module.SymDocuments;
ISymUnmanagedDocument symDoc = null;
foreach(ISymUnmanagedDocument d in symDocs) {
if (d.URL.ToLower() == this.SourceFullFilename.ToLower()) {
symDoc = d;
// "c:\project\file.cs" N/A
if (Path.IsPathRooted(filename) && checksum == null) {
foreach(ISymUnmanagedDocument symDoc in symDocs) {
if (symDoc.URL.ToLower() == filename) return symDoc;
}
return null; // Not found
}
if (symDoc == null) {
return false; // Does not use source file
// "c:\project\file.cs" 0123456789
if (Path.IsPathRooted(filename) && checksum != null) {
foreach(ISymUnmanagedDocument symDoc in symDocs) {
if (symDoc.URL.ToLower() == filename) return symDoc;
}
// Not found - try to find using checksum
filename = Path.GetFileName(filename);
}
uint validLine;
try {
validLine = symDoc.FindClosestLine((uint)StartLine);
} catch {
return false; // Not on a vaild point
// "file.cs" N/A
if (!Path.IsPathRooted(filename) && checksum == null) {
if (!filename.StartsWith(@"\")) {
filename = @"\" + filename;
}
foreach(ISymUnmanagedDocument symDoc in symDocs) {
if (symDoc.URL.ToLower().EndsWith(filename)) return symDoc;
}
return null; // Not found
}
if (validLine != StartLine && normailize) {
StartLine = (int)validLine;
EndLine = (int)validLine;
StartColumn = 0;
EndColumn = 0;
// "file.cs" 0123456789
if (!Path.IsPathRooted(filename) && checksum != null) {
if (!filename.StartsWith(@"\")) {
filename = @"\" + filename;
}
foreach(ISymUnmanagedDocument symDoc in symDocs) {
if (!symDoc.URL.ToLower().EndsWith(filename)) continue;
byte[] symDocCheckSum = symDoc.CheckSum;
if (symDocCheckSum.Length != checksum.Length) continue;
for (int i = 0; i < checksum.Length; i++) {
if (symDocCheckSum[i] != checksum[i]) continue;
}
return symDoc;
}
return null; // Not found
}
return null;
}
public static SourcecodeSegment Resolve(Module module, string fileName, byte[] checkSum, 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
ISymUnmanagedDocument symDoc = GetSymDocument(module, fileName, checkSum);
if (symDoc == null) return null; // Document not found
ISymUnmanagedMethod symMethod;
try {
symMethod = symReader.GetMethodFromDocumentPosition(symDoc, validLine, 0);
//uint validLine = symDoc.FindClosestLine((uint)StartLine);
symMethod = symReader.GetMethodFromDocumentPosition(symDoc, (uint)line, (uint)column);
} catch {
return false; //Not found
return null; //Not found
}
// Do not use ISymUnmanagedMethod.GetOffset! It sometimes returns negative offset
SequencePoint[] seqPoints = symMethod.SequencePoints;
Array.Sort(seqPoints);
if (seqPoints.Length == 0) return false;
if (this.StartLine < seqPoints[0].Line) return false;
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 (this.StartLine < sqPoint.EndLine || (this.StartLine == sqPoint.EndLine && this.StartColumn < sqPoint.EndColumn)) {
function = module.CorModule.GetFunctionFromToken(symMethod.Token);
ilOffset = (int)sqPoint.Offset;
startLine = (int)sqPoint.Line;
startColumn = (int)sqPoint.Column;
endLine = (int)sqPoint.EndLine;
endColumn = (int)sqPoint.EndColumn;
return true;
if (line < sqPoint.EndLine || (line == sqPoint.EndLine && column < sqPoint.EndColumn)) {
SourcecodeSegment segment = new SourcecodeSegment();
segment.module = module;
segment.filename = symDoc.URL;
segment.checkSum = symDoc.CheckSum;
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.Token);
segment.ilStart = (int)sqPoint.Offset;
segment.ilEnd = (int)sqPoint.Offset;
segment.stepRanges = null;
return segment;
}
}
return null;
}
/// <summary>
/// 'ILStart &lt;= ILOffset &lt;= ILEnd' and this range includes at least
/// the returned area of source code. (May incude some extra compiler generated IL too)
/// </summary>
internal static SourcecodeSegment Resolve(Module module, ICorDebugFunction corFunction, uint offset)
{
ISymUnmanagedReader symReader = module.SymReader;
if (symReader == null) return null; // No symbols
ISymUnmanagedMethod symMethod = symReader.GetMethod(corFunction.Token);
if (symMethod == null) return null;
uint sequencePointCount = symMethod.SequencePointCount;
SequencePoint[] sequencePoints = symMethod.SequencePoints;
// 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 (sequencePoints[i].Offset <= offset || i == 0) {
// Set inforamtion about current IL range
int codeSize = (int)corFunction.ILCode.Size;
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<int> stepRanges = new List<int>();
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 = sequencePoints[i].Document.URL;
segment.checkSum = sequencePoints[i].Document.CheckSum;
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();
return segment;
}
}
return false;
return null;
}
public override string ToString()
{
return string.Format("Start={0},{1} End={2},{3}", this.startLine, this.startColumn, this.endLine, this.endColumn);
return string.Format("{0}:{1},{2}-{3},{4}", Path.GetFileName(this.Filename), this.startLine, this.startColumn, this.endLine, this.endColumn);
}
}
}

17
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorSym/ISymUnmanagedDocument.cs

@ -10,8 +10,8 @@ @@ -10,8 +10,8 @@
namespace Debugger.Wrappers.CorSym
{
using System;
using System.Runtime.InteropServices;
public partial class ISymUnmanagedDocument
{
public string URL {
@ -19,6 +19,19 @@ namespace Debugger.Wrappers.CorSym @@ -19,6 +19,19 @@ namespace Debugger.Wrappers.CorSym
return Util.GetString(GetURL, 256, true);
}
}
public byte[] CheckSum {
get {
uint checkSumLength = 0;
GetCheckSum(checkSumLength, out checkSumLength, IntPtr.Zero);
IntPtr checkSumPtr = Marshal.AllocHGlobal((int)checkSumLength);
GetCheckSum(checkSumLength, out checkSumLength, checkSumPtr);
byte[] checkSumBytes = new byte[checkSumLength];
Marshal.Copy(checkSumPtr, checkSumBytes, 0, (int)checkSumLength);
Marshal.FreeHGlobal(checkSumPtr);
return checkSumBytes;
}
}
}
}

30
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Breakpoint.cs

@ -14,8 +14,8 @@ namespace Debugger.Tests.TestPrograms @@ -14,8 +14,8 @@ namespace Debugger.Tests.TestPrograms
public static void Main()
{
System.Diagnostics.Debugger.Break();
System.Diagnostics.Debug.WriteLine("Mark 1");
System.Diagnostics.Debug.WriteLine("Mark 2"); // Breakpoint
System.Diagnostics.Debug.WriteLine("Main 1");
System.Diagnostics.Debug.WriteLine("Main 2"); // Breakpoint
System.Diagnostics.Debugger.Break();
}
}
@ -30,11 +30,11 @@ namespace Debugger.Tests { @@ -30,11 +30,11 @@ namespace Debugger.Tests {
[NUnit.Framework.Test]
public void Breakpoint()
{
Breakpoint breakpoint = debugger.AddBreakpoint(@"F:\SharpDevelopTrunk\src\AddIns\Misc\Debugger\Debugger.Tests\Project\Src\TestPrograms\Breakpoint.cs", 18);
Breakpoint breakpoint = debugger.AddBreakpoint(@"Breakpoint.cs", 18);
StartTest("Breakpoint.cs");
Assert.IsTrue(breakpoint.HadBeenSet);
Assert.IsTrue(breakpoint.IsSet);
ObjectDump(breakpoint);
process.Continue();
process.Continue();
@ -58,22 +58,30 @@ namespace Debugger.Tests { @@ -58,22 +58,30 @@ namespace Debugger.Tests {
<ModuleLoaded symbols="False">System.dll</ModuleLoaded>
<DebuggingPaused>Break</DebuggingPaused>
<Object Type="Breakpoint" ToString="Debugger.Breakpoint">
<CheckSum>null</CheckSum>
<Column>0</Column>
<Enabled>True</Enabled>
<HadBeenSet>True</HadBeenSet>
<SourcecodeSegment>Start=18,0 End=18,0</SourcecodeSegment>
<FileName>Breakpoint.cs</FileName>
<IsSet>True</IsSet>
<Line>18</Line>
<OriginalLocation>Breakpoint.cs:18,4-18,49</OriginalLocation>
</Object>
<ModuleLoaded symbols="False">System.Configuration.dll</ModuleLoaded>
<ModuleLoaded symbols="False">System.Xml.dll</ModuleLoaded>
<LogMessage>Mark 1\r\n</LogMessage>
<LogMessage>Main 1\r\n</LogMessage>
<DebuggingPaused>Breakpoint</DebuggingPaused>
<LogMessage>Mark 2\r\n</LogMessage>
<LogMessage>Main 2\r\n</LogMessage>
<DebuggingPaused>Break</DebuggingPaused>
<ProcessExited />
<Object Type="Breakpoint" ToString="Debugger.Breakpoint">
<CheckSum>null</CheckSum>
<Column>0</Column>
<Enabled>True</Enabled>
<HadBeenSet>False</HadBeenSet>
<SourcecodeSegment>Start=18,0 End=18,0</SourcecodeSegment>
<FileName>Breakpoint.cs</FileName>
<IsSet>False</IsSet>
<Line>18</Line>
<OriginalLocation>Breakpoint.cs:18,4-18,49</OriginalLocation>
</Object>
</Test>
</DebuggerTests>
#endif // EXPECTED_OUTPUT
#endif // EXPECTED_OUTPUT

12
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Callstack.cs

@ -64,7 +64,7 @@ namespace Debugger.Tests { @@ -64,7 +64,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Sub2</MethodInfo>
<NextStatement>Start=26,4 End=26,40</NextStatement>
<NextStatement>Callstack.cs:26,4-26,40</NextStatement>
</Item>
<Item Type="StackFrame" ToString="Debugger.Tests.TestPrograms.Callstack.Sub1">
<ArgumentCount>0</ArgumentCount>
@ -72,7 +72,7 @@ namespace Debugger.Tests { @@ -72,7 +72,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Sub1</MethodInfo>
<NextStatement>Start=21,4 End=21,11</NextStatement>
<NextStatement>Callstack.cs:21,4-21,11</NextStatement>
</Item>
<Item Type="StackFrame" ToString="Debugger.Tests.TestPrograms.Callstack.Main">
<ArgumentCount>0</ArgumentCount>
@ -80,7 +80,7 @@ namespace Debugger.Tests { @@ -80,7 +80,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Main</MethodInfo>
<NextStatement>Start=16,4 End=16,11</NextStatement>
<NextStatement>Callstack.cs:16,4-16,11</NextStatement>
</Item>
</Callstack>
<DebuggingPaused>StepComplete</DebuggingPaused>
@ -91,7 +91,7 @@ namespace Debugger.Tests { @@ -91,7 +91,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Sub1</MethodInfo>
<NextStatement>Start=21,4 End=21,11</NextStatement>
<NextStatement>Callstack.cs:21,4-21,11</NextStatement>
</Item>
<Item Type="StackFrame" ToString="Debugger.Tests.TestPrograms.Callstack.Main">
<ArgumentCount>0</ArgumentCount>
@ -99,7 +99,7 @@ namespace Debugger.Tests { @@ -99,7 +99,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Main</MethodInfo>
<NextStatement>Start=16,4 End=16,11</NextStatement>
<NextStatement>Callstack.cs:16,4-16,11</NextStatement>
</Item>
</Callstack>
<DebuggingPaused>StepComplete</DebuggingPaused>
@ -110,7 +110,7 @@ namespace Debugger.Tests { @@ -110,7 +110,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Main</MethodInfo>
<NextStatement>Start=16,4 End=16,11</NextStatement>
<NextStatement>Callstack.cs:16,4-16,11</NextStatement>
</Item>
</Callstack>
<ProcessExited />

10
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/FunctionLifetime.cs

@ -76,7 +76,7 @@ namespace Debugger.Tests { @@ -76,7 +76,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Function</MethodInfo>
<NextStatement>Start=22,4 End=22,40</NextStatement>
<NextStatement>FunctionLifetime.cs:22,4-22,40</NextStatement>
</SelectedStackFrame>
<DebuggingPaused>Break</DebuggingPaused>
<Old_StackFrame Type="StackFrame" ToString="Debugger.Tests.TestPrograms.FunctionLifetime.Function">
@ -93,7 +93,7 @@ namespace Debugger.Tests { @@ -93,7 +93,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>SubFunction</MethodInfo>
<NextStatement>Start=29,4 End=29,40</NextStatement>
<NextStatement>FunctionLifetime.cs:29,4-29,40</NextStatement>
</SelectedStackFrame>
<DebuggingPaused>Break</DebuggingPaused>
<Old_StackFrame Type="StackFrame" ToString="Debugger.Tests.TestPrograms.FunctionLifetime.Function">
@ -110,7 +110,7 @@ namespace Debugger.Tests { @@ -110,7 +110,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Function</MethodInfo>
<NextStatement>Start=24,4 End=24,40</NextStatement>
<NextStatement>FunctionLifetime.cs:24,4-24,40</NextStatement>
</SelectedStackFrame>
<DebuggingPaused>Break</DebuggingPaused>
<Main Type="StackFrame" ToString="Debugger.Tests.TestPrograms.FunctionLifetime.Main">
@ -119,7 +119,7 @@ namespace Debugger.Tests { @@ -119,7 +119,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Main</MethodInfo>
<NextStatement>Start=17,4 End=17,40</NextStatement>
<NextStatement>FunctionLifetime.cs:17,4-17,40</NextStatement>
</Main>
<Old_StackFrame Type="StackFrame" ToString="Debugger.Tests.TestPrograms.FunctionLifetime.Function">
<ArgumentCount exception="StackFrame has expired" />
@ -135,7 +135,7 @@ namespace Debugger.Tests { @@ -135,7 +135,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Main</MethodInfo>
<NextStatement>Start=17,4 End=17,40</NextStatement>
<NextStatement>FunctionLifetime.cs:17,4-17,40</NextStatement>
</SelectedStackFrame>
<ProcessExited />
</Test>

16
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Generics.cs

@ -160,7 +160,7 @@ namespace Debugger.Tests { @@ -160,7 +160,7 @@ namespace Debugger.Tests {
<Module>Generics.exe</Module>
<Name>Metod</Name>
</MethodInfo>
<NextStatement>Start=48,4 End=48,40</NextStatement>
<NextStatement>Generics.cs:48,4-48,40</NextStatement>
</SelectedStackFrame>
<SelectedStackFrame-GetArguments Type="Value[]" ToString="Debugger.Value[]">
<Item Type="Value" ToString="v = 1">
@ -224,7 +224,7 @@ namespace Debugger.Tests { @@ -224,7 +224,7 @@ namespace Debugger.Tests {
<Module>Generics.exe</Module>
<Name>GenericMethod</Name>
</MethodInfo>
<NextStatement>Start=54,4 End=54,40</NextStatement>
<NextStatement>Generics.cs:54,4-54,40</NextStatement>
</SelectedStackFrame>
<SelectedStackFrame-GetArguments Type="Value[]" ToString="Debugger.Value[]">
<Item Type="Value" ToString="v = 2">
@ -288,7 +288,7 @@ namespace Debugger.Tests { @@ -288,7 +288,7 @@ namespace Debugger.Tests {
<Module>Generics.exe</Module>
<Name>StaticMetod</Name>
</MethodInfo>
<NextStatement>Start=60,4 End=60,40</NextStatement>
<NextStatement>Generics.cs:60,4-60,40</NextStatement>
</SelectedStackFrame>
<SelectedStackFrame-GetArguments Type="Value[]" ToString="Debugger.Value[]">
<Item Type="Value" ToString="v = 3">
@ -352,7 +352,7 @@ namespace Debugger.Tests { @@ -352,7 +352,7 @@ namespace Debugger.Tests {
<Module>Generics.exe</Module>
<Name>StaticGenericMethod</Name>
</MethodInfo>
<NextStatement>Start=66,4 End=66,40</NextStatement>
<NextStatement>Generics.cs:66,4-66,40</NextStatement>
</SelectedStackFrame>
<SelectedStackFrame-GetArguments Type="Value[]" ToString="Debugger.Value[]">
<Item Type="Value" ToString="v = 4">
@ -416,7 +416,7 @@ namespace Debugger.Tests { @@ -416,7 +416,7 @@ namespace Debugger.Tests {
<Module>Generics.exe</Module>
<Name>Metod</Name>
</MethodInfo>
<NextStatement>Start=75,4 End=75,40</NextStatement>
<NextStatement>Generics.cs:75,4-75,40</NextStatement>
</SelectedStackFrame>
<SelectedStackFrame-GetArguments Type="Value[]" ToString="Debugger.Value[]">
<Item Type="Value" ToString="v = 5">
@ -480,7 +480,7 @@ namespace Debugger.Tests { @@ -480,7 +480,7 @@ namespace Debugger.Tests {
<Module>Generics.exe</Module>
<Name>GenericMethod</Name>
</MethodInfo>
<NextStatement>Start=81,4 End=81,40</NextStatement>
<NextStatement>Generics.cs:81,4-81,40</NextStatement>
</SelectedStackFrame>
<SelectedStackFrame-GetArguments Type="Value[]" ToString="Debugger.Value[]">
<Item Type="Value" ToString="v = 6">
@ -544,7 +544,7 @@ namespace Debugger.Tests { @@ -544,7 +544,7 @@ namespace Debugger.Tests {
<Module>Generics.exe</Module>
<Name>StaticMetod</Name>
</MethodInfo>
<NextStatement>Start=87,4 End=87,40</NextStatement>
<NextStatement>Generics.cs:87,4-87,40</NextStatement>
</SelectedStackFrame>
<SelectedStackFrame-GetArguments Type="Value[]" ToString="Debugger.Value[]">
<Item Type="Value" ToString="v = 7">
@ -608,7 +608,7 @@ namespace Debugger.Tests { @@ -608,7 +608,7 @@ namespace Debugger.Tests {
<Module>Generics.exe</Module>
<Name>StaticGenericMethod</Name>
</MethodInfo>
<NextStatement>Start=93,4 End=93,40</NextStatement>
<NextStatement>Generics.cs:93,4-93,40</NextStatement>
</SelectedStackFrame>
<SelectedStackFrame-GetArguments Type="Value[]" ToString="Debugger.Value[]">
<Item Type="Value" ToString="v = 8">

2
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/StackOverflow.cs

@ -59,7 +59,7 @@ namespace Debugger.Tests { @@ -59,7 +59,7 @@ namespace Debugger.Tests {
<HasExpired>False</HasExpired>
<HasSymbols>True</HasSymbols>
<MethodInfo>Fun</MethodInfo>
<NextStatement>Start=21,3 End=21,4</NextStatement>
<NextStatement>StackOverflow.cs:21,3-21,4</NextStatement>
</LastStackFrame>
<ProcessExited />
</Test>

18
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Stepping.cs

@ -83,30 +83,30 @@ namespace Debugger.Tests { @@ -83,30 +83,30 @@ namespace Debugger.Tests {
<ModuleLoaded symbols="True">Stepping.exe</ModuleLoaded>
<ModuleLoaded symbols="False">System.dll</ModuleLoaded>
<DebuggingPaused>Break</DebuggingPaused>
<NextStatement>Start=16,4 End=16,40</NextStatement>
<NextStatement>Stepping.cs:16,4-16,40</NextStatement>
<DebuggingPaused>StepComplete</DebuggingPaused>
<NextStatement>Start=17,4 End=17,44</NextStatement>
<NextStatement>Stepping.cs:17,4-17,44</NextStatement>
<ModuleLoaded symbols="False">System.Configuration.dll</ModuleLoaded>
<ModuleLoaded symbols="False">System.Xml.dll</ModuleLoaded>
<LogMessage>1\r\n</LogMessage>
<DebuggingPaused>StepComplete</DebuggingPaused>
<NextStatement>Start=18,4 End=18,10</NextStatement>
<NextStatement>Stepping.cs:18,4-18,10</NextStatement>
<DebuggingPaused>StepComplete</DebuggingPaused>
<NextStatement>Start=23,3 End=23,4</NextStatement>
<NextStatement>Stepping.cs:23,3-23,4</NextStatement>
<DebuggingPaused>StepComplete</DebuggingPaused>
<NextStatement>Start=24,4 End=24,44</NextStatement>
<NextStatement>Stepping.cs:24,4-24,44</NextStatement>
<LogMessage>2\r\n</LogMessage>
<DebuggingPaused>StepComplete</DebuggingPaused>
<NextStatement>Start=25,4 End=25,44</NextStatement>
<NextStatement>Stepping.cs:25,4-25,44</NextStatement>
<LogMessage>3\r\n</LogMessage>
<LogMessage>4\r\n</LogMessage>
<DebuggingPaused>StepComplete</DebuggingPaused>
<NextStatement>Start=18,4 End=18,10</NextStatement>
<NextStatement>Stepping.cs:18,4-18,10</NextStatement>
<DebuggingPaused>StepComplete</DebuggingPaused>
<NextStatement>Start=19,4 End=19,11</NextStatement>
<NextStatement>Stepping.cs:19,4-19,11</NextStatement>
<LogMessage>5\r\n</LogMessage>
<DebuggingPaused>StepComplete</DebuggingPaused>
<NextStatement>Start=20,3 End=20,4</NextStatement>
<NextStatement>Stepping.cs:20,3-20,4</NextStatement>
<ProcessExited />
</Test>
</DebuggerTests>

Loading…
Cancel
Save