/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.Generic; namespace dnSpy.Contracts.Debugger { /// /// Manages all debug engines. All events are raised on the dispatcher thread. /// If you need to hook events before debugging starts, you should export an . /// It gets called when gets called for the first time. /// public abstract class DbgManager { /// /// Gets the dispatcher. All debugger events are raised on this thread. /// is also called on this thread including disposing of data added by eg. . /// public abstract DbgDispatcher Dispatcher { get; } /// /// Raised on the debugger thread when there's a new message, eg. a process was created, a thread has exited, etc. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? Message; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageProcessCreated; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageProcessExited; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageRuntimeCreated; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageRuntimeExited; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageAppDomainLoaded; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageAppDomainUnloaded; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageModuleLoaded; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageModuleUnloaded; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageThreadCreated; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageThreadExited; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageExceptionThrown; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageEntryPointBreak; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageProgramMessage; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageBoundBreakpoint; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageProgramBreak; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageStepComplete; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageSetIPComplete; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageUserMessage; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageBreak; /// /// Raised on the debugger thread when there's a new message. /// The listeners can pause the debugged program by setting to true. /// public abstract event EventHandler? MessageAsyncProgramMessage; /// /// Starts debugging. Returns an error string if it failed to create a debug engine, or null on success. /// See on how to get called the first time this method gets called. /// /// Options needed to start the program or attach to it public abstract string? Start(DebugProgramOptions options); /// /// true if can be called /// public abstract bool CanRestart { get; } /// /// Restarts the debugged program(s) /// public abstract void Restart(); /// /// true if a program is being debugged /// public abstract bool IsDebugging { get; } /// /// Raised when is changed /// public abstract event EventHandler? IsDebuggingChanged; /// /// true if all processes are running, false if they're all paused, and null /// if some are running and some are paused. /// This property is valid only if is true. /// public abstract bool? IsRunning { get; } /// /// Raised when is changed, see also /// public abstract event EventHandler? IsRunningChanged; /// /// Raised when all processes have been running for a little while, eg. 1 second. /// public abstract event EventHandler? DelayedIsRunningChanged; /// /// Gets all debug tags, see /// public abstract string[] DebugTags { get; } /// /// Raised when is changed /// public abstract event EventHandler>? DebugTagsChanged; /// /// Raised when a process gets paused due to some event in the process. If more than one process /// is being debugged, this is normally only raised once, for the first process. /// public abstract event EventHandler? ProcessPaused; /// /// Gets all debugged processes. Can be empty even if is true /// if the process hasn't been created yet. /// public abstract DbgProcess[] Processes { get; } /// /// Raised when is changed /// public abstract event EventHandler>? ProcessesChanged; /// /// Pauses all debugged processes /// public abstract void BreakAll(); /// /// Lets all programs run again. This is the inverse of /// public abstract void RunAll(); /// /// Lets run again. If /// is true, all other processes will also run. /// /// Process to run public abstract void Run(DbgProcess process); /// /// Stops debugging. All programs started by the debugger will be terminated. All /// other programs will be detached, if possible, else terminated. /// public abstract void StopDebuggingAll(); /// /// Terminates all debugged programs /// public abstract void TerminateAll(); /// /// Detaches all debugged programs, if possible. If it's not possible to detach a /// program, it will be terminated. /// public abstract void DetachAll(); /// /// true if can be called without terminating any programs /// public abstract bool CanDetachWithoutTerminating { get; } /// /// Gets the current process /// public abstract DbgCurrentObject CurrentProcess { get; } /// /// Raised when is changed /// public abstract event EventHandler>? CurrentProcessChanged; /// /// Gets the current runtime /// public abstract DbgCurrentObject CurrentRuntime { get; } /// /// Raised when is changed /// public abstract event EventHandler>? CurrentRuntimeChanged; /// /// Gets the current thread /// public abstract DbgCurrentObject CurrentThread { get; } /// /// Raised when is changed /// public abstract event EventHandler>? CurrentThreadChanged; /// /// Raised when the module's memory has been updated (eg. decrypted) /// public abstract event EventHandler? ModulesRefreshed; /// /// Returns true if the runtime can be debugged /// /// Process id /// Runtime id /// public abstract bool CanDebugRuntime(int pid, RuntimeId rid); /// /// Closes /// /// Object to close public abstract void Close(DbgObject obj); /// /// Closes /// /// Objects to close public abstract void Close(IEnumerable objs); /// /// Writes a message that will be shown in the output window /// /// Message public void WriteMessage(string message) => WriteMessage(PredefinedDbgManagerMessageKinds.Output, message); /// /// Shows an error message and returns immediately /// /// Error message public void ShowError(string errorMessage) => WriteMessage(PredefinedDbgManagerMessageKinds.ErrorUser, errorMessage); /// /// Writes a message /// /// Message kind, see /// Message public abstract void WriteMessage(string messageKind, string message); /// /// Raised when gets called. This event is raised on a random thread. /// public abstract event EventHandler? DbgManagerMessage; } /// /// Predefined message kinds, see /// public static class PredefinedDbgManagerMessageKinds { /// /// Output window /// public const string Output = nameof(Output); /// /// An error message that should be shown to the user /// public const string ErrorUser = nameof(ErrorUser); /// /// Messages by the stepper /// public const string StepFilter = nameof(StepFilter); } /// /// Message event args /// public readonly struct DbgManagerMessageEventArgs { /// /// Gets the message kind, see /// public string MessageKind { get; } /// /// Gets the message /// public string Message { get; } /// /// Constructor /// /// Message kind, see /// Message public DbgManagerMessageEventArgs(string messageKind, string message) { MessageKind = messageKind ?? throw new ArgumentNullException(nameof(messageKind)); Message = message ?? throw new ArgumentNullException(nameof(message)); } } /// /// Contains the current object and the object that caused the debugger to enter break mode /// /// Type of object public abstract class DbgCurrentObject where T : DbgObject { /// /// Gets the current object or null if none /// public abstract T? Current { get; set; } /// /// Gets the object that caused the debugger to enter break mode /// public abstract T? Break { get; } } /// /// changed event args /// /// public readonly struct DbgCurrentObjectChangedEventArgs where T : DbgObject { /// /// true if changed /// public bool CurrentChanged { get; } /// /// true if changed /// public bool BreakChanged { get; } /// /// Constructor /// /// true if changed /// true if changed public DbgCurrentObjectChangedEventArgs(bool currentChanged, bool breakChanged) { CurrentChanged = currentChanged; BreakChanged = breakChanged; } } /// /// Process paused event args /// public readonly struct ProcessPausedEventArgs { /// /// Gets the process /// public DbgProcess Process { get; } /// /// Gets the thread or null if unknown /// public DbgThread? Thread { get; } /// /// Constructor /// /// Process /// Thread or null if unknown public ProcessPausedEventArgs(DbgProcess process, DbgThread? thread) { Process = process ?? throw new ArgumentNullException(nameof(process)); Thread = thread; } } }