use nix::unistd::Pid;
use crate::{
breakpoint,
debug::{Dwarf, LineInfo},
diag::Result,
print::Layout,
};
pub enum Execution {
Exit,
Run,
Skip,
}
pub enum Mode {
Continue,
StepInto,
StepOver,
StepOverInProgress,
}
pub struct State<'a> {
pid: Pid,
dwarf: Option<&'a Dwarf<'a>>,
breakpoint_mgr: breakpoint::Manager,
layout: Layout,
requested_layout: Option<Layout>,
execution: Execution,
mode: Mode,
prev_rip: Option<u64>,
printed: Option<String>,
}
impl<'a> State<'a> {
#[must_use]
pub fn new(pid: Pid, dwarf: Option<&'a Dwarf<'a>>) -> Self {
Self {
pid,
dwarf,
breakpoint_mgr: breakpoint::Manager::new(pid),
layout: Layout::from(dwarf.is_some()),
requested_layout: None,
execution: Execution::Run,
mode: Mode::StepInto,
prev_rip: None,
printed: None,
}
}
#[must_use]
pub fn pid(&self) -> Pid {
self.pid
}
pub fn addr2line(&self, addr: u64) -> Result<Option<LineInfo>> {
self.dwarf.map_or(Ok(None), |dwarf| dwarf.addr2line(addr))
}
#[must_use]
pub fn initial_layout(&self) -> Layout {
Layout::from(self.dwarf.is_some())
}
#[must_use]
pub fn layout(&self) -> &Layout {
&self.layout
}
pub fn set_layout(&mut self, layout: Layout) {
self.layout = layout;
}
pub fn set_requested_layout(&mut self, layout: Layout) {
self.requested_layout = Some(layout);
}
#[must_use]
pub fn take_requested_layout(&mut self) -> Option<Layout> {
self.requested_layout.take()
}
pub fn breakpoint_mgr(&mut self) -> &mut breakpoint::Manager {
&mut self.breakpoint_mgr
}
pub fn print_breakpoints(&self) {
println!("{}", self.breakpoint_mgr);
}
#[must_use]
pub fn prev_rip(&self) -> Option<u64> {
self.prev_rip
}
pub fn set_prev_rip(&mut self, rip: u64) {
self.prev_rip = Some(rip);
}
#[must_use]
pub fn printed(&self) -> Option<&String> {
self.printed.as_ref()
}
pub fn set_printed(&mut self, printed: Option<String>) {
self.printed = printed;
}
#[must_use]
pub fn execution(&self) -> &Execution {
&self.execution
}
pub fn set_execution(&mut self, execution: Execution) {
self.execution = execution;
}
#[must_use]
pub fn mode(&self) -> &Mode {
&self.mode
}
pub fn set_mode(&mut self, mode: Mode) {
self.mode = mode;
}
}
pub trait ProgressFn = FnMut(&mut State) -> Result<()>;
pub fn default(_: &mut State) -> Result<()> {
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use nix::unistd::Pid;
#[test]
fn test_state_initial_layout_and_pid() {
let pid = Pid::from_raw(1234);
let state: State = State::new(pid, None);
assert_eq!(state.pid(), pid);
assert_eq!(state.initial_layout(), *state.layout());
}
#[test]
fn test_requested_layout_roundtrip() {
let pid = Pid::from_raw(1);
let mut state = State::new(pid, None);
let orig = state.initial_layout();
state.set_requested_layout(orig);
let taken = state.take_requested_layout();
assert!(taken.is_some());
assert_eq!(taken.unwrap(), state.initial_layout());
}
}