//! Debugging functionality
#![allow(missing_docs)]

use abi_serde::{impl_newtype_serde, impl_struct_serde};

pub use crate::generated::TraceLevel;
use crate::{arch::SavedFrame, bitflags, time::SystemTime};

// TODO SetSignal to send signals from the tracer to the tracee
request_group!(
    #[doc = "Debugging/tracing operation on a thread"]
    pub enum DebugControl<'de> {
        /// Attach to a tracee, stopping it
        0x1000: Attach((), ()),
        /// Detach the tracer from the thread, resuming it
        0x1001: Detach((), ()),
        /// Resume stopped tracee, optionally setting it into a single-step mode
        0x1002: Resume(bool, ()),
        /// Returns the current state of tracee's registers.
        ///
        /// Requires stopped tracee.
        0x1003: GetRegisters((), SavedFrame),
        /// Updates the current state of tracee's registers.
        ///
        /// Requires stopped tracee.
        0x1004: SetRegisters(SavedFrame, ()),
        /// Reads an `usize` from tracee's memory space.
        ///
        /// Requires stopped tracee.
        0x1005: ReadMemory(usize, usize),
        /// Writes an `usize` to tracee's memory space.
        ///
        /// Requires stopped tracee.
        0x1006: WriteMemory(WriteTraceeMemory, ()),
        /// Updates trace flags for the tracee.
        0x1007: SetTraceFlags(TraceFlags, ()),
        /// Returns current trace flags of the tracee.
        0x1008: GetTraceFlags((), TraceFlags),
    }
);

/// A request to write into tracee's memory space
#[derive(Debug, Clone, Copy)]
pub struct WriteTraceeMemory {
    /// Address to write to, must be `usize`-aligned
    pub address: usize,
    /// Value to write
    pub value: usize,
}
impl_struct_serde!(WriteTraceeMemory: [
    address,
    value
]);

bitflags! {
    /// Defines which trace events to record
    pub struct TraceFlags: u32 {
        /// Trace system call entries
        const SYSCALL_ENTRY: bit 0;
        /// Trace system call exits
        const SYSCALL_EXIT: bit 1;
    }
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub enum TraceEventPayload {
    SingleStep,
    SyscallEntry(u64),
    SyscallExit(u64),
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct TraceEvent {
    pub suspend: bool,
    pub timestamp: SystemTime,
    pub payload: TraceEventPayload,
}

impl_newtype_serde!(TraceFlags);
