Browse Source

Prototype of SetIP

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@252 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 21 years ago
parent
commit
8de9cde42b
  1. 4
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/WindowsDebugger.cs
  2. 61
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Breakpoints/Breakpoint.cs
  3. 3
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/DebuggerEvents/PausedReason.cs
  4. 228
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Function.cs
  5. 67
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/SourcecodeSegment.cs
  6. 21
      src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs

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

@ -265,6 +265,10 @@ namespace ICSharpCode.SharpDevelop.Services
RemoveBreakpoint(e.BreakpointBookmark); RemoveBreakpoint(e.BreakpointBookmark);
AddBreakpoint(e.BreakpointBookmark); AddBreakpoint(e.BreakpointBookmark);
}; };
DebuggerService.SetIPRequest += delegate (object sender, DebuggerService.SetIPArgs args) {
SourcecodeSegment seg = debugger.CurrentThread.CurrentFunction.SetIP(args.filename, args.line + 1, args.column);
};
RestoreNDebuggerBreakpoints(); RestoreNDebuggerBreakpoints();

61
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Breakpoints/Breakpoint.cs

@ -109,74 +109,29 @@ namespace DebuggerLibrary
} }
internal unsafe void SetBreakpoint() internal unsafe bool SetBreakpoint()
{ {
if (hadBeenSet) { if (hadBeenSet) {
return; return true;
} }
Module module = null;
ISymbolReader symReader = null;
ISymbolDocument symDoc = null;
// Try to get doc from seg.moduleFilename
if (sourcecodeSegment.ModuleFilename != null) {
try {
module = debugger.GetModule(sourcecodeSegment.ModuleFilename);
symReader = debugger.GetModule(sourcecodeSegment.ModuleFilename).SymReader;
symDoc = symReader.GetDocument(sourcecodeSegment.SourceFullFilename,Guid.Empty,Guid.Empty,Guid.Empty);
} catch {}
}
// search all modules
if (symDoc == null) {
foreach (Module m in debugger.Modules) {
module = m;
symReader = m.SymReader;
if (symReader == null) {
continue;
}
symDoc = symReader.GetDocument(sourcecodeSegment.SourceFullFilename,Guid.Empty,Guid.Empty,Guid.Empty);
if (symDoc != null) {
break;
}
}
}
if (symDoc == null) {
//throw new Exception("Failed to add breakpoint - (module not loaded? wrong sourceFilename?)");
return;
}
int validStartLine;
validStartLine = symDoc.FindClosestLine(sourcecodeSegment.StartLine);
if (validStartLine != sourcecodeSegment.StartLine) {
sourcecodeSegment.StartLine = validStartLine;
sourcecodeSegment.EndLine = validStartLine;
sourcecodeSegment.StartColumn = 0;
sourcecodeSegment.EndColumn = 0;
}
ISymbolMethod symMethod;
symMethod = symReader.GetMethodFromDocumentPosition(symDoc, sourcecodeSegment.StartLine, sourcecodeSegment.StartColumn);
int corInstructionPtr = symMethod.GetOffset(symDoc, sourcecodeSegment.StartLine, sourcecodeSegment.StartColumn);
ICorDebugFunction corFunction; ICorDebugFunction corFunction;
module.CorModule.GetFunctionFromToken((uint)symMethod.Token.GetToken(), out corFunction); int ilOffset;
if (!sourcecodeSegment.GetFunctionAndOffset(debugger, true, out corFunction, out ilOffset)) {
return false;
}
ICorDebugCode code; ICorDebugCode code;
corFunction.GetILCode(out code); corFunction.GetILCode(out code);
code.CreateBreakpoint((uint)corInstructionPtr, out corBreakpoint); code.CreateBreakpoint((uint)ilOffset, out corBreakpoint);
hadBeenSet = true; hadBeenSet = true;
corBreakpoint.Activate(enabled?1:0); corBreakpoint.Activate(enabled?1:0);
pBreakpoint = Marshal.GetComInterfaceForObject(corBreakpoint, typeof(ICorDebugFunctionBreakpoint)); pBreakpoint = Marshal.GetComInterfaceForObject(corBreakpoint, typeof(ICorDebugFunctionBreakpoint));
OnBreakpointStateChanged(); OnBreakpointStateChanged();
return true;
} }
} }
} }

3
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/DebuggerEvents/PausedReason.cs

@ -18,6 +18,7 @@ namespace DebuggerLibrary
EvalComplete, EvalComplete,
CurrentThreadChanged, CurrentThreadChanged,
CurrentFunctionChanged, CurrentFunctionChanged,
ExceptionIntercepted ExceptionIntercepted,
SetIP
} }
} }

228
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Function.cs

@ -185,110 +185,158 @@ namespace DebuggerLibrary
/// <summary> /// <summary>
/// Get the information about the next statement to be executed. /// Get the information about the next statement to be executed.
/// ///
/// Throws NextStatementNotAviableException on error. /// Returns null on error.
///
/// 'ILStart <= ILOffset <= ILEnd' and this range includes at least
/// the returned area of source code. (May incude some extra compiler generated IL too)
/// </summary> /// </summary>
public SourcecodeSegment NextStatement { public SourcecodeSegment NextStatement {
get { get {
ISymbolMethod symMethod; return GetSegmentForOffet(corInstructionPtr);
}
symMethod = this.symMethod; }
if (symMethod == null) {
return null;
}
int sequencePointCount = symMethod.SequencePointCount; /// <summary>
/// Returns null on error.
int[] offsets = new int[sequencePointCount]; ///
int[] startLine = new int[sequencePointCount]; /// 'ILStart <= ILOffset <= ILEnd' and this range includes at least
int[] startColumn = new int[sequencePointCount]; /// the returned area of source code. (May incude some extra compiler generated IL too)
int[] endLine = new int[sequencePointCount]; /// </summary>
int[] endColumn = new int[sequencePointCount]; SourcecodeSegment GetSegmentForOffet(uint offset)
{
ISymbolDocument[] Doc = new ISymbolDocument[sequencePointCount]; ISymbolMethod symMethod;
symMethod.GetSequencePoints( symMethod = this.symMethod;
offsets, if (symMethod == null) {
Doc, return null;
startLine, }
startColumn,
endLine, int sequencePointCount = symMethod.SequencePointCount;
endColumn
); int[] offsets = new int[sequencePointCount];
int[] startLine = new int[sequencePointCount];
uint corInstructionPtr = this.corInstructionPtr; // cache int[] startColumn = new int[sequencePointCount];
SourcecodeSegment retVal = new SourcecodeSegment(); int[] endLine = new int[sequencePointCount];
int[] endColumn = new int[sequencePointCount];
// Get i for which: offsets[i] <= corInstructionPtr < offsets[i + 1]
for (int i = sequencePointCount - 1; i >= 0; i--) // backwards ISymbolDocument[] Doc = new ISymbolDocument[sequencePointCount];
if (offsets[i] <= corInstructionPtr)
{ symMethod.GetSequencePoints(
// Set inforamtion about current IL range offsets,
ICorDebugCode code; Doc,
corFunction.GetILCode(out code); startLine,
uint codeSize; startColumn,
code.GetSize(out codeSize); endLine,
endColumn
retVal.ILOffset = (int)corInstructionPtr; );
retVal.ILStart = offsets[i];
SourcecodeSegment retVal = new SourcecodeSegment();
// Get i for which: offsets[i] <= corInstructionPtr < offsets[i + 1]
for (int i = sequencePointCount - 1; i >= 0; i--) // backwards
if (offsets[i] <= offset)
{
// Set inforamtion about current IL range
ICorDebugCode code;
corFunction.GetILCode(out code);
uint codeSize;
code.GetSize(out codeSize);
retVal.ILOffset = (int)offset;
retVal.ILStart = offsets[i];
retVal.ILEnd = (i + 1 < sequencePointCount) ? offsets[i + 1] : (int)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 && startLine[i] == 0xFeeFee) {
i++;
retVal.ILEnd = (i + 1 < sequencePointCount) ? offsets[i + 1] : (int)codeSize; retVal.ILEnd = (i + 1 < sequencePointCount) ? offsets[i + 1] : (int)codeSize;
}
// Look back for 'real' sequence
while (i - 1 >= 0 && startLine[i] == 0xFeeFee) {
i--;
retVal.ILStart = offsets[i];
}
// Wow, there are no 'real' sequences
if (startLine[i] == 0xFeeFee) {
return null;
}
// 0xFeeFee means "code generated by compiler" retVal.ModuleFilename = module.FullPath;
// 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 retVal.SourceFullFilename = Doc[i].URL;
while (i + 1 < sequencePointCount && startLine[i] == 0xFeeFee) {
i++; retVal.StartLine = startLine[i];
retVal.ILEnd = (i + 1 < sequencePointCount) ? offsets[i + 1] : (int)codeSize; retVal.StartColumn = startColumn[i];
} retVal.EndLine = endLine[i];
// Look back for 'real' sequence retVal.EndColumn = endColumn[i];
while (i - 1 >= 0 && startLine[i] == 0xFeeFee) {
i--;
retVal.ILStart = offsets[i];
}
// Wow, there are no 'real' sequences
if (startLine[i] == 0xFeeFee) {
return null;
}
retVal.ModuleFilename = module.FullPath;
List<int> stepRanges = new List<int>();
retVal.SourceFullFilename = Doc[i].URL; for (int j = 0; j < sequencePointCount; j++) {
// Step over compiler generated sequences and current statement
retVal.StartLine = startLine[i]; // 0xFeeFee means "code generated by compiler"
retVal.StartColumn = startColumn[i]; if (startLine[j] == 0xFeeFee || j == i) {
retVal.EndLine = endLine[i]; // Add start offset or remove last end (to connect two ranges into one)
retVal.EndColumn = endColumn[i]; if (stepRanges.Count > 0 && stepRanges[stepRanges.Count - 1] == offsets[j]) {
stepRanges.RemoveAt(stepRanges.Count - 1);
} else {
List<int> stepRanges = new List<int>(); stepRanges.Add(offsets[j]);
for (int j = 0; j < sequencePointCount; j++) { }
// Step over compiler generated sequences and current statement // Add end offset | handle last sequence point
// 0xFeeFee means "code generated by compiler" if (j + 1 < sequencePointCount) {
if (startLine[j] == 0xFeeFee || j == i) { stepRanges.Add(offsets[j + 1]);
// Add start offset or remove last end (to connect two ranges into one) } else {
if (stepRanges.Count > 0 && stepRanges[stepRanges.Count - 1] == offsets[j]) { stepRanges.Add((int)codeSize);
stepRanges.RemoveAt(stepRanges.Count - 1);
} else {
stepRanges.Add(offsets[j]);
}
// Add end offset | handle last sequence point
if (j + 1 < sequencePointCount) {
stepRanges.Add(offsets[j + 1]);
} else {
stepRanges.Add((int)codeSize);
}
} }
} }
}
retVal.StepRanges = stepRanges.ToArray(); retVal.StepRanges = stepRanges.ToArray();
return retVal; return retVal;
} }
return null;
}
public SourcecodeSegment CanSetIP(string filename, int line, int column)
{
return SetIP(true, filename, line, column);
}
public SourcecodeSegment SetIP(string filename, int line, int column)
{
return SetIP(false, filename, line, column);
}
SourcecodeSegment SetIP(bool simulate, string filename, int line, int column)
{
SourcecodeSegment suggestion = new SourcecodeSegment(filename, line, column, column);
ICorDebugFunction corFunction;
int ilOffset;
if (!suggestion.GetFunctionAndOffset(debugger, false, out corFunction, out ilOffset)) {
return null; return null;
} else {
uint token;
corFunction.GetToken(out token);
if (token != methodProps.Token) {
return null;
} else {
try {
if (simulate) {
corILFrame.CanSetIP((uint)ilOffset);
} else {
corILFrame.SetIP((uint)ilOffset);
Thread thread = debugger.CurrentThread;
debugger.OnDebuggingResumed();
thread.CurrentFunction = thread.LastFunctionWithLoadedSymbols;
debugger.OnDebuggingPaused(PausedReason.SetIP);
}
} catch {
return null;
}
return GetSegmentForOffet((uint)ilOffset);
}
} }
} }

67
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/SourcecodeSegment.cs

@ -8,6 +8,8 @@
using System; using System;
using System.Diagnostics.SymbolStore; using System.Diagnostics.SymbolStore;
using DebuggerInterop.Core;
namespace DebuggerLibrary namespace DebuggerLibrary
{ {
[Serializable] [Serializable]
@ -149,5 +151,70 @@ namespace DebuggerLibrary
ilEnd = value; ilEnd = value;
} }
} }
// Returns true if found
internal bool GetFunctionAndOffset(NDebugger debugger, bool normailize, out ICorDebugFunction function, out int ilOffset)
{
function = null;
ilOffset = 0;
Module module = null;
ISymbolReader symReader = null;
ISymbolDocument symDoc = null;
// Try to get doc from moduleFilename
if (moduleFilename != null) {
try {
module = debugger.GetModule(ModuleFilename);
symReader = module.SymReader;
symDoc = symReader.GetDocument(SourceFullFilename,Guid.Empty,Guid.Empty,Guid.Empty);
} catch {}
}
// search all modules
if (symDoc == null) {
foreach (Module m in debugger.Modules) {
module = m;
symReader = m.SymReader;
if (symReader == null) {
continue;
}
symDoc = symReader.GetDocument(SourceFullFilename,Guid.Empty,Guid.Empty,Guid.Empty);
if (symDoc != null) {
break;
}
}
}
if (symDoc == null) {
return false; //Not found
}
int validLine;
validLine = symDoc.FindClosestLine(StartLine);
if (validLine != StartLine) {
if (normailize) {
StartLine = validLine;
EndLine = validLine;
StartColumn = 0;
EndColumn = 0;
} else {
return false;
}
}
ISymbolMethod symMethod;
symMethod = symReader.GetMethodFromDocumentPosition(symDoc, StartLine, StartColumn);
ICorDebugFunction corFunction;
module.CorModule.GetFunctionFromToken((uint)symMethod.Token.GetToken(), out corFunction);
function = corFunction;
ilOffset = symMethod.GetOffset(symDoc, StartLine, StartColumn);
return true;
}
} }
} }

21
src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs

@ -243,6 +243,15 @@ namespace ICSharpCode.Core
static string oldExpression, oldToolTip; static string oldExpression, oldToolTip;
static int oldLine; static int oldLine;
public class SetIPArgs: EventArgs
{
public string filename;
public int line;
public int column;
}
public static event EventHandler<SetIPArgs> SetIPRequest;
/// <summary> /// <summary>
/// This function shows variable values as tooltips /// This function shows variable values as tooltips
/// </summary> /// </summary>
@ -261,6 +270,18 @@ namespace ICSharpCode.Core
Point logicPos = textArea.TextView.GetLogicalPosition(mousepos.X - viewRect.Left, Point logicPos = textArea.TextView.GetLogicalPosition(mousepos.X - viewRect.Left,
mousepos.Y - viewRect.Top); mousepos.Y - viewRect.Top);
if (logicPos.Y >= 0 && logicPos.Y < textArea.Document.TotalNumberOfLines) { if (logicPos.Y >= 0 && logicPos.Y < textArea.Document.TotalNumberOfLines) {
// This is for testing olny - it must be reworked properly
if (Control.ModifierKeys == Keys.Control) {
SetIPArgs a = new SetIPArgs();
a.filename = textArea.MotherTextEditorControl.FileName;
a.line = logicPos.Y;
a.column = logicPos.X;
if (SetIPRequest != null) {
SetIPRequest(null, a);
}
return;
}
IDocument doc = textArea.Document; IDocument doc = textArea.Document;
IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(textArea.MotherTextEditorControl.FileName); IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(textArea.MotherTextEditorControl.FileName);
if (expressionFinder == null) if (expressionFinder == null)

Loading…
Cancel
Save