22 changed files with 178 additions and 758 deletions
@ -1,204 +0,0 @@ |
|||||||
// 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)
|
|
||||||
using System; |
|
||||||
using System.Collections.Concurrent; |
|
||||||
using System.Collections.Generic; |
|
||||||
using System.IO; |
|
||||||
|
|
||||||
using ICSharpCode.Decompiler; |
|
||||||
using ICSharpCode.Decompiler.Ast; |
|
||||||
using ICSharpCode.Decompiler.ILAst; |
|
||||||
using ICSharpCode.ILSpyAddIn.LaunchILSpy; |
|
||||||
using ICSharpCode.SharpDevelop.Debugging; |
|
||||||
using ICSharpCode.SharpDevelop.Project; |
|
||||||
using Mono.Cecil; |
|
||||||
|
|
||||||
namespace ICSharpCode.ILSpyAddIn |
|
||||||
{ |
|
||||||
/* |
|
||||||
// Dummy class to avoid the build errors after updating the ICSharpCode.Decompiler version.
|
|
||||||
// TODO: get rid of this & fix debugging decompiled files
|
|
||||||
public class DecompileInformation { |
|
||||||
public dynamic LocalVariables; |
|
||||||
public dynamic CodeMappings; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Stores the decompilation information.
|
|
||||||
/// </summary>
|
|
||||||
public class DebuggerDecompilerService : IDebuggerDecompilerService |
|
||||||
{ |
|
||||||
ILSpyAssemblyResolver resolver; |
|
||||||
|
|
||||||
static DebuggerDecompilerService() |
|
||||||
{ |
|
||||||
DebugInformation = new ConcurrentDictionary<int, DecompileInformation>(); |
|
||||||
ProjectService.SolutionClosed += delegate { |
|
||||||
DebugInformation.Clear(); |
|
||||||
GC.Collect(); |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
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; |
|
||||||
DebugInformation.TryGetValue(typeToken, out data); |
|
||||||
DecompileInformation information = data as DecompileInformation; |
|
||||||
|
|
||||||
if (information == null) |
|
||||||
return false; |
|
||||||
|
|
||||||
if (information.CodeMappings == null) |
|
||||||
return false; |
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public void DecompileOnDemand(TypeDefinition type) |
|
||||||
{ |
|
||||||
if (type == null) |
|
||||||
return; |
|
||||||
|
|
||||||
if (CheckMappings(type.MetadataToken.ToInt32())) |
|
||||||
return; |
|
||||||
|
|
||||||
try { |
|
||||||
DecompilerContext context = new DecompilerContext(type.Module); |
|
||||||
AstBuilder astBuilder = new AstBuilder(context); |
|
||||||
astBuilder.AddType(type); |
|
||||||
DebuggerTextOutput output = new DebuggerTextOutput(new PlainTextOutput()); |
|
||||||
astBuilder.GenerateCode(output); |
|
||||||
|
|
||||||
// int token = type.MetadataToken.ToInt32();
|
|
||||||
// var info = new DecompileInformation {
|
|
||||||
// CodeMappings = astBuilder.CodeMappings,
|
|
||||||
// LocalVariables = astBuilder.LocalVariables,
|
|
||||||
// DecompiledMemberReferences = astBuilder.DecompiledMemberReferences
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// // save the data
|
|
||||||
// DebugInformation.AddOrUpdate(token, info, (k, v) => info);
|
|
||||||
} catch { |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public bool GetILAndTokenByLineNumber(int typeToken, int lineNumber, out int[] ilRanges, out int memberToken) |
|
||||||
{ |
|
||||||
ilRanges = null; |
|
||||||
memberToken = -1; |
|
||||||
if (!CheckMappings(typeToken)) |
|
||||||
return false; |
|
||||||
|
|
||||||
var data = (DecompileInformation)DebugInformation[typeToken]; |
|
||||||
var mappings = data.CodeMappings; |
|
||||||
foreach (var key in mappings.Keys) { |
|
||||||
var list = mappings[key]; |
|
||||||
var instruction = list.GetInstructionByLineNumber(lineNumber, out memberToken); |
|
||||||
if (instruction == null) |
|
||||||
continue; |
|
||||||
|
|
||||||
ilRanges = new int[] { instruction.ILInstructionOffset.From, instruction.ILInstructionOffset.To }; |
|
||||||
memberToken = instruction.MemberMapping.MetadataToken; |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public bool GetILAndLineNumber(int typeToken, int memberToken, int ilOffset, out int[] ilRange, out int line, out bool isMatch) |
|
||||||
{ |
|
||||||
ilRange = null; |
|
||||||
line = -1; |
|
||||||
isMatch = false; |
|
||||||
|
|
||||||
if (!CheckMappings(typeToken)) |
|
||||||
return false; |
|
||||||
|
|
||||||
var data = (DecompileInformation)DebugInformation[typeToken]; |
|
||||||
var mappings = data.CodeMappings; |
|
||||||
|
|
||||||
if (!mappings.ContainsKey(memberToken)) |
|
||||||
return false; |
|
||||||
|
|
||||||
var map = mappings[memberToken].GetInstructionByTokenAndOffset(memberToken, ilOffset, out isMatch); |
|
||||||
if (map != null) { |
|
||||||
ilRange = map.ToArray(isMatch); |
|
||||||
line = map.SourceCodeLine; |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
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; |
|
||||||
} |
|
||||||
|
|
||||||
public IAssemblyResolver GetAssemblyResolver(string assemblyFile) |
|
||||||
{ |
|
||||||
if (string.IsNullOrEmpty(assemblyFile)) |
|
||||||
throw new ArgumentException("assemblyFile is null or empty"); |
|
||||||
|
|
||||||
string folderPath = Path.GetDirectoryName(assemblyFile); |
|
||||||
if (resolver == null) |
|
||||||
return (resolver = new ILSpyAssemblyResolver(folderPath)); |
|
||||||
|
|
||||||
if (string.Compare(folderPath, resolver.FolderPath, StringComparison.OrdinalIgnoreCase) != 0) |
|
||||||
return (resolver = new ILSpyAssemblyResolver(folderPath)); |
|
||||||
|
|
||||||
return resolver; |
|
||||||
} |
|
||||||
} |
|
||||||
*/ |
|
||||||
} |
|
@ -1,84 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.ComponentModel.Design; |
|
||||||
using System.Windows.Controls; |
|
||||||
|
|
||||||
using ICSharpCode.AvalonEdit.AddIn; |
|
||||||
using ICSharpCode.AvalonEdit.Document; |
|
||||||
using ICSharpCode.AvalonEdit.Highlighting; |
|
||||||
using ICSharpCode.AvalonEdit.Search; |
|
||||||
using ICSharpCode.SharpDevelop; |
|
||||||
using ICSharpCode.SharpDevelop.Editor; |
|
||||||
using ICSharpCode.SharpDevelop.Editor.Bookmarks; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
|
|
||||||
namespace ICSharpCode.ILSpyAddIn.ViewContent |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Equivalent to AE.AddIn CodeEditor, but without editing capabilities.
|
|
||||||
/// </summary>
|
|
||||||
class CodeView : Grid, IDisposable, IPositionable |
|
||||||
{ |
|
||||||
readonly SharpDevelopTextEditor textEditor; |
|
||||||
readonly IconBarManager iconBarManager; |
|
||||||
readonly IconBarMargin iconMargin; |
|
||||||
readonly TextMarkerService textMarkerService; |
|
||||||
readonly AvalonEditTextEditorAdapter adapter; |
|
||||||
|
|
||||||
public CodeView() |
|
||||||
{ |
|
||||||
textEditor = new SharpDevelopTextEditor(); |
|
||||||
textEditor.IsReadOnly = true; |
|
||||||
this.Children.Add(textEditor); |
|
||||||
adapter = new AvalonEditTextEditorAdapter(textEditor); |
|
||||||
|
|
||||||
textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#"); |
|
||||||
|
|
||||||
// add margin
|
|
||||||
this.iconMargin = new IconBarMargin(iconBarManager = new IconBarManager()); |
|
||||||
textEditor.TextArea.LeftMargins.Insert(0, iconMargin); |
|
||||||
textEditor.TextArea.TextView.VisualLinesChanged += delegate { iconMargin.InvalidateVisual(); }; |
|
||||||
|
|
||||||
// add marker service
|
|
||||||
this.textMarkerService = new TextMarkerService(textEditor.Document); |
|
||||||
textEditor.TextArea.TextView.BackgroundRenderers.Add(textMarkerService); |
|
||||||
textEditor.TextArea.TextView.LineTransformers.Add(textMarkerService); |
|
||||||
var documentServiceContainer = textEditor.Document.GetRequiredService<ServiceContainer>(); |
|
||||||
documentServiceContainer.AddService(typeof(ITextMarkerService), textMarkerService); |
|
||||||
documentServiceContainer.AddService(typeof(IBookmarkMargin), iconBarManager); |
|
||||||
|
|
||||||
textEditor.TextArea.DefaultInputHandler.NestedInputHandlers.Add(new SearchInputHandler(textEditor.TextArea)); |
|
||||||
} |
|
||||||
|
|
||||||
public TextDocument Document { |
|
||||||
get { return textEditor.Document; } |
|
||||||
} |
|
||||||
|
|
||||||
public IconBarManager IconBarManager { |
|
||||||
get { return iconBarManager; } |
|
||||||
} |
|
||||||
|
|
||||||
public void Dispose() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public int Line { |
|
||||||
get { |
|
||||||
return textEditor.TextArea.Caret.Line; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public int Column { |
|
||||||
get { |
|
||||||
return textEditor.TextArea.Caret.Column; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void JumpTo(int line, int column) |
|
||||||
{ |
|
||||||
adapter.JumpTo(line, column); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,73 +0,0 @@ |
|||||||
// 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)
|
|
||||||
using System; |
|
||||||
using ICSharpCode.Core; |
|
||||||
using ICSharpCode.NRefactory; |
|
||||||
using ICSharpCode.SharpDevelop.Debugging; |
|
||||||
|
|
||||||
namespace ICSharpCode.SharpDevelop.Editor.Bookmarks |
|
||||||
{ |
|
||||||
/* |
|
||||||
public class DecompiledBreakpointBookmark : BreakpointBookmark |
|
||||||
{ |
|
||||||
public const string SEPARATOR = ","; // don't use '.'
|
|
||||||
|
|
||||||
MemberReference memberReference; |
|
||||||
string assemblyFile; |
|
||||||
|
|
||||||
public DecompiledBreakpointBookmark(FileName fileName, TextLocation location) |
|
||||||
: base(fileName, location) |
|
||||||
{ |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public MemberReference MemberReference { |
|
||||||
get { return memberReference; } |
|
||||||
} |
|
||||||
|
|
||||||
public MemberReference GetMemberReference(IAssemblyResolver resolver) |
|
||||||
{ |
|
||||||
if (resolver == null) |
|
||||||
throw new ArgumentNullException("resolver"); |
|
||||||
|
|
||||||
if (memberReference != null) |
|
||||||
return memberReference; |
|
||||||
|
|
||||||
// reload from filename
|
|
||||||
ReaderParameters readerParameters = new ReaderParameters(); |
|
||||||
// Use new assembly resolver instance so that the AssemblyDefinitions can be garbage-collected
|
|
||||||
// once the code is decompiled.
|
|
||||||
readerParameters.AssemblyResolver = resolver; |
|
||||||
|
|
||||||
string typeName; |
|
||||||
if (GetAssemblyAndType(FileName.ToString(), out assemblyFile, out typeName)) { |
|
||||||
ModuleDefinition module = ModuleDefinition.ReadModule(assemblyFile, readerParameters); |
|
||||||
TypeDefinition typeDefinition = module.GetType(typeName); |
|
||||||
if (typeDefinition == null) |
|
||||||
throw new InvalidOperationException("Could not find type"); |
|
||||||
memberReference = typeDefinition; |
|
||||||
} |
|
||||||
|
|
||||||
return memberReference; |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the assembly file and the type from the file name.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns><c>true</c>, if the operation succeded; <c>false</c>, otherwise.</returns>
|
|
||||||
public static bool GetAssemblyAndType(string fileName, out string assemblyFile, out string typeName) |
|
||||||
{ |
|
||||||
if (string.IsNullOrEmpty(fileName) || !fileName.Contains(",")) { |
|
||||||
assemblyFile = null; |
|
||||||
typeName = null; |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
int index = fileName.IndexOf(SEPARATOR); |
|
||||||
assemblyFile = fileName.Substring(0, index); |
|
||||||
typeName = fileName.Substring(index + 1, fileName.Length - index - 4); |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
*/ |
|
||||||
} |
|
Loading…
Reference in new issue