Browse Source

map code for assemblies without symbols

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
16d7bcde97
  1. 6
      Debugger/Debugger.Core/Breakpoint.cs
  2. 30
      Debugger/Debugger.Core/SourcecodeSegment.cs
  3. 10
      Debugger/Debugger.Core/StackFrame.cs
  4. 15
      Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs
  5. 4
      Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs
  6. 108
      Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs
  7. 9
      Debugger/ILSpy.Debugger/ToolTips/DebuggerTooltipControl.xaml.cs
  8. 3
      Debugger/ILSpy.Debugger/ToolTips/TextEditorListener.cs
  9. 16
      ILSpy/MainWindow.xaml.cs

6
Debugger/Debugger.Core/Breakpoint.cs

@ -187,7 +187,8 @@ namespace Debugger
internal override bool SetBreakpoint(Module module) internal override bool SetBreakpoint(Module module)
{ {
SourcecodeSegment segment = SourcecodeSegment.CreateForIL(module, this.Line, (int)MetadataToken, ILOffset); SourcecodeSegment segment = SourcecodeSegment.CreateForIL(module, this.Line, (int)MetadataToken, ILOffset);
if (segment == null)
return false;
try { try {
ICorDebugFunctionBreakpoint corBreakpoint = segment.CorFunction.GetILCode().CreateBreakpoint((uint)segment.ILStart); ICorDebugFunctionBreakpoint corBreakpoint = segment.CorFunction.GetILCode().CreateBreakpoint((uint)segment.ILStart);
corBreakpoint.Activate(Enabled ? 1 : 0); corBreakpoint.Activate(Enabled ? 1 : 0);
@ -197,8 +198,7 @@ namespace Debugger
OnSet(new BreakpointEventArgs(this)); OnSet(new BreakpointEventArgs(this));
return true; return true;
} } catch {
catch (COMException) {
return false; return false;
} }
} }

30
Debugger/Debugger.Core/SourcecodeSegment.cs

@ -346,8 +346,11 @@ namespace Debugger
this.startLine, this.startColumn, this.endLine, this.endColumn); this.startLine, this.startColumn, this.endLine, this.endColumn);
} }
#region ILSpy
public static SourcecodeSegment CreateForIL(Module module, int line, int metadataToken, int iLOffset) public static SourcecodeSegment CreateForIL(Module module, int line, int metadataToken, int iLOffset)
{ {
try {
SourcecodeSegment segment = new SourcecodeSegment(); SourcecodeSegment segment = new SourcecodeSegment();
segment.module = module; segment.module = module;
segment.typename = null; segment.typename = null;
@ -362,6 +365,33 @@ namespace Debugger
segment.stepRanges = null; segment.stepRanges = null;
return segment; return segment;
} catch {
return null;
}
}
public static SourcecodeSegment ResolveForIL(Module module, ICorDebugFunction corFunction, int line, int offset, int[] ranges)
{
try {
SourcecodeSegment segment = new SourcecodeSegment();
segment.module = module;
segment.typename = null;
segment.checkSum = null;
segment.startLine = line;
segment.startColumn = 0;
segment.endLine = line;
segment.endColumn = 0;
segment.corFunction = corFunction;
segment.ilStart = offset;
segment.ilEnd = offset;
segment.stepRanges = ranges;
return segment;
} catch {
return null;
}
} }
#endregion
} }
} }

10
Debugger/Debugger.Core/StackFrame.cs

@ -139,9 +139,13 @@ namespace Debugger
} }
} }
public int[] ILRanges { get; set; }
public int SourceCodeLine { get; set; }
SourcecodeSegment GetSegmentForOffet(int offset) SourcecodeSegment GetSegmentForOffet(int offset)
{ {
return SourcecodeSegment.Resolve(this.MethodInfo.DebugModule, corFunction, offset); return SourcecodeSegment.ResolveForIL(this.MethodInfo.DebugModule, corFunction, SourceCodeLine, offset, ILRanges);
} }
/// <summary> Step into next instruction </summary> /// <summary> Step into next instruction </summary>
@ -187,10 +191,6 @@ namespace Debugger
void AsyncStep(bool stepIn) void AsyncStep(bool stepIn)
{ {
if (this.MethodInfo.DebugModule.HasSymbols == false) {
throw new DebuggerException("Unable to step. No symbols loaded.");
}
SourcecodeSegment nextSt = NextStatement; SourcecodeSegment nextSt = NextStatement;
if (nextSt == null) { if (nextSt == null) {
throw new DebuggerException("Unable to step. Next statement not aviable"); throw new DebuggerException("Unable to step. Next statement not aviable");

15
Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs

@ -25,6 +25,7 @@ using System.Windows.Media;
using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.Decompiler;
using ILSpy.Debugger.Bookmarks; using ILSpy.Debugger.Bookmarks;
using ILSpy.Debugger.Services; using ILSpy.Debugger.Services;
using Mono.Cecil; using Mono.Cecil;
@ -237,15 +238,27 @@ namespace ILSpy.Debugger.AvalonEdit
BookmarkBase bm = GetBookmarkFromLine(line); BookmarkBase bm = GetBookmarkFromLine(line);
if (bm != null) { if (bm != null) {
bm.MouseUp(e); bm.MouseUp(e);
if (bm.CanToggle) { if (bm.CanToggle) {
BookmarkManager.RemoveMark(bm); BookmarkManager.RemoveMark(bm);
}
InvalidateVisual(); InvalidateVisual();
}
if (e.Handled) if (e.Handled)
return; return;
} }
if (e.ChangedButton == MouseButton.Left) { if (e.ChangedButton == MouseButton.Left) {
if (CurrentType != null) { if (CurrentType != null) {
// check if the codemappings exists for this line
var storage = CodeMappings.GetStorage(DebuggerService.CurrentDebugger.Language);
uint token;
if (storage.GetInstructionByTypeAndLine(CurrentType.FullName, line, out token) == null) {
MessageBox.Show(string.Format("Missing code mappings for {0} at line {1}", CurrentType.FullName, line),
"Code mappings", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// no bookmark on the line: create a new breakpoint // no bookmark on the line: create a new breakpoint
DebuggerService.ToggleBreakpointAt( DebuggerService.ToggleBreakpointAt(
CurrentType.FullName, CurrentType.FullName,

4
Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs

@ -13,6 +13,10 @@ namespace ILSpy.Debugger.Bookmarks
{ {
static CurrentLineBookmark instance; static CurrentLineBookmark instance;
public static CurrentLineBookmark Instance {
get { return instance; }
}
static int startLine; static int startLine;
static int startColumn; static int startColumn;
static int endLine; static int endLine;

108
Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs

@ -1,8 +1,10 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Windows; using System.Windows;
@ -45,6 +47,12 @@ namespace ILSpy.Debugger.Services
//DynamicTreeDebuggerRow currentTooltipRow; //DynamicTreeDebuggerRow currentTooltipRow;
//Expression currentTooltipExpression; //Expression currentTooltipExpression;
private ConcurrentDictionary<string, List<MethodMapping>> CodeMappingsStorage {
get {
return CodeMappings.GetStorage(Language);
}
}
public event EventHandler<ProcessEventArgs> ProcessSelected; public event EventHandler<ProcessEventArgs> ProcessSelected;
public NDebugger DebuggerCore { public NDebugger DebuggerCore {
@ -274,16 +282,43 @@ namespace ILSpy.Debugger.Services
// Stepping: // Stepping:
SourceCodeMapping GetNextCodeMapping()
{
uint token;
var instruction = CodeMappingsStorage.GetInstructionByTypeAndLine(
CurrentLineBookmark.Instance.TypeName,
CurrentLineBookmark.Instance.LineNumber, out token);
var val = CodeMappingsStorage[CurrentLineBookmark.Instance.TypeName];
var mapping = val.Find(m => m.MetadataToken == token);
return mapping.MethodCodeMappings.FirstOrDefault(s => s.ILInstructionOffset.From <= instruction.ILInstructionOffset.To);
}
public void StepInto() public void StepInto()
{ {
if (!IsDebugging) { if (!IsDebugging) {
MessageBox.Show(errorNotDebugging, "StepInto"); MessageBox.Show(errorNotDebugging, "StepInto");
return; return;
} }
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) {
// use most recent stack frame because we don't have the symbols
if (debuggedProcess.SelectedThread == null ||
debuggedProcess.SelectedThread.MostRecentStackFrame == null ||
debuggedProcess.IsRunning) {
MessageBox.Show(errorCannotStepNoActiveFunction, "StepInto"); MessageBox.Show(errorCannotStepNoActiveFunction, "StepInto");
} else { } else {
debuggedProcess.SelectedStackFrame.AsyncStepInto(); var map = GetNextCodeMapping();
if (map == null) {
CurrentLineBookmark.Remove();
Continue();
} else {
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
frame.SourceCodeLine = map.SourceCodeLine;
frame.ILRanges = (new List<int> { map.ILInstructionOffset.From, map.ILInstructionOffset.To }).ToArray();
frame.AsyncStepInto();
}
} }
} }
@ -292,11 +327,24 @@ namespace ILSpy.Debugger.Services
if (!IsDebugging) { if (!IsDebugging) {
MessageBox.Show(errorNotDebugging, "StepOver"); MessageBox.Show(errorNotDebugging, "StepOver");
return; return;
} }
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) { // use most recent stack frame because we don't have the symbols
if (debuggedProcess.SelectedThread == null ||
debuggedProcess.SelectedThread.MostRecentStackFrame == null ||
debuggedProcess.IsRunning) {
MessageBox.Show(errorCannotStepNoActiveFunction, "StepOver"); MessageBox.Show(errorCannotStepNoActiveFunction, "StepOver");
} else { } else {
debuggedProcess.SelectedStackFrame.AsyncStepOver(); var map = GetNextCodeMapping();
if (map == null) {
CurrentLineBookmark.Remove();
Continue();
} else {
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
frame.SourceCodeLine = map.SourceCodeLine;
frame.ILRanges = (new List<int> { map.ILInstructionOffset.From, map.ILInstructionOffset.To }).ToArray();
frame.AsyncStepOver();
}
} }
} }
@ -306,10 +354,23 @@ namespace ILSpy.Debugger.Services
MessageBox.Show(errorNotDebugging, "StepOut"); MessageBox.Show(errorNotDebugging, "StepOut");
return; return;
} }
if (debuggedProcess.SelectedStackFrame == null || debuggedProcess.IsRunning) {
// use most recent stack frame because we don't have the symbols
if (debuggedProcess.SelectedThread == null ||
debuggedProcess.SelectedThread.MostRecentStackFrame == null ||
debuggedProcess.IsRunning) {
MessageBox.Show(errorCannotStepNoActiveFunction, "StepOut"); MessageBox.Show(errorCannotStepNoActiveFunction, "StepOut");
} else { } else {
debuggedProcess.SelectedStackFrame.AsyncStepOut(); var map = GetNextCodeMapping();
if (map == null) {
CurrentLineBookmark.Remove();
Continue();
} else {
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
frame.SourceCodeLine = map.SourceCodeLine;
frame.ILRanges = (new List<int> { map.ILInstructionOffset.From, map.ILInstructionOffset.To }).ToArray();
frame.AsyncStepOut();
}
} }
} }
@ -335,7 +396,7 @@ namespace ILSpy.Debugger.Services
if (!CanEvaluate) { if (!CanEvaluate) {
return null; return null;
} }
return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, debuggedProcess.SelectedStackFrame); return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, debuggedProcess.SelectedThread.MostRecentStackFrame);
} }
/// <summary> /// <summary>
@ -381,7 +442,10 @@ namespace ILSpy.Debugger.Services
public bool CanEvaluate public bool CanEvaluate
{ {
get { get {
return debuggedProcess != null && !debuggedProcess.IsRunning && debuggedProcess.SelectedStackFrame != null; return debuggedProcess != null &&
!debuggedProcess.IsRunning &&
debuggedProcess.SelectedThread != null &&
debuggedProcess.SelectedThread.MostRecentStackFrame != null;
} }
} }
@ -429,8 +493,9 @@ namespace ILSpy.Debugger.Services
public bool CanSetInstructionPointer(string filename, int line, int column) public bool CanSetInstructionPointer(string filename, int line, int column)
{ {
if (debuggedProcess != null && debuggedProcess.IsPaused && debuggedProcess.SelectedStackFrame != null) { if (debuggedProcess != null && debuggedProcess.IsPaused &&
SourcecodeSegment seg = debuggedProcess.SelectedStackFrame.CanSetIP(filename, line, column); debuggedProcess.SelectedThread != null && debuggedProcess.SelectedThread.MostRecentStackFrame != null) {
SourcecodeSegment seg = debuggedProcess.SelectedThread.MostRecentStackFrame.CanSetIP(filename, line, column);
return seg != null; return seg != null;
} else { } else {
return false; return false;
@ -440,7 +505,7 @@ namespace ILSpy.Debugger.Services
public bool SetInstructionPointer(string filename, int line, int column) public bool SetInstructionPointer(string filename, int line, int column)
{ {
if (CanSetInstructionPointer(filename, line, column)) { if (CanSetInstructionPointer(filename, line, column)) {
SourcecodeSegment seg = debuggedProcess.SelectedStackFrame.SetIP(filename, line, column); SourcecodeSegment seg = debuggedProcess.SelectedThread.MostRecentStackFrame.SetIP(filename, line, column);
return seg != null; return seg != null;
} else { } else {
return false; return false;
@ -498,12 +563,10 @@ namespace ILSpy.Debugger.Services
{ {
Breakpoint breakpoint = null; Breakpoint breakpoint = null;
var storage = CodeMappings.GetStorage(Language);
if (Language == bookmark.Language) { if (Language == bookmark.Language) {
uint token; uint token;
SourceCodeMapping map = SourceCodeMapping map =
storage.GetInstructionByTypeAndLine( CodeMappingsStorage.GetInstructionByTypeAndLine(
bookmark.TypeName, bookmark.LineNumber, out token); bookmark.TypeName, bookmark.LineNumber, out token);
if (map != null) { if (map != null) {
@ -613,7 +676,7 @@ namespace ILSpy.Debugger.Services
{ {
try { try {
SupportedLanguage supportedLanguage = (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), language, true); SupportedLanguage supportedLanguage = (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), language, true);
Value val = ExpressionEvaluator.Evaluate(code, supportedLanguage, debuggedProcess.SelectedStackFrame); Value val = ExpressionEvaluator.Evaluate(code, supportedLanguage, debuggedProcess.SelectedThread.MostRecentStackFrame);
if (val != null && val.Type.IsPrimitive && val.PrimitiveValue is bool) if (val != null && val.Type.IsPrimitive && val.PrimitiveValue is bool)
return (bool)val.PrimitiveValue; return (bool)val.PrimitiveValue;
@ -746,14 +809,19 @@ namespace ILSpy.Debugger.Services
{ {
DebuggerService.RemoveCurrentLineMarker(); DebuggerService.RemoveCurrentLineMarker();
if (debuggedProcess != null && debuggedProcess.SelectedStackFrame != null) { if (debuggedProcess != null && debuggedProcess.SelectedThread != null) {
var storage = CodeMappings.GetStorage(Language);
// use most recent stack frame because we don't have the symbols
var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
if (frame == null)
return;
uint token = (uint)debuggedProcess.SelectedStackFrame.MethodInfo.MetadataToken; uint token = (uint)frame.MethodInfo.MetadataToken;
int ilOffset = debuggedProcess.SelectedStackFrame.IP; int ilOffset = frame.IP;
int line; int line;
string typeName; string typeName;
storage.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out typeName, out line); CodeMappingsStorage.GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out typeName, out line);
if (typeName != null) if (typeName != null)
DebuggerService.JumpToCurrentLine(typeName, line, 0, line, 0); DebuggerService.JumpToCurrentLine(typeName, line, 0, line, 0);
} }

9
Debugger/ILSpy.Debugger/ToolTips/DebuggerTooltipControl.xaml.cs

@ -227,17 +227,26 @@ namespace ILSpy.Debugger.Tooltips
private void handleScroll(object sender, ScrollChangedEventArgs e) private void handleScroll(object sender, ScrollChangedEventArgs e)
{ {
if (this.lazyGrid == null)
return;
btnUp.IsEnabled = !this.lazyGrid.IsScrolledToStart; btnUp.IsEnabled = !this.lazyGrid.IsScrolledToStart;
btnDown.IsEnabled = !this.lazyGrid.IsScrolledToEnd; btnDown.IsEnabled = !this.lazyGrid.IsScrolledToEnd;
} }
void BtnUp_Click(object sender, RoutedEventArgs e) void BtnUp_Click(object sender, RoutedEventArgs e)
{ {
if (this.lazyGrid == null)
return;
this.lazyGrid.ScrollViewer.ScrollUp(1); this.lazyGrid.ScrollViewer.ScrollUp(1);
} }
void BtnDown_Click(object sender, RoutedEventArgs e) void BtnDown_Click(object sender, RoutedEventArgs e)
{ {
if (this.lazyGrid == null)
return;
this.lazyGrid.ScrollViewer.ScrollDown(1); this.lazyGrid.ScrollViewer.ScrollDown(1);
} }

3
Debugger/ILSpy.Debugger/ToolTips/TextEditorListener.cs

@ -76,6 +76,9 @@ namespace ILSpy.Debugger.ToolTips
toolTip.IsOpen = false; toolTip.IsOpen = false;
TryCloseExistingPopup(true); TryCloseExistingPopup(true);
if (popup != null)
popup.IsOpen = false;
} }
void OnMouseHoverStopped(MouseEventArgs e) void OnMouseHoverStopped(MouseEventArgs e)

16
ILSpy/MainWindow.xaml.cs

@ -298,10 +298,6 @@ namespace ICSharpCode.ILSpy
} }
} }
#endregion
#region Debugger commands
void RefreshCommandExecuted(object sender, ExecutedRoutedEventArgs e) void RefreshCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{ {
if (!DebuggerService.CurrentDebugger.IsDebugging) { if (!DebuggerService.CurrentDebugger.IsDebugging) {
@ -312,6 +308,10 @@ namespace ICSharpCode.ILSpy
} }
} }
#endregion
#region Debugger commands
void AttachToProcessExecuted(object sender, ExecutedRoutedEventArgs e) void AttachToProcessExecuted(object sender, ExecutedRoutedEventArgs e)
{ {
if (!DebuggerService.CurrentDebugger.IsDebugging) { if (!DebuggerService.CurrentDebugger.IsDebugging) {
@ -335,7 +335,7 @@ namespace ICSharpCode.ILSpy
void DetachFromProcessExecuted(object sender, ExecutedRoutedEventArgs e) void DetachFromProcessExecuted(object sender, ExecutedRoutedEventArgs e)
{ {
if (DebuggerService.CurrentDebugger.IsDebugging){ if (DebuggerService.CurrentDebugger.IsDebugging && !DebuggerService.CurrentDebugger.IsProcessRunning){
DebuggerService.CurrentDebugger.Detach(); DebuggerService.CurrentDebugger.Detach();
EnableDebuggerUI(true); EnableDebuggerUI(true);
@ -351,19 +351,19 @@ namespace ICSharpCode.ILSpy
void StepIntoExecuted(object sender, ExecutedRoutedEventArgs e) void StepIntoExecuted(object sender, ExecutedRoutedEventArgs e)
{ {
if (DebuggerService.CurrentDebugger.IsDebugging) if (DebuggerService.CurrentDebugger.IsDebugging && !DebuggerService.CurrentDebugger.IsProcessRunning)
DebuggerService.CurrentDebugger.StepInto(); DebuggerService.CurrentDebugger.StepInto();
} }
void StepOverExecuted(object sender, ExecutedRoutedEventArgs e) void StepOverExecuted(object sender, ExecutedRoutedEventArgs e)
{ {
if (DebuggerService.CurrentDebugger.IsDebugging) if (DebuggerService.CurrentDebugger.IsDebugging && !DebuggerService.CurrentDebugger.IsProcessRunning)
DebuggerService.CurrentDebugger.StepOver(); DebuggerService.CurrentDebugger.StepOver();
} }
void StepOutExecuted(object sender, ExecutedRoutedEventArgs e) void StepOutExecuted(object sender, ExecutedRoutedEventArgs e)
{ {
if (DebuggerService.CurrentDebugger.IsDebugging) if (DebuggerService.CurrentDebugger.IsDebugging && !DebuggerService.CurrentDebugger.IsProcessRunning)
DebuggerService.CurrentDebugger.StepOut(); DebuggerService.CurrentDebugger.StepOut();
} }

Loading…
Cancel
Save