.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
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.
 
 
 
 

395 lines
12 KiB

// 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)
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.ILSpy.Bookmarks;
using ICSharpCode.ILSpy.Debugger;
using ICSharpCode.ILSpy.Debugger.Bookmarks;
using ICSharpCode.ILSpy.Debugger.Services;
using ICSharpCode.ILSpy.Debugger.UI;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.TreeView;
using Microsoft.Win32;
namespace ICSharpCode.ILSpy.Debugger.Commands
{
public abstract class DebuggerCommand : SimpleCommand
{
public DebuggerCommand()
{
MainWindow.Instance.KeyUp += OnKeyUp;
}
void OnKeyUp(object sender, KeyEventArgs e)
{
switch (e.Key) {
case Key.F5:
if (this is ContinueDebuggingCommand) {
((ContinueDebuggingCommand)this).Execute(null);
e.Handled = true;
}
break;
case Key.System:
if (this is StepOverCommand) {
((StepOverCommand)this).Execute(null);
e.Handled = true;
}
break;
case Key.F11:
if (this is StepIntoCommand) {
((StepIntoCommand)this).Execute(null);
e.Handled = true;
}
break;
default:
// do nothing
break;
}
}
#region Static members
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
uint uFlags);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
static readonly IntPtr HWND_TOP = new IntPtr(0);
static void SendWpfWindowPos(Window window, IntPtr place)
{
var hWnd = new WindowInteropHelper(window).Handle;
SetWindowPos(hWnd, place, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
}
#endregion
public override void Execute(object parameter)
{
DebugData.LoadedAssemblies = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().Select(a => a.AssemblyDefinition);
}
protected static IDebugger CurrentDebugger {
get {
return DebuggerService.CurrentDebugger;
}
}
protected void StartExecutable(string fileName, string workingDirectory, string arguments)
{
CurrentDebugger.Start(new ProcessStartInfo {
FileName = fileName,
WorkingDirectory = workingDirectory ?? Path.GetDirectoryName(fileName),
Arguments = arguments
});
Finish();
}
protected void StartAttaching(Process process)
{
CurrentDebugger.Attach(process);
Finish();
}
protected void Finish()
{
EnableDebuggerUI(false);
CurrentDebugger.DebugStopped += OnDebugStopped;
CurrentDebugger.IsProcessRunningChanged += CurrentDebugger_IsProcessRunningChanged;
MainWindow.Instance.SetStatus("Running...", Brushes.Black);
}
protected void OnDebugStopped(object sender, EventArgs e)
{
EnableDebuggerUI(true);
CurrentDebugger.DebugStopped -= OnDebugStopped;
CurrentDebugger.IsProcessRunningChanged -= CurrentDebugger_IsProcessRunningChanged;
MainWindow.Instance.SetStatus("Stand by...", Brushes.Black);
}
protected void EnableDebuggerUI(bool enable)
{
var menuItems = MainWindow.Instance.GetMainMenuItems();
var toolbarItems = MainWindow.Instance.GetToolBarItems();
// menu
var items = menuItems.OfType<MenuItem>().Where(m => (m.Header as string) == "_Debugger");
foreach (var item in items.First().Items.OfType<MenuItem>()) {
string header = (string)item.Header;
if (header.StartsWith("Remove")) continue;
if (header.StartsWith("Attach") || header.StartsWith("Debug"))
item.IsEnabled = enable;
else
item.IsEnabled = !enable;
}
//toolbar
var buttons = toolbarItems.OfType<Button>().Where(b => (b.Tag as string) == "Debugger");
foreach (var item in buttons) {
item.IsEnabled = enable;
}
// internal types
MainWindow.Instance.SessionSettings.FilterSettings.ShowInternalApi = true;
}
void CurrentDebugger_IsProcessRunningChanged(object sender, EventArgs e)
{
if (CurrentDebugger.IsProcessRunning) {
//SendWpfWindowPos(this, HWND_BOTTOM);
MainWindow.Instance.SetStatus("Running...", Brushes.Black);
return;
}
var inst = MainWindow.Instance;
// breakpoint was hit => bring to front the main window
SendWpfWindowPos(inst, HWND_TOP); inst.Activate();
// jump to type & expand folding
if (DebugData.DebugStepInformation != null)
inst.JumpToReference(DebugData.DebugStepInformation.Item3);
inst.SetStatus("Debugging...", Brushes.Red);
}
}
[ExportContextMenuEntry(Header = "_Debug Assembly", Icon = "Images/application-x-executable.png")]
internal sealed class DebugExecutableNodeCommand : DebuggerCommand, IContextMenuEntry
{
public bool IsVisible(SharpTreeNode[] selectedNodes)
{
return selectedNodes.All(n => n is AssemblyTreeNode && null != (n as AssemblyTreeNode).LoadedAssembly.AssemblyDefinition.EntryPoint);
}
public bool IsEnabled(SharpTreeNode[] selectedNodes)
{
return selectedNodes.Length == 1;
}
public void Execute(SharpTreeNode[] selectedNodes)
{
if (!CurrentDebugger.IsDebugging) {
AssemblyTreeNode n = selectedNodes[0] as AssemblyTreeNode;
var settings = ILSpySettings.Load();
XElement e = settings["DebuggerSettings"];
var askForArguments = (bool?)e.Attribute("askForArguments");
if (askForArguments.HasValue && askForArguments.Value) {
var window = new ExecuteProcessWindow { Owner = MainWindow.Instance,
SelectedExecutable = n.LoadedAssembly.FileName };
if (window.ShowDialog() == true) {
string fileName = window.SelectedExecutable;
// execute the process
this.StartExecutable(fileName, window.WorkingDirectory, window.Arguments);
}
} else {
this.StartExecutable(n.LoadedAssembly.FileName, null, null);
}
}
}
}
[ExportToolbarCommand(ToolTip = "Debug an executable",
ToolbarIcon = "Images/application-x-executable.png",
ToolbarCategory = "Debugger",
Tag = "Debugger",
ToolbarOrder = 0)]
[ExportMainMenuCommand(Menu = "_Debugger",
MenuIcon = "Images/application-x-executable.png",
MenuCategory = "Start",
Header = "Debug an _executable",
MenuOrder = 0)]
internal sealed class DebugExecutableCommand : DebuggerCommand
{
public override void Execute(object parameter)
{
if (!CurrentDebugger.IsDebugging) {
var settings = ILSpySettings.Load();
XElement e = settings["DebuggerSettings"];
var askForArguments = (bool?)e.Attribute("askForArguments");
if (askForArguments.HasValue && askForArguments.Value) {
var window = new ExecuteProcessWindow { Owner = MainWindow.Instance };
if (window.ShowDialog() == true) {
string fileName = window.SelectedExecutable;
// add it to references
MainWindow.Instance.OpenFiles(new [] { fileName }, false);
// execute the process
this.StartExecutable(fileName, window.WorkingDirectory, window.Arguments);
}
} else {
OpenFileDialog dialog = new OpenFileDialog() {
Filter = ".NET Executable (*.exe) | *.exe",
RestoreDirectory = true,
DefaultExt = "exe"
};
if (dialog.ShowDialog() == true) {
string fileName = dialog.FileName;
// add it to references
MainWindow.Instance.OpenFiles(new [] { fileName }, false);
// execute the process
this.StartExecutable(fileName, null, null);
}
}
}
}
}
[ExportMainMenuCommand(Menu = "_Debugger",
MenuCategory = "Start",
Header = "Attach to _running application",
MenuOrder = 1)]
internal sealed class AttachCommand : DebuggerCommand
{
public override void Execute(object parameter)
{
if (!CurrentDebugger.IsDebugging) {
var settings = ILSpySettings.Load();
XElement e = settings["DebuggerSettings"];
var showWarnings = (bool?)e.Attribute("showWarnings");
if ((showWarnings.HasValue && showWarnings.Value) || !showWarnings.HasValue)
MessageBox.Show("Warning: When attaching to an application, some local variables might not be available. If possible, use the \"Start Executable\" command.",
"Attach to a process", MessageBoxButton.OK, MessageBoxImage.Warning);
var window = new AttachToProcessWindow { Owner = MainWindow.Instance };
if (window.ShowDialog() == true) {
StartAttaching(window.SelectedProcess);
}
}
}
}
[ExportMainMenuCommand(Menu = "_Debugger",
MenuIcon = "Images/ContinueDebugging.png",
MenuCategory = "SteppingArea",
Header = "Continue debugging",
InputGestureText = "F5",
IsEnabled = false,
MenuOrder = 2)]
internal sealed class ContinueDebuggingCommand : DebuggerCommand
{
public override void Execute(object parameter)
{
if (CurrentDebugger.IsDebugging && !CurrentDebugger.IsProcessRunning) {
CurrentDebugger.Continue();
MainWindow.Instance.SetStatus("Running...", Brushes.Black);
}
}
}
[ExportMainMenuCommand(Menu = "_Debugger",
MenuIcon = "Images/StepInto.png",
MenuCategory = "SteppingArea",
Header = "Step into",
InputGestureText = "F11",
IsEnabled = false,
MenuOrder = 3)]
internal sealed class StepIntoCommand : DebuggerCommand
{
public override void Execute(object parameter)
{
if (CurrentDebugger.IsDebugging && !CurrentDebugger.IsProcessRunning) {
base.Execute(null);
CurrentDebugger.StepInto();
}
}
}
[ExportMainMenuCommand(Menu = "_Debugger",
MenuIcon = "Images/StepOver.png",
MenuCategory = "SteppingArea",
Header = "Step over",
InputGestureText = "F10",
IsEnabled = false,
MenuOrder = 4)]
internal sealed class StepOverCommand : DebuggerCommand
{
public override void Execute(object parameter)
{
if (CurrentDebugger.IsDebugging && !CurrentDebugger.IsProcessRunning) {
base.Execute(null);
CurrentDebugger.StepOver();
}
}
}
[ExportMainMenuCommand(Menu = "_Debugger",
MenuIcon = "Images/StepOut.png",
MenuCategory = "SteppingArea",
Header = "Step out",
IsEnabled = false,
MenuOrder = 5)]
internal sealed class StepOutCommand : DebuggerCommand
{
public override void Execute(object parameter)
{
if (CurrentDebugger.IsDebugging && !CurrentDebugger.IsProcessRunning) {
base.Execute(null);
CurrentDebugger.StepOut();
}
}
}
[ExportMainMenuCommand(Menu = "_Debugger",
MenuCategory = "SteppingArea",
Header = "_Detach from running application",
IsEnabled = false,
MenuOrder = 6)]
internal sealed class DetachCommand : DebuggerCommand
{
public override void Execute(object parameter)
{
if (CurrentDebugger.IsDebugging){
CurrentDebugger.Detach();
EnableDebuggerUI(true);
CurrentDebugger.DebugStopped -= OnDebugStopped;
}
}
}
[ExportMainMenuCommand(Menu = "_Debugger",
MenuIcon = "Images/DeleteAllBreakpoints.png",
MenuCategory = "Others",
Header = "Remove all _breakpoints",
MenuOrder = 7)]
internal sealed class RemoveBreakpointsCommand : DebuggerCommand
{
public override void Execute(object parameter)
{
for (int i = BookmarkManager.Bookmarks.Count - 1; i >= 0; --i) {
var bookmark = BookmarkManager.Bookmarks[i];
if (bookmark is BreakpointBookmark) {
BookmarkManager.RemoveMark(bookmark);
}
}
}
}
}