You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
8.1 KiB
230 lines
8.1 KiB
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this |
|
// software and associated documentation files (the "Software"), to deal in the Software |
|
// without restriction, including without limitation the rights to use, copy, modify, merge, |
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
|
// to whom the Software is furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included in all copies or |
|
// substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
// DEALINGS IN THE SOFTWARE. |
|
|
|
using System; |
|
using System.Collections.Generic; |
|
using System.Collections.ObjectModel; |
|
using System.Linq; |
|
using System.Text; |
|
using System.Windows.Controls; |
|
using System.Windows.Input; |
|
using System.Windows.Media; |
|
|
|
using Debugger; |
|
using ICSharpCode.Core.Presentation; |
|
using Debugger.AddIn.TreeModel; |
|
using ICSharpCode.Core; |
|
using ICSharpCode.SharpDevelop.Services; |
|
using ICSharpCode.SharpDevelop.Workbench; |
|
|
|
namespace ICSharpCode.SharpDevelop.Gui.Pads |
|
{ |
|
public class CallStackPad : AbstractPadContent |
|
{ |
|
ListView listView; |
|
|
|
public override object Control { |
|
get { return this.listView; } |
|
} |
|
|
|
public CallStackPad() |
|
{ |
|
var res = new CommonResources(); |
|
res.InitializeComponent(); |
|
|
|
listView = new ListView(); |
|
listView.View = (GridView)res["callstackGridView"]; |
|
listView.MouseDoubleClick += listView_MouseDoubleClick; |
|
listView.SetValue(GridViewColumnAutoSize.AutoWidthProperty, "100%"); |
|
|
|
listView.ContextMenu = CreateMenu(); |
|
|
|
WindowsDebugger.RefreshingPads += RefreshPad; |
|
RefreshPad(); |
|
} |
|
|
|
ContextMenu CreateMenu() |
|
{ |
|
MenuItem extMethodsItem = new MenuItem(); |
|
extMethodsItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowExternalMethods"); |
|
extMethodsItem.IsChecked = DebuggingOptions.Instance.ShowExternalMethods; |
|
extMethodsItem.Click += delegate { |
|
extMethodsItem.IsChecked = DebuggingOptions.Instance.ShowExternalMethods = !DebuggingOptions.Instance.ShowExternalMethods; |
|
WindowsDebugger.RefreshPads(); |
|
}; |
|
|
|
MenuItem moduleItem = new MenuItem(); |
|
moduleItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowModuleNames"); |
|
moduleItem.IsChecked = DebuggingOptions.Instance.ShowModuleNames; |
|
moduleItem.Click += delegate { |
|
moduleItem.IsChecked = DebuggingOptions.Instance.ShowModuleNames = !DebuggingOptions.Instance.ShowModuleNames; |
|
WindowsDebugger.RefreshPads(); |
|
}; |
|
|
|
MenuItem argNamesItem = new MenuItem(); |
|
argNamesItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowArgumentNames"); |
|
argNamesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentNames; |
|
argNamesItem.Click += delegate { |
|
argNamesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentNames = !DebuggingOptions.Instance.ShowArgumentNames; |
|
WindowsDebugger.RefreshPads(); |
|
}; |
|
|
|
MenuItem argValuesItem = new MenuItem(); |
|
argValuesItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowArgumentValues"); |
|
argValuesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentValues; |
|
argValuesItem.Click += delegate { |
|
argValuesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentValues = !DebuggingOptions.Instance.ShowArgumentValues; |
|
WindowsDebugger.RefreshPads(); |
|
}; |
|
|
|
MenuItem lineItem = new MenuItem(); |
|
lineItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowLineNumber"); |
|
lineItem.IsChecked = DebuggingOptions.Instance.ShowLineNumbers; |
|
lineItem.Click += delegate { |
|
lineItem.IsChecked = DebuggingOptions.Instance.ShowLineNumbers = !DebuggingOptions.Instance.ShowLineNumbers; |
|
WindowsDebugger.RefreshPads(); |
|
}; |
|
|
|
return new ContextMenu() { |
|
Items = { |
|
extMethodsItem, |
|
new Separator(), |
|
moduleItem, |
|
argNamesItem, |
|
argValuesItem, |
|
lineItem |
|
} |
|
}; |
|
} |
|
|
|
void listView_MouseDoubleClick(object sender, MouseButtonEventArgs e) |
|
{ |
|
CallStackItem item = listView.SelectedItem as CallStackItem; |
|
if ((item == null) || (item.Frame == null)) |
|
return; |
|
|
|
if (item.Frame.Process.IsPaused) { |
|
if (item.Frame != null) { |
|
WindowsDebugger.CurrentStackFrame = item.Frame; |
|
WindowsDebugger.Instance.JumpToCurrentLine(); |
|
WindowsDebugger.RefreshPads(); |
|
} |
|
} else { |
|
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.CallStack.CannotSwitchWhileRunning}", "${res:MainWindow.Windows.Debug.CallStack.FunctionSwitch}"); |
|
} |
|
} |
|
|
|
void RefreshPad() |
|
{ |
|
Thread thread = WindowsDebugger.CurrentThread; |
|
if (thread == null) { |
|
listView.ItemsSource = null; |
|
} else { |
|
var items = new ObservableCollection<CallStackItem>(); |
|
bool previousItemIsExternalMethod = false; |
|
WindowsDebugger.CurrentProcess.EnqueueForEach( |
|
listView.Dispatcher, |
|
thread.GetCallstack(100), |
|
f => items.AddIfNotNull(CreateItem(f, ref previousItemIsExternalMethod)) |
|
); |
|
listView.ItemsSource = items; |
|
} |
|
} |
|
|
|
CallStackItem CreateItem(StackFrame frame, ref bool previousItemIsExternalMethod) |
|
{ |
|
bool showExternalMethods = DebuggingOptions.Instance.ShowExternalMethods; |
|
var symSource = WindowsDebugger.PdbSymbolSource; |
|
bool hasSymbols = symSource.Handles(frame.MethodInfo) |
|
&& !symSource.IsCompilerGenerated(frame.MethodInfo) |
|
&& frame.NextStatement != null && !string.IsNullOrWhiteSpace(frame.NextStatement.Filename); |
|
if (showExternalMethods || hasSymbols) { |
|
// Show the method in the list |
|
previousItemIsExternalMethod = false; |
|
return new CallStackItem() { |
|
Frame = frame, |
|
ImageSource = SD.ResourceService.GetImageSource("Icons.16x16.Method"), |
|
Name = GetFullName(frame, hasSymbols), |
|
HasSymbols = hasSymbols, |
|
}; |
|
} else { |
|
// Show [External methods] in the list |
|
if (previousItemIsExternalMethod) |
|
return null; |
|
previousItemIsExternalMethod = true; |
|
return new CallStackItem() { |
|
Name = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ExternalMethods"), |
|
HasSymbols = false |
|
}; |
|
} |
|
} |
|
|
|
static string GetFullName(StackFrame frame, bool hasSymbols) |
|
{ |
|
StringBuilder name = new StringBuilder(64); |
|
if (DebuggingOptions.Instance.ShowModuleNames) { |
|
name.Append(frame.MethodInfo.ToString()); |
|
name.Append('!'); |
|
} |
|
name.Append(frame.MethodInfo.DeclaringType.FullName); |
|
name.Append('.'); |
|
name.Append(frame.MethodInfo.Name); |
|
if (DebuggingOptions.Instance.ShowArgumentNames || DebuggingOptions.Instance.ShowArgumentValues) { |
|
name.Append('('); |
|
for (int i = 0; i < frame.MethodInfo.Parameters.Count; i++) { |
|
if (DebuggingOptions.Instance.ShowArgumentNames) { |
|
name.Append(frame.MethodInfo.Parameters[i].Name); |
|
if (DebuggingOptions.Instance.ShowArgumentValues) { |
|
name.Append('='); |
|
} |
|
} |
|
if (DebuggingOptions.Instance.ShowArgumentValues) { |
|
try { |
|
name.Append(frame.GetArgumentValue(i, hasSymbols).AsString(100)); |
|
} catch (GetValueException) { |
|
name.Append(ResourceService.GetString("Global.NA")); |
|
} |
|
} |
|
if (i < frame.ArgumentCount - 1) { |
|
name.Append(", "); |
|
} |
|
} |
|
name.Append(')'); |
|
} |
|
if (DebuggingOptions.Instance.ShowLineNumbers) { |
|
if (frame.NextStatement != null) { |
|
name.Append(':'); |
|
name.Append(frame.NextStatement.StartLine.ToString()); |
|
} |
|
} |
|
return name.ToString(); |
|
} |
|
} |
|
|
|
public class CallStackItem |
|
{ |
|
public StackFrame Frame { get; set; } |
|
public ImageSource ImageSource { get; set; } |
|
public string Name { get; set; } |
|
public bool HasSymbols { get; set; } |
|
|
|
public Brush FontColor { |
|
get { return this.HasSymbols ? Brushes.Black : Brushes.Gray; } |
|
} |
|
} |
|
}
|
|
|