use nix::sys::ptrace;
use nix::unistd::Pid;
use crate::error::{Error, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RegisterType {
GeneralPurpose,
InstructionPointer,
Flags,
Segment,
}
#[derive(Debug, Clone, Copy)]
pub struct RegisterInfo {
pub name: &'static str,
pub dwarf_id: i32,
pub reg_type: RegisterType,
}
pub const REGISTERS: &[RegisterInfo] = &[
RegisterInfo {
name: "rax",
dwarf_id: 0,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "rdx",
dwarf_id: 1,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "rcx",
dwarf_id: 2,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "rbx",
dwarf_id: 3,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "rsi",
dwarf_id: 4,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "rdi",
dwarf_id: 5,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "rbp",
dwarf_id: 6,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "rsp",
dwarf_id: 7,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "r8",
dwarf_id: 8,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "r9",
dwarf_id: 9,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "r10",
dwarf_id: 10,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "r11",
dwarf_id: 11,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "r12",
dwarf_id: 12,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "r13",
dwarf_id: 13,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "r14",
dwarf_id: 14,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "r15",
dwarf_id: 15,
reg_type: RegisterType::GeneralPurpose,
},
RegisterInfo {
name: "rip",
dwarf_id: 16,
reg_type: RegisterType::InstructionPointer,
},
RegisterInfo {
name: "rflags",
dwarf_id: 49,
reg_type: RegisterType::Flags,
},
RegisterInfo {
name: "cs",
dwarf_id: 51,
reg_type: RegisterType::Segment,
},
RegisterInfo {
name: "ss",
dwarf_id: 52,
reg_type: RegisterType::Segment,
},
RegisterInfo {
name: "orig_rax",
dwarf_id: -1,
reg_type: RegisterType::GeneralPurpose,
},
];
pub struct Registers {
regs: libc::user_regs_struct,
}
impl Registers {
pub fn read(pid: Pid) -> Result<Self> {
let regs = ptrace::getregs(pid)?;
Ok(Registers { regs })
}
pub fn write(&self, pid: Pid) -> Result<()> {
ptrace::setregs(pid, self.regs)?;
Ok(())
}
pub fn get(&self, name: &str) -> Result<u64> {
match name {
"rax" => Ok(self.regs.rax),
"rbx" => Ok(self.regs.rbx),
"rcx" => Ok(self.regs.rcx),
"rdx" => Ok(self.regs.rdx),
"rsi" => Ok(self.regs.rsi),
"rdi" => Ok(self.regs.rdi),
"rbp" => Ok(self.regs.rbp),
"rsp" => Ok(self.regs.rsp),
"r8" => Ok(self.regs.r8),
"r9" => Ok(self.regs.r9),
"r10" => Ok(self.regs.r10),
"r11" => Ok(self.regs.r11),
"r12" => Ok(self.regs.r12),
"r13" => Ok(self.regs.r13),
"r14" => Ok(self.regs.r14),
"r15" => Ok(self.regs.r15),
"rip" => Ok(self.regs.rip),
"rflags" | "eflags" => Ok(self.regs.eflags),
"cs" => Ok(self.regs.cs),
"ss" => Ok(self.regs.ss),
"orig_rax" => Ok(self.regs.orig_rax),
_ => Err(Error::Register(format!("unknown register: {}", name))),
}
}
pub fn set(&mut self, name: &str, value: u64) -> Result<()> {
match name {
"rax" => self.regs.rax = value,
"rbx" => self.regs.rbx = value,
"rcx" => self.regs.rcx = value,
"rdx" => self.regs.rdx = value,
"rsi" => self.regs.rsi = value,
"rdi" => self.regs.rdi = value,
"rbp" => self.regs.rbp = value,
"rsp" => self.regs.rsp = value,
"r8" => self.regs.r8 = value,
"r9" => self.regs.r9 = value,
"r10" => self.regs.r10 = value,
"r11" => self.regs.r11 = value,
"r12" => self.regs.r12 = value,
"r13" => self.regs.r13 = value,
"r14" => self.regs.r14 = value,
"r15" => self.regs.r15 = value,
"rip" => self.regs.rip = value,
"rflags" | "eflags" => self.regs.eflags = value,
"cs" => self.regs.cs = value,
"ss" => self.regs.ss = value,
_ => return Err(Error::Register(format!("unknown register: {}", name))),
}
Ok(())
}
pub fn pc(&self) -> u64 {
self.regs.rip
}
pub fn set_pc(&mut self, addr: u64) {
self.regs.rip = addr;
}
pub fn raw(&self) -> &libc::user_regs_struct {
&self.regs
}
pub fn get_by_dwarf_id(&self, dwarf_id: i32) -> Result<u64> {
let info = REGISTERS
.iter()
.find(|r| r.dwarf_id == dwarf_id)
.ok_or_else(|| Error::Register(format!("unknown DWARF reg: {}", dwarf_id)))?;
self.get(info.name)
}
pub fn iter(&self) -> impl Iterator<Item = (&'static str, u64)> + '_ {
REGISTERS
.iter()
.filter_map(move |info| self.get(info.name).ok().map(|v| (info.name, v)))
}
}