From e1cacaecaaaffe811a2d11423b83a9bf4c7eb33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sm=C3=B3=C5=82ka?= Date: Thu, 28 May 2026 00:44:37 +0200 Subject: [PATCH] Handle multi-map of Sierra to Cairo variables --- Cargo.lock | 224 ++++++++++++++------- Cargo.toml | 10 +- src/debugger/context.rs | 67 +++++- src/debugger/context/variables.rs | 116 +++++++++-- src/debugger/state/call_stack.rs | 26 ++- src/debugger/state/call_stack/variables.rs | 41 +++- 6 files changed, 369 insertions(+), 115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d9d7b25..24810de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,18 +67,18 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bit-set" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +checksum = "34ddef2995421ab6a5c779542c81ee77c115206f4ad9d5a8e05f4ff49716a3dd" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" [[package]] name = "bitflags" @@ -104,7 +104,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -116,6 +116,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "borsh" version = "1.6.0" @@ -152,18 +161,16 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cairo-annotations" version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e954fe93c0783b0f314977abbc9a94799cc4f217c2873616db8cdb368e036de" +source = "git+https://github.com/software-mansion/cairo-annotations?branch=debugger-annotations-v2#2b8e2a4c043f40510d4c0e026137eaca208d52b2" dependencies = [ "cairo-lang-sierra", "cairo-lang-sierra-to-casm", "cairo-lang-sierra-type-size", "camino", "derive_more", - "regex", "serde", "serde_json", - "starknet-types-core", + "starknet-types-core 1.0.0", "strum", "strum_macros", "thiserror 2.0.18", @@ -184,15 +191,14 @@ dependencies = [ "indexmap", "scarb-metadata", "serde_json", - "starknet-types-core", + "starknet-types-core 0.2.4", "tracing", ] [[package]] name = "cairo-lang-casm" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ba7355bf81c515c65e2359593deef373678e719f4847e2a7de82e5cde7a042" +version = "2.18.0" +source = "git+https://github.com/starkware-libs/cairo?branch=debugger-annotations-v2%2Fsemantic-mapping#3efa3eb9169a1f9f246be5ebf87a82580b8774bc" dependencies = [ "cairo-lang-utils", "indoc", @@ -204,9 +210,8 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3898ff7b4c1cdb0bb1b126985e900421cbdb829b4a0282e3cf5980a3925c186" +version = "2.18.0" +source = "git+https://github.com/starkware-libs/cairo?branch=debugger-annotations-v2%2Fsemantic-mapping#3efa3eb9169a1f9f246be5ebf87a82580b8774bc" dependencies = [ "cairo-lang-utils", "good_lp", @@ -214,9 +219,8 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502621e024cee958383911a0f452dd5ca9f28fb38a19af1c5495959e37a3eb61" +version = "2.18.0" +source = "git+https://github.com/starkware-libs/cairo?branch=debugger-annotations-v2%2Fsemantic-mapping#3efa3eb9169a1f9f246be5ebf87a82580b8774bc" dependencies = [ "anyhow", "cairo-lang-utils", @@ -232,17 +236,16 @@ dependencies = [ "regex", "serde", "serde_json", - "sha3", + "sha3 0.11.0", "smol_str", - "starknet-types-core", + "starknet-types-core 0.2.4", "thiserror 2.0.18", ] [[package]] name = "cairo-lang-sierra-ap-change" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c66ee91c74c1904ef34baa459ba15f6a0862a512bbb21bd31d28c74adeded0d" +version = "2.18.0" +source = "git+https://github.com/starkware-libs/cairo?branch=debugger-annotations-v2%2Fsemantic-mapping#3efa3eb9169a1f9f246be5ebf87a82580b8774bc" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -256,9 +259,8 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4edc5decd268d87cfb6b1216f97a19251f61036766f86e54e60c28875aa1981b" +version = "2.18.0" +source = "git+https://github.com/starkware-libs/cairo?branch=debugger-annotations-v2%2Fsemantic-mapping#3efa3eb9169a1f9f246be5ebf87a82580b8774bc" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -272,9 +274,8 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "383614515e62d7b4cbf57ee957c856cb74f41cdca8d39fd91d4b6167fe7d5205" +version = "2.18.0" +source = "git+https://github.com/starkware-libs/cairo?branch=debugger-annotations-v2%2Fsemantic-mapping#3efa3eb9169a1f9f246be5ebf87a82580b8774bc" dependencies = [ "assert_matches", "cairo-lang-casm", @@ -287,15 +288,14 @@ dependencies = [ "itertools", "num-bigint", "num-traits", - "starknet-types-core", + "starknet-types-core 0.2.4", "thiserror 2.0.18", ] [[package]] name = "cairo-lang-sierra-type-size" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf49a0eea70720f60a3c62b739e102e731898ab6b86b9137128cb6675b2946f" +version = "2.18.0" +source = "git+https://github.com/starkware-libs/cairo?branch=debugger-annotations-v2%2Fsemantic-mapping#3efa3eb9169a1f9f246be5ebf87a82580b8774bc" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -303,11 +303,10 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a7b5af507f42080931a1562560736a09ba934226189cc6d7404a966d0313cfb" +version = "2.18.0" +source = "git+https://github.com/starkware-libs/cairo?branch=debugger-annotations-v2%2Fsemantic-mapping#3efa3eb9169a1f9f246be5ebf87a82580b8774bc" dependencies = [ - "hashbrown 0.16.1", + "hashbrown 0.17.0", "indexmap", "itertools", "num-bigint", @@ -333,7 +332,7 @@ dependencies = [ "bitvec", "generic-array", "indoc", - "keccak", + "keccak 0.1.5", "lazy_static", "nom", "num-bigint", @@ -345,9 +344,9 @@ dependencies = [ "serde", "serde_json", "sha2", - "sha3", + "sha3 0.10.8", "starknet-crypto", - "starknet-types-core", + "starknet-types-core 0.2.4", "thiserror 2.0.18", "tracing", "zip", @@ -380,6 +379,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "const_format" version = "0.2.35" @@ -427,6 +432,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -491,6 +505,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "dap" version = "0.4.1-alpha1" @@ -561,11 +584,22 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.6", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.0", + "const-oid", + "crypto-common 0.2.2", +] + [[package]] name = "dyn-clone" version = "1.0.20" @@ -691,9 +725,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" dependencies = [ "allocator-api2", "equivalent", @@ -702,12 +736,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "hashbrown" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" - [[package]] name = "hashlink" version = "0.10.0" @@ -735,7 +763,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", ] [[package]] @@ -819,14 +856,24 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", +] + +[[package]] +name = "keccak" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", ] [[package]] name = "lalrpop" -version = "0.22.2" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501" +checksum = "98a80a963123205c7157323c99611bc4abb65dcbd62ef46dc4bac74a3941bc75" dependencies = [ "ascii-canvas", "bit-set", @@ -837,7 +884,7 @@ dependencies = [ "pico-args", "regex", "regex-syntax", - "sha3", + "sha3 0.10.8", "string_cache", "term", "unicode-xid", @@ -846,12 +893,11 @@ dependencies = [ [[package]] name = "lalrpop-util" -version = "0.22.2" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5baa5e9ff84f1aefd264e6869907646538a52147a755d494517a8007fb48733" +checksum = "884f3e747ed2dcee867cda1b0c31a048f9e20de2d916a248949319921a2e666e" dependencies = [ "regex-automata", - "rustversion", ] [[package]] @@ -865,7 +911,7 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "sha2", - "sha3", + "sha3 0.10.8", ] [[package]] @@ -1149,19 +1195,20 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.7.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", + "hashbrown 0.15.5", "indexmap", ] [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher", ] @@ -1604,8 +1651,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", ] [[package]] @@ -1614,8 +1661,18 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest", - "keccak", + "digest 0.10.7", + "keccak 0.1.5", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak 0.2.0", ] [[package]] @@ -1682,7 +1739,7 @@ dependencies = [ "rfc6979", "sha2", "starknet-curve", - "starknet-types-core", + "starknet-types-core 0.2.4", "zeroize", ] @@ -1692,7 +1749,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22c898ae81b6409532374cf237f1bd752d068b96c6ad500af9ebbd0d9bb712f6" dependencies = [ - "starknet-types-core", + "starknet-types-core 0.2.4", ] [[package]] @@ -1703,7 +1760,7 @@ checksum = "90d23b1bc014ee4cce40056ab3114bcbcdc2dbc1e845bbfb1f8bd0bab63507d4" dependencies = [ "arbitrary", "blake2", - "digest", + "digest 0.10.7", "lambdaworks-crypto", "lambdaworks-math", "lazy_static", @@ -1715,11 +1772,28 @@ dependencies = [ "zeroize", ] +[[package]] +name = "starknet-types-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a12690813e587969cb4a9e7d8ebdb069d4bb7ec8d03275c5f719310c8e1f07c" +dependencies = [ + "generic-array", + "lambdaworks-crypto", + "lambdaworks-math", + "num-bigint", + "num-integer", + "num-traits", + "rand 0.9.2", + "serde", + "zeroize", +] + [[package]] name = "string_cache" -version = "0.8.9" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" dependencies = [ "new_debug_unreachable", "parking_lot", @@ -1979,9 +2053,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "unicode-ident" diff --git a/Cargo.toml b/Cargo.toml index 1c211cd..41c1ca6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,11 +5,11 @@ edition = "2024" [dependencies] anyhow = "1.0" -cairo-annotations = { version = "0.8.0", features = ["cairo-lang"] } -cairo-lang-casm = "2.17.0" -cairo-lang-sierra = "2.17.0" -cairo-lang-sierra-to-casm = "2.17.0" -cairo-lang-sierra-type-size = "2.17.0" +cairo-annotations = { git = "https://github.com/software-mansion/cairo-annotations", branch = "debugger-annotations-v2", features = ["cairo-lang"] } +cairo-lang-casm = { git = "https://github.com/starkware-libs/cairo", branch = "debugger-annotations-v2/semantic-mapping" } +cairo-lang-sierra = { git = "https://github.com/starkware-libs/cairo", branch = "debugger-annotations-v2/semantic-mapping" } +cairo-lang-sierra-to-casm = { git = "https://github.com/starkware-libs/cairo", branch = "debugger-annotations-v2/semantic-mapping" } +cairo-lang-sierra-type-size = { git = "https://github.com/starkware-libs/cairo", branch = "debugger-annotations-v2/semantic-mapping" } cairo-vm = { version = "3.2.0", features = ["test_utils"] } dap = { git = "https://github.com/software-mansion-labs/dap-rs", rev = "27542c413184732cd8cb5632c8349d605ed4fe04" } indexmap = "2.14" diff --git a/src/debugger/context.rs b/src/debugger/context.rs index 62916be..42b25c2 100644 --- a/src/debugger/context.rs +++ b/src/debugger/context.rs @@ -7,18 +7,20 @@ use cairo_annotations::annotations::TryFromDebugInfo; use cairo_annotations::annotations::coverage::{ CodeLocation, CoverageAnnotationsV1 as SierraCodeLocations, }; -use cairo_annotations::annotations::debugger::DebuggerAnnotationsV1 as FunctionsDebugInfo; +use cairo_annotations::annotations::debugger::VersionedDebuggerAnnotations; use cairo_annotations::annotations::profiler::{ FunctionName, ProfilerAnnotationsV1 as SierraFunctionNames, }; use cairo_annotations::{MappingResult, map_pc_to_sierra_statement_id}; use cairo_lang_sierra::extensions::core::CoreConcreteLibfunc; +use cairo_lang_sierra::extensions::function_call::FunctionCallLibfunc; use cairo_lang_sierra::extensions::lib_func::BranchSignature; use cairo_lang_sierra::extensions::types::TypeInfo; -use cairo_lang_sierra::extensions::{ConcreteLibfunc, ConcreteType}; -use cairo_lang_sierra::ids::{ConcreteTypeId, VarId}; +use cairo_lang_sierra::extensions::{ConcreteLibfunc, ConcreteType, GenericLibfunc}; +use cairo_lang_sierra::ids::{ConcreteLibfuncId, ConcreteTypeId, FunctionId, VarId}; use cairo_lang_sierra::program::{ - Function, GenBranchTarget, GenInvocation, Program, ProgramArtifact, Statement, StatementIdx, + Function, GenBranchTarget, GenInvocation, GenericArg, Program, ProgramArtifact, Statement, + StatementIdx, }; use cairo_lang_sierra_to_casm::compiler::{CairoProgramDebugInfo, SierraToCasmConfig}; use cairo_lang_sierra_to_casm::metadata::calc_metadata; @@ -26,7 +28,7 @@ use cairo_lang_sierra_type_size::ProgramRegistryInfo; use scarb_metadata::MetadataCommand; use crate::debugger::context::file_locations::{FileCodeLocationsData, build_file_locations_map}; -use crate::debugger::context::variables::build_cairo_var_to_casm_map; +use crate::debugger::context::variables::{CairoVarToCasmMaps, build_cairo_var_to_casm_maps}; mod file_locations; #[cfg(feature = "dev")] @@ -43,6 +45,7 @@ pub struct Context { casm_debug_info: CairoProgramDebugInfo, files_data: HashMap, pub cairo_var_map: HashMap, + pub function_param_var_map: HashMap>, #[cfg(feature = "dev")] labels: HashMap, } @@ -64,14 +67,27 @@ impl Context { let program_registry_info = ProgramRegistryInfo::new(&program).context("creating program registry failed")?; + eprintln!("{program}"); + let debug_info = sierra_program.debug_info.ok_or_else(|| { anyhow!("sierra debug info is missing - enable generating it in your Scarb.toml") })?; let code_locations = SierraCodeLocations::try_from_debug_info(&debug_info) .context("statements code locations debug info is missing - enable generating it in your Scarb.toml")?; - let functions_debug_info = FunctionsDebugInfo::try_from_debug_info(&debug_info) - .context("functions debug info is missing - enable generating it in your Scarb.toml")?; + let functions_debug_info = + match VersionedDebuggerAnnotations::try_from_debug_info(&debug_info).context( + "functions debug info is missing - enable generating it in your Scarb.toml", + )? { + VersionedDebuggerAnnotations::V2(v2) => v2, + VersionedDebuggerAnnotations::V1(_) => { + return Err(anyhow!( + "this project was compiled with a toolchain that predates the \ + multi-binding debug info format; rebuild with an up-to-date scarb \ + to enable variable display" + )); + } + }; let function_names = SierraFunctionNames::try_from_debug_info(&debug_info).context( "statements functions debug info is missing - enable generating it in your Scarb.toml", )?; @@ -79,8 +95,16 @@ impl Context { // TODO(#61) let casm_debug_info = compile_sierra_to_get_casm_debug_info(&program, &program_registry_info)?; - let cairo_var_map = - build_cairo_var_to_casm_map(&program, &casm_debug_info, functions_debug_info); + + let CairoVarToCasmMaps { + local_vars: cairo_var_map, + function_params: function_param_var_map, + } = build_cairo_var_to_casm_maps( + &program, + &casm_debug_info, + &functions_debug_info, + &program_registry_info.type_sizes, + ); let files_data = build_file_locations_map(&casm_debug_info, &code_locations); @@ -99,6 +123,7 @@ impl Context { casm_debug_info, files_data, cairo_var_map, + function_param_var_map, }) } @@ -109,6 +134,28 @@ impl Context { } } + pub fn user_function_for_concrete_libfunc( + &self, + concrete_libfunc_id: &ConcreteLibfuncId, + ) -> Option { + let libfunc_long_id = &self + .sierra_context + .program + .libfunc_declarations + .iter() + .find(|libfunc_declaration| &libfunc_declaration.id == concrete_libfunc_id)? + .long_id; + + FunctionCallLibfunc::by_id(&libfunc_long_id.generic_id)?; + + match &libfunc_long_id.generic_args[..] { + [GenericArg::UserFunc(function_id)] => Some(function_id.clone()), + _ => unreachable!( + "function_call libfunc is expected to have exactly one generic arg of type user function" + ), + } + } + /// Return code location for the current statement, not including inlined code locations. pub fn code_location_for_statement_idx( &self, @@ -243,7 +290,7 @@ impl Context { .expect("type id is expected to exist in type size map") } - fn statement_idx_to_statement(&self, statement_idx: StatementIdx) -> &Statement { + pub fn statement_idx_to_statement(&self, statement_idx: StatementIdx) -> &Statement { &self.sierra_context.program.statements[statement_idx.0] } diff --git a/src/debugger/context/variables.rs b/src/debugger/context/variables.rs index e15cf90..fe50a94 100644 --- a/src/debugger/context/variables.rs +++ b/src/debugger/context/variables.rs @@ -1,17 +1,24 @@ use std::collections::HashMap; use std::fmt::{Debug, Formatter}; +use std::slice; use cairo_annotations::annotations::coverage::SourceCodeSpan; use cairo_annotations::annotations::debugger::{ - DebuggerAnnotationsV1 as FunctionsDebugInfo, FunctionDebugInfo, SierraFunctionId, SierraVarId, + DebuggerAnnotationsV2 as FunctionsDebugInfo, SierraFunctionId, SierraVarId, }; -use cairo_lang_sierra::ids::VarId; +use cairo_lang_sierra::ids::{FunctionId, VarId}; use cairo_lang_sierra::program::{GenBranchTarget, Program, Statement, StatementIdx}; use cairo_lang_sierra_to_casm::compiler::{CairoProgramDebugInfo, StatementKindDebugInfo}; -use cairo_lang_sierra_to_casm::references::ReferenceExpression; +use cairo_lang_sierra_to_casm::references::{ReferenceExpression, build_function_parameters_refs}; +use cairo_lang_sierra_type_size::TypeSizeMap; use crate::debugger::context::sierra_function_for_statement; +pub struct CairoVarToCasmMaps { + pub function_params: HashMap>, + pub local_vars: HashMap, +} + pub struct CairoVarsInStatement { #[expect(dead_code)] /// Variables consumed by the sierra statement. @@ -28,14 +35,14 @@ impl Debug for CairoVarsInStatement { } /// Unique identifier of a Cairo variable. -#[derive(Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct CairoVarId { pub name: String, pub definition_span: SourceCodeSpan, } /// Sierra and CASM references to a Cairo variable. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct CairoVarReference { pub sierra_id: VarId, pub ref_expr: ReferenceExpression, @@ -58,12 +65,67 @@ impl From> for GenBranchTargetHashable { } } -pub fn build_cairo_var_to_casm_map( +pub fn build_cairo_var_to_casm_maps( program: &Program, casm_debug_info: &CairoProgramDebugInfo, - functions_debug_info: FunctionsDebugInfo, -) -> HashMap { - let mut result = HashMap::new(); + functions_debug_info: &FunctionsDebugInfo, + type_sizes: &TypeSizeMap, +) -> CairoVarToCasmMaps { + let mut local_vars = HashMap::new(); + + let mut functions_sierra_to_cairo_vars_maps: HashMap<_, HashMap<_, slice::Iter<_>>> = + functions_debug_info + .functions_info + .iter() + .map(|(function_id, func_debug_info)| { + let sierra_to_cairo_var_map: HashMap<_, _> = func_debug_info + .sierra_to_cairo_variables + .iter() + .map(|(sierra_id, cairo_vars)| (sierra_id, cairo_vars.iter())) + .collect(); + (function_id, sierra_to_cairo_var_map) + }) + .collect(); + + let function_params: HashMap<_, HashMap<_, _>> = program + .funcs + .iter() + .filter_map(|function| { + let Some(func_sierra_to_cairo_var_map) = + functions_sierra_to_cairo_vars_maps.get_mut(&SierraFunctionId(function.id.id)) + else { + // TODO: fix in the compiler + eprintln!( + "function {} should be present in the variable map", + function.id.debug_name.as_deref().unwrap_or_default() + ); + return None; + }; + + let param_refs = build_function_parameters_refs(function, type_sizes) + .expect("function param refs construction should not fail"); + + let cairo_var_map = param_refs + .into_iter() + .filter_map(|(sierra_id, ref_value)| { + let (name, definition_span) = func_sierra_to_cairo_var_map + .get_mut(&SierraVarId(sierra_id.id))? + .next()? + .clone(); + + let cairo_var_id = CairoVarId { name, definition_span }; + + let cairo_var_ref = + CairoVarReference { sierra_id, ref_expr: ref_value.expression.clone() }; + + Some((cairo_var_id, cairo_var_ref)) + }) + .collect(); + + Some((function.id.clone(), cairo_var_map)) + }) + .collect(); + for (idx, statement_debug_info) in casm_debug_info.sierra_statement_info.iter().enumerate() { // Join information from casm debug info and sierra program to get casm reference for each // sierra var id. This is implemented as collecting vectors of `CairoVarReference`. @@ -120,38 +182,52 @@ pub fn build_cairo_var_to_casm_map( _ => unreachable!(), }; + let statement_idx = StatementIdx(idx); let function_id = &sierra_function_for_statement(idx, program).id; - let func_debug_info = - &functions_debug_info.functions_info[&SierraFunctionId(function_id.id)]; - let consumed = extract_cairo_var_map(consumed, func_debug_info); + let Some(func_sierra_to_cairo_var_map) = + functions_sierra_to_cairo_vars_maps.get_mut(&SierraFunctionId(function_id.id)) + else { + // TODO: fix in the compiler + continue; + }; + + let consumed = extract_cairo_var_map(consumed, func_sierra_to_cairo_var_map); + let produced: HashMap<_, _> = produced .into_iter() .map(|(branch_target, cairo_var_refs)| { - let produced_in_branch = extract_cairo_var_map(cairo_var_refs, func_debug_info); + let produced_in_branch = + extract_cairo_var_map(cairo_var_refs, func_sierra_to_cairo_var_map); (branch_target, produced_in_branch) }) .collect(); if !consumed.is_empty() || !produced.is_empty() { - result.insert(StatementIdx(idx), CairoVarsInStatement { consumed, produced }); + local_vars.insert(statement_idx, CairoVarsInStatement { consumed, produced }); } } - result + CairoVarToCasmMaps { function_params, local_vars } } -/// For each var reference use its sierra var id to get the Cairo variable it corresponds to. +/// For each var reference use its Sierra var id to get the Cairo variable it corresponds to. fn extract_cairo_var_map( var_refs: Vec, - func_debug_info: &FunctionDebugInfo, + func_sierra_to_cairo_vars_map: &mut HashMap< + &SierraVarId, + slice::Iter<(String, SourceCodeSpan)>, + >, ) -> HashMap { var_refs .into_iter() .filter_map(|var_ref| { - let (name, span) = - func_debug_info.sierra_to_cairo_variable.get(&SierraVarId(var_ref.sierra_id.id))?; - let var_id = CairoVarId { name: name.clone(), definition_span: span.clone() }; + let (name, definition_span) = func_sierra_to_cairo_vars_map + .get_mut(&SierraVarId(var_ref.sierra_id.id))? + .next()? + .clone(); + + let var_id = CairoVarId { name, definition_span }; Some((var_id, var_ref)) }) diff --git a/src/debugger/state/call_stack.rs b/src/debugger/state/call_stack.rs index 29c940f..c0b13ae 100644 --- a/src/debugger/state/call_stack.rs +++ b/src/debugger/state/call_stack.rs @@ -13,7 +13,9 @@ use indexmap::IndexMap; use crate::debugger::MIN_OBJECT_REFERENCE; use crate::debugger::context::Context; -use crate::debugger::state::call_stack::variables::get_values_of_variables; +use crate::debugger::state::call_stack::variables::{ + get_values_of_function_params, get_values_of_variables, +}; mod variables; @@ -152,12 +154,29 @@ impl CallStack { } }; - let FunctionVariables { names_to_values } = if flat_index >= self.flat_length() { - get_values_of_variables( + let names_to_values = if flat_index >= self.flat_length() { + let mut current_function_variables = get_values_of_variables( ctx, vm, &self.current_sierra_function_context.post_statements_registers, ) + .names_to_values; + + let mut current_function_params = + if let Some((_, caller_context)) = self.call_frames_and_vars.last() { + // Snapshot of VM registers right after function call that invoked the current function. + // (or eqivalently: right before the execution of the first statement in this function). + // Access to function params in VM's memory is based only on FP, which is fixed for each function execution. + let register_values_on_call = RegistersValues { ap: 0, fp: vm.get_fp().offset }; + + get_values_of_function_params(ctx, vm, caller_context, ®ister_values_on_call) + .unwrap_or_default() + } else { + Default::default() + }; + + current_function_params.append(&mut current_function_variables); + current_function_params } else { self.call_frames_and_vars .iter() @@ -166,6 +185,7 @@ impl CallStack { .nth(flat_index) .unwrap() .clone() + .names_to_values }; names_to_values diff --git a/src/debugger/state/call_stack/variables.rs b/src/debugger/state/call_stack/variables.rs index ef5ba4e..362dbc5 100644 --- a/src/debugger/state/call_stack/variables.rs +++ b/src/debugger/state/call_stack/variables.rs @@ -2,7 +2,7 @@ use cairo_annotations::annotations::coverage::SourceCodeSpan; use cairo_lang_casm::cell_expression::{CellExpression, CellOperator}; use cairo_lang_casm::operand::{CellRef, DerefOrImmediate}; use cairo_lang_sierra::ids::VarId; -use cairo_lang_sierra::program::{ConcreteTypeLongId, GenericArg}; +use cairo_lang_sierra::program::{ConcreteTypeLongId, GenericArg, Statement}; use cairo_vm::Felt252; use cairo_vm::vm::vm_core::VirtualMachine; use indexmap::IndexMap; @@ -11,7 +11,7 @@ use tracing::{error, warn}; use crate::debugger::context::{CairoVarId, CairoVarReference, Context}; use crate::debugger::state::call_stack::{ - FunctionVariables, PostStatementsRegisters, RegistersValues, + FunctionVariables, PostStatementsRegisters, RegistersValues, SierraFunctionContext, }; pub fn get_values_of_variables( @@ -88,6 +88,43 @@ pub fn get_values_of_variables( FunctionVariables { names_to_values } } +pub fn get_values_of_function_params( + ctx: &Context, + vm: &VirtualMachine, + caller_context: &SierraFunctionContext, + registers_on_call: &RegistersValues, +) -> Option> { + // "Caller" is the function that invoked the current function. + // Last executed statement of the caller is the invocation of the current function. + let invocation_statement_idx = caller_context.last_executed_statement?; + + let Statement::Invocation(invocation_statement) = + ctx.statement_idx_to_statement(invocation_statement_idx) + else { + return None; + }; + + let user_function_id = + ctx.user_function_for_concrete_libfunc(&invocation_statement.libfunc_id)?; + let params = ctx.function_param_var_map.get(&user_function_id)?; + + let result: IndexMap<_, _> = params + .iter() + .map(|(CairoVarId { name, .. }, CairoVarReference { ref_expr, .. })| { + let val = ref_expr + .cells + .iter() + .filter_map(|cell| maybe_extract_felt_from_cell(cell, registers_on_call, vm)) + .next() + .unwrap_or_default(); + + (name.to_owned(), val.to_string()) + }) + .collect(); + + Some(result) +} + fn is_panic_result(type_long_id: &ConcreteTypeLongId) -> bool { if type_long_id.generic_id.0 == "Enum" && let GenericArg::UserType(user_type) = &type_long_id.generic_args[0]