Browse Source

Store code mappings using token as key. Sync bookmarks.

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
f6ecd0645a
  1. 4
      Debugger/Debugger.Core/Breakpoint.cs
  2. 75
      Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs
  3. 55
      Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs
  4. 2
      Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs
  5. 5
      Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs
  6. 6
      Debugger/ILSpy.Debugger/DebuggedData.cs
  7. 107
      Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs
  8. 43
      Debugger/ILSpy.Debugger/Services/ExtensionMethods.cs
  9. 77
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  10. 40
      ICSharpCode.Decompiler/CodeMappings.cs
  11. 83
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  12. 19
      ILSpy/Commands/DebuggerCommands.cs
  13. 7
      ILSpy/Language.cs
  14. 24
      ILSpy/TextView/DecompilerTextView.cs

4
Debugger/Debugger.Core/Breakpoint.cs

@ -176,7 +176,7 @@ namespace Debugger
public class ILBreakpoint : Breakpoint public class ILBreakpoint : Breakpoint
{ {
public ILBreakpoint(NDebugger debugger, string typeName, string memberReferenceName, int line, uint metadataToken, int offset, bool enabled) public ILBreakpoint(NDebugger debugger, string typeName, string memberReferenceName, int line, int metadataToken, int offset, bool enabled)
{ {
this.Debugger = debugger; this.Debugger = debugger;
this.Line = line; this.Line = line;
@ -187,7 +187,7 @@ namespace Debugger
this.Enabled = enabled; this.Enabled = enabled;
} }
public uint MetadataToken { get; private set; } public int MetadataToken { get; private set; }
public int ILOffset { get; private set; } public int ILOffset { get; private set; }

75
Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
@ -62,7 +63,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
Dictionary<int, BookmarkBase> bookmarkDict = new Dictionary<int, BookmarkBase>(); Dictionary<int, BookmarkBase> bookmarkDict = new Dictionary<int, BookmarkBase>();
foreach (var bm in BookmarkManager.Bookmarks) { foreach (var bm in BookmarkManager.Bookmarks) {
if (DebugData.DecompiledMemberReferences == null || DebugData.DecompiledMemberReferences.Count == 0 || if (DebugData.DecompiledMemberReferences == null || DebugData.DecompiledMemberReferences.Count == 0 ||
!DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.FullName)) !DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.MetadataToken.ToInt32()))
continue; continue;
int line = bm.LineNumber; int line = bm.LineNumber;
@ -121,7 +122,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
BookmarkBase result = null; BookmarkBase result = null;
foreach (BookmarkBase bm in BookmarkManager.Bookmarks) { foreach (BookmarkBase bm in BookmarkManager.Bookmarks) {
if (bm.LineNumber == line && if (bm.LineNumber == line &&
DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.FullName)) { DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.MetadataToken.ToInt32())) {
if (result == null || bm.ZOrder > result.ZOrder) if (result == null || bm.ZOrder > result.ZOrder)
result = bm; result = bm;
} }
@ -191,7 +192,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
} }
BreakpointBookmark bm = BookmarkManager.Bookmarks.Find( BreakpointBookmark bm = BookmarkManager.Bookmarks.Find(
b => DebugData.CodeMappings.ContainsKey(b.MemberReference.FullName) && b => DebugData.CodeMappings != null && DebugData.CodeMappings.ContainsKey(b.MemberReference.MetadataToken.ToInt32()) &&
b.LineNumber == GetLineFromMousePosition(e) b.LineNumber == GetLineFromMousePosition(e)
&& b is BreakpointBookmark) as BreakpointBookmark; && b is BreakpointBookmark) as BreakpointBookmark;
@ -224,14 +225,13 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
return; return;
} }
if (e.ChangedButton == MouseButton.Left) { if (e.ChangedButton == MouseButton.Left) {
if (DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.Count > 0) { if (DebugData.CodeMappings != null && DebugData.CodeMappings.Count > 0) {
// check if the codemappings exists for this line // check if the codemappings exists for this line
var storage = DebugData.CodeMappings; var storage = DebugData.CodeMappings;
uint token = 0; int token = 0;
foreach (var member in DebugData.DecompiledMemberReferences.Values) { foreach (var key in storage.Keys) {
string memberName = member.FullName; var instruction = storage[key].GetInstructionByLineNumber(line, out token);
var instruction = storage[memberName].GetInstructionByLineNumber(line, out token);
if (instruction == null) { if (instruction == null) {
continue; continue;
@ -239,7 +239,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
// no bookmark on the line: create a new breakpoint // no bookmark on the line: create a new breakpoint
DebuggerService.ToggleBreakpointAt( DebuggerService.ToggleBreakpointAt(
member, DebugData.DecompiledMemberReferences[key],
line, line,
instruction.ILInstructionOffset, instruction.ILInstructionOffset,
DebugData.Language); DebugData.Language);
@ -259,7 +259,8 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
public void SyncBookmarks() public void SyncBookmarks()
{ {
if (DebugData.CodeMappings == null || DebugData.CodeMappings.Count == 0) var storage = DebugData.CodeMappings;
if (storage == null || storage.Count == 0)
return; return;
//remove existing bookmarks and create new ones //remove existing bookmarks and create new ones
@ -269,46 +270,22 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
if (breakpoint == null) if (breakpoint == null)
continue; continue;
foreach (var key in DebugData.CodeMappings.Keys) { var key = breakpoint.MemberReference.MetadataToken.ToInt32();
var member = DebugData.DecompiledMemberReferences[key]; if (!storage.ContainsKey(key))
continue;
uint token;
if (member is TypeDefinition) { var member = DebugData.DecompiledMemberReferences[key];
var m = member as TypeDefinition;
if (breakpoint.MemberReference is TypeDefinition) { bool isMatch;
if (member != breakpoint.MemberReference) SourceCodeMapping map = storage[key].GetInstructionByTokenAndOffset(
continue; member.MetadataToken.ToInt32(), breakpoint.ILRange.From, out isMatch);
token = (uint)member.MetadataToken.ToInt32();
} else { if (map != null) {
if (!m.ContainsMember(breakpoint.MemberReference)) newBookmarks.Add(new BreakpointBookmark(
continue; member, new AstLocation(map.SourceCodeLine, 0),
token = (uint)breakpoint.MemberReference.MetadataToken.ToInt32(); map.ILInstructionOffset, BreakpointAction.Break, DebugData.Language));
}
} else {
if (breakpoint.MemberReference is TypeDefinition) {
if (!(breakpoint.MemberReference as TypeDefinition).ContainsMember(member))
continue;
token = (uint)member.MetadataToken.ToInt32();
} else {
if (breakpoint.MemberReference != member)
continue;
token = (uint)breakpoint.MemberReference.MetadataToken.ToInt32();
}
}
bool isMatch;
SourceCodeMapping map = DebugData.CodeMappings[key]
.GetInstructionByTokenAndOffset(token, breakpoint.ILRange.From, out isMatch);
if (map != null) { BookmarkManager.RemoveMark(breakpoint);
newBookmarks.Add(new BreakpointBookmark(
DebugData.DecompiledMemberReferences[key],
new AstLocation(map.SourceCodeLine, 0),
map.ILInstructionOffset, BreakpointAction.Break, DebugData.Language));
BookmarkManager.RemoveMark(breakpoint);
break;
}
} }
} }

55
Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs

@ -152,71 +152,24 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
int line = CurrentLineBookmark.Instance.LineNumber; int line = CurrentLineBookmark.Instance.LineNumber;
var markerType = CurrentLineBookmark.Instance.MemberReference; var markerType = CurrentLineBookmark.Instance.MemberReference;
if (!oldMappings.ContainsKey(markerType.FullName) || !newMappings.ContainsKey(markerType.FullName)) if (!oldMappings.ContainsKey(markerType.MetadataToken.ToInt32()) || !newMappings.ContainsKey(markerType.MetadataToken.ToInt32()))
return; return;
// 2. Remove it // 2. Remove it
CurrentLineBookmark.Remove(); CurrentLineBookmark.Remove();
// 3. map the marker line // 3. map the marker line
uint token; int token;
var instruction = oldMappings[markerType.FullName].GetInstructionByLineNumber(line, out token); var instruction = oldMappings[markerType.MetadataToken.ToInt32()].GetInstructionByLineNumber(line, out token);
if (instruction == null) if (instruction == null)
return; return;
MemberReference memberReference; MemberReference memberReference;
int newline; int newline;
if (newMappings[markerType.FullName].GetSourceCodeFromMetadataTokenAndOffset(token, instruction.ILInstructionOffset.From, out memberReference, out newline)) { if (newMappings[markerType.MetadataToken.ToInt32()].GetSourceCodeFromMetadataTokenAndOffset(token, instruction.ILInstructionOffset.From, out memberReference, out newline)) {
// 4. create breakpoint for new languages // 4. create breakpoint for new languages
CurrentLineBookmark.SetPosition(memberReference, newline, 0, newline, 0); CurrentLineBookmark.SetPosition(memberReference, newline, 0, newline, 0);
} }
} }
/// <summary>
/// Synchronize the IL<->C# breakpoints bookmarks.
/// </summary>
/// <param name="oldLanguage">Old language.</param>
/// <param name="newLanguage">New language.</param>
static void SyncBreakpointBookmarks(DecompiledLanguages oldLanguage, DecompiledLanguages newLanguage)
{
// checks
var oldMappings = DebugData.OldCodeMappings;
var newMappings = DebugData.CodeMappings;
if (oldMappings == null || newMappings == null)
return;
// 1. map the breakpoint lines
var oldbps = bookmarks.FindAll(b => b is BreakpointBookmark &&
((BreakpointBookmark)b).Language == oldLanguage);
if (oldbps == null || oldbps.Count == 0)
return;
foreach (var bp in oldbps) {
uint token;
string name = bp.MemberReference.FullName;
if (!oldMappings.ContainsKey(name) || !newMappings.ContainsKey(name))
continue;
var instruction = oldMappings[name].GetInstructionByLineNumber(bp.LineNumber, out token);
if (instruction == null)
continue;
MemberReference memberReference;
int 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), instruction.ILInstructionOffset, BreakpointAction.Break, newLanguage);
AddMark(bookmark);
}
}
// 3. remove all breakpoints for the old language
for (int i = bookmarks.Count - 1; i >= 0; --i) {
var bm = bookmarks[i];
if (bm is BreakpointBookmark && ((BreakpointBookmark)bm).Language == oldLanguage)
RemoveMark(bm);
}
}
} }
} }

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

@ -92,7 +92,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
marker.BackgroundColor = Color.FromRgb(180, 38, 38); marker.BackgroundColor = Color.FromRgb(180, 38, 38);
marker.ForegroundColor = Colors.White; marker.ForegroundColor = Colors.White;
marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences != null && marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences != null &&
DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.FullName); DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.MetadataToken.ToInt32());
marker.Bookmark = this; marker.Bookmark = this;
this.Marker = marker; this.Marker = marker;

5
Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs

@ -3,9 +3,10 @@
using System; using System;
using System.Windows.Media; using System.Windows.Media;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.Debugger.AvalonEdit; using ICSharpCode.ILSpy.Debugger.AvalonEdit;
using ICSharpCode.ILSpy.Debugger.Services; using ICSharpCode.ILSpy.Debugger.Services;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
using Mono.CSharp; using Mono.CSharp;
@ -82,7 +83,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
marker.BackgroundColor = Colors.Yellow; marker.BackgroundColor = Colors.Yellow;
marker.ForegroundColor = Colors.Blue; marker.ForegroundColor = Colors.Blue;
marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences != null && marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences != null &&
DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.FullName); DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.MetadataToken.ToInt32());
marker.Bookmark = this; marker.Bookmark = this;
this.Marker = marker; this.Marker = marker;
return marker; return marker;

6
Debugger/ILSpy.Debugger/DebuggedData.cs

@ -40,7 +40,7 @@ namespace ICSharpCode.ILSpy.Debugger
/// <summary> /// <summary>
/// Gets or sets the current code mappings. /// Gets or sets the current code mappings.
/// </summary> /// </summary>
public static Dictionary<string, List<MemberMapping>> CodeMappings { get; set; } public static Dictionary<int, List<MemberMapping>> CodeMappings { get; set; }
/// <summary> /// <summary>
/// Gets or sets the local variables of the current decompiled type, method, etc. /// Gets or sets the local variables of the current decompiled type, method, etc.
@ -50,12 +50,12 @@ namespace ICSharpCode.ILSpy.Debugger
/// <summary> /// <summary>
/// Gets or sets the old code mappings. /// Gets or sets the old code mappings.
/// </summary> /// </summary>
public static Dictionary<string, List<MemberMapping>> OldCodeMappings { get; set; } public static Dictionary<int, List<MemberMapping>> OldCodeMappings { get; set; }
/// <summary> /// <summary>
/// Gets or sets the MembeReference that was decompiled (a TypeDefinition, MethodDefinition, etc) /// Gets or sets the MembeReference that was decompiled (a TypeDefinition, MethodDefinition, etc)
/// </summary> /// </summary>
public static Dictionary<string, MemberReference> DecompiledMemberReferences { get; set; } public static Dictionary<int, MemberReference> DecompiledMemberReferences { get; set; }
/// <summary> /// <summary>
/// Occures when the language is changed. /// Occures when the language is changed.

107
Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs

@ -288,13 +288,10 @@ namespace ICSharpCode.ILSpy.Debugger.Services
{ {
isMatch = false; isMatch = false;
frame = debuggedProcess.SelectedThread.MostRecentStackFrame; frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
var debugType = (DebugType)frame.MethodInfo.DeclaringType; int key = frame.MethodInfo.MetadataToken;
string nameKey = debugType.FullNameWithoutGenericArguments;
// get the mapped instruction from the current line marker or the next one // get the mapped instruction from the current line marker or the next one
return DebugData.CodeMappings[nameKey].GetInstructionByTokenAndOffset( return DebugData.CodeMappings[key].GetInstructionByTokenAndOffset(key, frame.IP, out isMatch);
(uint)frame.MethodInfo.MetadataToken,
frame.IP, out isMatch);
} }
StackFrame GetStackFrame() StackFrame GetStackFrame()
@ -560,25 +557,14 @@ namespace ICSharpCode.ILSpy.Debugger.Services
{ {
Breakpoint breakpoint = null; Breakpoint breakpoint = null;
uint token; breakpoint = new ILBreakpoint(
SourceCodeMapping map = DebugData.CodeMappings[bookmark.MemberReference.FullName] debugger,
.GetInstructionByLineNumber(bookmark.LineNumber, out token); bookmark.MemberReference.DeclaringType.FullName,
bookmark.MemberReference.FullName,
if (map != null) { bookmark.LineNumber,
var declaringType = bookmark.MemberReference.DeclaringType; bookmark.MemberReference.MetadataToken.ToInt32(),
bookmark.ILRange.From,
breakpoint = new ILBreakpoint( bookmark.IsEnabled);
debugger,
(declaringType ?? bookmark.MemberReference).FullName,
bookmark.MemberReference.FullName,
bookmark.LineNumber,
token,
map.ILInstructionOffset.From,
bookmark.IsEnabled);
}
if (breakpoint == null)
return;
debugger.Breakpoints.Add(breakpoint); debugger.Breakpoints.Add(breakpoint);
// Action setBookmarkColor = delegate { // Action setBookmarkColor = delegate {
@ -749,7 +735,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services
foreach (var bookmark in DebuggerService.Breakpoints) { foreach (var bookmark in DebuggerService.Breakpoints) {
var breakpoint = var breakpoint =
debugger.Breakpoints.FirstOrDefault( debugger.Breakpoints.FirstOrDefault(
b => b.Line == bookmark.LineNumber && (b as ILBreakpoint).MemberReferenceName.CreateKey() == bookmark.MemberReference.FullName.CreateKey()); b => b.Line == bookmark.LineNumber && (b as ILBreakpoint).MetadataToken == bookmark.MemberReference.MetadataToken.ToInt32());
if (breakpoint == null) if (breakpoint == null)
continue; continue;
// set the breakpoint only if the module contains the type // set the breakpoint only if the module contains the type
@ -817,32 +803,33 @@ namespace ICSharpCode.ILSpy.Debugger.Services
if (frame == null) if (frame == null)
return; return;
uint token = (uint)frame.MethodInfo.MetadataToken; int token = frame.MethodInfo.MetadataToken;
var debugType = (DebugType)frame.MethodInfo.DeclaringType;
int ilOffset = frame.IP; int ilOffset = frame.IP;
int line; int line;
MemberReference memberReference; MemberReference memberReference;
string nameKey = debugType.FullNameWithoutGenericArguments;
foreach (var key in DebugData.CodeMappings.Keys) { if (DebugData.CodeMappings.ContainsKey(token)) {
if (key.CreateKey() == nameKey.CreateKey()) { if (DebugData.CodeMappings[token].GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out memberReference, out line)) {
if (DebugData.CodeMappings[key].GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out memberReference, out line)) { DebuggerService.RemoveCurrentLineMarker();
DebuggerService.RemoveCurrentLineMarker(); DebuggerService.JumpToCurrentLine(memberReference, line, 0, line, 0);
DebuggerService.JumpToCurrentLine(memberReference, line, 0, line, 0); } else {
} else { // is possible that the type is not decompiled yet, so we must do a decompilation on demand
// is possible that the type is not decompiled yet, so we must do a decompilation on demand DecompileOnDemand(frame);
DecompileOnDemand(frame);
}
} }
} }
else {
// is possible that the type is not decompiled yet, so we must do a decompilation on demand
DecompileOnDemand(frame);
}
} }
} }
void DecompileOnDemand(StackFrame frame) void DecompileOnDemand(StackFrame frame)
{ {
string debuggeeVersion = frame.MethodInfo.DebugModule.Process.DebuggeeVersion.Substring(1, 3); // should retrieve 2.0, 3.0, 4.0 string debuggeeVersion = frame.MethodInfo.DebugModule.Process.DebuggeeVersion.Substring(1, 3); // should retrieve 2.0, 3.0, 4.0
var debugType = (DebugType)frame.MethodInfo.DeclaringType; var debugType = (DebugType)frame.MethodInfo.DeclaringType;
uint token = (uint)frame.MethodInfo.MetadataToken; int token = frame.MethodInfo.MetadataToken;
int ilOffset = frame.IP; int ilOffset = frame.IP;
string fullName = debugType.FullNameWithoutGenericArguments; string fullName = debugType.FullNameWithoutGenericArguments;
@ -852,7 +839,6 @@ namespace ICSharpCode.ILSpy.Debugger.Services
// search for type in the current assembly list // search for type in the current assembly list
TypeDefinition typeDef = null; TypeDefinition typeDef = null;
TypeDefinition nestedTypeDef = null; TypeDefinition nestedTypeDef = null;
MemberReference member = null;
foreach (var assembly in DebugData.LoadedAssemblies) { foreach (var assembly in DebugData.LoadedAssemblies) {
if ((assembly.FullName.StartsWith("System") || assembly.FullName.StartsWith("Microsoft") || assembly.FullName.StartsWith("mscorlib")) && if ((assembly.FullName.StartsWith("System") || assembly.FullName.StartsWith("Microsoft") || assembly.FullName.StartsWith("mscorlib")) &&
@ -876,40 +862,55 @@ namespace ICSharpCode.ILSpy.Debugger.Services
} }
if (typeDef != null) { if (typeDef != null) {
member = nestedTypeDef ?? typeDef; TypeDefinition type = nestedTypeDef ?? typeDef;
MemberReference memberReference = null;
// decompile on demand if the type was not decompiled // decompile on demand if the type was no decompiled
Dictionary<string, List<MemberMapping>> codeMappings = null; Dictionary<int, List<MemberMapping>> codeMappings = null;
if (!DebugData.CodeMappings.ContainsKey(member.FullName)) { Dictionary<int, MemberReference> members = null;
if (!DebugData.CodeMappings.ContainsKey(token)) {
if (DebugData.Language == DecompiledLanguages.IL) { if (DebugData.Language == DecompiledLanguages.IL) {
var dis = new ReflectionDisassembler(new PlainTextOutput(), true, CancellationToken.None); var dis = new ReflectionDisassembler(new PlainTextOutput(), true, CancellationToken.None);
dis.DisassembleType(nestedTypeDef ?? typeDef); dis.DisassembleType(type);
codeMappings = dis.CodeMappings; codeMappings = dis.CodeMappings;
} else { } else {
// decompile type
AstBuilder builder = new AstBuilder(new DecompilerContext(typeDef.Module)); AstBuilder builder = new AstBuilder(new DecompilerContext(typeDef.Module));
builder.AddType(nestedTypeDef ?? typeDef); builder.AddType(type);
builder.GenerateCode(new PlainTextOutput()); builder.GenerateCode(new PlainTextOutput());
codeMappings = builder.CodeMappings; memberReference = builder.DecompiledMemberReferences[token];
// decompile member
var context = new DecompilerContext(typeDef.Module);
context.CurrentType = type;
builder = new AstBuilder(context);
if (memberReference is PropertyDefinition)
builder.AddProperty(memberReference as PropertyDefinition);
else if (memberReference is MethodDefinition)
builder.AddMethod(memberReference as MethodDefinition);
else if (memberReference is EventDefinition)
builder.AddEvent(memberReference as EventDefinition);
builder.GenerateCode(new PlainTextOutput());
DebugData.CodeMappings = codeMappings = builder.CodeMappings;
DebugData.DecompiledMemberReferences = members = builder.DecompiledMemberReferences;
} }
} }
// try jump // try jump
int line; int line;
MemberReference memberReference;
codeMappings = codeMappings ?? DebugData.CodeMappings; codeMappings = codeMappings ?? DebugData.CodeMappings;
string name = (nestedTypeDef ?? typeDef).FullName; if (codeMappings[token].GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out memberReference, out line)) {
if (codeMappings[name].GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out memberReference, out line)) {
DebuggerService.RemoveCurrentLineMarker(); DebuggerService.RemoveCurrentLineMarker();
DebuggerService.JumpToCurrentLine(nestedTypeDef ?? typeDef, line, 0, line, 0); DebuggerService.JumpToCurrentLine(members[token], line, 0, line, 0);
} else { } else {
StepOut(); StepOut();
} }
} else {
// continue since we cannot find the debugged type
Debug.Assert(typeDef != null, string.Format("The type {0} was not found!", fullName));
} }
} }
} }
public void ShowAttachDialog() public void ShowAttachDialog()
{ {
throw new NotImplementedException(); throw new NotImplementedException();

43
Debugger/ILSpy.Debugger/Services/ExtensionMethods.cs

@ -400,48 +400,5 @@ namespace ICSharpCode.ILSpy.Debugger.Services
{ {
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset); scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset);
} }
/// <summary>
/// Verifies if the type contains the member.
/// </summary>
/// <param name="type"></param>
/// <param name="member"></param>
/// <returns></returns>
public static bool ContainsMember(this TypeDefinition type, MemberReference member)
{
// check fields
if (member is FieldDefinition) {
foreach (var field in type.Fields) {
if (field == member)
return true;
}
}
// check properties
if (member is PropertyDefinition) {
foreach (var field in type.Properties) {
if (field.Resolve() == member)
return true;
}
}
// check methods
if (member is MethodDefinition) {
foreach (var field in type.Methods) {
if (field == member)
return true;
}
}
// check events
if (member is EventDefinition) {
foreach (var field in type.Events) {
if (field == member)
return true;
}
}
return false;
}
} }
} }

77
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -46,8 +46,8 @@ namespace ICSharpCode.Decompiler.Ast
this.DecompileMethodBodies = true; this.DecompileMethodBodies = true;
this.LocalVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>(); this.LocalVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>();
this.CodeMappings = new Dictionary<string, List<MemberMapping>>(); this.CodeMappings = new Dictionary<int, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<string, MemberReference>(); this.DecompiledMemberReferences = new Dictionary<int, MemberReference>();
} }
public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings) public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings)
@ -161,10 +161,6 @@ namespace ICSharpCode.Decompiler.Ast
public void AddType(TypeDefinition typeDef) 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); var astType = CreateType(typeDef);
NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace); NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace);
if (astNS != null) { if (astNS != null) {
@ -176,36 +172,22 @@ namespace ICSharpCode.Decompiler.Ast
public void AddMethod(MethodDefinition method) 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); AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method);
astCompileUnit.AddChild(node, CompilationUnit.MemberRole); astCompileUnit.AddChild(node, CompilationUnit.MemberRole);
} }
public void AddProperty(PropertyDefinition property) 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); astCompileUnit.AddChild(CreateProperty(property), CompilationUnit.MemberRole);
} }
public void AddField(FieldDefinition field) public void AddField(FieldDefinition field)
{ {
this.DecompiledMemberReferences.Add(field.FullName, field);
astCompileUnit.AddChild(CreateField(field), CompilationUnit.MemberRole); astCompileUnit.AddChild(CreateField(field), CompilationUnit.MemberRole);
} }
public void AddEvent(EventDefinition ev) 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); astCompileUnit.AddChild(CreateEvent(ev), CompilationUnit.MemberRole);
} }
@ -215,7 +197,7 @@ namespace ICSharpCode.Decompiler.Ast
/// <param name="typeDef"></param> /// <param name="typeDef"></param>
/// <returns>TypeDeclaration or DelegateDeclaration.</returns> /// <returns>TypeDeclaration or DelegateDeclaration.</returns>
public AttributedNode CreateType(TypeDefinition typeDef) public AttributedNode CreateType(TypeDefinition typeDef)
{ {
// create type // create type
TypeDefinition oldCurrentType = context.CurrentType; TypeDefinition oldCurrentType = context.CurrentType;
context.CurrentType = typeDef; context.CurrentType = typeDef;
@ -619,12 +601,12 @@ namespace ICSharpCode.Decompiler.Ast
// Add events // Add events
foreach(EventDefinition eventDef in typeDef.Events) { foreach(EventDefinition eventDef in typeDef.Events) {
astType.AddChild(CreateEvent(eventDef, true), TypeDeclaration.MemberRole); astType.AddChild(CreateEvent(eventDef), TypeDeclaration.MemberRole);
} }
// Add properties // Add properties
foreach(PropertyDefinition propDef in typeDef.Properties) { foreach(PropertyDefinition propDef in typeDef.Properties) {
astType.Members.Add(CreateProperty(propDef, true)); astType.Members.Add(CreateProperty(propDef));
} }
// Add methods // Add methods
@ -632,17 +614,17 @@ namespace ICSharpCode.Decompiler.Ast
if (MemberIsHidden(methodDef, context.Settings)) continue; if (MemberIsHidden(methodDef, context.Settings)) continue;
if (methodDef.IsConstructor) if (methodDef.IsConstructor)
astType.Members.Add(CreateConstructor(methodDef, true)); astType.Members.Add(CreateConstructor(methodDef));
else else
astType.Members.Add(CreateMethod(methodDef, true)); astType.Members.Add(CreateMethod(methodDef));
} }
} }
AttributedNode CreateMethod(MethodDefinition methodDef, bool isTypeDecompiled = false) AttributedNode CreateMethod(MethodDefinition methodDef)
{ {
// Create mapping - used in debugger // Create mapping - used in debugger
string name = isTypeDecompiled ? methodDef.DeclaringType.FullName : methodDef.FullName; int currentMemberToken = CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef);
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled); MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[currentMemberToken]);
MethodDeclaration astMethod = new MethodDeclaration(); MethodDeclaration astMethod = new MethodDeclaration();
astMethod.AddAnnotation(methodDef); astMethod.AddAnnotation(methodDef);
@ -734,11 +716,11 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef, bool isTypeDecompiled = false) ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
{ {
// Create mapping - used in debugger // Create mapping - used in debugger
string name = isTypeDecompiled ? methodDef.DeclaringType.FullName : methodDef.FullName; int currentMemberToken = CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef);
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled); MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[currentMemberToken]);
ConstructorDeclaration astMethod = new ConstructorDeclaration(); ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.AddAnnotation(methodDef); astMethod.AddAnnotation(methodDef);
@ -768,7 +750,7 @@ namespace ICSharpCode.Decompiler.Ast
return m & ~Modifiers.Private; return m & ~Modifiers.Private;
} }
MemberDeclaration CreateProperty(PropertyDefinition propDef, bool isTypeDecompiled = false) MemberDeclaration CreateProperty(PropertyDefinition propDef)
{ {
PropertyDeclaration astProp = new PropertyDeclaration(); PropertyDeclaration astProp = new PropertyDeclaration();
astProp.AddAnnotation(propDef); astProp.AddAnnotation(propDef);
@ -804,11 +786,10 @@ namespace ICSharpCode.Decompiler.Ast
astProp.Name = CleanName(propDef.Name); astProp.Name = CleanName(propDef.Name);
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
string name = isTypeDecompiled ? propDef.DeclaringType.FullName : propDef.FullName;
if (propDef.GetMethod != null) { if (propDef.GetMethod != null) {
// Create mapping - used in debugger // Create mapping - used in debugger
MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled); int currentMemberToken = CreateCodeMappings(propDef.GetMethod.MetadataToken.ToInt32(), propDef);
MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings[currentMemberToken]);
astProp.Getter = new Accessor(); astProp.Getter = new Accessor();
astProp.Getter.Body = CreateMethodBody(propDef.GetMethod); astProp.Getter.Body = CreateMethodBody(propDef.GetMethod);
@ -822,7 +803,8 @@ namespace ICSharpCode.Decompiler.Ast
} }
if (propDef.SetMethod != null) { if (propDef.SetMethod != null) {
// Create mapping - used in debugger // Create mapping - used in debugger
MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled); int currentMemberToken = CreateCodeMappings(propDef.SetMethod.MetadataToken.ToInt32(), propDef);
MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings[currentMemberToken]);
astProp.Setter = new Accessor(); astProp.Setter = new Accessor();
astProp.Setter.Body = CreateMethodBody(propDef.SetMethod); astProp.Setter.Body = CreateMethodBody(propDef.SetMethod);
@ -858,7 +840,7 @@ namespace ICSharpCode.Decompiler.Ast
return astIndexer; return astIndexer;
} }
AttributedNode CreateEvent(EventDefinition eventDef, bool isTypeDecompiled = false) AttributedNode CreateEvent(EventDefinition eventDef)
{ {
if (eventDef.AddMethod != null && eventDef.AddMethod.IsAbstract) { if (eventDef.AddMethod != null && eventDef.AddMethod.IsAbstract) {
// An abstract event cannot be custom // An abstract event cannot be custom
@ -881,11 +863,10 @@ namespace ICSharpCode.Decompiler.Ast
else else
astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType); astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType);
string name = isTypeDecompiled ? eventDef.DeclaringType.FullName : eventDef.FullName;
if (eventDef.AddMethod != null) { if (eventDef.AddMethod != null) {
// Create mapping - used in debugger // Create mapping - used in debugger
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled); int currentMemberToken = CreateCodeMappings(eventDef.AddMethod.MetadataToken.ToInt32(), eventDef);
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[currentMemberToken]);
astEvent.AddAccessor = new Accessor { astEvent.AddAccessor = new Accessor {
Body = CreateMethodBody(eventDef.AddMethod) Body = CreateMethodBody(eventDef.AddMethod)
@ -896,7 +877,8 @@ namespace ICSharpCode.Decompiler.Ast
} }
if (eventDef.RemoveMethod != null) { if (eventDef.RemoveMethod != null) {
// Create mapping - used in debugger // Create mapping - used in debugger
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled); int currentMemberToken = CreateCodeMappings(eventDef.RemoveMethod.MetadataToken.ToInt32(), eventDef);
MemberMapping methodMapping = eventDef.RemoveMethod.CreateCodeMapping(this.CodeMappings[currentMemberToken]);
astEvent.RemoveAccessor = new Accessor { astEvent.RemoveAccessor = new Accessor {
Body = CreateMethodBody(eventDef.RemoveMethod) Body = CreateMethodBody(eventDef.RemoveMethod)
@ -926,6 +908,8 @@ namespace ICSharpCode.Decompiler.Ast
FieldDeclaration CreateField(FieldDefinition fieldDef) FieldDeclaration CreateField(FieldDefinition fieldDef)
{ {
this.DecompiledMemberReferences.Add(fieldDef.MetadataToken.ToInt32(), fieldDef);
FieldDeclaration astField = new FieldDeclaration(); FieldDeclaration astField = new FieldDeclaration();
astField.AddAnnotation(fieldDef); astField.AddAnnotation(fieldDef);
VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name)); VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name));
@ -1395,7 +1379,7 @@ namespace ICSharpCode.Decompiler.Ast
/// <summary> /// <summary>
/// <inheritdoc/> /// <inheritdoc/>
/// </summary> /// </summary>
public Dictionary<string, List<MemberMapping>> CodeMappings { get; private set; } public Dictionary<int, List<MemberMapping>> CodeMappings { get; private set; }
/// <summary> /// <summary>
/// Gets the local variables for the current decompiled type, method, etc. /// Gets the local variables for the current decompiled type, method, etc.
@ -1406,6 +1390,13 @@ namespace ICSharpCode.Decompiler.Ast
/// <summary> /// <summary>
/// <inheritdoc/> /// <inheritdoc/>
/// </summary> /// </summary>
public Dictionary<string, MemberReference> DecompiledMemberReferences { get; private set; } public Dictionary<int, MemberReference> DecompiledMemberReferences { get; private set; }
private int CreateCodeMappings(int token, MemberReference member)
{
this.CodeMappings.Add(token, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(token, member);
return token;
}
} }
} }

40
ICSharpCode.Decompiler/CodeMappings.cs

@ -41,13 +41,15 @@ namespace ICSharpCode.Decompiler
{ {
/// <summary> /// <summary>
/// Gets the code mappings. /// Gets the code mappings.
/// <remarks>Key is the metadata token.</remarks>
/// </summary> /// </summary>
Dictionary<string, List<MemberMapping>> CodeMappings { get; } Dictionary<int, List<MemberMapping>> CodeMappings { get; }
/// <summary> /// <summary>
/// Gets the MembeReference that is decompiled (a TypeDefinition, MethodDefinition, etc) /// Gets the MembeReference that is decompiled (a TypeDefinition, MethodDefinition, etc)
/// <remarks>Key is the metadata token.</remarks>
/// </summary> /// </summary>
Dictionary<string, MemberReference> DecompiledMemberReferences { get; } Dictionary<int, MemberReference> DecompiledMemberReferences { get; }
} }
/// <summary> /// <summary>
@ -117,9 +119,9 @@ namespace ICSharpCode.Decompiler
public MemberReference MemberReference { get; internal set; } public MemberReference MemberReference { get; internal set; }
/// <summary> /// <summary>
/// Metadata token of the method. /// Metadata token of the member.
/// </summary> /// </summary>
public uint MetadataToken { get; internal set; } public int MetadataToken { get; internal set; }
/// <summary> /// <summary>
/// Gets or sets the code size for the member mapping. /// Gets or sets the code size for the member mapping.
@ -162,8 +164,7 @@ namespace ICSharpCode.Decompiler
/// <param name="isTypeDecompiled">True, if a full type was decompiled; false otherwise.</param> /// <param name="isTypeDecompiled">True, if a full type was decompiled; false otherwise.</param>
internal static MemberMapping CreateCodeMapping( internal static MemberMapping CreateCodeMapping(
this MethodDefinition member, this MethodDefinition member,
List<MemberMapping> codeMappings, List<MemberMapping> codeMappings)
bool isTypeDecompiled)
{ {
if (member == null || !member.HasBody) if (member == null || !member.HasBody)
return null; return null;
@ -173,20 +174,15 @@ namespace ICSharpCode.Decompiler
// create IL/CSharp code mappings - used in debugger // create IL/CSharp code mappings - used in debugger
MemberMapping currentMemberMapping = null; MemberMapping currentMemberMapping = null;
string key = isTypeDecompiled ? member.DeclaringType.FullName : member.FullName;
if (codeMappings.Find(map => (int)map.MetadataToken == member.MetadataToken.ToInt32()) == null) { if (codeMappings.Find(map => map.MetadataToken == member.MetadataToken.ToInt32()) == null) {
currentMemberMapping = new MemberMapping() { currentMemberMapping = new MemberMapping() {
MetadataToken = (uint)member.MetadataToken.ToInt32(), MetadataToken = member.MetadataToken.ToInt32(),
MemberCodeMappings = new List<SourceCodeMapping>(), MemberCodeMappings = new List<SourceCodeMapping>(),
MemberReference = member,
CodeSize = member.Body.CodeSize CodeSize = member.Body.CodeSize
}; };
if (isTypeDecompiled)
currentMemberMapping.MemberReference = member.DeclaringType.Resolve();
else
currentMemberMapping.MemberReference = member.Resolve();
codeMappings.Add(currentMemberMapping); codeMappings.Add(currentMemberMapping);
} }
@ -204,7 +200,7 @@ namespace ICSharpCode.Decompiler
public static SourceCodeMapping GetInstructionByLineNumber( public static SourceCodeMapping GetInstructionByLineNumber(
this List<MemberMapping> codeMappings, this List<MemberMapping> codeMappings,
int lineNumber, int lineNumber,
out uint metadataToken) out int metadataToken)
{ {
if (codeMappings == null) if (codeMappings == null)
throw new ArgumentException("CodeMappings storage must be valid!"); throw new ArgumentException("CodeMappings storage must be valid!");
@ -231,7 +227,7 @@ namespace ICSharpCode.Decompiler
/// <returns>A code mapping.</returns> /// <returns>A code mapping.</returns>
public static SourceCodeMapping GetInstructionByTokenAndOffset( public static SourceCodeMapping GetInstructionByTokenAndOffset(
this List<MemberMapping> codeMappings, this List<MemberMapping> codeMappings,
uint token, int token,
int ilOffset, int ilOffset,
out bool isMatch) out bool isMatch)
{ {
@ -273,7 +269,7 @@ namespace ICSharpCode.Decompiler
/// <remarks>It is possible to exist to different types from different assemblies with the same metadata token.</remarks> /// <remarks>It is possible to exist to different types from different assemblies with the same metadata token.</remarks>
public static bool GetSourceCodeFromMetadataTokenAndOffset( public static bool GetSourceCodeFromMetadataTokenAndOffset(
this List<MemberMapping> codeMappings, this List<MemberMapping> codeMappings,
uint token, int token,
int ilOffset, int ilOffset,
out MemberReference member, out MemberReference member,
out int line) out int line)
@ -303,15 +299,5 @@ namespace ICSharpCode.Decompiler
line = codeMapping.SourceCodeLine; line = codeMapping.SourceCodeLine;
return true; 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);
}
} }
} }

83
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -35,6 +35,7 @@ namespace ICSharpCode.Decompiler.Disassembler
bool detectControlStructure; bool detectControlStructure;
bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings) bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings)
MethodBodyDisassembler methodBodyDisassembler; MethodBodyDisassembler methodBodyDisassembler;
int currentMemberToken;
public ReflectionDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken) public ReflectionDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken)
{ {
@ -45,8 +46,8 @@ namespace ICSharpCode.Decompiler.Disassembler
this.detectControlStructure = detectControlStructure; this.detectControlStructure = detectControlStructure;
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken); this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken);
this.CodeMappings = new Dictionary<string, List<MemberMapping>>(); this.CodeMappings = new Dictionary<int, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<string, MemberReference>(); this.DecompiledMemberReferences = new Dictionary<int, MemberReference>();
} }
#region Disassemble Method #region Disassemble Method
@ -95,21 +96,17 @@ namespace ICSharpCode.Decompiler.Disassembler
{ MethodImplAttributes.NoOptimization, "nooptimization" }, { MethodImplAttributes.NoOptimization, "nooptimization" },
}; };
public void DisassembleMethod(MethodDefinition method, bool isTypeDecompiled = false) public void DisassembleMethod(MethodDefinition method)
{ {
// create mappings for decompiled methods only // create mappings for decompiled methods only
string name = isTypeDecompiled ? method.DeclaringType.FullName : method.FullName; currentMemberToken = CreateCodeMappings(method.MetadataToken.ToInt32(), method);
if (!isTypeDecompiled) {
this.CodeMappings.Add(name, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(method.FullName, method);
}
// write method header // write method header
output.WriteDefinition(".method ", method); output.WriteDefinition(".method ", method);
DisassembleMethodInternal(method, isTypeDecompiled); DisassembleMethodInternal(method);
} }
void DisassembleMethodInternal(MethodDefinition method, bool isTypeDecompiled) void DisassembleMethodInternal(MethodDefinition method)
{ {
// .method public hidebysig specialname // .method public hidebysig specialname
// instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed // instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed
@ -158,8 +155,7 @@ namespace ICSharpCode.Decompiler.Disassembler
if (method.HasBody) { if (method.HasBody) {
// create IL code mappings - used in debugger // create IL code mappings - used in debugger
string name = isTypeDecompiled ? method.DeclaringType.FullName : method.FullName; MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings[currentMemberToken]);
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
methodBodyDisassembler.Disassemble(method.Body, methodMapping); methodBodyDisassembler.Disassemble(method.Body, methodMapping);
} }
@ -203,12 +199,10 @@ namespace ICSharpCode.Decompiler.Disassembler
{ FieldAttributes.NotSerialized, "notserialized" }, { FieldAttributes.NotSerialized, "notserialized" },
}; };
public void DisassembleField(FieldDefinition field, bool isTypeDecompiled = false) public void DisassembleField(FieldDefinition field)
{ {
// create mappings for decompiled fields only // create mappings for decompiled fields only
if (!isTypeDecompiled) { this.DecompiledMemberReferences.Add(field.MetadataToken.ToInt32(), field);
this.DecompiledMemberReferences.Add(field.FullName, field);
}
output.WriteDefinition(".field ", field); output.WriteDefinition(".field ", field);
WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility); WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility);
@ -237,14 +231,10 @@ namespace ICSharpCode.Decompiler.Disassembler
{ PropertyAttributes.HasDefault, "hasdefault" }, { PropertyAttributes.HasDefault, "hasdefault" },
}; };
public void DisassembleProperty(PropertyDefinition property, bool isTypeDecompiled = false) public void DisassembleProperty(PropertyDefinition property)
{ {
// create mappings for decompiled properties only // create mappings for decompiled properties only
string name = isTypeDecompiled ? property.DeclaringType.FullName : property.FullName; currentMemberToken = CreateCodeMappings(property.MetadataToken.ToInt32(), property);
if (!isTypeDecompiled) {
this.CodeMappings.Add(name, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(property.FullName, property);
}
output.WriteDefinition(".property ", property); output.WriteDefinition(".property ", property);
WriteFlags(property.Attributes, propertyAttributes); WriteFlags(property.Attributes, propertyAttributes);
@ -253,22 +243,22 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(DisassemblerHelpers.Escape(property.Name)); output.Write(DisassemblerHelpers.Escape(property.Name));
OpenBlock(false); OpenBlock(false);
WriteAttributes(property.CustomAttributes); WriteAttributes(property.CustomAttributes);
WriteNestedMethod(".get", property.GetMethod, isTypeDecompiled); WriteNestedMethod(".get", property.GetMethod);
WriteNestedMethod(".set", property.SetMethod, isTypeDecompiled); WriteNestedMethod(".set", property.SetMethod);
foreach (var method in property.OtherMethods) { foreach (var method in property.OtherMethods) {
WriteNestedMethod(".method", method, isTypeDecompiled); WriteNestedMethod(".method", method);
} }
CloseBlock(); CloseBlock();
} }
void WriteNestedMethod(string keyword, MethodDefinition method, bool isTypeDecompiled) void WriteNestedMethod(string keyword, MethodDefinition method)
{ {
if (method == null) if (method == null)
return; return;
if (detectControlStructure) { if (detectControlStructure) {
output.WriteDefinition(keyword, method); output.WriteDefinition(keyword, method);
output.Write(' '); output.Write(' ');
DisassembleMethodInternal(method, isTypeDecompiled); DisassembleMethodInternal(method);
} else { } else {
output.Write(keyword); output.Write(keyword);
output.Write(' '); output.Write(' ');
@ -284,14 +274,10 @@ namespace ICSharpCode.Decompiler.Disassembler
{ EventAttributes.RTSpecialName, "rtspecialname" }, { EventAttributes.RTSpecialName, "rtspecialname" },
}; };
public void DisassembleEvent(EventDefinition ev, bool isTypeDecompiled = false) public void DisassembleEvent(EventDefinition ev)
{ {
// create mappings for decompiled events only // create mappings for decompiled events only
string name = isTypeDecompiled ? ev.DeclaringType.FullName : ev.FullName; currentMemberToken = CreateCodeMappings(ev.MetadataToken.ToInt32(), ev);
if (!isTypeDecompiled) {
this.CodeMappings.Add(name, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(ev.FullName, ev);
}
output.WriteDefinition(".event ", ev); output.WriteDefinition(".event ", ev);
WriteFlags(ev.Attributes, eventAttributes); WriteFlags(ev.Attributes, eventAttributes);
@ -300,11 +286,11 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(DisassemblerHelpers.Escape(ev.Name)); output.Write(DisassemblerHelpers.Escape(ev.Name));
OpenBlock(false); OpenBlock(false);
WriteAttributes(ev.CustomAttributes); WriteAttributes(ev.CustomAttributes);
WriteNestedMethod(".add", ev.AddMethod, isTypeDecompiled); WriteNestedMethod(".add", ev.AddMethod);
WriteNestedMethod(".remove", ev.RemoveMethod, isTypeDecompiled); WriteNestedMethod(".remove", ev.RemoveMethod);
WriteNestedMethod(".invoke", ev.InvokeMethod, isTypeDecompiled); WriteNestedMethod(".invoke", ev.InvokeMethod);
foreach (var method in ev.OtherMethods) { foreach (var method in ev.OtherMethods) {
WriteNestedMethod(".method", method, isTypeDecompiled); WriteNestedMethod(".method", method);
} }
CloseBlock(); CloseBlock();
} }
@ -346,10 +332,6 @@ namespace ICSharpCode.Decompiler.Disassembler
public void DisassembleType(TypeDefinition type) public void DisassembleType(TypeDefinition type)
{ {
// create IL code mappings - used for debugger
this.CodeMappings.Add(type.FullName, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(type.FullName, type);
// start writing IL // start writing IL
output.WriteDefinition(".class ", type); output.WriteDefinition(".class ", type);
@ -413,7 +395,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Fields"); output.WriteLine("// Fields");
foreach (var field in type.Fields) { foreach (var field in type.Fields) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
DisassembleField(field, true); DisassembleField(field);
} }
output.WriteLine(); output.WriteLine();
} }
@ -421,7 +403,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Properties"); output.WriteLine("// Properties");
foreach (var prop in type.Properties) { foreach (var prop in type.Properties) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
DisassembleProperty(prop, true); DisassembleProperty(prop);
} }
output.WriteLine(); output.WriteLine();
} }
@ -429,7 +411,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Events"); output.WriteLine("// Events");
foreach (var ev in type.Events) { foreach (var ev in type.Events) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
DisassembleEvent(ev, true); DisassembleEvent(ev);
output.WriteLine(); output.WriteLine();
} }
output.WriteLine(); output.WriteLine();
@ -440,7 +422,7 @@ namespace ICSharpCode.Decompiler.Disassembler
foreach (var m in type.Methods) { foreach (var m in type.Methods) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
if (!(detectControlStructure && accessorMethods.Contains(m))) { if (!(detectControlStructure && accessorMethods.Contains(m))) {
DisassembleMethod(m, true); DisassembleMethod(m);
output.WriteLine(); output.WriteLine();
} }
} }
@ -638,11 +620,18 @@ namespace ICSharpCode.Decompiler.Disassembler
/// <summary> /// <summary>
/// <inheritdoc/> /// <inheritdoc/>
/// </summary> /// </summary>
public Dictionary<string, List<MemberMapping>> CodeMappings { get; private set; } public Dictionary<int, List<MemberMapping>> CodeMappings { get; private set; }
/// <summary> /// <summary>
/// <inheritdoc/> /// <inheritdoc/>
/// </summary> /// </summary>
public Dictionary<string, MemberReference> DecompiledMemberReferences { get; private set; } public Dictionary<int, MemberReference> DecompiledMemberReferences { get; private set; }
private int CreateCodeMappings(int token, MemberReference member)
{
this.CodeMappings.Add(token, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(token, member);
return token;
}
} }
} }

19
ILSpy/Commands/DebuggerCommands.cs

@ -11,6 +11,7 @@ using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Xml.Linq; using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.ILSpy.Debugger; using ICSharpCode.ILSpy.Debugger;
using ICSharpCode.ILSpy.Debugger.Bookmarks; using ICSharpCode.ILSpy.Debugger.Bookmarks;
using ICSharpCode.ILSpy.Debugger.Services; using ICSharpCode.ILSpy.Debugger.Services;
@ -157,19 +158,21 @@ namespace ICSharpCode.ILSpy.Commands
return; return;
} }
var inst = MainWindow.Instance;
// breakpoint was hit => bring to front the main window // breakpoint was hit => bring to front the main window
SendWpfWindowPos(MainWindow.Instance, HWND_TOP); SendWpfWindowPos(inst, HWND_TOP); inst.Activate();
MainWindow.Instance.Activate();
// jump to type & expand folding // jump to type & expand folding
if (CurrentLineBookmark.Instance != null) { var bm = CurrentLineBookmark.Instance;
if (!DebugData.DecompiledMemberReferences.ContainsKey(CurrentLineBookmark.Instance.MemberReference.FullName)) if (bm != null) {
MainWindow.Instance.JumpToReference(CurrentLineBookmark.Instance.MemberReference); if (!DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.MetadataToken.ToInt32()))
inst.JumpToReference(bm.MemberReference);
MainWindow.Instance.TextView.UnfoldAndScroll(CurrentLineBookmark.Instance.LineNumber);
inst.TextView.UnfoldAndScroll(bm.LineNumber);
} }
MainWindow.Instance.SetStatus("Debugging...", Brushes.Red); inst.SetStatus("Debugging...", Brushes.Red);
} }
} }

7
ILSpy/Language.cs

@ -32,12 +32,12 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Decompilation event arguments. /// Decompilation event arguments.
/// </summary> /// </summary>
public sealed class DecompileEventArgs : EventArgs public sealed class DecompileEventArgs : EventArgs, ICodeMappings
{ {
/// <summary> /// <summary>
/// Gets ot sets the code mappings /// Gets ot sets the code mappings
/// </summary> /// </summary>
public Dictionary<string, List<MemberMapping>> CodeMappings { get; set; } public Dictionary<int, List<MemberMapping>> CodeMappings { get; set; }
/// <summary> /// <summary>
/// Gets or sets the local variables. /// Gets or sets the local variables.
@ -47,7 +47,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Gets the list of MembeReferences that are decompiled (TypeDefinitions, MethodDefinitions, etc) /// Gets the list of MembeReferences that are decompiled (TypeDefinitions, MethodDefinitions, etc)
/// </summary> /// </summary>
public Dictionary<string, MemberReference> DecompiledMemberReferences { get; set; } public Dictionary<int, MemberReference> DecompiledMemberReferences { get; set; }
} }
/// <summary> /// <summary>
@ -111,6 +111,7 @@ namespace ICSharpCode.ILSpy
public virtual void DecompileNamespace(string nameSpace, IEnumerable<TypeDefinition> types, ITextOutput output, DecompilationOptions options) public virtual void DecompileNamespace(string nameSpace, IEnumerable<TypeDefinition> types, ITextOutput output, DecompilationOptions options)
{ {
WriteCommentLine(output, nameSpace); WriteCommentLine(output, nameSpace);
OnDecompilationFinished(null);
} }
public virtual void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) public virtual void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)

24
ILSpy/TextView/DecompilerTextView.cs

@ -394,7 +394,7 @@ namespace ICSharpCode.ILSpy.TextView
// show the currentline marker // show the currentline marker
var bm = CurrentLineBookmark.Instance; var bm = CurrentLineBookmark.Instance;
if (bm != null) { if (bm != null) {
if (DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.FullName)) { if (DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.MetadataToken.ToInt32())) {
DocumentLine line = textEditor.Document.GetLineByNumber(bm.LineNumber); DocumentLine line = textEditor.Document.GetLineByNumber(bm.LineNumber);
bm.Marker = bm.CreateMarker(textMarkerService, line.Offset, line.Length); bm.Marker = bm.CreateMarker(textMarkerService, line.Offset, line.Length);
} }
@ -456,6 +456,11 @@ namespace ICSharpCode.ILSpy.TextView
static void DecompileNodes(DecompilationContext context, ITextOutput textOutput) static void DecompileNodes(DecompilationContext context, ITextOutput textOutput)
{ {
// reset data
DebugData.CodeMappings = null;
DebugData.LocalVariables = null;
DebugData.DecompiledMemberReferences = null;
var nodes = context.TreeNodes; var nodes = context.TreeNodes;
context.Language.DecompileFinished += Language_DecompileFinished; context.Language.DecompileFinished += Language_DecompileFinished;
for (int i = 0; i < nodes.Length; i++) { for (int i = 0; i < nodes.Length; i++) {
@ -471,13 +476,16 @@ namespace ICSharpCode.ILSpy.TextView
static void Language_DecompileFinished(object sender, DecompileEventArgs e) static void Language_DecompileFinished(object sender, DecompileEventArgs e)
{ {
if (e != null) { if (e != null) {
DebugData.CodeMappings = e.CodeMappings; if (DebugData.CodeMappings == null) {
DebugData.LocalVariables = e.LocalVariables; DebugData.CodeMappings = e.CodeMappings;
DebugData.DecompiledMemberReferences = e.DecompiledMemberReferences; DebugData.LocalVariables = e.LocalVariables;
} else { DebugData.DecompiledMemberReferences = e.DecompiledMemberReferences;
DebugData.CodeMappings = null; } else {
DebugData.LocalVariables = null; DebugData.CodeMappings.AddRange(e.CodeMappings);
DebugData.DecompiledMemberReferences = null; DebugData.DecompiledMemberReferences.AddRange(e.DecompiledMemberReferences);
if (e.LocalVariables != null)
DebugData.LocalVariables.AddRange(e.LocalVariables);
}
} }
} }
#endregion #endregion

Loading…
Cancel
Save