/* 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.ComponentModel; using System.Diagnostics; using dnSpy.Contracts.Debugger.CallStack; using dnSpy.Contracts.Debugger.Code; using dnSpy.Contracts.Debugger.Steppers; namespace dnSpy.Contracts.Debugger { /// /// A thread in a debugged process /// public abstract class DbgThread : DbgObject, INotifyPropertyChanged { /// /// Raised when a property is changed /// public abstract event PropertyChangedEventHandler? PropertyChanged; /// /// Gets the runtime /// public abstract DbgRuntime Runtime { get; } /// /// Gets the process /// public DbgProcess Process => Runtime.Process; /// /// Gets the app domain or null if it's a process thread /// /// public abstract DbgAppDomain? AppDomain { get; } /// /// true if this is the main thread /// public bool IsMain => Kind == PredefinedThreadKinds.Main; /// /// Gets the thread kind, see /// public abstract string Kind { get; } /// /// Gets the id of this thread /// public abstract ulong Id { get; } /// /// Gets the managed id of this thread or null if it's unknown or if it's not a managed thread /// public abstract ulong? ManagedId { get; } /// /// Gets the thread name /// public abstract string Name { get; } /// /// Gets the thread name shown in the UI /// public abstract string UIName { get; set; } /// /// Gets the suspended count. It's 0 if the thread isn't suspended, and greater than zero if it's suspended. /// public abstract int SuspendedCount { get; } /// /// Thread state /// public abstract ReadOnlyCollection State { get; } /// /// Returns true if the thread has a name /// /// public abstract bool HasName(); /// /// Freezes the thread /// public abstract void Freeze(); /// /// Thaws the thread /// public abstract void Thaw(); /// /// Creates a new instance that can be used to get the call stack. /// /// public abstract DbgStackWalker CreateStackWalker(); /// /// Gets the top stack frame or null if there's none /// /// public DbgStackFrame? GetTopStackFrame() { DbgStackWalker? stackWalker = null; try { stackWalker = CreateStackWalker(); var frames = stackWalker.GetNextStackFrames(1); Debug.Assert(frames.Length <= 1); return frames.Length == 0 ? null : frames[0]; } finally { stackWalker?.Close(); } } /// /// Gets the first frames. /// The returned frame count can be less than if there's not enough frames available. /// /// Max number of frames to return /// public DbgStackFrame[] GetFrames(int count) { if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); if (count == 0) return Array.Empty(); DbgStackWalker? stackWalker = null; try { stackWalker = CreateStackWalker(); var frames = stackWalker.GetNextStackFrames(count); Debug.Assert(frames.Length <= count); return frames; } finally { stackWalker?.Close(); } } /// /// Creates a stepper. /// The caller must close the returned instance by calling . /// /// public abstract DbgStepper CreateStepper(); /// /// Sets a new instruction pointer /// /// New location public abstract void SetIP(DbgCodeLocation location); /// /// Checks if can be called /// /// New location /// public abstract bool CanSetIP(DbgCodeLocation location); } }