Browse Source

evaluate local variables (not only parameters) for decompiled code.

pull/15/merge
Eusebiu Marcu 14 years ago
parent
commit
6701792f39
  1. 6
      src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs
  2. 48
      src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs
  3. 12
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs
  4. 32
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs
  5. 52
      src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerDecompilerService.cs
  6. 6
      src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs
  7. 24
      src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs

6
src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs

@ -53,7 +53,11 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -53,7 +53,11 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
}
try {
var context = !process.IsInExternalCode ? process.SelectedStackFrame : process.SelectedThread.MostRecentStackFrame;
Value val = ExpressionEvaluator.Evaluate(code, SelectedLanguage, context);
var debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
object data = debugger.debuggerDecompilerService.GetLocalVariableIndex(context.MethodInfo.DeclaringType.MetadataToken,
context.MethodInfo.MetadataToken,
code);
Value val = ExpressionEvaluator.Evaluate(code, SelectedLanguage, context, data);
return ExpressionEvaluator.FormatValue(val);
} catch (GetValueException e) {
return e.Message;

48
src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs

@ -50,6 +50,8 @@ namespace ICSharpCode.SharpDevelop.Services @@ -50,6 +50,8 @@ namespace ICSharpCode.SharpDevelop.Services
Process debuggedProcess;
ProcessMonitor monitor;
internal IDebuggerDecompilerService debuggerDecompilerService;
//DynamicTreeDebuggerRow currentTooltipRow;
//Expression currentTooltipExpression;
@ -470,8 +472,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -470,8 +472,7 @@ namespace ICSharpCode.SharpDevelop.Services
int methodToken = frame.MethodInfo.MetadataToken;
// get the mapped instruction from the current line marker or the next one
var decompilerService = GetDecompilerService();
if (!decompilerService.GetILAndLineNumber(typeToken, methodToken, frame.IP, out ilRange, out line, out isMatch)){
if (!debuggerDecompilerService.GetILAndLineNumber(typeToken, methodToken, frame.IP, out ilRange, out line, out isMatch)){
frame.SourceCodeLine = 0;
frame.ILRanges = new [] { 0, 1 };
} else {
@ -581,10 +582,12 @@ namespace ICSharpCode.SharpDevelop.Services @@ -581,10 +582,12 @@ namespace ICSharpCode.SharpDevelop.Services
}
var stackFrame = !debuggedProcess.IsInExternalCode ? debuggedProcess.SelectedStackFrame : debuggedProcess.SelectedThread.MostRecentStackFrame;
try {
object data = debuggerDecompilerService.GetLocalVariableIndex(stackFrame.MethodInfo.DeclaringType.MetadataToken,
stackFrame.MethodInfo.MetadataToken,
variableName);
// evaluate expression
return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, stackFrame);
return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, stackFrame, data);
} catch {
throw;
}
@ -713,10 +716,14 @@ namespace ICSharpCode.SharpDevelop.Services @@ -713,10 +716,14 @@ namespace ICSharpCode.SharpDevelop.Services
new RemotingConfigurationHelpper(path).Configure();
}
debugger = new NDebugger();
debugger.Options = DebuggingOptions.Instance;
// get decompiler service
var items = AddInTree.BuildItems<IDebuggerDecompilerService>("/SharpDevelop/Services/DebuggerDecompilerService", null, false);
if (items.Count > 0)
debuggerDecompilerService = items[0];
// init NDebugger
debugger = new NDebugger();
debugger.Options = DebuggingOptions.Instance;
debugger.DebuggerTraceMessage += debugger_TraceMessage;
debugger.Processes.Added += debugger_ProcessStarted;
debugger.Processes.Removed += debugger_ProcessExited;
@ -750,15 +757,14 @@ namespace ICSharpCode.SharpDevelop.Services @@ -750,15 +757,14 @@ namespace ICSharpCode.SharpDevelop.Services
if (bookmark is DecompiledBreakpointBookmark) {
var dbb = (DecompiledBreakpointBookmark)bookmark;
var memberReference = dbb.MemberReference;
var decompilerService = GetDecompilerService();
int token = memberReference.MetadataToken.ToInt32();
if (!decompilerService.CheckMappings(token))
decompilerService.DecompileOnDemand(memberReference as TypeDefinition);
if (!debuggerDecompilerService.CheckMappings(token))
debuggerDecompilerService.DecompileOnDemand(memberReference as TypeDefinition);
int[] ilRanges;
int methodToken;
if (decompilerService.GetILAndTokenByLineNumber(token, dbb.LineNumber, out ilRanges, out methodToken)) {
if (debuggerDecompilerService.GetILAndTokenByLineNumber(token, dbb.LineNumber, out ilRanges, out methodToken)) {
dbb.ILFrom = ilRanges[0];
dbb.ILTo = ilRanges[1];
// create BP
@ -1032,6 +1038,10 @@ namespace ICSharpCode.SharpDevelop.Services @@ -1032,6 +1038,10 @@ namespace ICSharpCode.SharpDevelop.Services
DebuggerService.JumpToCurrentLine(nextStatement.Filename, nextStatement.StartLine, nextStatement.StartColumn, nextStatement.EndLine, nextStatement.EndColumn);
}
} else {
if (debuggerDecompilerService == null) {
LoggingService.Warn("No IDebuggerDecompilerService found!");
return;
}
// use most recent stack frame because we don't have the symbols
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
if (frame == null)
@ -1042,12 +1052,11 @@ namespace ICSharpCode.SharpDevelop.Services @@ -1042,12 +1052,11 @@ namespace ICSharpCode.SharpDevelop.Services
int methodToken = frame.MethodInfo.MetadataToken;
int ilOffset = frame.IP;
var decompilerService = GetDecompilerService();
int[] ilRanges = null;
int line = -1;
bool isMatch = false;
if (decompilerService.GetILAndLineNumber(typeToken, methodToken, ilOffset, out ilRanges, out line, out isMatch)) {
DebuggerService.DebugStepInformation = null; // we do not need to step into/out
if (debuggerDecompilerService.GetILAndLineNumber(typeToken, methodToken, ilOffset, out ilRanges, out line, out isMatch)) {
debuggerDecompilerService.DebugStepInformation = null; // we do not need to step into/out
// update marker
var debugType = (DebugType)frame.MethodInfo.DeclaringType;
@ -1077,19 +1086,10 @@ namespace ICSharpCode.SharpDevelop.Services @@ -1077,19 +1086,10 @@ namespace ICSharpCode.SharpDevelop.Services
{
var debugType = (DebugType)frame.MethodInfo.DeclaringType;
string fullName = debugType.FullNameWithoutGenericArguments;
DebuggerService.DebugStepInformation = Tuple.Create(token, ilOffset);
debuggerDecompilerService.DebugStepInformation = Tuple.Create(token, ilOffset);
NavigationService.NavigateTo(debugType.DebugModule.FullPath, debugType.FullNameWithoutGenericArguments, string.Empty);
}
IDebuggerDecompilerService GetDecompilerService()
{
var items = AddInTree.BuildItems<IDebuggerDecompilerService>("/SharpDevelop/Services/DebuggerDecompilerService", null, false);
if (items.Count == 0)
return null;
return items[0];
}
StopAttachedProcessDialogResult ShowStopAttachedProcessDialog()
{
string caption = StringParser.Parse("${res:XML.MainMenu.DebugMenu.Stop}");

12
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs

@ -157,6 +157,18 @@ namespace Debugger.AddIn.TreeModel @@ -157,6 +157,18 @@ namespace Debugger.AddIn.TreeModel
Value val;
try {
var process = WindowsDebugger.DebuggedProcess;
var context = !process.IsInExternalCode ? process.SelectedStackFrame : process.SelectedThread.MostRecentStackFrame;
var debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
object data = debugger.debuggerDecompilerService.GetLocalVariableIndex(context.MethodInfo.DeclaringType.MetadataToken,
context.MethodInfo.MetadataToken,
Name);
if (expression is MemberReferenceExpression) {
var memberExpression = (MemberReferenceExpression)expression;
memberExpression.TargetObject.UserData = data;
} else {
expression.UserData = data;
}
// evaluate expression
val = expression.Evaluate(process);
} catch (GetValueException e) {

32
src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs

@ -1,10 +1,13 @@ @@ -1,10 +1,13 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using Debugger.MetaData;
using System.Collections.Generic;
using Debugger.MetaData;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.TreeModel
{
@ -33,12 +36,27 @@ namespace Debugger.AddIn.TreeModel @@ -33,12 +36,27 @@ namespace Debugger.AddIn.TreeModel
expression.ImageName = imageName;
yield return expression;
}
foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables(this.StackFrame.IP)) {
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
var expression = new ExpressionNode(image, locVar.Name, locVar.GetExpression());
expression.ImageName = imageName;
yield return expression;
if (this.stackFrame.HasSymbols) {
foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables(this.StackFrame.IP)) {
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
var expression = new ExpressionNode(image, locVar.Name, locVar.GetExpression());
expression.ImageName = imageName;
yield return expression;
}
} else {
WindowsDebugger debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
if (debugger.debuggerDecompilerService != null) {
int typeToken = this.stackFrame.MethodInfo.DeclaringType.MetadataToken;
int methodToken = this.stackFrame.MethodInfo.MetadataToken;
foreach (var localVar in debugger.debuggerDecompilerService.GetLocalVariables(typeToken, methodToken)) {
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
var expression = new ExpressionNode(image, localVar, ExpressionEvaluator.ParseExpression(localVar, SupportedLanguage.CSharp));
expression.ImageName = imageName;
yield return expression;
}
}
}
if (stackFrame.Thread.CurrentException != null) {
yield return new ExpressionNode(null, "__exception", new IdentifierExpression("__exception"));

52
src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerDecompilerService.cs

@ -2,16 +2,18 @@ @@ -2,16 +2,18 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.SharpDevelop.Debugging;
using Mono.Cecil;
namespace ICSharpCode.ILSpyAddIn
{
/// <summary>
/// Description of DebuggerDecompilerService.
/// Stores the decompilation information.
/// </summary>
public class DebuggerDecompilerService : IDebuggerDecompilerService
{
@ -20,12 +22,21 @@ namespace ICSharpCode.ILSpyAddIn @@ -20,12 +22,21 @@ namespace ICSharpCode.ILSpyAddIn
DebugInformation = new ConcurrentDictionary<int, DecompileInformation>();
}
internal static IDebuggerDecompilerService Instance { get; private set; }
/// <summary>
/// Gets or sets the external debug information.
/// <summary>This constains the code mappings and local variables.</summary>
/// </summary>
internal static ConcurrentDictionary<int, DecompileInformation> DebugInformation { get; private set; }
public DebuggerDecompilerService()
{
Instance = this;
}
public Tuple<int, int> DebugStepInformation { get; set; }
public bool CheckMappings(int typeToken)
{
DecompileInformation data = null;
@ -116,5 +127,44 @@ namespace ICSharpCode.ILSpyAddIn @@ -116,5 +127,44 @@ namespace ICSharpCode.ILSpyAddIn
return false;
}
public IEnumerable<string> GetLocalVariables(int typeToken, int memberToken)
{
if (DebugInformation == null || !DebugInformation.ContainsKey(typeToken))
yield break;
var externalData = DebugInformation[typeToken];
IEnumerable<ILVariable> list;
if (externalData.LocalVariables.TryGetValue(memberToken, out list)) {
foreach (var local in list) {
if (local.IsParameter)
continue;
if (string.IsNullOrEmpty(local.Name))
continue;
yield return local.Name;
}
}
}
public object GetLocalVariableIndex(int typeToken, int memberToken, string name)
{
if (DebugInformation == null || !DebugInformation.ContainsKey(typeToken))
return null;
var externalData = DebugInformation[typeToken];
IEnumerable<ILVariable> list;
if (externalData.LocalVariables.TryGetValue(memberToken, out list)) {
foreach (var local in list) {
if (local.IsParameter)
continue;
if (local.Name == name)
return new[] { local.OriginalVariable.Index };
}
}
return null;
}
}
}

6
src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs

@ -222,13 +222,13 @@ namespace ICSharpCode.ILSpyAddIn @@ -222,13 +222,13 @@ namespace ICSharpCode.ILSpyAddIn
int typeToken = MemberReference.MetadataToken.ToInt32();
if (!DebuggerDecompilerService.DebugInformation.ContainsKey(typeToken))
return;
if (DebuggerService.DebugStepInformation == null)
if (DebuggerDecompilerService.Instance == null || DebuggerDecompilerService.Instance.DebugStepInformation == null)
return;
// get debugging information
DecompileInformation debugInformation = (DecompileInformation)DebuggerDecompilerService.DebugInformation[typeToken];
int token = DebuggerService.DebugStepInformation.Item1;
int ilOffset = DebuggerService.DebugStepInformation.Item2;
int token = DebuggerDecompilerService.Instance.DebugStepInformation.Item1;
int ilOffset = DebuggerDecompilerService.Instance.DebugStepInformation.Item2;
int line;
MemberReference member;
if (debugInformation.CodeMappings == null || !debugInformation.CodeMappings.ContainsKey(token))

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

@ -102,15 +102,6 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -102,15 +102,6 @@ namespace ICSharpCode.SharpDevelop.Debugging
get { return debuggerStarted; }
}
#region Debug third party code
/// <summary>
/// Gets or sets the current token and IL offset. Used for step in/out.
/// </summary>
public static Tuple<int, int> DebugStepInformation { get; set; }
#endregion
public static event EventHandler DebugStarting;
public static event EventHandler DebugStarted;
public static event EventHandler DebugStopped;
@ -460,6 +451,11 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -460,6 +451,11 @@ namespace ICSharpCode.SharpDevelop.Debugging
/// </summary>
public interface IDebuggerDecompilerService
{
/// <summary>
/// Gets or sets the current method token and IL offset. Used for step in/out.
/// </summary>
Tuple<int, int> DebugStepInformation { get; set; }
/// <summary>
/// Checks the code mappings.
/// </summary>
@ -479,5 +475,15 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -479,5 +475,15 @@ namespace ICSharpCode.SharpDevelop.Debugging
/// Gets the ILRange and source code line number.
/// </summary>
bool GetILAndLineNumber(int typeToken, int memberToken, int ilOffset, out int[] ilRange, out int line, out bool isMatch);
/// <summary>
/// Gets the local variables of a type and a member.
/// </summary>
IEnumerable<string> GetLocalVariables(int typeToken, int memberToken);
/// <summary>
/// Gets the local variable index.
/// </summary>
object GetLocalVariableIndex(int typeToken, int memberToken, string name);
}
}

Loading…
Cancel
Save