/* 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 dnSpy.Contracts.Debugger.Breakpoints.Code; using dnSpy.Contracts.Debugger.Exceptions; namespace dnSpy.Contracts.Debugger { /// /// Debugger message kind /// public enum DbgMessageKind { /// /// A process was created () /// ProcessCreated, /// /// A process has exited () /// ProcessExited, /// /// A runtime was created () /// RuntimeCreated, /// /// A runtime has exited () /// RuntimeExited, /// /// An app domain was loaded () /// AppDomainLoaded, /// /// An app domain was unloaded (). This message isn't sent if the program has exited. /// AppDomainUnloaded, /// /// A module was loaded () /// ModuleLoaded, /// /// A module was unloaded (). This message isn't sent if the program has exited or if its app domain has unloaded. /// ModuleUnloaded, /// /// A thread was created () /// ThreadCreated, /// /// A thread has exited (). This message isn't sent if the program has exited. /// ThreadExited, /// /// An exception was thrown () /// ExceptionThrown, /// /// The entry point has been reached (). /// This message is only sent if the user chose to break at the entry point. /// EntryPointBreak, /// /// Message from the debugged program () /// ProgramMessage, /// /// A bound breakpoint was hit () /// BoundBreakpoint, /// /// The program paused itself by executing a break instruction or method () /// ProgramBreak, /// /// Step into/over/out is complete () /// StepComplete, /// /// SetIP() is complete () /// SetIPComplete, /// /// Some message that should be shown to the user, eg. we failed to connect to the debugged process () /// UserMessage, /// /// The program was paused by the user, or because some other program was paused for some other reason () /// Break, /// /// Message from the debugged program () /// AsyncProgramMessage, } /// /// Base class of all debugger messages /// public abstract class DbgMessageEventArgs : EventArgs { /// /// Gets the message kind /// public abstract DbgMessageKind Kind { get; } /// /// true if the program should be paused. It's only possible to write true to this property. /// public bool Pause { get => pause; set => pause |= value; } bool pause; } /// /// Process message base class /// public abstract class DbgMessageProcessEventArgs : DbgMessageEventArgs { /// /// Gets the process /// public DbgProcess Process { get; } /// /// Constructor /// /// Process protected DbgMessageProcessEventArgs(DbgProcess process) => Process = process ?? throw new ArgumentNullException(nameof(process)); } /// /// Process created message () /// public sealed class DbgMessageProcessCreatedEventArgs : DbgMessageProcessEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.ProcessCreated; /// /// Constructor /// /// Process public DbgMessageProcessCreatedEventArgs(DbgProcess process) : base(process) { } } /// /// Process exited message () /// public sealed class DbgMessageProcessExitedEventArgs : DbgMessageProcessEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.ProcessExited; /// /// Gets the exit code /// public int ExitCode { get; } /// /// Constructor /// /// Process /// Process exit code public DbgMessageProcessExitedEventArgs(DbgProcess process, int exitCode) : base(process) { } } /// /// Runtime message base class /// public abstract class DbgMessageRuntimeEventArgs : DbgMessageEventArgs { /// /// Gets the runtime /// public DbgRuntime Runtime { get; } /// /// Constructor /// /// Runtime protected DbgMessageRuntimeEventArgs(DbgRuntime runtime) => Runtime = runtime ?? throw new ArgumentNullException(nameof(runtime)); } /// /// Runtime created message () /// public sealed class DbgMessageRuntimeCreatedEventArgs : DbgMessageRuntimeEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.RuntimeCreated; /// /// Constructor /// /// Runtime public DbgMessageRuntimeCreatedEventArgs(DbgRuntime runtime) : base(runtime) { } } /// /// Runtime exited message () /// public sealed class DbgMessageRuntimeExitedEventArgs : DbgMessageRuntimeEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.RuntimeExited; /// /// Constructor /// /// Runtime public DbgMessageRuntimeExitedEventArgs(DbgRuntime runtime) : base(runtime) { } } /// /// App domain message base class /// public abstract class DbgMessageAppDomainEventArgs : DbgMessageEventArgs { /// /// Gets the app domain /// public DbgAppDomain AppDomain { get; } /// /// Constructor /// /// App domain protected DbgMessageAppDomainEventArgs(DbgAppDomain appDomain) => AppDomain = appDomain ?? throw new ArgumentNullException(nameof(appDomain)); } /// /// App domain loaded message () /// public sealed class DbgMessageAppDomainLoadedEventArgs : DbgMessageAppDomainEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.AppDomainLoaded; /// /// Constructor /// /// App domain public DbgMessageAppDomainLoadedEventArgs(DbgAppDomain appDomain) : base(appDomain) { } } /// /// App domain unloaded message () /// public sealed class DbgMessageAppDomainUnloadedEventArgs : DbgMessageAppDomainEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.AppDomainUnloaded; /// /// Constructor /// /// App domain public DbgMessageAppDomainUnloadedEventArgs(DbgAppDomain appDomain) : base(appDomain) { } } /// /// Module message base class /// public abstract class DbgMessageModuleEventArgs : DbgMessageEventArgs { /// /// Gets the module /// public DbgModule Module { get; } /// /// Constructor /// /// Module protected DbgMessageModuleEventArgs(DbgModule module) => Module = module ?? throw new ArgumentNullException(nameof(module)); } /// /// Module loaded message () /// public sealed class DbgMessageModuleLoadedEventArgs : DbgMessageModuleEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.ModuleLoaded; /// /// Constructor /// /// Module public DbgMessageModuleLoadedEventArgs(DbgModule module) : base(module) { } } /// /// Module unloaded message () /// public sealed class DbgMessageModuleUnloadedEventArgs : DbgMessageModuleEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.ModuleUnloaded; /// /// Constructor /// /// Module public DbgMessageModuleUnloadedEventArgs(DbgModule module) : base(module) { } } /// /// Thread message base class /// public abstract class DbgMessageThreadEventArgs : DbgMessageEventArgs { /// /// Gets the thread /// public DbgThread Thread { get; } /// /// Constructor /// /// Thread protected DbgMessageThreadEventArgs(DbgThread thread) => Thread = thread ?? throw new ArgumentNullException(nameof(thread)); } /// /// Thread created message () /// public sealed class DbgMessageThreadCreatedEventArgs : DbgMessageThreadEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.ThreadCreated; /// /// Constructor /// /// Thread public DbgMessageThreadCreatedEventArgs(DbgThread thread) : base(thread) { } } /// /// Thread exited message () /// public sealed class DbgMessageThreadExitedEventArgs : DbgMessageThreadEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.ThreadExited; /// /// Gets the exit code /// public int ExitCode { get; } /// /// Constructor /// /// Thread /// Thread exit code public DbgMessageThreadExitedEventArgs(DbgThread thread, int exitCode) : base(thread) { } } /// /// Exception thrown message () /// public sealed class DbgMessageExceptionThrownEventArgs : DbgMessageEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.ExceptionThrown; /// /// Gets the exception /// public DbgException Exception { get; } /// /// Constructor /// /// Exception public DbgMessageExceptionThrownEventArgs(DbgException exception) => Exception = exception ?? throw new ArgumentNullException(nameof(exception)); } /// /// The entry point has been reached (). /// This message is only sent if the user chose to break at the entry point. /// public sealed class DbgMessageEntryPointBreakEventArgs : DbgMessageEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.EntryPointBreak; /// /// Gets the runtime /// public DbgRuntime Runtime { get; } /// /// Gets the thread or null if it's unknown /// public DbgThread? Thread { get; } /// /// Constructor /// /// Runtime /// Thread or null if it's unknown public DbgMessageEntryPointBreakEventArgs(DbgRuntime runtime, DbgThread? thread) { Runtime = runtime ?? throw new ArgumentNullException(nameof(runtime)); Thread = thread; } } /// /// Message from the debugged program () /// public sealed class DbgMessageProgramMessageEventArgs : DbgMessageEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.ProgramMessage; /// /// Gets the text /// public string Message { get; } /// /// Gets the runtime /// public DbgRuntime Runtime { get; } /// /// Gets the thread or null if it's unknown /// public DbgThread? Thread { get; } /// /// Constructor /// /// Message /// Runtime /// Thread or null if it's unknown public DbgMessageProgramMessageEventArgs(string message, DbgRuntime runtime, DbgThread? thread) { Message = message ?? throw new ArgumentNullException(nameof(message)); Runtime = runtime ?? throw new ArgumentNullException(nameof(runtime)); Thread = thread; } } /// /// A bound breakpoint was hit () /// public sealed class DbgMessageBoundBreakpointEventArgs : DbgMessageEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.BoundBreakpoint; /// /// Gets the bound breakpoint /// public DbgBoundCodeBreakpoint BoundBreakpoint { get; } /// /// Gets the thread or null if it's unknown /// public DbgThread? Thread { get; } /// /// Constructor /// /// Bound breakpoint /// Thread or null if it's unknown public DbgMessageBoundBreakpointEventArgs(DbgBoundCodeBreakpoint boundBreakpoint, DbgThread? thread) { BoundBreakpoint = boundBreakpoint ?? throw new ArgumentNullException(nameof(boundBreakpoint)); Thread = thread; } } /// /// The program paused itself by executing a break instruction or method () /// public sealed class DbgMessageProgramBreakEventArgs : DbgMessageEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.ProgramBreak; /// /// Gets the runtime /// public DbgRuntime Runtime { get; } /// /// Gets the thread or null if it's unknown /// public DbgThread? Thread { get; } /// /// Constructor /// /// Runtime /// Thread or null if it's unknown public DbgMessageProgramBreakEventArgs(DbgRuntime runtime, DbgThread? thread) { Runtime = runtime ?? throw new ArgumentNullException(nameof(runtime)); Thread = thread; } } /// /// Step into/over/out is complete () /// public sealed class DbgMessageStepCompleteEventArgs : DbgMessageEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.StepComplete; /// /// Gets the runtime /// public DbgRuntime Runtime => Thread.Runtime; /// /// Gets the thread /// public DbgThread Thread { get; } /// /// Gets the error message or null if none /// public string? Error { get; } /// /// true if there was an error. Error message is in /// public bool HasError => Error is not null; /// /// Constructor /// /// Thread /// Error message or null if none public DbgMessageStepCompleteEventArgs(DbgThread thread, string? error) { Thread = thread ?? throw new ArgumentNullException(nameof(thread)); Error = error; } } /// /// SetIP() is complete () /// public sealed class DbgMessageSetIPCompleteEventArgs : DbgMessageEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.SetIPComplete; /// /// Gets the runtime /// public DbgRuntime Runtime => Thread.Runtime; /// /// Gets the thread /// public DbgThread Thread { get; } /// /// true if all frames in the thread have been invalidated /// public bool FramesInvalidated { get; } /// /// Gets the error message or null if none /// public string? Error { get; } /// /// true if there was an error. Error message is in /// public bool HasError => Error is not null; /// /// Constructor /// /// Thread /// true if all frames in the thread have been invalidated /// Error message or null if none public DbgMessageSetIPCompleteEventArgs(DbgThread thread, bool framesInvalidated, string? error) { Thread = thread ?? throw new ArgumentNullException(nameof(thread)); FramesInvalidated = framesInvalidated; Error = error; } } /// /// A message that should be shown to the user /// public sealed class DbgMessageUserMessageEventArgs : DbgMessageEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.UserMessage; /// /// Gets the message kind /// public UserMessageKind MessageKind { get; } /// /// Gets the message /// public string Message { get; } /// /// Constructor /// /// Message kind /// Message public DbgMessageUserMessageEventArgs(UserMessageKind messageKind, string message) { MessageKind = messageKind; Message = message ?? throw new ArgumentNullException(nameof(message)); } } /// /// message kinds /// public enum UserMessageKind { /// /// We failed to connect to the debugged process /// CouldNotConnect, /// /// Could not break the debugged process /// CouldNotBreak, } /// /// The program was paused by the user, or because some other program was paused for some other reason () /// public sealed class DbgMessageBreakEventArgs : DbgMessageEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.Break; /// /// Gets the runtime /// public DbgRuntime Runtime { get; } /// /// Gets the thread or null if it's unknown /// public DbgThread? Thread { get; } /// /// Constructor /// /// Runtime /// Thread or null if it's unknown public DbgMessageBreakEventArgs(DbgRuntime runtime, DbgThread? thread) { Runtime = runtime ?? throw new ArgumentNullException(nameof(runtime)); Thread = thread; } } /// /// Message source kind /// public enum AsyncProgramMessageSource { /// /// Some other source /// Other, /// /// Standard output text /// StandardOutput, /// /// Standard error text /// StandardError, } /// /// Message from the debugged program () /// public sealed class DbgMessageAsyncProgramMessageEventArgs : DbgMessageEventArgs { /// /// Returns /// public override DbgMessageKind Kind => DbgMessageKind.AsyncProgramMessage; /// /// Gets the message source kind /// public AsyncProgramMessageSource Source { get; } /// /// Gets the text /// public string Message { get; } /// /// Gets the runtime /// public DbgRuntime Runtime { get; } /// /// Constructor /// /// Source /// Message /// Runtime public DbgMessageAsyncProgramMessageEventArgs(AsyncProgramMessageSource source, string message, DbgRuntime runtime) { Source = source; Message = message ?? throw new ArgumentNullException(nameof(message)); Runtime = runtime ?? throw new ArgumentNullException(nameof(runtime)); } } }