Skip to content

Commit 03b5d7e

Browse files
committed
feat: tried to abstract stepping/loading locals for db and rr
loading locals still TODO in rr; overally not very tested in db
1 parent d8fa03e commit 03b5d7e

File tree

5 files changed

+175
-115
lines changed

5 files changed

+175
-115
lines changed

src/db-backend/src/db.rs

Lines changed: 113 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::distinct_vec::DistinctVec;
1515
use crate::expr_loader::ExprLoader;
1616
use crate::lang::Lang;
1717
use crate::replay::{Events, Replay};
18-
use crate::task::{Call, CallArg, Location, ProgramEvent, RRTicks, NO_INDEX, NO_PATH, NO_POSITION};
18+
use crate::task::{Action, Call, CallArg, Location, ProgramEvent, RRTicks, NO_INDEX, NO_PATH, NO_POSITION, CtLoadLocalsArguments, Variable};
1919
use crate::value::{Type, Value};
2020

2121
const NEXT_INTERNAL_STEP_OVERS_LIMIT: usize = 1_000;
@@ -773,15 +773,25 @@ pub enum EndOfProgram {
773773
// pub place: Place,
774774
// }
775775

776+
#[derive(Debug, Clone, Serialize, Deserialize)]
777+
pub struct BreakpointRecord {
778+
pub is_active: bool,
779+
}
780+
781+
// type LineTraceMap = HashMap<usize, Vec<(usize, String)>>;
782+
776783
#[derive(Debug)]
777784
pub struct DbReplay {
778785
pub db: Box<Db>,
779786
pub step_id: StepId,
787+
pub breakpoint_list: Vec<HashMap<usize, BreakpointRecord>>,
780788
}
781789

782790
impl DbReplay {
783791
pub fn new(db: Box<Db>) -> DbReplay {
784-
DbReplay { db, step_id: StepId(0) }
792+
let mut breakpoint_list: Vec<HashMap<usize, BreakpointRecord>> = Default::default();
793+
breakpoint_list.resize_with(db.paths.len(), HashMap::new);
794+
DbReplay { db, step_id: StepId(0), breakpoint_list }
785795
}
786796

787797
pub fn step_id_jump(&mut self, step_id: StepId) {
@@ -850,6 +860,65 @@ impl DbReplay {
850860
step_index
851861
}
852862
}
863+
864+
fn step_in(&mut self, forward: bool) -> Result<bool, Box<dyn Error>> {
865+
self.step_id = StepId(self.single_step_line(self.step_id.0 as usize, forward) as i64);
866+
Ok(true)
867+
}
868+
869+
fn step_out(&mut self, forward: bool) -> Result<bool, Box<dyn Error>> {
870+
(self.step_id, _) = self.db.step_out_step_id_relative_to(self.step_id, forward);
871+
Ok(true)
872+
}
873+
874+
fn next(&mut self, forward: bool) -> Result<bool, Box<dyn Error>> {
875+
let step_to_different_line = true; // which is better/should be let the user configure it?
876+
(self.step_id, _) = self
877+
.db
878+
.next_step_id_relative_to(self.step_id, forward, step_to_different_line);
879+
Ok(true)
880+
}
881+
882+
// returns if it has hit any breakpoints
883+
fn step_continue(&mut self, forward: bool) -> Result<bool, Box<dyn Error>> {
884+
for step in self.db.step_from(self.step_id, forward) {
885+
if !self.breakpoint_list.is_empty() {
886+
if let Some(is_active) = self.breakpoint_list[step.path_id.0]
887+
.get(&step.line.into())
888+
.map(|bp| bp.is_active)
889+
{
890+
if is_active {
891+
self.step_id_jump(step.step_id);
892+
// true: has hit a breakpoint
893+
return Ok(true);
894+
}
895+
}
896+
} else {
897+
break;
898+
}
899+
}
900+
901+
// If the continue step doesn't find a valid breakpoint.
902+
if forward {
903+
self.step_id_jump(
904+
self.db
905+
.steps
906+
.last()
907+
.expect("unexpected 0 steps in trace for step_continue")
908+
.step_id,
909+
);
910+
} else {
911+
self.step_id_jump(
912+
self.db
913+
.steps
914+
.first()
915+
.expect("unexpected 0 steps in trace for step_continue")
916+
.step_id,
917+
)
918+
}
919+
// false: hasn't hit a breakpoint
920+
Ok(false)
921+
}
853922
}
854923

855924
impl Replay for DbReplay {
@@ -886,12 +955,50 @@ impl Replay for DbReplay {
886955
})
887956
}
888957

889-
fn step_in(&mut self, forward: bool) -> Result<(), Box<dyn Error>> {
890-
self.step_id = StepId(self.single_step_line(self.step_id.0 as usize, forward) as i64);
891-
Ok(())
958+
// for Ok cases:
959+
// continue returns if it has hit any breakpoints, others return always true
960+
fn step(&mut self, action: Action, forward: bool) -> Result<bool, Box<dyn Error>> {
961+
match action {
962+
Action::StepIn => self.step_in(forward),
963+
Action::StepOut => self.step_out(forward),
964+
Action::Next => self.next(forward),
965+
Action::Continue => self.step_continue(forward),
966+
_ => todo!(),
967+
}
892968
}
893969

894-
fn current_step_id(&self) -> StepId {
970+
fn load_locals(&mut self, _arg: CtLoadLocalsArguments) -> Result<Vec<Variable>, Box<dyn Error>> {
971+
let full_value_locals: Vec<Variable> = self.db.variables[self.step_id]
972+
.iter()
973+
.map(|v| Variable {
974+
expression: self.db.variable_name(v.variable_id).to_string(),
975+
value: self.db.to_ct_value(&v.value),
976+
})
977+
.collect();
978+
979+
// TODO: fix random order here as well: ensure order(or in final locals?)
980+
let value_tracking_locals: Vec<Variable> = self.db.variable_cells[self.step_id]
981+
.iter()
982+
.map(|(variable_id, place)| {
983+
let name = self.db.variable_name(*variable_id);
984+
info!("log local {variable_id:?} {name} place: {place:?}");
985+
let value = self.db.load_value_for_place(*place, self.step_id);
986+
Variable {
987+
expression: self.db.variable_name(*variable_id).to_string(),
988+
value: self.db.to_ct_value(&value),
989+
}
990+
})
991+
.collect();
992+
// based on https://stackoverflow.com/a/56490417/438099
993+
let mut locals: Vec<Variable> = full_value_locals.into_iter().chain(value_tracking_locals).collect();
994+
995+
locals.sort_by(|left, right| Ord::cmp(&left.expression, &right.expression));
996+
// for now just removing duplicated variables/expressions: even if storing different values
997+
locals.dedup_by(|a, b| a.expression == b.expression);
998+
999+
Ok(locals)
1000+
}
1001+
fn current_step_id(&mut self) -> StepId {
8951002
self.step_id
8961003
}
8971004
}

src/db-backend/src/handler.rs

Lines changed: 32 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use runtime_tracing::{CallKey, EventLogKind, Line, PathId, StepId, VariableId, N
1010

1111
use crate::calltrace::Calltrace;
1212
use crate::dap::{self, DapClient, DapMessage};
13-
use crate::db::{Db, DbCall, DbRecordEvent, DbReplay, DbStep};
13+
use crate::db::{BreakpointRecord, Db, DbCall, DbRecordEvent, DbReplay, DbStep};
1414
use crate::event_db::{EventDb, SingleTableId};
1515
use crate::expr_loader::ExprLoader;
1616
use crate::flow_preloader::FlowPreloader;
@@ -66,13 +66,6 @@ pub enum TraceKind {
6666
RR,
6767
}
6868

69-
#[derive(Debug, Clone, Serialize, Deserialize)]
70-
pub struct BreakpointRecord {
71-
pub is_active: bool,
72-
}
73-
74-
type LineTraceMap = HashMap<usize, Vec<(usize, String)>>;
75-
7669
// two choices:
7770
// return results and potentially
7871
// generate multiple events as a generator
@@ -338,44 +331,17 @@ impl Handler {
338331
Ok(())
339332
}
340333

341-
pub fn load_locals(&mut self, req: dap::Request, _args: task::CtLoadLocalsArguments) -> Result<(), Box<dyn Error>> {
342-
if self.trace_kind == TraceKind::RR {
343-
let locals: Vec<Variable> = vec![];
344-
warn!("load_locals not implemented for rr yet");
334+
pub fn load_locals(&mut self, req: dap::Request, args: task::CtLoadLocalsArguments) -> Result<(), Box<dyn Error>> {
335+
// if self.trace_kind == TraceKind::RR {
336+
// let locals: Vec<Variable> = vec![];
337+
// warn!("load_locals not implemented for rr yet");
338+
let locals = self.replay.load_locals(args)?;
345339
self.respond_dap(req, task::CtLoadLocalsResponseBody { locals })?;
346-
return Ok(());
347-
}
348-
349-
let full_value_locals: Vec<Variable> = self.db.variables[self.step_id]
350-
.iter()
351-
.map(|v| Variable {
352-
expression: self.db.variable_name(v.variable_id).to_string(),
353-
value: self.db.to_ct_value(&v.value),
354-
})
355-
.collect();
356-
357-
// TODO: fix random order here as well: ensure order(or in final locals?)
358-
let value_tracking_locals: Vec<Variable> = self.db.variable_cells[self.step_id]
359-
.iter()
360-
.map(|(variable_id, place)| {
361-
let name = self.db.variable_name(*variable_id);
362-
info!("log local {variable_id:?} {name} place: {place:?}");
363-
let value = self.db.load_value_for_place(*place, self.step_id);
364-
Variable {
365-
expression: self.db.variable_name(*variable_id).to_string(),
366-
value: self.db.to_ct_value(&value),
367-
}
368-
})
369-
.collect();
370-
// based on https://stackoverflow.com/a/56490417/438099
371-
let mut locals: Vec<Variable> = full_value_locals.into_iter().chain(value_tracking_locals).collect();
372-
373-
locals.sort_by(|left, right| Ord::cmp(&left.expression, &right.expression));
374-
// for now just removing duplicated variables/expressions: even if storing different values
375-
locals.dedup_by(|a, b| a.expression == b.expression);
340+
Ok(())
341+
// }
376342

377-
self.respond_dap(req, task::CtLoadLocalsResponseBody { locals })?;
378-
Ok(())
343+
// self.respond_dap(req, task::CtLoadLocalsResponseBody { locals })?;
344+
// Ok(())
379345
}
380346

381347
// pub fn load_callstack(&mut self, task: Task) -> Result<(), Box<dyn Error>> {
@@ -563,7 +529,7 @@ impl Handler {
563529
}
564530

565531
pub fn step_in(&mut self, forward: bool) -> Result<(), Box<dyn Error>> {
566-
self.replay.step_in(forward)?;
532+
self.replay.step(Action::StepIn, forward)?;
567533
self.step_id = self.replay.current_step_id();
568534

569535
Ok(())
@@ -596,57 +562,23 @@ impl Handler {
596562
}
597563

598564
pub fn next(&mut self, forward: bool) -> Result<(), Box<dyn Error>> {
599-
let step_to_different_line = true; // which is better/should be let the user configure it?
600-
(self.step_id, _) = self
601-
.db
602-
.next_step_id_relative_to(self.step_id, forward, step_to_different_line);
565+
self.replay.step(Action::Next, forward)?;
566+
self.step_id = self.replay.current_step_id();
603567
Ok(())
604568
}
605569

606570
pub fn step_out(&mut self, forward: bool) -> Result<(), Box<dyn Error>> {
607-
(self.step_id, _) = self.db.step_out_step_id_relative_to(self.step_id, forward);
571+
self.replay.step(Action::StepOut, forward)?;
572+
self.step_id = self.replay.current_step_id();
608573
Ok(())
609574
}
610575

611576
#[allow(clippy::expect_used)]
612577
pub fn step_continue(&mut self, forward: bool) -> Result<(), Box<dyn Error>> {
613-
for step in self.db.step_from(self.step_id, forward) {
614-
if !self.breakpoint_list.is_empty() {
615-
if let Some(is_active) = self.breakpoint_list[step.path_id.0]
616-
.get(&step.line.into())
617-
.map(|bp| bp.is_active)
618-
{
619-
if is_active {
620-
self.step_id_jump(step.step_id);
621-
self.complete_move(false)?;
622-
return Ok(());
623-
}
624-
}
625-
} else {
626-
break;
627-
}
578+
if !self.replay.step(Action::Continue, forward)? {
579+
self.send_notification(NotificationKind::Info, "No breakpoints were hit!", false)?;
628580
}
629-
630-
// If the continue step doesn't find a valid breakpoint.
631-
if forward {
632-
self.step_id_jump(
633-
self.db
634-
.steps
635-
.last()
636-
.expect("unexpected 0 steps in trace for step_continue")
637-
.step_id,
638-
);
639-
} else {
640-
self.step_id_jump(
641-
self.db
642-
.steps
643-
.first()
644-
.expect("unexpected 0 steps in trace for step_continue")
645-
.step_id,
646-
)
647-
}
648-
self.complete_move(false)?;
649-
self.send_notification(NotificationKind::Info, "No breakpoints were hit!", false)?;
581+
self.step_id = self.replay.current_step_id();
650582
Ok(())
651583
}
652584

@@ -663,21 +595,23 @@ impl Handler {
663595
Action::Continue => self.step_continue(!arg.reverse)?,
664596
_ => error!("action {:?} not implemented", arg.action),
665597
}
666-
if arg.complete && arg.action != Action::Continue {
598+
if arg.complete { // && arg.action != Action::Continue {
667599
self.complete_move(false)?;
668600
}
669601

670-
if original_step_id == self.step_id {
671-
let location = if self.step_id == StepId(0) { "beginning" } else { "end" };
672-
self.send_notification(
673-
NotificationKind::Warning,
674-
&format!("Limit of record at the {location} already reached!"),
675-
false,
676-
)?;
677-
} else if self.step_id == StepId(0) {
678-
self.send_notification(NotificationKind::Info, "Beginning of record reached", false)?;
679-
} else if self.step_id.0 as usize == self.db.steps.len() - 1 {
680-
self.send_notification(NotificationKind::Info, "End of record reached", false)?;
602+
if self.trace_kind == TraceKind::DB {
603+
if original_step_id == self.step_id {
604+
let location = if self.step_id == StepId(0) { "beginning" } else { "end" };
605+
self.send_notification(
606+
NotificationKind::Warning,
607+
&format!("Limit of record at the {location} already reached!"),
608+
false,
609+
)?;
610+
} else if self.step_id == StepId(0) {
611+
self.send_notification(NotificationKind::Info, "Beginning of record reached", false)?;
612+
} else if self.step_id.0 as usize == self.db.steps.len() - 1 {
613+
self.send_notification(NotificationKind::Info, "End of record reached", false)?;
614+
}
681615
}
682616
// } else if arg.action == Action::Next {
683617
// let new_step = self.db.steps[self.step_id];

src/db-backend/src/query.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
use serde::{Deserialize, Serialize};
22

3+
use crate::task::{Action, CtLoadLocalsArguments};
4+
35
#[derive(Debug, Clone, Serialize, Deserialize)]
46
#[serde(tag = "kind")]
57
pub enum CtRRQuery {
68
RunToEntry,
79
LoadLocation,
10+
Step { action: Action, forward: bool },
11+
LoadLocals { arg: CtLoadLocalsArguments },
812
}

src/db-backend/src/replay.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use runtime_tracing::StepId;
22
use std::error::Error;
33

44
use crate::expr_loader::ExprLoader;
5-
use crate::task::{Location, ProgramEvent};
5+
use crate::task::{Action, Location, ProgramEvent, CtLoadLocalsArguments, Variable};
66

77
#[derive(Debug, Clone)]
88
pub struct Events {
@@ -15,6 +15,7 @@ pub trait Replay: std::fmt::Debug {
1515
fn load_location(&mut self, expr_loader: &mut ExprLoader) -> Result<Location, Box<dyn Error>>;
1616
fn run_to_entry(&mut self) -> Result<(), Box<dyn Error>>;
1717
fn load_events(&mut self) -> Result<Events, Box<dyn Error>>;
18-
fn step_in(&mut self, forward: bool) -> Result<(), Box<dyn Error>>;
19-
fn current_step_id(&self) -> StepId;
18+
fn step(&mut self, action: Action, forward: bool) -> Result<bool, Box<dyn Error>>;
19+
fn load_locals(&mut self, arg: CtLoadLocalsArguments) -> Result<Vec<Variable>, Box<dyn Error>>;
20+
fn current_step_id(&mut self) -> StepId;
2021
}

0 commit comments

Comments
 (0)