diff --git a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs index 79cb5dbb8..513e3e0ec 100644 --- a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs +++ b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs @@ -287,21 +287,22 @@ namespace ILSpy.Debugger.Services // Stepping: - SourceCodeMapping GetCurrentCodeMapping() + SourceCodeMapping GetCurrentCodeMapping(out bool isMatch) { + isMatch = false; if (CurrentLineBookmark.Instance == null) return null; + var frame = debuggedProcess.SelectedThread.MostRecentStackFrame; // get the mapped instruction from the current line marker or the next one - uint token; return CodeMappingsStorage.GetInstructionByTypeAndLine( - CurrentLineBookmark.Instance.Type.FullName, - CurrentLineBookmark.Instance.LineNumber, out token); + CurrentLineBookmark.Instance.Type.FullName, (uint)frame.MethodInfo.MetadataToken, frame.IP, out isMatch); } StackFrame GetStackFrame() { - var map = GetCurrentCodeMapping(); + bool isMatch; + var map = GetCurrentCodeMapping(out isMatch); if (map == null) { CurrentLineBookmark.Remove(); Continue(); @@ -309,7 +310,7 @@ namespace ILSpy.Debugger.Services } else { var frame = debuggedProcess.SelectedThread.MostRecentStackFrame; frame.SourceCodeLine = map.SourceCodeLine; - frame.ILRanges = map.ToArray(); + frame.ILRanges = map.ToArray(isMatch); return frame; } } diff --git a/ICSharpCode.Decompiler/CodeMappings.cs b/ICSharpCode.Decompiler/CodeMappings.cs index f2c961489..cb27c520f 100644 --- a/ICSharpCode.Decompiler/CodeMappings.cs +++ b/ICSharpCode.Decompiler/CodeMappings.cs @@ -42,17 +42,26 @@ namespace ICSharpCode.Decompiler /// /// Retrieves the array that contains the IL range and the missing gaps between ranges. /// - /// - public int[] ToArray() + /// The array representation of the step aranges. + public int[] ToArray(bool isMatch) { + var currentList = new List(); + // add list for the current source code line - var currentList = MemberMapping.MemberCodeMappings - .FindAll(m => m.SourceCodeLine == this.SourceCodeLine) - .ConvertAll(m => m.ILInstructionOffset); + currentList.AddRange(ILRange.OrderAndJoint(MemberMapping.MemberCodeMappings + .FindAll(m => m.SourceCodeLine == this.SourceCodeLine) + .ConvertAll(m => m.ILInstructionOffset))); - // add inverted - currentList.AddRange(MemberMapping.InvertedList); + if (!isMatch) { + // add inverted + currentList.AddRange(MemberMapping.InvertedList); + } else { + // if the current list contains the last mapping, add also the last gap + if (currentList.Count == 1) + currentList.Add(MemberMapping.InvertedList.LastOrDefault()); + } + // set the output var resultList = new List(); foreach (var element in ILRange.OrderAndJoint(currentList)) { resultList.Add(element.From); @@ -101,7 +110,7 @@ namespace ICSharpCode.Decompiler if (invertedList == null) { var list = MemberCodeMappings.ConvertAll( s => new ILRange { From = s.ILInstructionOffset.From, To = s.ILInstructionOffset.To }); - invertedList = ILRange.Invert(list, CodeSize); + invertedList = ILRange.OrderAndJoint(ILRange.Invert(list, CodeSize)); } return invertedList; } @@ -201,6 +210,40 @@ namespace ICSharpCode.Decompiler return null; } + public static SourceCodeMapping GetInstructionByTypeAndLine( + this ConcurrentDictionary> codeMappings, + string typeName, + uint token, + int ilOffset, out bool isMatch) + { + isMatch = false; + + if (codeMappings == null) + throw new ArgumentNullException("CodeMappings storage must be valid!"); + + if (!codeMappings.ContainsKey(typeName)) { + return null; + } + + var methodMappings = codeMappings[typeName]; + var maping = methodMappings.Find(m => m.MetadataToken == token); + // try find an exact match + var map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To); + + if (map == null) { + // get the immediate next one + map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From >= ilOffset); + isMatch = false; + if (map == null) + map = maping.MemberCodeMappings.LastOrDefault(); // get the last + + return map; + } + + isMatch = true; + return map; + } + /// /// Gets the source code and type name from metadata token and offset. /// diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs index 5fbd2e385..3608cacc1 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs @@ -224,7 +224,10 @@ namespace ICSharpCode.Decompiler.ILAst public static List OrderAndJoint(IEnumerable input) { - List ranges = input.OrderBy(r => r.From).ToList(); + if (input == null) + throw new ArgumentNullException("Input is null!"); + + List ranges = input.Where(r => r != null).OrderBy(r => r.From).ToList(); for (int i = 0; i < ranges.Count - 1;) { ILRange curr = ranges[i]; ILRange next = ranges[i + 1]; @@ -241,6 +244,12 @@ namespace ICSharpCode.Decompiler.ILAst public static IEnumerable Invert(IEnumerable input, int codeSize) { + if (input == null) + throw new ArgumentNullException("Input is null!"); + + if (codeSize <= 0) + throw new ArgumentException("Code size must be grater than 0"); + var ordered = OrderAndJoint(input); if (ordered.Count == 0) { yield return new ILRange() { From = 0, To = codeSize };