Skip to content

Commit

Permalink
feat: expand capabiliies of the debug instruction
Browse files Browse the repository at this point in the history
  • Loading branch information
Fumuran committed Oct 13, 2023
1 parent 6d8cb96 commit e13205f
Show file tree
Hide file tree
Showing 6 changed files with 369 additions and 6 deletions.
42 changes: 40 additions & 2 deletions assembly/src/assembler/instruction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::{
};
use crate::utils::bound_into_included_u64;
use core::ops::RangeBounds;
use vm_core::{Decorator, FieldElement, StarkField};
use vm_core::{DebugOptions, Decorator, FieldElement, StarkField};

mod adv_ops;
mod crypto_ops;
Expand Down Expand Up @@ -339,7 +339,7 @@ impl Assembler {

Instruction::Debug(options) => {
if self.in_debug_mode() {
span.push_decorator(Decorator::Debug(*options))
span.push_decorator(process_debug_options(ctx, options)?)
}
Ok(None)
}
Expand Down Expand Up @@ -408,3 +408,41 @@ where
)
})
}

/// Returns a [Decorator::Debug] created with provided information and procedure context.
///
/// This function is used to create a [DebugOptions] instance based on information about number of
/// procedure locals from the procedure context.
fn process_debug_options(
ctx: &AssemblyContext,
options: &DebugOptions,
) -> Result<Decorator, AssemblyError> {
let num_locals = ctx.num_proc_locals() as u32;
match options {
DebugOptions::LocalIndex(n) => {
if *n >= num_locals {
return Err(AssemblyError::ParsingError(format!(
"Local addres should be less than {}, but {} was provided",
num_locals, n
)));
}
Ok(Decorator::Debug(*options))
}
DebugOptions::LocalInterval(_, m, print_all) => {
if *print_all {
let locals_all = DebugOptions::LocalInterval(0, num_locals - 1, true);
Ok(Decorator::Debug(locals_all))
} else {
if *m >= num_locals {
return Err(AssemblyError::ParsingError(format!("The index of the end of the interval should be less than {}, but {} was provided", num_locals, m)));
}
Ok(Decorator::Debug(*options))
}
}
DebugOptions::All(_) => {
let all = DebugOptions::All(ctx.num_proc_locals());
Ok(Decorator::Debug(all))
}
_ => Ok(Decorator::Debug(*options)),
}
}
54 changes: 54 additions & 0 deletions assembly/src/ast/nodes/serde/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ use super::{super::DebugOptions, ByteReader, ByteWriter, DeserializationError, T

const STACK_ALL: u8 = 0;
const STACK_TOP: u8 = 1;
const MEM_ALL: u8 = 2;
const MEM_ADDR: u8 = 3;
const MEM_INTERVAL: u8 = 4;
const LOCAL_INDEX: u8 = 5;
const LOCAL_INTERVAL: u8 = 6;
const ALL: u8 = 7;

/// Writes the provided [DebugOptions] into the provided target.
pub fn write_options_into<W: ByteWriter>(target: &mut W, options: &DebugOptions) {
Expand All @@ -11,6 +17,30 @@ pub fn write_options_into<W: ByteWriter>(target: &mut W, options: &DebugOptions)
target.write_u8(STACK_TOP);
target.write_u16(*n);
}
DebugOptions::MemAll => target.write_u8(MEM_ALL),
DebugOptions::MemAddr(n) => {
target.write_u8(MEM_ADDR);
target.write_u32(*n);
}
DebugOptions::MemInterval(n, m) => {
target.write_u8(MEM_INTERVAL);
target.write_u32(*n);
target.write_u32(*m);
}
DebugOptions::LocalIndex(n) => {
target.write_u8(LOCAL_INDEX);
target.write_u32(*n);
}
DebugOptions::LocalInterval(n, m, print_all) => {
target.write_u8(LOCAL_INTERVAL);
target.write_u32(*n);
target.write_u32(*m);
target.write_bool(*print_all);
}
DebugOptions::All(num_locals) => {
target.write_u8(ALL);
target.write_u16(*num_locals);
}
}
}

Expand All @@ -27,6 +57,30 @@ pub fn read_options_from<R: ByteReader>(
}
Ok(DebugOptions::StackTop(n))
}
MEM_ALL => Ok(DebugOptions::MemAll),
MEM_ADDR => {
let n = source.read_u32()?;
Ok(DebugOptions::MemAddr(n))
}
MEM_INTERVAL => {
let n = source.read_u32()?;
let m = source.read_u32()?;
Ok(DebugOptions::MemInterval(n, m))
}
LOCAL_INDEX => {
let n = source.read_u32()?;
Ok(DebugOptions::LocalIndex(n))
}
LOCAL_INTERVAL => {
let n = source.read_u32()?;
let m = source.read_u32()?;
let print_all = source.read_bool()?;
Ok(DebugOptions::LocalInterval(n, m, print_all))
}
ALL => {
let num_locals = source.read_u16()?;
Ok(DebugOptions::All(num_locals))
}
val => Err(DeserializationError::InvalidValue(val.to_string())),
}
}
33 changes: 33 additions & 0 deletions assembly/src/ast/parsers/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,39 @@ pub fn parse_debug(op: &Token) -> Result<Node, ParsingError> {
}
_ => return Err(ParsingError::extra_param(op)),
},
"mem" => match op.num_parts() {
2 => DebugOptions::MemAll,
3 => {
let n: u32 = parse_checked_param(op, 2, 1..=u32::MAX)?;
DebugOptions::MemAddr(n)
}
4 => {
let n: u32 = parse_checked_param(op, 2, 0..=u32::MAX)?;
let m: u32 = parse_checked_param(op, 3, 0..=u32::MAX)?;
if m < n {
return Err(ParsingError::invalid_param_with_reason(op, 3, "the index of the end of the interval must be greater than the index of its beginning"));
}
DebugOptions::MemInterval(n, m)
}
_ => return Err(ParsingError::extra_param(op)),
},
"local" => match op.num_parts() {
2 => DebugOptions::LocalInterval(0, 0, true),
3 => {
let n: u32 = parse_checked_param(op, 2, 0..=u32::MAX)?;
DebugOptions::LocalIndex(n)
}
4 => {
let n: u32 = parse_checked_param(op, 2, 0..=u32::MAX)?;
let m: u32 = parse_checked_param(op, 3, 0..=u32::MAX)?;
if m < n {
return Err(ParsingError::invalid_param_with_reason(op, 3, "the index of the end of the interval must be greater than the index of its beginning"));
}
DebugOptions::LocalInterval(n, m, false)
}
_ => return Err(ParsingError::extra_param(op)),
},
"all" => DebugOptions::All(0),
_ => return Err(ParsingError::invalid_op(op)),
};

Expand Down
27 changes: 27 additions & 0 deletions core/src/operations/decorators/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,40 @@ pub enum DebugOptions {
StackAll,
/// Prints out the top n items of the stack for the current context.
StackTop(u16),
/// Prints out the entire contents of RAM.
MemAll,
/// Prints out contents of memory at the provided address.
MemAddr(u32),
/// Prints out the contents of memory stored in the provided interval. Interval boundaries are
/// both inclusive.
MemInterval(u32, u32),
/// Prints out contents of the local at the provided index for the currently executing
/// procedure.
LocalIndex(u32),
/// Prints out locals stored in the provided interval of the currently executing procedure.
/// Interval boundaries are both inclusive.
LocalInterval(u32, u32, bool),
/// Prints out the entire state of the VM (stack and RAM).
All(u16),
}

impl fmt::Display for DebugOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::StackAll => write!(f, "stack"),
Self::StackTop(n) => write!(f, "stack.{n}"),
Self::MemAll => write!(f, "mem"),
Self::MemAddr(n) => write!(f, "mem.{n}"),
Self::MemInterval(n, m) => write!(f, "mem.{n}.{m}"),
Self::LocalIndex(n) => write!(f, "local.{n}"),
Self::LocalInterval(n, m, print_all) => {
if *print_all {
write!(f, "local")
} else {
write!(f, "local.{n}.{m}")
}
}
Self::All(_) => write!(f, "all"),
}
}
}
Loading

0 comments on commit e13205f

Please sign in to comment.