Browse Source

Prototype of SetIP

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@252 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 20 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 @@ -265,6 +265,10 @@ namespace ICSharpCode.SharpDevelop.Services
RemoveBreakpoint(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();

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

@ -109,74 +109,29 @@ namespace DebuggerLibrary @@ -109,74 +109,29 @@ namespace DebuggerLibrary
}
internal unsafe void SetBreakpoint()
internal unsafe bool SetBreakpoint()
{
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;
module.CorModule.GetFunctionFromToken((uint)symMethod.Token.GetToken(), out corFunction);
int ilOffset;
if (!sourcecodeSegment.GetFunctionAndOffset(debugger, true, out corFunction, out ilOffset)) {
return false;
}
ICorDebugCode code;
corFunction.GetILCode(out code);
code.CreateBreakpoint((uint)corInstructionPtr, out corBreakpoint);
code.CreateBreakpoint((uint)ilOffset, out corBreakpoint);
hadBeenSet = true;
corBreakpoint.Activate(enabled?1:0);
pBreakpoint = Marshal.GetComInterfaceForObject(corBreakpoint, typeof(ICorDebugFunctionBreakpoint));
OnBreakpointStateChanged();
return true;
}
}
}

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

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

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

@ -185,110 +185,158 @@ namespace DebuggerLibrary @@ -185,110 +185,158 @@ namespace DebuggerLibrary
/// <summary>
/// Get the information about the next statement to be executed.
///
/// Throws NextStatementNotAviableException 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)
/// Returns null on error.
/// </summary>
public SourcecodeSegment NextStatement {
get {
ISymbolMethod symMethod;
symMethod = this.symMethod;
if (symMethod == null) {
return null;
}
return GetSegmentForOffet(corInstructionPtr);
}
}
int sequencePointCount = symMethod.SequencePointCount;
int[] offsets = new int[sequencePointCount];
int[] startLine = new int[sequencePointCount];
int[] startColumn = new int[sequencePointCount];
int[] endLine = new int[sequencePointCount];
int[] endColumn = new int[sequencePointCount];
ISymbolDocument[] Doc = new ISymbolDocument[sequencePointCount];
/// <summary>
/// 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>
SourcecodeSegment GetSegmentForOffet(uint offset)
{
ISymbolMethod symMethod;
symMethod.GetSequencePoints(
offsets,
Doc,
startLine,
startColumn,
endLine,
endColumn
);
uint corInstructionPtr = this.corInstructionPtr; // cache
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] <= corInstructionPtr)
{
// Set inforamtion about current IL range
ICorDebugCode code;
corFunction.GetILCode(out code);
uint codeSize;
code.GetSize(out codeSize);
retVal.ILOffset = (int)corInstructionPtr;
retVal.ILStart = offsets[i];
symMethod = this.symMethod;
if (symMethod == null) {
return null;
}
int sequencePointCount = symMethod.SequencePointCount;
int[] offsets = new int[sequencePointCount];
int[] startLine = new int[sequencePointCount];
int[] startColumn = new int[sequencePointCount];
int[] endLine = new int[sequencePointCount];
int[] endColumn = new int[sequencePointCount];
ISymbolDocument[] Doc = new ISymbolDocument[sequencePointCount];
symMethod.GetSequencePoints(
offsets,
Doc,
startLine,
startColumn,
endLine,
endColumn
);
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;
}
// 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"
// If we are in generated sequence use to closest real one instead,
// extend the ILStart and ILEnd to include the 'real' sequence
retVal.ModuleFilename = module.FullPath;
// Look ahead for 'real' sequence
while (i + 1 < sequencePointCount && startLine[i] == 0xFeeFee) {
i++;
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;
}
retVal.SourceFullFilename = Doc[i].URL;
retVal.StartLine = startLine[i];
retVal.StartColumn = startColumn[i];
retVal.EndLine = endLine[i];
retVal.EndColumn = endColumn[i];
retVal.ModuleFilename = module.FullPath;
retVal.SourceFullFilename = Doc[i].URL;
retVal.StartLine = startLine[i];
retVal.StartColumn = startColumn[i];
retVal.EndLine = endLine[i];
retVal.EndColumn = endColumn[i];
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 (startLine[j] == 0xFeeFee || j == i) {
// Add start offset or remove last end (to connect two ranges into one)
if (stepRanges.Count > 0 && stepRanges[stepRanges.Count - 1] == offsets[j]) {
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);
}
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 (startLine[j] == 0xFeeFee || j == i) {
// Add start offset or remove last end (to connect two ranges into one)
if (stepRanges.Count > 0 && stepRanges[stepRanges.Count - 1] == offsets[j]) {
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;
} 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 @@ @@ -8,6 +8,8 @@
using System;
using System.Diagnostics.SymbolStore;
using DebuggerInterop.Core;
namespace DebuggerLibrary
{
[Serializable]
@ -149,5 +151,70 @@ namespace DebuggerLibrary @@ -149,5 +151,70 @@ namespace DebuggerLibrary
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 @@ -243,6 +243,15 @@ namespace ICSharpCode.Core
static string oldExpression, oldToolTip;
static int oldLine;
public class SetIPArgs: EventArgs
{
public string filename;
public int line;
public int column;
}
public static event EventHandler<SetIPArgs> SetIPRequest;
/// <summary>
/// This function shows variable values as tooltips
/// </summary>
@ -261,6 +270,18 @@ namespace ICSharpCode.Core @@ -261,6 +270,18 @@ namespace ICSharpCode.Core
Point logicPos = textArea.TextView.GetLogicalPosition(mousepos.X - viewRect.Left,
mousepos.Y - viewRect.Top);
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;
IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(textArea.MotherTextEditorControl.FileName);
if (expressionFinder == null)

Loading…
Cancel
Save