midenc_debug/exec/
host.rs1use std::{collections::BTreeMap, sync::Arc};
2
3use miden_core::crypto::hash::RpoDigest;
4use miden_processor::{
5 AdviceExtractor, AdviceInjector, AdviceProvider, ExecutionError, Host, HostResponse,
6 MastForest, MastForestStore, MemAdviceProvider, MemMastForestStore, ProcessState, RowIndex,
7};
8
9use super::{TraceEvent, TraceHandler};
10
11#[derive(Default)]
15pub struct DebuggerHost {
16 adv_provider: MemAdviceProvider,
17 store: MemMastForestStore,
18 tracing_callbacks: BTreeMap<u32, Vec<Box<TraceHandler>>>,
19 on_assert_failed: Option<Box<TraceHandler>>,
20}
21impl DebuggerHost {
22 pub fn new(adv_provider: MemAdviceProvider) -> Self {
24 Self {
25 adv_provider,
26 store: Default::default(),
27 tracing_callbacks: Default::default(),
28 on_assert_failed: None,
29 }
30 }
31
32 pub fn register_trace_handler<F>(&mut self, event: TraceEvent, callback: F)
34 where
35 F: FnMut(RowIndex, TraceEvent) + 'static,
36 {
37 let key = match event {
38 TraceEvent::AssertionFailed(None) => u32::MAX,
39 ev => ev.into(),
40 };
41 self.tracing_callbacks.entry(key).or_default().push(Box::new(callback));
42 }
43
44 pub fn register_assert_failed_tracer<F>(&mut self, callback: F)
46 where
47 F: FnMut(RowIndex, TraceEvent) + 'static,
48 {
49 self.on_assert_failed = Some(Box::new(callback));
50 }
51
52 pub fn load_mast_forest(&mut self, forest: MastForest) {
54 self.store.insert(forest);
55 }
56}
57
58impl Host for DebuggerHost {
59 fn get_advice<P: ProcessState>(
60 &mut self,
61 process: &P,
62 extractor: AdviceExtractor,
63 ) -> Result<HostResponse, ExecutionError> {
64 self.adv_provider.get_advice(process, &extractor)
65 }
66
67 fn set_advice<P: ProcessState>(
68 &mut self,
69 process: &P,
70 injector: AdviceInjector,
71 ) -> Result<HostResponse, ExecutionError> {
72 self.adv_provider.set_advice(process, &injector)
73 }
74
75 fn get_mast_forest(&self, node_digest: &RpoDigest) -> Option<Arc<MastForest>> {
76 self.store.get(node_digest)
77 }
78
79 fn on_trace<S: ProcessState>(
80 &mut self,
81 process: &S,
82 trace_id: u32,
83 ) -> Result<HostResponse, ExecutionError> {
84 let event = TraceEvent::from(trace_id);
85 let clk = process.clk();
86 if let Some(handlers) = self.tracing_callbacks.get_mut(&trace_id) {
87 for handler in handlers.iter_mut() {
88 handler(clk, event);
89 }
90 }
91 Ok(HostResponse::None)
92 }
93
94 fn on_assert_failed<S: ProcessState>(&mut self, process: &S, err_code: u32) -> ExecutionError {
95 let clk = process.clk();
96 if let Some(handler) = self.on_assert_failed.as_mut() {
97 handler(clk, TraceEvent::AssertionFailed(core::num::NonZeroU32::new(err_code)));
98 }
99 let err_msg = match err_code {
100 midenc_hir::ASSERT_FAILED_ALIGNMENT => Some(
101 "failed alignment: use of memory address violates minimum alignment requirements \
102 for that use"
103 .to_string(),
104 ),
105 _ => None,
106 };
107 ExecutionError::FailedAssertion {
108 clk,
109 err_code,
110 err_msg,
111 }
112 }
113}