Browse Source

synchronize CurrentLineBookmark

fix stepping issue
pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
10f225ffdd
  1. 148
      Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs
  2. 2
      Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs
  3. 8
      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

148
Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs

@ -13,55 +13,8 @@ namespace ILSpy.Debugger.Bookmarks
/// <summary> /// <summary>
/// Static class that maintains the list of bookmarks and breakpoints. /// Static class that maintains the list of bookmarks and breakpoints.
/// </summary> /// </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>(); static List<BookmarkBase> bookmarks = new List<BookmarkBase>();
public static List<BookmarkBase> Bookmarks { public static List<BookmarkBase> Bookmarks {
@ -160,4 +113,103 @@ namespace ILSpy.Debugger.Bookmarks
public static event BookmarkEventHandler Removed; public static event BookmarkEventHandler Removed;
public static event BookmarkEventHandler Added; 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
public override ITextMarker CreateMarker(ITextMarkerService markerService, int offset, int length) 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.BackgroundColor = Colors.Yellow;
marker.ForegroundColor = Colors.Blue; marker.ForegroundColor = Colors.Blue;
marker.IsVisible = b => b is MarkerBookmark && ((MarkerBookmark)b).Type == DebugData.CurrentType; marker.IsVisible = b => b is MarkerBookmark && ((MarkerBookmark)b).Type == DebugData.CurrentType;

8
Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs

@ -829,6 +829,9 @@ namespace ILSpy.Debugger.Services
var debugType = frame.MethodInfo.DeclaringType; var debugType = frame.MethodInfo.DeclaringType;
string fullName = debugType.Namespace + "." + debugType.Name; string fullName = debugType.Namespace + "." + debugType.Name;
if (DebugData.LoadedAssemblies == null)
Continue();
else {
// search for type in the current assembly list // search for type in the current assembly list
TypeReference typeRef = null; TypeReference typeRef = null;
foreach (var assembly in DebugData.LoadedAssemblies) { foreach (var assembly in DebugData.LoadedAssemblies) {
@ -851,10 +854,13 @@ namespace ILSpy.Debugger.Services
// jump // jump
if (CodeMappingsStorage.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out type, out line)) { if (CodeMappingsStorage.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out type, out line)) {
DebuggerService.JumpToCurrentLine(type, line, 0, line, 0); DebuggerService.JumpToCurrentLine(type, line, 0, line, 0);
} else {
StepOut();
} }
} else { } else {
// continue since we cannot find the debugged type // continue since we cannot find the debugged type
Continue(); StepOut();
}
} }
} }
} }

6
ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

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

62
ICSharpCode.Decompiler/CodeMappings.cs

@ -34,13 +34,32 @@ namespace ICSharpCode.Decompiler
/// </summary> /// </summary>
public ILRange ILInstructionOffset { get; set; } 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() public int[] ToArray()
{ {
int[] result = new int[2]; var resultList = new List<int>();
result[0] = ILInstructionOffset.From; resultList.Add(ILInstructionOffset.From);
result[1] = ILInstructionOffset.To; 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
/// </summary> /// </summary>
public List<SourceCodeMapping> MemberCodeMappings { get; set; } 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]; var result = new List<int>();
int i = 0; var data = MemberCodeMappings.OrderBy(m => m.ILInstructionOffset.From);
foreach (var element in MemberCodeMappings) { var prevMap = data.ElementAt(0);
result[i] = element.ILInstructionOffset.From;
result[i+1] = element.ILInstructionOffset.To; for (int i = 1; i < data.Count(); ++i) {
i+=2; 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; return result;

6
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -87,7 +87,8 @@ namespace ICSharpCode.Decompiler.Disassembler
methodMapping.MemberCodeMappings.Add( methodMapping.MemberCodeMappings.Add(
new SourceCodeMapping() { new SourceCodeMapping() {
SourceCodeLine = output.CurrentLine, 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); inst.WriteTo(output);
@ -155,7 +156,8 @@ namespace ICSharpCode.Decompiler.Disassembler
currentMethodMapping.MemberCodeMappings.Add( currentMethodMapping.MemberCodeMappings.Add(
new SourceCodeMapping() { new SourceCodeMapping() {
SourceCodeLine = output.CurrentLine, 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