Browse Source

Store the code mappings when decompiling multiple member references (TypeDefinitions, MethodDefinitions, PropertyDefinitions, etc).

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
a2b35dbd60
  1. 5
      Debugger/Debugger.Core/Breakpoint.cs
  2. 35
      Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs
  3. 48
      Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs
  4. 12
      Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs
  5. 4
      Debugger/ILSpy.Debugger/Bookmarks/BookmarkBase.cs
  6. 21
      Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs
  7. 2
      Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs
  8. 2
      Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs
  9. 28
      Debugger/ILSpy.Debugger/DebuggedData.cs
  10. 18
      Debugger/ILSpy.Debugger/DebuggerSettings.cs
  11. 2
      Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs
  12. 59
      Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs
  13. 69
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  14. 107
      ICSharpCode.Decompiler/CodeMappings.cs
  15. 90
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  16. 10
      ILSpy/CSharpLanguage.cs
  17. 4
      ILSpy/Commands/DebuggerCommands.cs
  18. 14
      ILSpy/ILLanguage.cs
  19. 7
      ILSpy/Language.cs
  20. 3
      ILSpy/Options/DebuggerSettingsPanel.xaml
  21. 16
      ILSpy/Options/DebuggerSettingsPanel.xaml.cs
  22. 34
      ILSpy/TextView/DecompilerTextView.cs

5
Debugger/Debugger.Core/Breakpoint.cs

@ -176,11 +176,12 @@ namespace Debugger @@ -176,11 +176,12 @@ namespace Debugger
public class ILBreakpoint : Breakpoint
{
public ILBreakpoint(NDebugger debugger, string typeName, int line, uint metadataToken, int offset, bool enabled)
public ILBreakpoint(NDebugger debugger, string typeName, string memberReferenceName, int line, uint metadataToken, int offset, bool enabled)
{
this.Debugger = debugger;
this.Line = line;
this.TypeName = typeName;
this.MemberReferenceName = memberReferenceName;
this.MetadataToken = metadataToken;
this.ILOffset = offset;
this.Enabled = enabled;
@ -190,6 +191,8 @@ namespace Debugger @@ -190,6 +191,8 @@ namespace Debugger
public int ILOffset { get; private set; }
public string MemberReferenceName { get; private set; }
public override bool SetBreakpoint(Module module)
{
SourcecodeSegment segment = SourcecodeSegment.CreateForIL(module, this.Line, (int)MetadataToken, ILOffset);

35
Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs

@ -68,7 +68,7 @@ namespace Debugger.MetaData @@ -68,7 +68,7 @@ namespace Debugger.MetaData
sb.Append(this.ReturnType.Name);
sb.Append(" ");
} else {
sb.Append("void ");
sb.Append("System.Void ");
}
sb.Append(this.DeclaringType.FullName);
@ -80,7 +80,7 @@ namespace Debugger.MetaData @@ -80,7 +80,7 @@ namespace Debugger.MetaData
if (!first)
sb.Append(", ");
first = false;
sb.Append(p.ParameterType.Name);
sb.Append(p.ParameterType.FullName);
sb.Append(" ");
sb.Append(p.Name);
}
@ -89,6 +89,37 @@ namespace Debugger.MetaData @@ -89,6 +89,37 @@ namespace Debugger.MetaData
}
}
/// <summary> Name including the declaring type, return type without parameters names</summary>
public string FullNameWithoutParameterNames {
get {
StringBuilder sb = new StringBuilder();
if (this.IsStatic) {
sb.Append("static ");
}
if (this.ReturnType != null) {
sb.Append(this.ReturnType.Name);
sb.Append(" ");
} else {
sb.Append("System.Void ");
}
sb.Append(this.DeclaringType.FullName);
sb.Append(".");
sb.Append(this.Name);
sb.Append("(");
bool first = true;
foreach(DebugParameterInfo p in GetParameters()) {
if (!first)
sb.Append(", ");
first = false;
sb.Append(p.ParameterType.FullName);
}
sb.Append(")");
return sb.ToString();
}
}
/// <inheritdoc/>
public override string Name {
get { return methodProps.Name; }

48
Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs

@ -4,10 +4,10 @@ @@ -4,10 +4,10 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
@ -59,7 +59,8 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit @@ -59,7 +59,8 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
// create a dictionary line number => first bookmark
Dictionary<int, BookmarkBase> bookmarkDict = new Dictionary<int, BookmarkBase>();
foreach (var bm in BookmarkManager.Bookmarks) {
if (DebugData.CurrentMemberReference == null || bm.Member.FullName != DebugData.CurrentMemberReference.FullName)
if (DebugData.DecompiledMemberReferences == null || DebugData.DecompiledMemberReferences.Count == 0 ||
!DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.FullName))
continue;
if (bm is BreakpointBookmark &&
((BreakpointBookmark)bm).Language != DebugData.Language)
@ -121,8 +122,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit @@ -121,8 +122,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
BookmarkBase result = null;
foreach (BookmarkBase bm in BookmarkManager.Bookmarks) {
if (bm.LineNumber == line &&
DebugData.CurrentMemberReference != null &&
bm.Member.FullName == DebugData.CurrentMemberReference.FullName) {
DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.FullName)) {
if (result == null || bm.ZOrder > result.ZOrder)
result = bm;
}
@ -190,16 +190,6 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit @@ -190,16 +190,6 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
dragStarted = true;
InvalidateVisual();
}
if (DebugData.CurrentMemberReference == null)
return;
BreakpointBookmark bm = BookmarkManager.Bookmarks.Find(
b => b.Member.FullName == DebugData.CurrentMemberReference.FullName &&
b.LineNumber == GetLineFromMousePosition(e)
&& b is BreakpointBookmark) as BreakpointBookmark;
this.ToolTip = (bm != null) ? bm.Tooltip : null;
}
protected override void OnMouseUp(MouseButtonEventArgs e)
@ -228,24 +218,32 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit @@ -228,24 +218,32 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
return;
}
if (e.ChangedButton == MouseButton.Left) {
if (DebugData.CurrentMemberReference != null) {
if (DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.Count > 0) {
// check if the codemappings exists for this line
var storage = DebugData.CodeMappings;
uint token;
var instruction = storage.GetInstructionByTypeAndLine(DebugData.CurrentMemberReference.FullName, line, out token);
uint token = 0;
foreach (var member in DebugData.DecompiledMemberReferences.Values) {
string memberName = member.FullName;
var instruction = storage[memberName].GetInstructionByTypeAndLine(memberName, line, out token);
if (instruction == null) {
continue;
}
// no bookmark on the line: create a new breakpoint
DebuggerService.ToggleBreakpointAt(
member,
line,
DebugData.Language);
break;
}
if (instruction == null) {
MessageBox.Show(string.Format("Missing code mappings for {0} at line {1}", DebugData.CurrentMemberReference.FullName, line),
if (token == 0) {
MessageBox.Show(string.Format("Missing code mappings at line {0}.", line),
"Code mappings", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// no bookmark on the line: create a new breakpoint
DebuggerService.ToggleBreakpointAt(
DebugData.CurrentMemberReference,
line,
DebugData.Language);
}
}
InvalidateVisual();

12
Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit @@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
TextSegmentCollection<TextMarker> markers = new TextSegmentCollection<TextMarker>();
public TextMarkerService()
{
{
BookmarkManager.Added += new BookmarkEventHandler(BookmarkManager_Added);
BookmarkManager.Removed += new BookmarkEventHandler(BookmarkManager_Removed);
}
@ -53,11 +53,9 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit @@ -53,11 +53,9 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
{
if (e.Bookmark is MarkerBookmark) {
var bm = (MarkerBookmark)e.Bookmark;
if (DebugData.CurrentMemberReference != null && DebugData.CurrentMemberReference == bm.Member) {
// add bookmark for the current type
DocumentLine line = codeEditor.Document.GetLineByNumber(bm.LineNumber);
bm.CreateMarker(this, line.Offset, line.Length);
}
// add bookmark for the current type
DocumentLine line = codeEditor.Document.GetLineByNumber(bm.LineNumber);
bm.CreateMarker(this, line.Offset, line.Length);
}
}
@ -305,7 +303,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit @@ -305,7 +303,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
Redraw();
}
}
}
/// <inheritdoc/>
public object ToolTip { get; set; }

4
Debugger/ILSpy.Debugger/Bookmarks/BookmarkBase.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks @@ -41,7 +41,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
}
public MemberReference Member { get; set; }
public MemberReference MemberReference { get; set; }
public int LineNumber {
get { return location.Line; }
@ -66,7 +66,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks @@ -66,7 +66,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
public BookmarkBase(MemberReference member, AstLocation location)
{
this.Member = member;
this.MemberReference = member;
this.Location = location;
}

21
Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks @@ -31,7 +31,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
List<BookmarkBase> marks = new List<BookmarkBase>();
foreach (BookmarkBase mark in bookmarks) {
if (typeName == mark.Member.FullName) {
if (typeName == mark.MemberReference.FullName) {
marks.Add(mark);
}
}
@ -56,7 +56,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks @@ -56,7 +56,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
return false;
if (a.GetType() != b.GetType())
return false;
if (a.Member.FullName != b.Member.FullName)
if (a.MemberReference.FullName != b.MemberReference.FullName)
return false;
return a.LineNumber == b.LineNumber;
}
@ -150,20 +150,23 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks @@ -150,20 +150,23 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
// 1. Save it's data
int line = CurrentLineBookmark.Instance.LineNumber;
var markerType = CurrentLineBookmark.Instance.Member;
var markerType = CurrentLineBookmark.Instance.MemberReference;
if (!oldMappings.ContainsKey(markerType.FullName) || !oldMappings.ContainsKey(markerType.FullName))
return;
// 2. Remove it
CurrentLineBookmark.Remove();
// 3. map the marker line
uint token;
var instruction = oldMappings.GetInstructionByTypeAndLine(markerType.FullName, line, out token);
var instruction = oldMappings[markerType.FullName].GetInstructionByTypeAndLine(markerType.FullName, line, out token);
if (instruction == null)
return;
MemberReference memberReference;
int newline;
if (newMappings.GetSourceCodeFromMetadataTokenAndOffset(markerType.FullName, token, instruction.ILInstructionOffset.From, out memberReference, out newline)) {
if (newMappings[markerType.FullName].GetSourceCodeFromMetadataTokenAndOffset(token, instruction.ILInstructionOffset.From, out memberReference, out newline)) {
// 4. create breakpoint for new languages
CurrentLineBookmark.SetPosition(memberReference, newline, 0, newline, 0);
}
@ -191,13 +194,17 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks @@ -191,13 +194,17 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
foreach (var bp in oldbps) {
uint token;
var instruction = oldMappings.GetInstructionByTypeAndLine(bp.Member.FullName, bp.LineNumber, out token);
string name = bp.MemberReference.FullName;
if (!oldMappings.ContainsKey(name) || !oldMappings.ContainsKey(name))
continue;
var instruction = oldMappings[name].GetInstructionByTypeAndLine(bp.MemberReference.FullName, bp.LineNumber, out token);
if (instruction == null)
continue;
MemberReference memberReference;
int line;
if (newMappings.GetSourceCodeFromMetadataTokenAndOffset(bp.Member.FullName, token, instruction.ILInstructionOffset.From, out memberReference, out line)) {
if (newMappings[name].GetSourceCodeFromMetadataTokenAndOffset(token, instruction.ILInstructionOffset.From, out memberReference, out line)) {
// 2. create breakpoint for new languages
var bookmark = new BreakpointBookmark(memberReference, new AstLocation(line, 0), BreakpointAction.Break, newLanguage);
AddMark(bookmark);

2
Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs

@ -91,7 +91,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks @@ -91,7 +91,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
ITextMarker marker = markerService.Create(offset, length);
marker.BackgroundColor = Color.FromRgb(180, 38, 38);
marker.ForegroundColor = Colors.White;
marker.IsVisible = b => b is MarkerBookmark && ((MarkerBookmark)b).Member == DebugData.CurrentMemberReference;
marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.FullName);
marker.Bookmark = this;
this.Marker = marker;

2
Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs

@ -81,7 +81,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks @@ -81,7 +81,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
ITextMarker marker = markerService.Create(offset + startColumn - 1, length + 1);
marker.BackgroundColor = Colors.Yellow;
marker.ForegroundColor = Colors.Blue;
marker.IsVisible = b => b is MarkerBookmark && ((MarkerBookmark)b).Member == DebugData.CurrentMemberReference;
marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.FullName);
marker.Bookmark = this;
this.Marker = marker;
return marker;

28
Debugger/ILSpy.Debugger/DebuggedData.cs

@ -18,11 +18,6 @@ namespace ICSharpCode.ILSpy.Debugger @@ -18,11 +18,6 @@ namespace ICSharpCode.ILSpy.Debugger
{
static DecompiledLanguages language;
/// <summary>
/// Gets or sets the current debugged member reference. Can be a type or a member of a type (method, property).
/// </summary>
public static MemberReference CurrentMemberReference { get; set; }
/// <summary>
/// Gets or sets the decompiled language.
/// </summary>
@ -42,19 +37,10 @@ namespace ICSharpCode.ILSpy.Debugger @@ -42,19 +37,10 @@ namespace ICSharpCode.ILSpy.Debugger
/// </summary>
public static IEnumerable<AssemblyDefinition> LoadedAssemblies { get; set; }
/// <summary>
/// Returns true if the CurrentMember is a type (TypeDefinition). Otherwise, returns false (is MethodDefinition or PropertyDefinition).
/// </summary>
public static bool IsCurrentMemberReferenceType {
get {
return CurrentMemberReference is TypeDefinition;
}
}
/// <summary>
/// Gets or sets the current code mappings.
/// </summary>
public static Tuple<string, List<MemberMapping>> CodeMappings { get; set; }
public static Dictionary<string, List<MemberMapping>> CodeMappings { get; set; }
/// <summary>
/// Gets or sets the local variables of the current decompiled type, method, etc.
@ -64,7 +50,17 @@ namespace ICSharpCode.ILSpy.Debugger @@ -64,7 +50,17 @@ namespace ICSharpCode.ILSpy.Debugger
/// <summary>
/// Gets or sets the old code mappings.
/// </summary>
public static Tuple<string, List<MemberMapping>> OldCodeMappings { get; set; }
public static Dictionary<string, List<MemberMapping>> OldCodeMappings { get; set; }
/// <summary>
/// Gets or sets the MembeReference that was decompiled (a TypeDefinition, MethodDefinition, etc)
/// </summary>
public static Dictionary<string, MemberReference> DecompiledMemberReferences { get; set; }
/// <summary>
/// Gets or sets the debug type.
/// </summary>
public static bool DebugWholeTypesOnly { get; set; }
/// <summary>
/// Occures when the language is changed.

18
Debugger/ILSpy.Debugger/DebuggerSettings.cs

@ -9,10 +9,13 @@ namespace ICSharpCode.ILSpy.Debugger @@ -9,10 +9,13 @@ namespace ICSharpCode.ILSpy.Debugger
public class DebuggerSettings : INotifyPropertyChanged
{
bool showWarnings = true;
bool debugWholeTypesOnly = false;
/// <summary>
/// Show warnings messages.
/// <remarks>Default value is true.</remarks>
/// </summary>
[DefaultValue(true)]
public bool ShowWarnings {
get { return showWarnings; }
set {
@ -23,6 +26,21 @@ namespace ICSharpCode.ILSpy.Debugger @@ -23,6 +26,21 @@ namespace ICSharpCode.ILSpy.Debugger
}
}
/// <summary>
/// True, if debug only whole types; otherwise false (debug only methods and properties).
/// <remarks>Default value is false.</remarks>
/// </summary>
[DefaultValue(false)]
public bool DebugWholeTypesOnly {
get { return debugWholeTypesOnly; }
set {
if (debugWholeTypesOnly != value) {
debugWholeTypesOnly = value;
OnPropertyChanged("DebugWholeTypesOnly");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)

2
Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs

@ -166,7 +166,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services @@ -166,7 +166,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services
public static void ToggleBreakpointAt(MemberReference member, int lineNumber, DecompiledLanguages language)
{
BookmarkManager.ToggleBookmark(
member.FullName, lineNumber,
member.FullName.Replace("::", "."), lineNumber,
b => b.CanToggle && b is BreakpointBookmark,
location => new BreakpointBookmark(member, location, BreakpointAction.Break, language));
}

59
Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs

@ -288,10 +288,11 @@ namespace ICSharpCode.ILSpy.Debugger.Services @@ -288,10 +288,11 @@ namespace ICSharpCode.ILSpy.Debugger.Services
{
isMatch = false;
frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
var debugType = (DebugType)frame.MethodInfo.DeclaringType;
string nameKey = DebugData.DebugWholeTypesOnly ? debugType.FullNameWithoutGenericArguments : frame.MethodInfo.FullNameWithoutParameterNames;
// get the mapped instruction from the current line marker or the next one
return DebugData.CodeMappings.GetInstructionByTypeTokenAndOffset(
((DebugType)frame.MethodInfo.DeclaringType).FullNameWithoutGenericArguments,
return DebugData.CodeMappings[nameKey].GetInstructionByTypeTokenAndOffset(
(uint)frame.MethodInfo.MetadataToken,
frame.IP, out isMatch);
}
@ -560,13 +561,16 @@ namespace ICSharpCode.ILSpy.Debugger.Services @@ -560,13 +561,16 @@ namespace ICSharpCode.ILSpy.Debugger.Services
Breakpoint breakpoint = null;
uint token;
SourceCodeMapping map = DebugData.CodeMappings
.GetInstructionByTypeAndLine(bookmark.Member.FullName, bookmark.LineNumber, out token);
SourceCodeMapping map = DebugData.CodeMappings[bookmark.MemberReference.FullName]
.GetInstructionByTypeAndLine(bookmark.MemberReference.FullName, bookmark.LineNumber, out token);
if (map != null) {
var declaringType = bookmark.MemberReference.DeclaringType;
breakpoint = new ILBreakpoint(
debugger,
bookmark.Member.FullName,
(declaringType ?? bookmark.MemberReference).FullName,
bookmark.MemberReference.FullName,
bookmark.LineNumber,
token,
map.ILInstructionOffset.From,
@ -745,7 +749,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services @@ -745,7 +749,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services
foreach (var bookmark in DebuggerService.Breakpoints) {
var breakpoint =
debugger.Breakpoints.FirstOrDefault(
b => b.Line == bookmark.LineNumber && b.TypeName == bookmark.Member.FullName);
b => b.Line == bookmark.LineNumber && (b as ILBreakpoint).MemberReferenceName.CreateKey() == bookmark.MemberReference.FullName.CreateKey());
if (breakpoint == null)
continue;
// set the breakpoint only if the module contains the type
@ -818,14 +822,18 @@ namespace ICSharpCode.ILSpy.Debugger.Services @@ -818,14 +822,18 @@ namespace ICSharpCode.ILSpy.Debugger.Services
int ilOffset = frame.IP;
int line;
MemberReference memberReference;
string nameKey = DebugData.DebugWholeTypesOnly ? debugType.FullNameWithoutGenericArguments : frame.MethodInfo.FullNameWithoutParameterNames;
if (DebugData.CodeMappings.GetSourceCodeFromMetadataTokenAndOffset(debugType.FullNameWithoutGenericArguments, token, ilOffset, out memberReference, out line)
&& memberReference.DeclaringType == null) {
DebuggerService.RemoveCurrentLineMarker();
DebuggerService.JumpToCurrentLine(memberReference, line, 0, line, 0);
} else {
// is possible that the type is not decompiled yet, so we must do a decompilation on demand
DecompileOnDemand(frame);
foreach (var key in DebugData.CodeMappings.Keys) {
if (key.CreateKey() == nameKey.CreateKey()) {
if (DebugData.CodeMappings[key].GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out memberReference, out line)) {
DebuggerService.RemoveCurrentLineMarker();
DebuggerService.JumpToCurrentLine(memberReference, line, 0, line, 0);
} else {
// is possible that the type is not decompiled yet, so we must do a decompilation on demand
DecompileOnDemand(frame);
}
}
}
}
}
@ -837,7 +845,6 @@ namespace ICSharpCode.ILSpy.Debugger.Services @@ -837,7 +845,6 @@ namespace ICSharpCode.ILSpy.Debugger.Services
uint token = (uint)frame.MethodInfo.MetadataToken;
int ilOffset = frame.IP;
string fullName = debugType.FullNameWithoutGenericArguments;
fullName = fullName.Replace("+", "/");
if (DebugData.LoadedAssemblies == null)
throw new NullReferenceException("No DebugData assemblies!");
@ -845,6 +852,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services @@ -845,6 +852,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services
// search for type in the current assembly list
TypeDefinition typeDef = null;
TypeDefinition nestedTypeDef = null;
MemberReference member = null;
foreach (var assembly in DebugData.LoadedAssemblies) {
if ((assembly.FullName.StartsWith("System") || assembly.FullName.StartsWith("Microsoft") || assembly.FullName.StartsWith("mscorlib")) &&
@ -854,9 +862,9 @@ namespace ICSharpCode.ILSpy.Debugger.Services @@ -854,9 +862,9 @@ namespace ICSharpCode.ILSpy.Debugger.Services
foreach (var module in assembly.Modules) {
var localType = module.GetType(fullName);
if (localType != null) {
if (localType.DeclaringType == null)
if (localType.DeclaringType == null) {
typeDef = localType;
else {
} else {
nestedTypeDef = localType;
typeDef = localType.DeclaringType;
}
@ -868,12 +876,22 @@ namespace ICSharpCode.ILSpy.Debugger.Services @@ -868,12 +876,22 @@ namespace ICSharpCode.ILSpy.Debugger.Services
}
if (typeDef != null) {
// decompile on demand
Tuple<string, List<MemberMapping>> codeMappings = null;
if (DebugData.CodeMappings.Item1 != (nestedTypeDef ?? typeDef).FullName) {
member = nestedTypeDef ?? typeDef;
// decompile on demand if the type was not decompiled
Dictionary<string, List<MemberMapping>> codeMappings = null;
if (!DebugData.CodeMappings.ContainsKey(member.FullName)) {
if (DebugData.Language == DecompiledLanguages.IL) {
var dis = new ReflectionDisassembler(new PlainTextOutput(), true, CancellationToken.None);
dis.DisassembleType(nestedTypeDef ?? typeDef);
// else if (ICSharpCode.Decompiler.CodeMappings.DecompiledMember is MethodDefinition)
// dis.DisassembleMethod(ICSharpCode.Decompiler.CodeMappings.DecompiledMember as MethodDefinition);
// else if (ICSharpCode.Decompiler.CodeMappings.DecompiledMember is PropertyDefinition)
// dis.DisassembleProperty(ICSharpCode.Decompiler.CodeMappings.DecompiledMember as PropertyDefinition);
// else if (ICSharpCode.Decompiler.CodeMappings.DecompiledMember is EventDefinition)
// dis.DisassembleEvent(ICSharpCode.Decompiler.CodeMappings.DecompiledMember as EventDefinition);
codeMappings = dis.CodeMappings;
} else {
AstBuilder builder = new AstBuilder(new DecompilerContext(typeDef.Module));
@ -886,7 +904,8 @@ namespace ICSharpCode.ILSpy.Debugger.Services @@ -886,7 +904,8 @@ namespace ICSharpCode.ILSpy.Debugger.Services
int line;
MemberReference memberReference;
codeMappings = codeMappings ?? DebugData.CodeMappings;
if (codeMappings.GetSourceCodeFromMetadataTokenAndOffset((nestedTypeDef ?? typeDef).FullName, token, ilOffset, out memberReference, out line)) {
string name = (nestedTypeDef ?? typeDef).FullName;
if (codeMappings[name].GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out memberReference, out line)) {
DebuggerService.RemoveCurrentLineMarker();
DebuggerService.JumpToCurrentLine(nestedTypeDef ?? typeDef, line, 0, line, 0);
} else {

69
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -46,6 +46,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -46,6 +46,8 @@ namespace ICSharpCode.Decompiler.Ast
this.DecompileMethodBodies = true;
this.LocalVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>();
this.CodeMappings = new Dictionary<string, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<string, MemberReference>();
}
public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings)
@ -159,6 +161,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -159,6 +161,10 @@ namespace ICSharpCode.Decompiler.Ast
public void AddType(TypeDefinition typeDef)
{
// add to mappings information
this.DecompiledMemberReferences.Add(typeDef.FullName, typeDef);
this.CodeMappings.Add(typeDef.FullName, new List<MemberMapping>());
var astType = CreateType(typeDef);
NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace);
if (astNS != null) {
@ -170,22 +176,36 @@ namespace ICSharpCode.Decompiler.Ast @@ -170,22 +176,36 @@ namespace ICSharpCode.Decompiler.Ast
public void AddMethod(MethodDefinition method)
{
// add to mappings information
this.CodeMappings.Add(method.FullName, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(method.FullName, method);
AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method);
astCompileUnit.AddChild(node, CompilationUnit.MemberRole);
}
public void AddProperty(PropertyDefinition property)
{
// add to mappings information
this.CodeMappings.Add(property.FullName, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(property.FullName, property);
astCompileUnit.AddChild(CreateProperty(property), CompilationUnit.MemberRole);
}
public void AddField(FieldDefinition field)
{
this.DecompiledMemberReferences.Add(field.FullName, field);
astCompileUnit.AddChild(CreateField(field), CompilationUnit.MemberRole);
}
public void AddEvent(EventDefinition ev)
{
// add to mappings information
this.DecompiledMemberReferences.Add(ev.FullName, ev);
this.CodeMappings.Add(ev.FullName, new List<MemberMapping>());
astCompileUnit.AddChild(CreateEvent(ev), CompilationUnit.MemberRole);
}
@ -195,11 +215,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -195,11 +215,7 @@ namespace ICSharpCode.Decompiler.Ast
/// <param name="typeDef"></param>
/// <returns>TypeDeclaration or DelegateDeclaration.</returns>
public AttributedNode CreateType(TypeDefinition typeDef)
{
// create CSharp code mappings - used for debugger
if (this.CodeMappings == null)
this.CodeMappings = new Tuple<string, List<MemberMapping>>(typeDef.FullName, new List<MemberMapping>());
{
// create type
TypeDefinition oldCurrentType = context.CurrentType;
context.CurrentType = typeDef;
@ -603,12 +619,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -603,12 +619,12 @@ namespace ICSharpCode.Decompiler.Ast
// Add events
foreach(EventDefinition eventDef in typeDef.Events) {
astType.AddChild(CreateEvent(eventDef), TypeDeclaration.MemberRole);
astType.AddChild(CreateEvent(eventDef, true), TypeDeclaration.MemberRole);
}
// Add properties
foreach(PropertyDefinition propDef in typeDef.Properties) {
astType.Members.Add(CreateProperty(propDef));
astType.Members.Add(CreateProperty(propDef, true));
}
// Add methods
@ -616,16 +632,17 @@ namespace ICSharpCode.Decompiler.Ast @@ -616,16 +632,17 @@ namespace ICSharpCode.Decompiler.Ast
if (MemberIsHidden(methodDef, context.Settings)) continue;
if (methodDef.IsConstructor)
astType.Members.Add(CreateConstructor(methodDef));
astType.Members.Add(CreateConstructor(methodDef, true));
else
astType.Members.Add(CreateMethod(methodDef));
astType.Members.Add(CreateMethod(methodDef, true));
}
}
AttributedNode CreateMethod(MethodDefinition methodDef)
AttributedNode CreateMethod(MethodDefinition methodDef, bool isTypeDecompiled = false)
{
// Create mapping - used in debugger
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings);
string name = isTypeDecompiled ? methodDef.DeclaringType.FullName : methodDef.FullName;
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
MethodDeclaration astMethod = new MethodDeclaration();
astMethod.AddAnnotation(methodDef);
@ -717,10 +734,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -717,10 +734,11 @@ namespace ICSharpCode.Decompiler.Ast
}
}
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef, bool isTypeDecompiled = false)
{
// Create mapping - used in debugger
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings);
string name = isTypeDecompiled ? methodDef.DeclaringType.FullName : methodDef.FullName;
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.AddAnnotation(methodDef);
@ -750,7 +768,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -750,7 +768,7 @@ namespace ICSharpCode.Decompiler.Ast
return m & ~Modifiers.Private;
}
MemberDeclaration CreateProperty(PropertyDefinition propDef)
MemberDeclaration CreateProperty(PropertyDefinition propDef, bool isTypeDecompiled = false)
{
PropertyDeclaration astProp = new PropertyDeclaration();
astProp.AddAnnotation(propDef);
@ -785,9 +803,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -785,9 +803,12 @@ namespace ICSharpCode.Decompiler.Ast
}
astProp.Name = CleanName(propDef.Name);
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
string name = isTypeDecompiled ? propDef.DeclaringType.FullName : propDef.FullName;
if (propDef.GetMethod != null) {
// Create mapping - used in debugger
MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings);
MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
astProp.Getter = new Accessor();
astProp.Getter.Body = CreateMethodBody(propDef.GetMethod);
@ -801,7 +822,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -801,7 +822,7 @@ namespace ICSharpCode.Decompiler.Ast
}
if (propDef.SetMethod != null) {
// Create mapping - used in debugger
MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings);
MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
astProp.Setter = new Accessor();
astProp.Setter.Body = CreateMethodBody(propDef.SetMethod);
@ -837,7 +858,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -837,7 +858,7 @@ namespace ICSharpCode.Decompiler.Ast
return astIndexer;
}
AttributedNode CreateEvent(EventDefinition eventDef)
AttributedNode CreateEvent(EventDefinition eventDef, bool isTypeDecompiled = false)
{
if (eventDef.AddMethod != null && eventDef.AddMethod.IsAbstract) {
// An abstract event cannot be custom
@ -859,9 +880,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -859,9 +880,12 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
else
astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType);
string name = isTypeDecompiled ? eventDef.DeclaringType.FullName : eventDef.FullName;
if (eventDef.AddMethod != null) {
// Create mapping - used in debugger
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings);
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
astEvent.AddAccessor = new Accessor {
Body = CreateMethodBody(eventDef.AddMethod)
@ -872,7 +896,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -872,7 +896,7 @@ namespace ICSharpCode.Decompiler.Ast
}
if (eventDef.RemoveMethod != null) {
// Create mapping - used in debugger
MemberMapping methodMapping = eventDef.RemoveMethod.CreateCodeMapping(this.CodeMappings);
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
astEvent.RemoveAccessor = new Accessor {
Body = CreateMethodBody(eventDef.RemoveMethod)
@ -1371,12 +1395,17 @@ namespace ICSharpCode.Decompiler.Ast @@ -1371,12 +1395,17 @@ namespace ICSharpCode.Decompiler.Ast
/// <summary>
/// <inheritdoc/>
/// </summary>
public Tuple<string, List<MemberMapping>> CodeMappings { get; private set; }
public Dictionary<string, List<MemberMapping>> CodeMappings { get; private set; }
/// <summary>
/// Gets the local variables for the current decompiled type, method, etc.
/// <remarks>The key is the metadata token.</remarks>
/// </summary>
public ConcurrentDictionary<int, IEnumerable<ILVariable>> LocalVariables { get; private set; }
/// <summary>
/// <inheritdoc/>
/// </summary>
public Dictionary<string, MemberReference> DecompiledMemberReferences { get; private set; }
}
}

107
ICSharpCode.Decompiler/CodeMappings.cs

@ -27,7 +27,12 @@ namespace ICSharpCode.Decompiler @@ -27,7 +27,12 @@ namespace ICSharpCode.Decompiler
/// <summary>
/// Gets the code mappings.
/// </summary>
Tuple<string, List<MemberMapping>> CodeMappings { get; }
Dictionary<string, List<MemberMapping>> CodeMappings { get; }
/// <summary>
/// Gets the MembeReference that is decompiled (a TypeDefinition, MethodDefinition, etc)
/// </summary>
Dictionary<string, MemberReference> DecompiledMemberReferences { get; }
}
/// <summary>
@ -133,15 +138,17 @@ namespace ICSharpCode.Decompiler @@ -133,15 +138,17 @@ namespace ICSharpCode.Decompiler
/// Code mappings helper class.
/// </summary>
public static class CodeMappings
{
{
/// <summary>
/// Create code mapping for a method.
/// </summary>
/// <param name="method">Method to create the mapping for.</param>
/// <param name="sourceCodeMappings">Source code mapping storage.</param>
/// <param name="codeMappings">Source code mapping storage.</param>
/// <param name="isTypeDecompiled">True, if a full type was decompiled; false otherwise.</param>
internal static MemberMapping CreateCodeMapping(
this MethodDefinition member,
Tuple<string, List<MemberMapping>> codeMappings)
List<MemberMapping> codeMappings,
bool isTypeDecompiled)
{
if (member == null || !member.HasBody)
return null;
@ -151,17 +158,21 @@ namespace ICSharpCode.Decompiler @@ -151,17 +158,21 @@ namespace ICSharpCode.Decompiler
// create IL/CSharp code mappings - used in debugger
MemberMapping currentMemberMapping = null;
if (codeMappings.Item1 == member.DeclaringType.FullName) {
var mapping = codeMappings.Item2;
if (mapping.Find(map => (int)map.MetadataToken == member.MetadataToken.ToInt32()) == null) {
currentMemberMapping = new MemberMapping() {
MetadataToken = (uint)member.MetadataToken.ToInt32(),
MemberReference = member.DeclaringType.Resolve(),
MemberCodeMappings = new List<SourceCodeMapping>(),
CodeSize = member.Body.CodeSize
};
mapping.Add(currentMemberMapping);
}
string key = isTypeDecompiled ? member.DeclaringType.FullName : member.FullName;
if (codeMappings.Find(map => (int)map.MetadataToken == member.MetadataToken.ToInt32()) == null) {
currentMemberMapping = new MemberMapping() {
MetadataToken = (uint)member.MetadataToken.ToInt32(),
MemberCodeMappings = new List<SourceCodeMapping>(),
CodeSize = member.Body.CodeSize
};
if (isTypeDecompiled)
currentMemberMapping.MemberReference = member.DeclaringType.Resolve();
else
currentMemberMapping.MemberReference = member.Resolve();
codeMappings.Add(currentMemberMapping);
}
return currentMemberMapping;
@ -171,31 +182,20 @@ namespace ICSharpCode.Decompiler @@ -171,31 +182,20 @@ namespace ICSharpCode.Decompiler
/// Gets source code mapping and metadata token based on type name and line number.
/// </summary>
/// <param name="codeMappings">Code mappings storage.</param>
/// <param name="typeName">Type name.</param>
/// <param name="typeName">Member reference name.</param>
/// <param name="lineNumber">Line number.</param>
/// <param name="metadataToken">Metadata token.</param>
/// <returns></returns>
public static SourceCodeMapping GetInstructionByTypeAndLine(
this Tuple<string, List<MemberMapping>> codeMappings,
this List<MemberMapping> codeMappings,
string memberReferenceName,
int lineNumber,
out uint metadataToken)
{
if (codeMappings == null)
throw new ArgumentNullException("CodeMappings storage must be valid!");
if (codeMappings.Item1 != memberReferenceName) {
metadataToken = 0;
return null;
}
if (lineNumber <= 0) {
metadataToken = 0;
return null;
}
throw new ArgumentException("CodeMappings storage must be valid!");
var methodMappings = codeMappings.Item2;
foreach (var maping in methodMappings) {
foreach (var maping in codeMappings) {
var map = maping.MemberCodeMappings.Find(m => m.SourceCodeLine == lineNumber);
if (map != null) {
metadataToken = maping.MetadataToken;
@ -211,33 +211,26 @@ namespace ICSharpCode.Decompiler @@ -211,33 +211,26 @@ namespace ICSharpCode.Decompiler
/// Gets a mapping given a type, a token and an IL offset.
/// </summary>
/// <param name="codeMappings">Code mappings storage.</param>
/// <param name="typeName">Type name.</param>
/// <param name="memberReferenceName">Member reference name.</param>
/// <param name="token">Token.</param>
/// <param name="ilOffset">IL offset.</param>
/// <param name="isMatch">True, if perfect match.</param>
/// <returns>A code mapping.</returns>
public static SourceCodeMapping GetInstructionByTypeTokenAndOffset(
this Tuple<string, List<MemberMapping>> codeMappings,
string memberReferenceName,
this List<MemberMapping> codeMappings,
uint token,
int ilOffset, out bool isMatch)
int ilOffset,
out bool isMatch)
{
isMatch = false;
memberReferenceName = memberReferenceName.Replace("+", "/");
if (codeMappings == null)
throw new ArgumentNullException("CodeMappings storage must be valid!");
if (codeMappings.Item1 != memberReferenceName) {
return null;
}
var methodMappings = codeMappings.Item2;
var maping = methodMappings.Find(m => m.MetadataToken == token);
var maping = codeMappings.Find(m => m.MetadataToken == token);
if (maping == null) {
if (maping == null)
return null;
}
// try find an exact match
var map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To);
@ -260,31 +253,25 @@ namespace ICSharpCode.Decompiler @@ -260,31 +253,25 @@ namespace ICSharpCode.Decompiler
/// Gets the source code and type name from metadata token and offset.
/// </summary>
/// <param name="codeMappings">Code mappings storage.</param>
/// <param name="typeName">Current type name.</param>
/// <param name="token">Metadata token.</param>
/// <param name="ilOffset">IL offset.</param>
/// <param name="typeName">Type definition.</param>
/// <param name="line">Line number.</param>
/// <remarks>It is possible to exist to different types from different assemblies with the same metadata token.</remarks>
public static bool GetSourceCodeFromMetadataTokenAndOffset(
this Tuple<string, List<MemberMapping>> codeMappings,
string memberReferenceName,
this List<MemberMapping> codeMappings,
uint token,
int ilOffset,
out MemberReference type,
out MemberReference member,
out int line)
{
type = null;
member = null;
line = 0;
if (codeMappings == null)
throw new ArgumentNullException("CodeMappings storage must be valid!");
throw new ArgumentException("CodeMappings storage must be valid!");
memberReferenceName = memberReferenceName.Replace("+", "/");
if (codeMappings.Item1 != memberReferenceName)
return false;
var mapping = codeMappings.Item2.Find(m => m.MetadataToken == token);
var mapping = codeMappings.Find(m => m.MetadataToken == token);
if (mapping == null)
return false;
@ -299,9 +286,19 @@ namespace ICSharpCode.Decompiler @@ -299,9 +286,19 @@ namespace ICSharpCode.Decompiler
}
}
type = mapping.MemberReference;
member = mapping.MemberReference;
line = codeMapping.SourceCodeLine;
return true;
}
/// <summary>
/// Create a key by replacing "::" with ".", "+" with "/", " " with "";
/// </summary>
/// <param name="item">Item to convert.</param>
/// <returns></returns>
public static string CreateKey(this string item)
{
return item.Replace("+", "/").Replace("::", ".").Replace(" ", string.Empty);
}
}
}

90
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -44,6 +44,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -44,6 +44,9 @@ namespace ICSharpCode.Decompiler.Disassembler
this.cancellationToken = cancellationToken;
this.detectControlStructure = detectControlStructure;
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken);
this.CodeMappings = new Dictionary<string, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<string, MemberReference>();
}
#region Disassemble Method
@ -92,14 +95,21 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -92,14 +95,21 @@ namespace ICSharpCode.Decompiler.Disassembler
{ MethodImplAttributes.NoOptimization, "nooptimization" },
};
public void DisassembleMethod(MethodDefinition method)
public void DisassembleMethod(MethodDefinition method, bool isTypeDecompiled = false)
{
// create mappings for decompiled methods only
string name = isTypeDecompiled ? method.DeclaringType.FullName : method.FullName;
if (!isTypeDecompiled) {
this.CodeMappings.Add(name, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(method.FullName, method);
}
// write method header
output.WriteDefinition(".method ", method);
DisassembleMethodInternal(method);
DisassembleMethodInternal(method, isTypeDecompiled);
}
void DisassembleMethodInternal(MethodDefinition method)
void DisassembleMethodInternal(MethodDefinition method, bool isTypeDecompiled)
{
// .method public hidebysig specialname
// instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed
@ -118,7 +128,6 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -118,7 +128,6 @@ namespace ICSharpCode.Decompiler.Disassembler
//call convention
WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention);
//return type
method.ReturnType.WriteTo(output);
output.Write(' ');
@ -149,7 +158,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -149,7 +158,9 @@ namespace ICSharpCode.Decompiler.Disassembler
if (method.HasBody) {
// create IL code mappings - used in debugger
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings);
string name = isTypeDecompiled ? method.DeclaringType.FullName : method.FullName;
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
methodBodyDisassembler.Disassemble(method.Body, methodMapping);
}
@ -192,8 +203,13 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -192,8 +203,13 @@ namespace ICSharpCode.Decompiler.Disassembler
{ FieldAttributes.NotSerialized, "notserialized" },
};
public void DisassembleField(FieldDefinition field)
public void DisassembleField(FieldDefinition field, bool isTypeDecompiled = false)
{
// create mappings for decompiled fields only
if (!isTypeDecompiled) {
this.DecompiledMemberReferences.Add(field.FullName, field);
}
output.WriteDefinition(".field ", field);
WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility);
WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | FieldAttributes.HasDefault), fieldAttributes);
@ -221,8 +237,15 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -221,8 +237,15 @@ namespace ICSharpCode.Decompiler.Disassembler
{ PropertyAttributes.HasDefault, "hasdefault" },
};
public void DisassembleProperty(PropertyDefinition property)
public void DisassembleProperty(PropertyDefinition property, bool isTypeDecompiled = false)
{
// create mappings for decompiled properties only
string name = isTypeDecompiled ? property.DeclaringType.FullName : property.FullName;
if (!isTypeDecompiled) {
this.CodeMappings.Add(name, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(property.FullName, property);
}
output.WriteDefinition(".property ", property);
WriteFlags(property.Attributes, propertyAttributes);
property.PropertyType.WriteTo(output);
@ -230,22 +253,22 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -230,22 +253,22 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(DisassemblerHelpers.Escape(property.Name));
OpenBlock(false);
WriteAttributes(property.CustomAttributes);
WriteNestedMethod(".get", property.GetMethod);
WriteNestedMethod(".set", property.SetMethod);
WriteNestedMethod(".get", property.GetMethod, isTypeDecompiled);
WriteNestedMethod(".set", property.SetMethod, isTypeDecompiled);
foreach (var method in property.OtherMethods) {
WriteNestedMethod(".method", method);
WriteNestedMethod(".method", method, isTypeDecompiled);
}
CloseBlock();
}
void WriteNestedMethod(string keyword, MethodDefinition method)
void WriteNestedMethod(string keyword, MethodDefinition method, bool isTypeDecompiled)
{
if (method == null)
return;
if (detectControlStructure) {
output.WriteDefinition(keyword, method);
output.Write(' ');
DisassembleMethodInternal(method);
DisassembleMethodInternal(method, isTypeDecompiled);
} else {
output.Write(keyword);
output.Write(' ');
@ -261,8 +284,15 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -261,8 +284,15 @@ namespace ICSharpCode.Decompiler.Disassembler
{ EventAttributes.RTSpecialName, "rtspecialname" },
};
public void DisassembleEvent(EventDefinition ev)
public void DisassembleEvent(EventDefinition ev, bool isTypeDecompiled = false)
{
// create mappings for decompiled events only
string name = isTypeDecompiled ? ev.DeclaringType.FullName : ev.FullName;
if (!isTypeDecompiled) {
this.CodeMappings.Add(name, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(ev.FullName, ev);
}
output.WriteDefinition(".event ", ev);
WriteFlags(ev.Attributes, eventAttributes);
ev.EventType.WriteTo(output);
@ -270,11 +300,11 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -270,11 +300,11 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(DisassemblerHelpers.Escape(ev.Name));
OpenBlock(false);
WriteAttributes(ev.CustomAttributes);
WriteNestedMethod(".add", ev.AddMethod);
WriteNestedMethod(".remove", ev.RemoveMethod);
WriteNestedMethod(".invoke", ev.InvokeMethod);
WriteNestedMethod(".add", ev.AddMethod, isTypeDecompiled);
WriteNestedMethod(".remove", ev.RemoveMethod, isTypeDecompiled);
WriteNestedMethod(".invoke", ev.InvokeMethod, isTypeDecompiled);
foreach (var method in ev.OtherMethods) {
WriteNestedMethod(".method", method);
WriteNestedMethod(".method", method, isTypeDecompiled);
}
CloseBlock();
}
@ -317,8 +347,10 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -317,8 +347,10 @@ namespace ICSharpCode.Decompiler.Disassembler
public void DisassembleType(TypeDefinition type)
{
// create IL code mappings - used for debugger
if (this.CodeMappings == null)
this.CodeMappings = new Tuple<string, List<MemberMapping>>(type.FullName, new List<MemberMapping>());
if (this.CodeMappings == null) {
this.CodeMappings.Add(type.FullName, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(type.FullName, type);
}
// start writing IL
output.WriteDefinition(".class ", type);
@ -383,7 +415,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -383,7 +415,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Fields");
foreach (var field in type.Fields) {
cancellationToken.ThrowIfCancellationRequested();
DisassembleField(field);
DisassembleField(field, true);
}
output.WriteLine();
}
@ -391,7 +423,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -391,7 +423,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Properties");
foreach (var prop in type.Properties) {
cancellationToken.ThrowIfCancellationRequested();
DisassembleProperty(prop);
DisassembleProperty(prop, true);
}
output.WriteLine();
}
@ -399,7 +431,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -399,7 +431,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Events");
foreach (var ev in type.Events) {
cancellationToken.ThrowIfCancellationRequested();
DisassembleEvent(ev);
DisassembleEvent(ev, true);
output.WriteLine();
}
output.WriteLine();
@ -410,7 +442,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -410,7 +442,7 @@ namespace ICSharpCode.Decompiler.Disassembler
foreach (var m in type.Methods) {
cancellationToken.ThrowIfCancellationRequested();
if (!(detectControlStructure && accessorMethods.Contains(m))) {
DisassembleMethod(m);
DisassembleMethod(m, true);
output.WriteLine();
}
}
@ -605,10 +637,14 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -605,10 +637,14 @@ namespace ICSharpCode.Decompiler.Disassembler
CloseBlock();
}
/// <summary>
/// <inheritdoc/>
public Tuple<string, List<MemberMapping>> CodeMappings {
get;
private set;
}
/// </summary>
public Dictionary<string, List<MemberMapping>> CodeMappings { get; private set; }
/// <summary>
/// <inheritdoc/>
/// </summary>
public Dictionary<string, MemberReference> DecompiledMemberReferences { get; private set; }
}
}

10
ILSpy/CSharpLanguage.cs

@ -92,7 +92,7 @@ namespace ICSharpCode.ILSpy @@ -92,7 +92,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddMethod(method);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables });
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables, DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
}
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
@ -102,7 +102,7 @@ namespace ICSharpCode.ILSpy @@ -102,7 +102,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddProperty(property);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables });
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables, DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
}
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
@ -112,7 +112,7 @@ namespace ICSharpCode.ILSpy @@ -112,7 +112,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddField(field);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
OnDecompilationFinished(null);
OnDecompilationFinished(new DecompileEventArgs { DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
}
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
@ -122,7 +122,7 @@ namespace ICSharpCode.ILSpy @@ -122,7 +122,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddEvent(ev);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables });
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables, DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
}
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
@ -131,7 +131,7 @@ namespace ICSharpCode.ILSpy @@ -131,7 +131,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddType(type);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables });
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables, DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
}
public override void DecompileAssembly(AssemblyDefinition assembly, string fileName, ITextOutput output, DecompilationOptions options)

4
ILSpy/Commands/DebuggerCommands.cs

@ -163,8 +163,8 @@ namespace ICSharpCode.ILSpy.Commands @@ -163,8 +163,8 @@ namespace ICSharpCode.ILSpy.Commands
// jump to type & expand folding
if (CurrentLineBookmark.Instance != null) {
if (CurrentLineBookmark.Instance.Member != DebugData.CurrentMemberReference)
MainWindow.Instance.JumpToReference(CurrentLineBookmark.Instance.Member);
if (!DebugData.DecompiledMemberReferences.ContainsKey(CurrentLineBookmark.Instance.MemberReference.FullName))
MainWindow.Instance.JumpToReference(CurrentLineBookmark.Instance.MemberReference);
MainWindow.Instance.TextView.UnfoldAndScroll(CurrentLineBookmark.Instance.LineNumber);
}

14
ILSpy/ILLanguage.cs

@ -55,35 +55,35 @@ namespace ICSharpCode.ILSpy @@ -55,35 +55,35 @@ namespace ICSharpCode.ILSpy
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleMethod(method);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings });
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings, DecompiledMemberReferences = dis.DecompiledMemberReferences });
}
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{
new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleField(field);
OnDecompilationFinished(null);
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleField(field);
OnDecompilationFinished(new DecompileEventArgs { DecompiledMemberReferences = dis.DecompiledMemberReferences });
}
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleProperty(property);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings });
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings, DecompiledMemberReferences = dis.DecompiledMemberReferences });
}
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleEvent(ev);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings });
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings, DecompiledMemberReferences = dis.DecompiledMemberReferences });
}
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleType(type);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings });
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings , DecompiledMemberReferences = dis.DecompiledMemberReferences});
}
public override void DecompileNamespace(string nameSpace, IEnumerable<TypeDefinition> types, ITextOutput output, DecompilationOptions options)

7
ILSpy/Language.cs

@ -37,12 +37,17 @@ namespace ICSharpCode.ILSpy @@ -37,12 +37,17 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Gets ot sets the code mappings
/// </summary>
public Tuple<string, List<MemberMapping>> CodeMappings { get; set; }
public Dictionary<string, List<MemberMapping>> CodeMappings { get; set; }
/// <summary>
/// Gets or sets the local variables.
/// </summary>
public ConcurrentDictionary<int, IEnumerable<ILVariable>> LocalVariables { get; set; }
/// <summary>
/// Gets the list of MembeReferences that are decompiled (TypeDefinitions, MethodDefinitions, etc)
/// </summary>
public Dictionary<string, MemberReference> DecompiledMemberReferences { get; set; }
}
/// <summary>

3
ILSpy/Options/DebuggerSettingsPanel.xaml

@ -5,6 +5,9 @@ @@ -5,6 +5,9 @@
<Grid>
<StackPanel Margin="10">
<CheckBox IsChecked="{Binding ShowWarnings}">Show warning messages</CheckBox>
<CheckBox
ToolTip="If checked, debug only whole types; otherwise debug only methods or properties."
IsChecked="{Binding DebugWholeTypesOnly}">Debug whole types only</CheckBox>
</StackPanel>
</Grid>
</UserControl>

16
ILSpy/Options/DebuggerSettingsPanel.xaml.cs

@ -19,6 +19,10 @@ namespace ICSharpCode.ILSpy.Options @@ -19,6 +19,10 @@ namespace ICSharpCode.ILSpy.Options
[ExportOptionPage(Title = "Debugger", Order = 1)]
partial class DebuggerSettingsPanel : UserControl, IOptionPage
{
private const string DEBUGGER_SETTINGS = "DebuggerSettings";
private const string SHOW_WARNINGS = "showWarnings";
private const string DEBUG_WHOLE_TYPES_ONLY = "debugWholeTypesOnly";
public DebuggerSettingsPanel()
{
InitializeComponent();
@ -39,19 +43,21 @@ namespace ICSharpCode.ILSpy.Options @@ -39,19 +43,21 @@ namespace ICSharpCode.ILSpy.Options
public static DebuggerSettings LoadDebuggerSettings(ILSpySettings settings)
{
XElement e = settings["DebuggerSettings"];
XElement e = settings[DEBUGGER_SETTINGS];
DebuggerSettings s = new DebuggerSettings();
s.ShowWarnings = (bool?)e.Attribute("showWarnings") ?? s.ShowWarnings;
s.ShowWarnings = (bool?)e.Attribute(SHOW_WARNINGS) ?? s.ShowWarnings;
s.DebugWholeTypesOnly = (bool?)e.Attribute(DEBUG_WHOLE_TYPES_ONLY) ?? s.DebugWholeTypesOnly;
return s;
}
public void Save(XElement root)
{
var s = (DebuggerSettings)this.DataContext;
XElement section = new XElement("DebuggerSettings");
section.SetAttributeValue("showWarnings", s.ShowWarnings);
XElement section = new XElement(DEBUGGER_SETTINGS);
section.SetAttributeValue(SHOW_WARNINGS, s.ShowWarnings);
section.SetAttributeValue(DEBUG_WHOLE_TYPES_ONLY, s.DebugWholeTypesOnly);
XElement existingElement = root.Element("DebuggerSettings");
XElement existingElement = root.Element(DEBUGGER_SETTINGS);
if (existingElement != null)
existingElement.ReplaceWith(section);
else

34
ILSpy/TextView/DecompilerTextView.cs

@ -44,6 +44,7 @@ using ICSharpCode.ILSpy.Debugger; @@ -44,6 +44,7 @@ using ICSharpCode.ILSpy.Debugger;
using ICSharpCode.ILSpy.Debugger.AvalonEdit;
using ICSharpCode.ILSpy.Debugger.Bookmarks;
using ICSharpCode.ILSpy.Debugger.Tooltips;
using ICSharpCode.ILSpy.Options;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.XmlDoc;
using ICSharpCode.NRefactory.Documentation;
@ -335,9 +336,9 @@ namespace ICSharpCode.ILSpy.TextView @@ -335,9 +336,9 @@ namespace ICSharpCode.ILSpy.TextView
void DoDecompile(DecompilationContext context, int outputLengthLimit)
{
// reset type
DebugData.CurrentMemberReference = null;
DebugData.OldCodeMappings = DebugData.CodeMappings;
TextEditorListener.Instance.ClosePopup();
bool isDecompilationOk = true;
RunWithCancellation(
delegate (CancellationToken ct) { // creation of the background task
@ -363,39 +364,34 @@ namespace ICSharpCode.ILSpy.TextView @@ -363,39 +364,34 @@ namespace ICSharpCode.ILSpy.TextView
output.WriteLine(ex.ToString());
}
ShowOutput(output);
// reset type
DebugData.CurrentMemberReference = null;
isDecompilationOk = false;
}
finally {
// set the language
DebugData.Language = MainWindow.Instance.sessionSettings.FilterSettings.Language.Name.StartsWith("IL") ? DecompiledLanguages.IL : DecompiledLanguages.CSharp;
bool debugOnlyTypes = DebuggerSettingsPanel.CurrentDebuggerSettings.DebugWholeTypesOnly;
DebugData.DebugWholeTypesOnly = debugOnlyTypes;
if (DebugData.CurrentMemberReference != null) {
// TODO: show margin for single methods and properties
if (context.TreeNodes.Count() == 1 && DebugData.IsCurrentMemberReferenceType) {
iconMargin.Visibility = Visibility.Visible;
if (isDecompilationOk) {
if (DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.Count > 0) {
// repaint bookmarks
iconMargin.InvalidateVisual();
// show the currentline marker
var bm = CurrentLineBookmark.Instance;
if (bm != null && DebugData.CurrentMemberReference != null) {
if (DebugData.CurrentMemberReference == bm.Member) {
if (bm != null) {
if (DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.FullName)) {
DocumentLine line = textEditor.Document.GetLineByNumber(bm.LineNumber);
bm.Marker = bm.CreateMarker(textMarkerService, line.Offset, line.Length);
}
UnfoldAndScroll(bm.LineNumber);
}
} else {
// hide the margin
iconMargin.Visibility = Visibility.Collapsed;
}
} else {
// remove currentline marker
CurrentLineBookmark.Remove();
iconMargin.Visibility = Visibility.Collapsed;
}
}
});
@ -454,9 +450,6 @@ namespace ICSharpCode.ILSpy.TextView @@ -454,9 +450,6 @@ namespace ICSharpCode.ILSpy.TextView
if (i > 0)
textOutput.WriteLine();
if (nodes[i] is IMemberTreeNode) {
DebugData.CurrentMemberReference = (nodes[i] as IMemberTreeNode).Member;
}
context.Options.CancellationToken.ThrowIfCancellationRequested();
nodes[i].Decompile(context.Language, textOutput, context.Options);
}
@ -466,8 +459,13 @@ namespace ICSharpCode.ILSpy.TextView @@ -466,8 +459,13 @@ namespace ICSharpCode.ILSpy.TextView
static void Language_DecompileFinished(object sender, DecompileEventArgs e)
{
if (e != null) {
DebugData.CodeMappings = e.CodeMappings;
DebugData.CodeMappings = e.CodeMappings;
DebugData.LocalVariables = e.LocalVariables;
DebugData.DecompiledMemberReferences = e.DecompiledMemberReferences;
} else {
DebugData.CodeMappings = null;
DebugData.LocalVariables = null;
DebugData.DecompiledMemberReferences = null;
}
}
#endregion

Loading…
Cancel
Save