/*
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);
}
}