use std::time::Duration;
use crate::error::Result;
use crate::gdb::RegisterMap;
use crate::types::VirtAddr;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BugcheckInfo {
pub code: u32,
pub parameters: [u64; 4],
pub driver: Option<String>,
}
pub struct StopEvent {
pub thread_id: Option<String>,
pub exception_code: Option<u32>,
pub program_counter: Option<u64>,
pub is_bugcheck: bool,
pub bugcheck: Option<BugcheckInfo>,
pub target_reloaded: bool,
pub target_kernel_base_hint: Option<VirtAddr>,
pub assisted_breakin: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DebugCapability {
MemoryIntrospection,
ExecutionControl,
InterruptTarget,
SingleStep,
ReadRegisters,
WriteRegisters,
ThreadList,
ThreadSelection,
KernelBreakpoints,
UserModeBreakpoints,
TargetReloadDetection,
KernelBaseHint,
BugcheckDetection,
BugcheckDetails,
DebugOutput,
}
impl DebugCapability {
pub fn label(self) -> &'static str {
match self {
Self::MemoryIntrospection => "memory introspection",
Self::ExecutionControl => "execution control",
Self::InterruptTarget => "target interrupt",
Self::SingleStep => "single step",
Self::ReadRegisters => "register read",
Self::WriteRegisters => "register write",
Self::ThreadList => "context enumeration",
Self::ThreadSelection => "context selection",
Self::KernelBreakpoints => "kernel breakpoints",
Self::UserModeBreakpoints => "usermode breakpoints",
Self::TargetReloadDetection => "target reload detection",
Self::KernelBaseHint => "kernel base hint",
Self::BugcheckDetection => "bugcheck stop detection",
Self::BugcheckDetails => "bugcheck details",
Self::DebugOutput => "debug output",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BackendCapability {
pub capability: DebugCapability,
pub supported: bool,
}
impl BackendCapability {
pub fn supported(capability: DebugCapability) -> Self {
Self {
capability,
supported: true,
}
}
pub fn unsupported(capability: DebugCapability) -> Self {
Self {
capability,
supported: false,
}
}
}
pub trait DebugBackend {
fn register_map(&self) -> &RegisterMap;
fn read_registers(&mut self) -> Result<Vec<u8>>;
fn write_registers(&mut self, data: &[u8]) -> Result<()>;
fn set_breakpoint(&mut self, addr: u64) -> Result<()>;
fn remove_breakpoint(&mut self, addr: u64) -> Result<()>;
fn supports_user_mode_breakpoints(&self) -> bool {
false
}
fn optional_capabilities(&self) -> Vec<BackendCapability> {
vec![
BackendCapability {
capability: DebugCapability::UserModeBreakpoints,
supported: self.supports_user_mode_breakpoints(),
},
BackendCapability::unsupported(DebugCapability::TargetReloadDetection),
BackendCapability::unsupported(DebugCapability::KernelBaseHint),
BackendCapability::unsupported(DebugCapability::BugcheckDetection),
BackendCapability::unsupported(DebugCapability::BugcheckDetails),
BackendCapability::unsupported(DebugCapability::DebugOutput),
]
}
fn capabilities(&self) -> Vec<BackendCapability> {
let mut capabilities = vec![
BackendCapability::supported(DebugCapability::MemoryIntrospection),
BackendCapability::supported(DebugCapability::ExecutionControl),
BackendCapability::supported(DebugCapability::InterruptTarget),
BackendCapability::supported(DebugCapability::SingleStep),
BackendCapability::supported(DebugCapability::ReadRegisters),
BackendCapability::supported(DebugCapability::WriteRegisters),
BackendCapability::supported(DebugCapability::ThreadList),
BackendCapability::supported(DebugCapability::ThreadSelection),
BackendCapability::supported(DebugCapability::KernelBreakpoints),
];
capabilities.extend(self.optional_capabilities());
capabilities
}
fn note_breakpoint_installed(&mut self, _addr: u64) {}
fn note_breakpoint_uninstalled(&mut self, _addr: u64) {}
fn note_target_rediscovery_pending(&mut self) {}
fn note_target_rediscovery_complete(&mut self) {}
fn target_kernel_base_hint(&mut self) -> Result<Option<VirtAddr>> {
Ok(None)
}
fn continue_execution(&mut self) -> Result<()>;
fn step(&mut self) -> Result<()>;
fn interrupt(&mut self) -> Result<StopEvent>;
fn wait_for_stop(&mut self) -> Result<StopEvent>;
fn try_wait_for_stop(&mut self, timeout: Duration) -> Result<Option<StopEvent>>;
fn thread_list(&mut self) -> Result<Vec<String>>;
fn set_current_thread(&mut self, thread_id: &str) -> Result<()>;
fn stopped_thread_id(&mut self) -> Result<String>;
fn is_running(&self) -> bool;
fn prepare_for_exit(&mut self, leave_running: bool) -> Result<()> {
if leave_running && !self.is_running() {
self.continue_execution()?;
}
Ok(())
}
fn take_modules_changed(&mut self) -> bool {
false
}
}