use std::ffi::CString;
use std::fmt::Display;
use std::path::PathBuf;
use nix::libc::user_regs_struct;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "plugins")]
use steckrs::PluginIDOwned;
use crate::breakpoint::Breakpoint;
use crate::dbginfo::OwnedSymbol;
use crate::disassemble::Disassembly;
use crate::errors::DebuggerError;
use crate::memorymap::ProcessMemoryMap;
use crate::unwind::Backtrace;
use crate::variable::VariableValue;
use crate::{Addr, Register, Word};
#[non_exhaustive]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "PascalCase")]
pub enum Status {
Backtrace,
StepOver,
StepInto,
StepOut,
StepSingle,
GetSymbolsByName(String),
DisassembleAt(Addr, usize, bool),
DebuggerQuit,
Continue,
SetBreakpoint(Addr),
GetBreakpoint(Addr),
DelBreakpoint(Addr),
DumpRegisters,
SetRegister(Register, u64),
WriteMem(Addr, Word),
ReadMem(Addr),
Infos,
ReadVariable(String),
WriteVariable(String, usize),
GetStack,
ProcMap,
Run(
PathBuf,
#[serde(serialize_with = "serialize_cstring_vec")]
#[serde(deserialize_with = "deserialize_cstring_vec")]
Vec<CString>,
),
SetLastSignal(i32),
#[serde(skip)]
#[cfg(feature = "plugins")]
PluginContinue,
#[cfg(feature = "plugins")]
PluginSetEnable(PluginIDOwned, bool),
#[cfg(feature = "plugins")]
PluginGetStatus(PluginIDOwned),
#[cfg(feature = "plugins")]
PluginGetList,
}
#[non_exhaustive]
#[derive(Debug, Serialize)]
pub enum Feedback {
Word(Word),
Addr(Addr),
Registers(UserRegs),
Error(DebuggerError),
Ok,
Disassembly(Disassembly),
Backtrace(Backtrace),
Symbols(Vec<OwnedSymbol>),
Variable(VariableValue),
Stack(crate::stack::Stack),
ProcessMap(ProcessMemoryMap),
Exit(i32),
Breakpoint(Option<Breakpoint>),
#[cfg(feature = "plugins")]
PluginStatus(Option<bool>),
#[cfg(feature = "plugins")]
PluginList(Vec<(PluginIDOwned, bool)>),
#[serde(skip)]
#[allow(private_interfaces)] Internal(InternalFeedback),
}
#[derive(Debug)]
#[non_exhaustive]
pub(crate) enum InternalFeedback {
Quit,
}
impl Display for Feedback {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Feedback::Ok => write!(f, "Ok")?,
Feedback::Error(e) => write!(f, "Error: {e}")?,
Feedback::Registers(regs) => write!(f, "Registers: {regs:#x?}")?,
Feedback::Word(w) => write!(f, "Word: {w:#018x?}")?,
Feedback::Addr(w) => write!(f, "Address: {w}")?,
Feedback::Disassembly(t) => write!(f, "{t:#?}")?,
Feedback::Symbols(t) => write!(f, "Symbols: {t:#?}")?,
Feedback::Backtrace(t) => write!(f, "Backtrace: {t:#?}")?,
Feedback::Variable(t) => write!(f, "Variable: {t:#?}")?,
Feedback::Stack(t) => write!(f, "Stack:\n{t}")?,
Feedback::ProcessMap(pm) => write!(f, "Process Map:\n{pm:#x?}")?,
Feedback::Exit(code) => write!(f, "Debugee exited with code {code}")?,
Feedback::Breakpoint(bp) => write!(f, "Breakpoint: {bp:?}")?,
Feedback::Internal(_) => write!(f, "Internal Feedback")?,
#[cfg(feature = "plugins")]
Feedback::PluginStatus(ps) => write!(f, "Plugin Status: {ps:?}")?,
#[cfg(feature = "plugins")]
Feedback::PluginList(list) => {
write!(f, "Plugin List:")?;
for (pl, s) in list {
write!(f, "\n {pl:<20}: {s}")?;
}
}
}
Ok(())
}
}
impl From<Result<Feedback, DebuggerError>> for Feedback {
fn from(value: Result<Feedback, DebuggerError>) -> Self {
match value {
Ok(f) => f,
Err(e) => Feedback::Error(e),
}
}
}
#[derive(Debug, Clone, Serialize)]
#[allow(missing_docs)] pub struct UserRegs {
pub r15: u64,
pub r14: u64,
pub r13: u64,
pub r12: u64,
pub rbp: u64,
pub rbx: u64,
pub r11: u64,
pub r10: u64,
pub r9: u64,
pub r8: u64,
pub rax: u64,
pub rcx: u64,
pub rdx: u64,
pub rsi: u64,
pub rdi: u64,
pub orig_rax: u64,
pub rip: u64,
pub cs: u64,
pub eflags: u64,
pub rsp: u64,
pub ss: u64,
pub fs_base: u64,
pub gs_base: u64,
pub ds: u64,
pub es: u64,
pub fs: u64,
pub gs: u64,
}
impl From<user_regs_struct> for UserRegs {
fn from(regs: user_regs_struct) -> Self {
Self {
r15: regs.r15,
r14: regs.r14,
r13: regs.r13,
r12: regs.r12,
rbp: regs.rbp,
rbx: regs.rbx,
r11: regs.r11,
r10: regs.r10,
r9: regs.r9,
r8: regs.r8,
rax: regs.rax,
rcx: regs.rcx,
rdx: regs.rdx,
rsi: regs.rsi,
rdi: regs.rdi,
orig_rax: regs.orig_rax,
rip: regs.rip,
cs: regs.cs,
eflags: regs.eflags,
rsp: regs.rsp,
ss: regs.ss,
fs_base: regs.fs_base,
gs_base: regs.gs_base,
ds: regs.ds,
es: regs.es,
fs: regs.fs,
gs: regs.gs,
}
}
}
fn serialize_cstring_vec<S>(items: &[CString], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let strings: Vec<&str> = items
.iter()
.map(|c| c.to_str().map_err(serde::ser::Error::custom))
.collect::<Result<_, _>>()?;
strings.serialize(serializer)
}
fn deserialize_cstring_vec<'de, D>(deserializer: D) -> Result<Vec<CString>, D::Error>
where
D: Deserializer<'de>,
{
let strings: Vec<String> = Vec::deserialize(deserializer)?;
strings
.into_iter()
.map(|s| CString::new(s).map_err(serde::de::Error::custom))
.collect()
}