|
|
@ -1,8 +1,10 @@ |
|
|
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
|
|
// 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)
|
|
|
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
|
|
using System; |
|
|
|
using System; |
|
|
|
|
|
|
|
using System.Collections.Concurrent; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Diagnostics; |
|
|
|
|
|
|
|
using System.Linq; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
using System.Text; |
|
|
|
using System.Text; |
|
|
|
using System.Windows; |
|
|
|
using System.Windows; |
|
|
@ -45,6 +47,12 @@ namespace ILSpy.Debugger.Services |
|
|
|
//DynamicTreeDebuggerRow currentTooltipRow;
|
|
|
|
//DynamicTreeDebuggerRow currentTooltipRow;
|
|
|
|
//Expression currentTooltipExpression;
|
|
|
|
//Expression currentTooltipExpression;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private ConcurrentDictionary<string, List<MethodMapping>> CodeMappingsStorage { |
|
|
|
|
|
|
|
get { |
|
|
|
|
|
|
|
return CodeMappings.GetStorage(Language); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public event EventHandler<ProcessEventArgs> ProcessSelected; |
|
|
|
public event EventHandler<ProcessEventArgs> ProcessSelected; |
|
|
|
|
|
|
|
|
|
|
|
public NDebugger DebuggerCore { |
|
|
|
public NDebugger DebuggerCore { |
|
|
@ -274,16 +282,43 @@ namespace ILSpy.Debugger.Services |
|
|
|
|
|
|
|
|
|
|
|
// Stepping:
|
|
|
|
// Stepping:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SourceCodeMapping GetNextCodeMapping() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
uint token; |
|
|
|
|
|
|
|
var instruction = CodeMappingsStorage.GetInstructionByTypeAndLine( |
|
|
|
|
|
|
|
CurrentLineBookmark.Instance.TypeName, |
|
|
|
|
|
|
|
CurrentLineBookmark.Instance.LineNumber, out token); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var val = CodeMappingsStorage[CurrentLineBookmark.Instance.TypeName]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var mapping = val.Find(m => m.MetadataToken == token); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return mapping.MethodCodeMappings.FirstOrDefault(s => s.ILInstructionOffset.From <= instruction.ILInstructionOffset.To); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void StepInto() |
|
|
|
public void StepInto() |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!IsDebugging) { |
|
|
|
if (!IsDebugging) { |
|
|
|
MessageBox.Show(errorNotDebugging, "StepInto"); |
|
|
|
MessageBox.Show(errorNotDebugging, "StepInto"); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) { |
|
|
|
|
|
|
|
|
|
|
|
// use most recent stack frame because we don't have the symbols
|
|
|
|
|
|
|
|
if (debuggedProcess.SelectedThread == null || |
|
|
|
|
|
|
|
debuggedProcess.SelectedThread.MostRecentStackFrame == null || |
|
|
|
|
|
|
|
debuggedProcess.IsRunning) { |
|
|
|
MessageBox.Show(errorCannotStepNoActiveFunction, "StepInto"); |
|
|
|
MessageBox.Show(errorCannotStepNoActiveFunction, "StepInto"); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
debuggedProcess.SelectedStackFrame.AsyncStepInto(); |
|
|
|
var map = GetNextCodeMapping(); |
|
|
|
|
|
|
|
if (map == null) { |
|
|
|
|
|
|
|
CurrentLineBookmark.Remove(); |
|
|
|
|
|
|
|
Continue(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame; |
|
|
|
|
|
|
|
frame.SourceCodeLine = map.SourceCodeLine; |
|
|
|
|
|
|
|
frame.ILRanges = (new List<int> { map.ILInstructionOffset.From, map.ILInstructionOffset.To }).ToArray(); |
|
|
|
|
|
|
|
frame.AsyncStepInto(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -292,11 +327,24 @@ namespace ILSpy.Debugger.Services |
|
|
|
if (!IsDebugging) { |
|
|
|
if (!IsDebugging) { |
|
|
|
MessageBox.Show(errorNotDebugging, "StepOver"); |
|
|
|
MessageBox.Show(errorNotDebugging, "StepOver"); |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) { |
|
|
|
// use most recent stack frame because we don't have the symbols
|
|
|
|
|
|
|
|
if (debuggedProcess.SelectedThread == null || |
|
|
|
|
|
|
|
debuggedProcess.SelectedThread.MostRecentStackFrame == null || |
|
|
|
|
|
|
|
debuggedProcess.IsRunning) { |
|
|
|
MessageBox.Show(errorCannotStepNoActiveFunction, "StepOver"); |
|
|
|
MessageBox.Show(errorCannotStepNoActiveFunction, "StepOver"); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
debuggedProcess.SelectedStackFrame.AsyncStepOver(); |
|
|
|
var map = GetNextCodeMapping(); |
|
|
|
|
|
|
|
if (map == null) { |
|
|
|
|
|
|
|
CurrentLineBookmark.Remove(); |
|
|
|
|
|
|
|
Continue(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame; |
|
|
|
|
|
|
|
frame.SourceCodeLine = map.SourceCodeLine; |
|
|
|
|
|
|
|
frame.ILRanges = (new List<int> { map.ILInstructionOffset.From, map.ILInstructionOffset.To }).ToArray(); |
|
|
|
|
|
|
|
frame.AsyncStepOver(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -306,10 +354,23 @@ namespace ILSpy.Debugger.Services |
|
|
|
MessageBox.Show(errorNotDebugging, "StepOut"); |
|
|
|
MessageBox.Show(errorNotDebugging, "StepOut"); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) { |
|
|
|
|
|
|
|
|
|
|
|
// use most recent stack frame because we don't have the symbols
|
|
|
|
|
|
|
|
if (debuggedProcess.SelectedThread == null || |
|
|
|
|
|
|
|
debuggedProcess.SelectedThread.MostRecentStackFrame == null || |
|
|
|
|
|
|
|
debuggedProcess.IsRunning) { |
|
|
|
MessageBox.Show(errorCannotStepNoActiveFunction, "StepOut"); |
|
|
|
MessageBox.Show(errorCannotStepNoActiveFunction, "StepOut"); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
debuggedProcess.SelectedStackFrame.AsyncStepOut(); |
|
|
|
var map = GetNextCodeMapping(); |
|
|
|
|
|
|
|
if (map == null) { |
|
|
|
|
|
|
|
CurrentLineBookmark.Remove(); |
|
|
|
|
|
|
|
Continue(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame; |
|
|
|
|
|
|
|
frame.SourceCodeLine = map.SourceCodeLine; |
|
|
|
|
|
|
|
frame.ILRanges = (new List<int> { map.ILInstructionOffset.From, map.ILInstructionOffset.To }).ToArray(); |
|
|
|
|
|
|
|
frame.AsyncStepOut(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -335,7 +396,7 @@ namespace ILSpy.Debugger.Services |
|
|
|
if (!CanEvaluate) { |
|
|
|
if (!CanEvaluate) { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, debuggedProcess.SelectedStackFrame); |
|
|
|
return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, debuggedProcess.SelectedThread.MostRecentStackFrame); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
@ -381,7 +442,10 @@ namespace ILSpy.Debugger.Services |
|
|
|
public bool CanEvaluate |
|
|
|
public bool CanEvaluate |
|
|
|
{ |
|
|
|
{ |
|
|
|
get { |
|
|
|
get { |
|
|
|
return debuggedProcess != null && !debuggedProcess.IsRunning && debuggedProcess.SelectedStackFrame != null; |
|
|
|
return debuggedProcess != null && |
|
|
|
|
|
|
|
!debuggedProcess.IsRunning && |
|
|
|
|
|
|
|
debuggedProcess.SelectedThread != null && |
|
|
|
|
|
|
|
debuggedProcess.SelectedThread.MostRecentStackFrame != null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -429,8 +493,9 @@ namespace ILSpy.Debugger.Services |
|
|
|
|
|
|
|
|
|
|
|
public bool CanSetInstructionPointer(string filename, int line, int column) |
|
|
|
public bool CanSetInstructionPointer(string filename, int line, int column) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (debuggedProcess != null && debuggedProcess.IsPaused && debuggedProcess.SelectedStackFrame != null) { |
|
|
|
if (debuggedProcess != null && debuggedProcess.IsPaused && |
|
|
|
SourcecodeSegment seg = debuggedProcess.SelectedStackFrame.CanSetIP(filename, line, column); |
|
|
|
debuggedProcess.SelectedThread != null && debuggedProcess.SelectedThread.MostRecentStackFrame != null) { |
|
|
|
|
|
|
|
SourcecodeSegment seg = debuggedProcess.SelectedThread.MostRecentStackFrame.CanSetIP(filename, line, column); |
|
|
|
return seg != null; |
|
|
|
return seg != null; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
return false; |
|
|
|
return false; |
|
|
@ -440,7 +505,7 @@ namespace ILSpy.Debugger.Services |
|
|
|
public bool SetInstructionPointer(string filename, int line, int column) |
|
|
|
public bool SetInstructionPointer(string filename, int line, int column) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (CanSetInstructionPointer(filename, line, column)) { |
|
|
|
if (CanSetInstructionPointer(filename, line, column)) { |
|
|
|
SourcecodeSegment seg = debuggedProcess.SelectedStackFrame.SetIP(filename, line, column); |
|
|
|
SourcecodeSegment seg = debuggedProcess.SelectedThread.MostRecentStackFrame.SetIP(filename, line, column); |
|
|
|
return seg != null; |
|
|
|
return seg != null; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
return false; |
|
|
|
return false; |
|
|
@ -498,12 +563,10 @@ namespace ILSpy.Debugger.Services |
|
|
|
{ |
|
|
|
{ |
|
|
|
Breakpoint breakpoint = null; |
|
|
|
Breakpoint breakpoint = null; |
|
|
|
|
|
|
|
|
|
|
|
var storage = CodeMappings.GetStorage(Language); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (Language == bookmark.Language) { |
|
|
|
if (Language == bookmark.Language) { |
|
|
|
uint token; |
|
|
|
uint token; |
|
|
|
SourceCodeMapping map = |
|
|
|
SourceCodeMapping map = |
|
|
|
storage.GetInstructionByTypeAndLine( |
|
|
|
CodeMappingsStorage.GetInstructionByTypeAndLine( |
|
|
|
bookmark.TypeName, bookmark.LineNumber, out token); |
|
|
|
bookmark.TypeName, bookmark.LineNumber, out token); |
|
|
|
|
|
|
|
|
|
|
|
if (map != null) { |
|
|
|
if (map != null) { |
|
|
@ -613,7 +676,7 @@ namespace ILSpy.Debugger.Services |
|
|
|
{ |
|
|
|
{ |
|
|
|
try { |
|
|
|
try { |
|
|
|
SupportedLanguage supportedLanguage = (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), language, true); |
|
|
|
SupportedLanguage supportedLanguage = (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), language, true); |
|
|
|
Value val = ExpressionEvaluator.Evaluate(code, supportedLanguage, debuggedProcess.SelectedStackFrame); |
|
|
|
Value val = ExpressionEvaluator.Evaluate(code, supportedLanguage, debuggedProcess.SelectedThread.MostRecentStackFrame); |
|
|
|
|
|
|
|
|
|
|
|
if (val != null && val.Type.IsPrimitive && val.PrimitiveValue is bool) |
|
|
|
if (val != null && val.Type.IsPrimitive && val.PrimitiveValue is bool) |
|
|
|
return (bool)val.PrimitiveValue; |
|
|
|
return (bool)val.PrimitiveValue; |
|
|
@ -746,14 +809,19 @@ namespace ILSpy.Debugger.Services |
|
|
|
{ |
|
|
|
{ |
|
|
|
DebuggerService.RemoveCurrentLineMarker(); |
|
|
|
DebuggerService.RemoveCurrentLineMarker(); |
|
|
|
|
|
|
|
|
|
|
|
if (debuggedProcess != null && debuggedProcess.SelectedStackFrame != null) { |
|
|
|
if (debuggedProcess != null && debuggedProcess.SelectedThread != null) { |
|
|
|
var storage = CodeMappings.GetStorage(Language); |
|
|
|
|
|
|
|
|
|
|
|
// use most recent stack frame because we don't have the symbols
|
|
|
|
|
|
|
|
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (frame == null) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
uint token = (uint)debuggedProcess.SelectedStackFrame.MethodInfo.MetadataToken; |
|
|
|
uint token = (uint)frame.MethodInfo.MetadataToken; |
|
|
|
int ilOffset = debuggedProcess.SelectedStackFrame.IP; |
|
|
|
int ilOffset = frame.IP; |
|
|
|
int line; |
|
|
|
int line; |
|
|
|
string typeName; |
|
|
|
string typeName; |
|
|
|
storage.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out typeName, out line); |
|
|
|
CodeMappingsStorage.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out typeName, out line); |
|
|
|
if (typeName != null) |
|
|
|
if (typeName != null) |
|
|
|
DebuggerService.JumpToCurrentLine(typeName, line, 0, line, 0); |
|
|
|
DebuggerService.JumpToCurrentLine(typeName, line, 0, line, 0); |
|
|
|
} |
|
|
|
} |
|
|
|