Browse Source

synchronize CurrentLineBookmark

fix stepping issue
pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
10f225ffdd
  1. 152
      Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs
  2. 2
      Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs
  3. 54
      Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs
  4. 6
      ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  5. 62
      ICSharpCode.Decompiler/CodeMappings.cs
  6. 6
      ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

152
Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs

@ -13,55 +13,8 @@ namespace ILSpy.Debugger.Bookmarks @@ -13,55 +13,8 @@ namespace ILSpy.Debugger.Bookmarks
/// <summary>
/// Static class that maintains the list of bookmarks and breakpoints.
/// </summary>
public static class BookmarkManager
public static partial class BookmarkManager
{
static BookmarkManager()
{
DebugData.LanguageChanged += OnLanguageChanged;
}
static void OnLanguageChanged(object sender, LanguageEventArgs e)
{
var oldLanguage = e.OldLanguage;
var newLanguage = e.NewLanguage;
// synchronize the IL<->C# breakpoints
// 1. map the breakpoint lines
var oldbps = bookmarks.FindAll(b => b is BreakpointBookmark && ((BreakpointBookmark)b).Language == oldLanguage);
if (oldbps == null || oldbps.Count == 0)
return;
var oldMappings = CodeMappings.GetStorage(oldLanguage);
var newMappings = CodeMappings.GetStorage(newLanguage);
if (oldMappings == null || oldMappings.Count == 0 ||
newMappings == null || newMappings.Count == 0)
return;
foreach (var bp in oldbps) {
uint token;
var instruction = oldMappings.GetInstructionByTypeAndLine(DebugData.CurrentType.FullName, bp.LineNumber, out token);
if (instruction == null)
continue;
TypeDefinition type;
int line;
if (newMappings.GetSourceCodeFromMetadataTokenAndOffset(token, instruction.ILInstructionOffset.From, out type, out line)) {
// 2. create breakpoint for new languages
var bookmark = new BreakpointBookmark(type, new AstLocation(line, 0), 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);
}
}
static List<BookmarkBase> bookmarks = new List<BookmarkBase>();
public static List<BookmarkBase> Bookmarks {
@ -138,7 +91,7 @@ namespace ILSpy.Debugger.Bookmarks @@ -138,7 +91,7 @@ namespace ILSpy.Debugger.Bookmarks
static void OnAdded(BookmarkEventArgs e)
{
if (Added != null) {
Added(null, e);
Added(null, e);
}
}
@ -153,11 +106,110 @@ namespace ILSpy.Debugger.Bookmarks @@ -153,11 +106,110 @@ namespace ILSpy.Debugger.Bookmarks
}
}
// no bookmark at that line: create a new bookmark
// no bookmark at that line: create a new bookmark
BookmarkManager.AddMark(bookmarkFactory(new AstLocation(line, 0)));
}
public static event BookmarkEventHandler Removed;
public static event BookmarkEventHandler Added;
}
// This is for the synchronize bookmarks logic
public static partial class BookmarkManager
{
static BookmarkManager()
{
DebugData.LanguageChanged += OnLanguageChanged;
}
static void OnLanguageChanged(object sender, LanguageEventArgs e)
{
var oldLanguage = e.OldLanguage;
var newLanguage = e.NewLanguage;
SyncCurrentLineBookmark(oldLanguage, newLanguage);
SyncBreakpointBookmarks(oldLanguage, newLanguage);
}
/// <summary>
/// Synchronize the IL<->C# current line marker.
/// </summary>
/// <param name="oldLanguage">Old language.</param>
/// <param name="newLanguage">New language.</param>
static void SyncCurrentLineBookmark(DecompiledLanguages oldLanguage, DecompiledLanguages newLanguage)
{
// checks
if (CurrentLineBookmark.Instance == null)
return;
var oldMappings = CodeMappings.GetStorage(oldLanguage);
var newMappings = CodeMappings.GetStorage(newLanguage);
if (oldMappings == null || oldMappings.Count == 0 || newMappings == null || newMappings.Count == 0)
return;
// 1. Save it's data
int line = CurrentLineBookmark.Instance.LineNumber;
var markerType = CurrentLineBookmark.Instance.Type;
// 2. Remove it
CurrentLineBookmark.Remove();
// 3. map the marker line
uint token;
var instruction = oldMappings.GetInstructionByTypeAndLine(markerType.FullName, line, out token);
if (instruction == null)
return;
TypeDefinition type;
int newline;
if (newMappings.GetSourceCodeFromMetadataTokenAndOffset(token, instruction.ILInstructionOffset.From, out type, out newline)) {
// 4. create breakpoint for new languages
CurrentLineBookmark.SetPosition(type, 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 = CodeMappings.GetStorage(oldLanguage);
var newMappings = CodeMappings.GetStorage(newLanguage);
if (oldMappings == null || oldMappings.Count == 0 || newMappings == null || newMappings.Count == 0)
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;
var instruction = oldMappings.GetInstructionByTypeAndLine(bp.Type.FullName, bp.LineNumber, out token);
if (instruction == null)
continue;
TypeDefinition type;
int line;
if (newMappings.GetSourceCodeFromMetadataTokenAndOffset(token, instruction.ILInstructionOffset.From, out type, out line)) {
// 2. create breakpoint for new languages
var bookmark = new BreakpointBookmark(type, new AstLocation(line, 0), 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/CurrentLineBookmark.cs

@ -78,7 +78,7 @@ namespace ILSpy.Debugger.Bookmarks @@ -78,7 +78,7 @@ namespace ILSpy.Debugger.Bookmarks
public override ITextMarker CreateMarker(ITextMarkerService markerService, int offset, int length)
{
ITextMarker marker = markerService.Create(offset + startColumn - 1, length);
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).Type == DebugData.CurrentType;

54
Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs

@ -299,9 +299,9 @@ namespace ILSpy.Debugger.Services @@ -299,9 +299,9 @@ namespace ILSpy.Debugger.Services
CurrentLineBookmark.Instance.LineNumber, out token);
// var val = CodeMappingsStorage[CurrentLineBookmark.Instance.Type.FullName];
//
//
// var mapping = val.Find(m => m.MetadataToken == token);
//
//
// return mapping.MemberCodeMappings.FirstOrDefault(s => s.ILInstructionOffset.From == instruction.ILInstructionOffset.From);
}
@ -829,32 +829,38 @@ namespace ILSpy.Debugger.Services @@ -829,32 +829,38 @@ namespace ILSpy.Debugger.Services
var debugType = frame.MethodInfo.DeclaringType;
string fullName = debugType.Namespace + "." + debugType.Name;
// search for type in the current assembly list
TypeReference typeRef = null;
foreach (var assembly in DebugData.LoadedAssemblies) {
foreach (var module in assembly.Modules) {
if (module.TryGetTypeReference(fullName, out typeRef)) {
break;
if (DebugData.LoadedAssemblies == null)
Continue();
else {
// search for type in the current assembly list
TypeReference typeRef = null;
foreach (var assembly in DebugData.LoadedAssemblies) {
foreach (var module in assembly.Modules) {
if (module.TryGetTypeReference(fullName, out typeRef)) {
break;
}
}
if (typeRef != null)
break;
}
if (typeRef != null)
break;
}
if (typeRef != null) {
// decompile on demand
AstBuilder builder = new AstBuilder(new DecompilerContext());
builder.AddType(typeRef.Resolve());
builder.GenerateCode(new PlainTextOutput());
// jump
if (CodeMappingsStorage.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out type, out line)) {
DebuggerService.JumpToCurrentLine(type, line, 0, line, 0);
if (typeRef != null) {
// decompile on demand
AstBuilder builder = new AstBuilder(new DecompilerContext());
builder.AddType(typeRef.Resolve());
builder.GenerateCode(new PlainTextOutput());
// jump
if (CodeMappingsStorage.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out type, out line)) {
DebuggerService.JumpToCurrentLine(type, line, 0, line, 0);
} else {
StepOut();
}
} else {
// continue since we cannot find the debugged type
StepOut();
}
} else {
// continue since we cannot find the debugged type
Continue();
}
}
}

6
ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -124,7 +124,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -124,7 +124,7 @@ namespace ICSharpCode.Decompiler.Ast
public void StartNode(AstNode node)
{
var ranges = node.Annotation<List<ILRange>>();
if (ranges != null)
if (ranges != null && ranges.Count > 0)
{
// find the ancestor that has method mapping as annotation
if (node.Ancestors != null && node.Ancestors.Count() > 0)
@ -135,10 +135,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -135,10 +135,12 @@ namespace ICSharpCode.Decompiler.Ast
var map = mapping.MemberCodeMappings.Find(s => s.SourceCodeLine == output.CurrentLine);
foreach (var range in ranges) {
// make sure we have one ILRange per source code line
if (map == null) {
mapping.MemberCodeMappings.Add(new SourceCodeMapping {
ILInstructionOffset = range,
SourceCodeLine = output.CurrentLine
SourceCodeLine = output.CurrentLine,
MemberMapping = mapping
});
} else {
if (map.ILInstructionOffset.From > range.From)

62
ICSharpCode.Decompiler/CodeMappings.cs

@ -34,13 +34,32 @@ namespace ICSharpCode.Decompiler @@ -34,13 +34,32 @@ namespace ICSharpCode.Decompiler
/// </summary>
public ILRange ILInstructionOffset { get; set; }
/// <summary>
/// Gets or sets the member mapping this source code mapping belongs to.
/// </summary>
public MemberMapping MemberMapping { get; set; }
/// <summary>
/// Retrieves the array that contains the IL range and the missing gaps between ranges.
/// </summary>
/// <returns></returns>
public int[] ToArray()
{
int[] result = new int[2];
result[0] = ILInstructionOffset.From;
result[1] = ILInstructionOffset.To;
var resultList = new List<int>();
resultList.Add(ILInstructionOffset.From);
resultList.Add(ILInstructionOffset.To);
return result;
var map = MemberMapping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From >= ILInstructionOffset.To);
if (map != null && map.ILInstructionOffset.From != ILInstructionOffset.To) {
resultList.Add(ILInstructionOffset.To);
resultList.Add(map.ILInstructionOffset.From);
}
// var tempList = MemberMapping.GetAllUnknownMappings(ILInstructionOffset.To);
// if (tempList.Count != 0)
// resultList.AddRange(tempList);
return resultList.ToArray();
}
}
@ -64,14 +83,35 @@ namespace ICSharpCode.Decompiler @@ -64,14 +83,35 @@ namespace ICSharpCode.Decompiler
/// </summary>
public List<SourceCodeMapping> MemberCodeMappings { get; set; }
public int[] ToArray()
/// <summary>
/// Gets the list of all unknown/gaps code mappings greater than a value.<br/>
/// Eg.: for (0-9, 11-14, 16-27) the return list is (9,11,14,16) for start value 0 (or lower than 9).
/// </summary>
/// <param name="startValue">Start value.</param>
/// <returns></returns>
public List<int> GetAllUnknownMappings(int startValue)
{
int[] result = new int[MemberCodeMappings.Count * 2];
int i = 0;
foreach (var element in MemberCodeMappings) {
result[i] = element.ILInstructionOffset.From;
result[i+1] = element.ILInstructionOffset.To;
i+=2;
var result = new List<int>();
var data = MemberCodeMappings.OrderBy(m => m.ILInstructionOffset.From);
var prevMap = data.ElementAt(0);
for (int i = 1; i < data.Count(); ++i) {
var map = data.ElementAt(i);
// consider only the next mappings
if (map.ILInstructionOffset.To <= startValue) {
prevMap = map;
continue;
}
// if there is not gap, move on
if (prevMap.ILInstructionOffset.To == map.ILInstructionOffset.From) {
prevMap = map;
continue;
}
result.Add(prevMap.ILInstructionOffset.To);
result.Add(map.ILInstructionOffset.From);
prevMap = map;
}
return result;

6
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -87,7 +87,8 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -87,7 +87,8 @@ namespace ICSharpCode.Decompiler.Disassembler
methodMapping.MemberCodeMappings.Add(
new SourceCodeMapping() {
SourceCodeLine = output.CurrentLine,
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset }
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset },
MemberMapping = methodMapping
});
inst.WriteTo(output);
@ -155,7 +156,8 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -155,7 +156,8 @@ namespace ICSharpCode.Decompiler.Disassembler
currentMethodMapping.MemberCodeMappings.Add(
new SourceCodeMapping() {
SourceCodeLine = output.CurrentLine,
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset }
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset },
MemberMapping = currentMethodMapping
});
}

Loading…
Cancel
Save