/* 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.ObjectModel; using System.Linq; using dnSpy.Contracts.Debugger.Breakpoints.Code; using dnSpy.Contracts.Debugger.Code; using dnSpy.Contracts.Debugger.Engine.CallStack; using dnSpy.Contracts.Debugger.Exceptions; namespace dnSpy.Contracts.Debugger.Engine { /// /// Used by a to create new modules, threads, etc. /// /// /// The engines don't need to worry about locks, or raising events in the correct thread, /// or updating collections in the right thread, or closing dbg objects, etc... /// It's taken care of by dnSpy. /// public abstract class DbgObjectFactory { /// /// Gets the debug manager /// public abstract DbgManager DbgManager { get; } /// /// Gets the process /// public DbgProcess Process => Runtime.Process; /// /// Gets the runtime /// public abstract DbgRuntime Runtime { get; } /// /// Creates an app domain. The engine has paused the program. /// /// App domain object created by the debug engine /// New value /// New value /// Message flags /// public DbgEngineAppDomain CreateAppDomain(DbgInternalAppDomain internalAppDomain, string name, int id, DbgEngineMessageFlags messageFlags) => CreateAppDomain(internalAppDomain, name, id, messageFlags, null, null); /// /// Creates an app domain. The engine has paused the program. /// /// Type of data /// App domain object created by the debug engine /// New value /// New value /// Message flags /// Data to add to the or null if nothing gets added /// Called right after creating the app domain but before adding it to internal data structures. This can be null. /// public abstract DbgEngineAppDomain CreateAppDomain(DbgInternalAppDomain internalAppDomain, string name, int id, DbgEngineMessageFlags messageFlags, T? data, Action? onCreated = null) where T : class; /// /// Creates a module. The engine has paused the program. /// /// New value /// Module object created by the debug engine /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// Message flags /// public DbgEngineModule CreateModule(DbgAppDomain? appDomain, DbgInternalModule internalModule, bool isExe, ulong address, uint size, DbgImageLayout imageLayout, string name, string filename, bool isDynamic, bool isInMemory, bool? isOptimized, int order, DateTime? timestamp, string version, DbgEngineMessageFlags messageFlags) => CreateModule(appDomain, internalModule, isExe, address, size, imageLayout, name, filename, isDynamic, isInMemory, isOptimized, order, timestamp, version, messageFlags, null, null); /// /// Creates a module. The engine has paused the program. /// /// Type of data /// New value /// Module object created by the debug engine /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// Message flags /// Data to add to the or null if nothing gets added /// Called right after creating the module but before adding it to internal data structures. This can be null. /// public abstract DbgEngineModule CreateModule(DbgAppDomain? appDomain, DbgInternalModule internalModule, bool isExe, ulong address, uint size, DbgImageLayout imageLayout, string name, string filename, bool isDynamic, bool isInMemory, bool? isOptimized, int order, DateTime? timestamp, string version, DbgEngineMessageFlags messageFlags, T? data, Action? onCreated = null) where T : class; /// /// Creates a thread. The engine has paused the program. /// /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// Message flags /// public DbgEngineThread CreateThread(DbgAppDomain? appDomain, string kind, ulong id, ulong? managedId, string? name, int suspendedCount, ReadOnlyCollection state, DbgEngineMessageFlags messageFlags) => CreateThread(appDomain, kind, id, managedId, name, suspendedCount, state, messageFlags, null, null); /// /// Creates a thread. The engine has paused the program. /// /// Type of data /// New value /// New value /// New value /// New value /// New value /// New value /// New value /// Message flags /// Data to add to the or null if nothing gets added /// Called right after creating the thread but before adding it to internal data structures. This can be null. /// public abstract DbgEngineThread CreateThread(DbgAppDomain? appDomain, string kind, ulong id, ulong? managedId, string? name, int suspendedCount, ReadOnlyCollection state, DbgEngineMessageFlags messageFlags, T? data, Action? onCreated = null) where T : class; /// /// Creates an exception. The engine has paused the program. /// /// Exception id /// Exception event flags /// Exception message or null if it's not available /// Thread where exception was thrown or null if it's unknown /// Module where exception was thrown or null if it's unknown /// Message flags /// public DbgException CreateException(DbgExceptionId id, DbgExceptionEventFlags flags, string? message, DbgThread? thread, DbgModule? module, DbgEngineMessageFlags messageFlags) => CreateException(id, flags, message, thread, module, messageFlags, null, null); /// /// Creates an exception. The engine has paused the program. /// /// Type of data /// Exception id /// Exception event flags /// Exception message or null if it's not available /// Thread where exception was thrown or null if it's unknown /// Module where exception was thrown or null if it's unknown /// Message flags /// Data to add to the or null if nothing gets added /// Called right after creating the exception but before adding it to internal data structures. This can be null. /// public abstract DbgException CreateException(DbgExceptionId id, DbgExceptionEventFlags flags, string? message, DbgThread? thread, DbgModule? module, DbgEngineMessageFlags messageFlags, T? data, Action? onCreated = null) where T : class; /// /// Value used when the bound breakpoint's address isn't known /// public const ulong BoundBreakpointNoAddress = ulong.MaxValue; /// /// Creates a bound breakpoint. This method returns null if there was no breakpoint matching . /// /// To get notified when a bound breakpoint gets deleted, add custom data that implements . /// /// Breakpoint location /// Module or null if none /// Address or if unknown /// Warning/error message or default if none /// public DbgEngineBoundCodeBreakpoint? Create(DbgCodeLocation location, DbgModule? module, ulong address, DbgEngineBoundCodeBreakpointMessage message) => Create(new[] { new DbgBoundCodeBreakpointInfo(location, module, address, message, null) }).FirstOrDefault(); /// /// Creates a bound breakpoint. This method returns null if there was no breakpoint matching . /// /// To get notified when a bound breakpoint gets deleted, add custom data that implements . /// /// Type of data /// Breakpoint location /// Module or null if none /// Address or if unknown /// Warning/error message or default if none /// Data to add to the or null if nothing gets added /// public DbgEngineBoundCodeBreakpoint? Create(DbgCodeLocation location, DbgModule? module, ulong address, DbgEngineBoundCodeBreakpointMessage message, T? data) where T : class => Create(new[] { new DbgBoundCodeBreakpointInfo(location, module, address, message, data) }).FirstOrDefault(); /// /// Creates bound breakpoints. Locations that don't match an existing breakpoint are ignored, and all user data /// are disposed if they implement . /// /// To get notified when a bound breakpoint gets deleted, add custom data that implements . /// /// Type of data /// Bound breakpoints to create /// public abstract DbgEngineBoundCodeBreakpoint[] Create(DbgBoundCodeBreakpointInfo[] infos) where T : class; /// /// Creates a special stack frame that's displayed as [name], eg. [Managed to Native Transition] /// /// Name, eg. "Managed to Native Transition" /// Location or null /// Module or null /// Function offset /// Function token /// public abstract DbgEngineStackFrame CreateSpecialStackFrame(string name, DbgCodeLocation? location = null, DbgModule? module = null, uint functionOffset = 0, uint functionToken = DbgEngineStackFrame.InvalidFunctionToken); } /// /// Bound breakpoint info /// /// Type of data public readonly struct DbgBoundCodeBreakpointInfo where T : class { /// /// Value used when the bound breakpoint's address isn't known /// public const ulong NoAddress = DbgObjectFactory.BoundBreakpointNoAddress; /// /// Gets the location /// public DbgCodeLocation Location { get; } /// /// Gets the module or null if none /// public DbgModule? Module { get; } /// /// Gets the address or if it's not known /// public ulong Address { get; } /// /// Gets the warning/error message or default if none /// public DbgEngineBoundCodeBreakpointMessage Message { get; } /// /// Gets the data to add to the or null if nothing gets added. /// If the data implements , it gets disposed when the bound breakpoint gets deleted. /// public T? Data { get; } /// /// Constructor /// /// Location /// Module or null if none /// Address or if it's not known /// Warning/error message or default if none /// Data to add to the or null if nothing gets added. /// If the data implements , it gets disposed when the bound breakpoint gets deleted. public DbgBoundCodeBreakpointInfo(DbgCodeLocation location, DbgModule? module, ulong address, DbgEngineBoundCodeBreakpointMessage message, T? data) { Location = location ?? throw new ArgumentNullException(nameof(location)); Module = module; Address = address; Message = message; Data = data; } } }