Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
6126471
initial version: debug tests with `nargo debug --test-name`
anaPerezGhiglia Feb 13, 2025
63c98da
Configure oracle-resolver in DebugForeignCallExecutor
anaPerezGhiglia Feb 7, 2025
866833b
Spawn debugger in different thread than REPL
anaPerezGhiglia Feb 12, 2025
517647a
fix: set root_path and package_name on ForeignCallResolver from debugger
anaPerezGhiglia Feb 13, 2025
6ea307c
debug println!
anaPerezGhiglia Feb 13, 2025
84e2cf7
run cargo fmt
anaPerezGhiglia Feb 14, 2025
f25241e
Map opcode resulution erros in debugger as well
anaPerezGhiglia Feb 14, 2025
f59e08e
Use PrettyFormatter for printing test result in debug_cmd
anaPerezGhiglia Feb 14, 2025
2b08935
Instrument contract functions + set package_build_path in context
anaPerezGhiglia Feb 18, 2025
0bba2ec
set pedantic_solving when creating the BlackBoxSolver
anaPerezGhiglia Feb 18, 2025
7ead710
avoid printing __debug foreign calls
anaPerezGhiglia Feb 18, 2025
2ce58af
workaround: retry rpc request restarting http_client on transport error
anaPerezGhiglia Feb 19, 2025
ab1dbcc
fix context.restart function
anaPerezGhiglia Feb 24, 2025
f66c650
run cargo fmt
anaPerezGhiglia Feb 24, 2025
c44e440
A bit of code cleanup and enhancements
anaPerezGhiglia Feb 24, 2025
1dbb666
Adapt breakpoint by sourcecode line to debugger in separate thread impl
anaPerezGhiglia Jun 7, 2024
86ae83a
refactor: encapsulate debug-test logic into smaller functions
anaPerezGhiglia Feb 25, 2025
caa6d15
extract runtime debugger and structs to separate file
anaPerezGhiglia Feb 25, 2025
d1655df
fix debugger panic
anaPerezGhiglia Feb 25, 2025
e7c9e30
get rid of nested Results
anaPerezGhiglia Feb 25, 2025
00b83b6
abstract extracting value from enum with extract! macro
anaPerezGhiglia Feb 25, 2025
14977fd
some more code cleanup
anaPerezGhiglia Feb 26, 2025
0591747
cargo fmt & clippy
anaPerezGhiglia Feb 26, 2025
ba139bd
refactor to avoid exceeding # of function args
anaPerezGhiglia Feb 26, 2025
fccbd1c
adapt dap iterface to debug test functions
anaPerezGhiglia Feb 27, 2025
e7f1d1e
Analyze test result when running DAP debugger interface
anaPerezGhiglia Feb 28, 2025
d59b879
Define DebugExecutionResult struct
anaPerezGhiglia Mar 5, 2025
4cda3e9
simplify dap_cmd functions by using compile_options struct
anaPerezGhiglia Mar 5, 2025
f0ee01e
Create new Project struct to encapsulate info needed for debugging
anaPerezGhiglia Mar 5, 2025
0d5ce43
Move RunParams to debugger and use it in repl and dap interfaces
anaPerezGhiglia Mar 5, 2025
0277c3e
Remove unnecessary get_foreign_call_resolver_url function
anaPerezGhiglia Mar 6, 2025
9351e17
Some code enhancements
anaPerezGhiglia Mar 6, 2025
6a9d509
cargo fmt
anaPerezGhiglia Mar 6, 2025
06cff99
unify AsyncDebugger and ReplDebugger
anaPerezGhiglia Mar 7, 2025
301fe72
Remove unused DebuggerStatus::Error variant
anaPerezGhiglia Mar 10, 2025
3c80145
Create new nargo::ops::debug mod and organize functions
anaPerezGhiglia Mar 10, 2025
5dfe858
Merge branch 'master' into feat/debug-tests-2025
anaPerezGhiglia Mar 11, 2025
382f229
cargo fmt
anaPerezGhiglia Mar 11, 2025
1478461
Update tooling/debugger/src/context.rs
anaPerezGhiglia Mar 11, 2025
8896492
Update tooling/debugger/src/repl.rs
anaPerezGhiglia Mar 11, 2025
5fcf344
simplify instrument_module function
anaPerezGhiglia Mar 11, 2025
559b7e8
Minor tweaks and comments
anaPerezGhiglia Mar 11, 2025
725580c
Add doc to nargo::errors::execution_error_from
anaPerezGhiglia Mar 11, 2025
5ebfe5e
simplify DebugInstrumenter.insert_state_set_oracle signature
anaPerezGhiglia Mar 12, 2025
b34b6ab
remove TODO comments since topics were already discussed
anaPerezGhiglia Mar 12, 2025
8f0fc9e
enable silence-warnings when debugging
anaPerezGhiglia Mar 12, 2025
2568961
disable deny_warnings option when debugging
anaPerezGhiglia Mar 12, 2025
872e148
Include new features to debugger documentation
anaPerezGhiglia Mar 12, 2025
cbea200
cargo fmt
anaPerezGhiglia Mar 12, 2025
78c359b
Tweak debugger docs text
anaPerezGhiglia Mar 14, 2025
f1c23ac
Use exact matching test if multiple matches when debugging tests
anaPerezGhiglia Mar 17, 2025
ac55d8b
Create debug-test tests for every noir_test_success case
anaPerezGhiglia Mar 17, 2025
1df8141
Merge branch 'master' into feat/debug-tests-2025
anaPerezGhiglia Mar 19, 2025
4516a5e
noir_debugger: enable rpc feature when declaring nargo dependency
anaPerezGhiglia Mar 19, 2025
0fea2b8
Remove warning message when building debugger tests
anaPerezGhiglia Mar 19, 2025
82667e0
Fix debugger_expected_call_stack test
anaPerezGhiglia Mar 19, 2025
814a0af
Repl: wait for debugger to be idle after command
anaPerezGhiglia Mar 19, 2025
8492fd5
cargo fmt
anaPerezGhiglia Mar 19, 2025
1bd0906
ignore ski_calculus tests since they require an unstable feature
anaPerezGhiglia Mar 20, 2025
0f7d353
Merge branch 'master' into feat/debug-tests-2025
anaPerezGhiglia Mar 20, 2025
affdcde
Add gear to 'Debug test' codelens to mimic Rust's codelens
anaPerezGhiglia Mar 20, 2025
717a9e7
Rename DebugCommander and generate debugger tests function
anaPerezGhiglia Mar 21, 2025
1be4c19
Merge branch 'master' into feat/debug-tests-2025
anaPerezGhiglia Mar 21, 2025
fa028e7
remove useless white spaces
anaPerezGhiglia Mar 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 18 additions & 11 deletions compiler/noirc_frontend/src/debug/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
use crate::ast::PathSegment;
use crate::parse_program;
use crate::parser::ParsedModule;
use crate::parser::{ParsedModule, ParsedSubModule};
use crate::signed_field::SignedField;
use crate::{
ast,
ast::Path,
parser::{Item, ItemKind},
};
use crate::{ast, ast::Path, parser::ItemKind};
use fm::FileId;
use noirc_errors::debug_info::{DebugFnId, DebugFunction};
use noirc_errors::{Location, Span};
Expand Down Expand Up @@ -60,13 +56,24 @@
impl DebugInstrumenter {
pub fn instrument_module(&mut self, module: &mut ParsedModule, file: FileId) {
module.items.iter_mut().for_each(|item| {
if let Item { kind: ItemKind::Function(f), .. } = item {
self.walk_fn(&mut f.def);
match &mut item.kind {
// Instrument top-level functions of a module
ItemKind::Function(f) => self.walk_fn(&mut f.def),
// Instrument contract module
ItemKind::Submodules(ParsedSubModule {
is_contract: true,
contents: contract_module,
..
}) => {
self.instrument_module(contract_module, file);
}
_ => (),
}
});

// this part absolutely must happen after ast traversal above
// so that oracle functions don't get wrapped, resulting in infinite recursion:
self.insert_state_set_oracle(module, 8, file);
self.insert_state_set_oracle(module, file);
}

fn insert_var(&mut self, var_name: &str) -> Option<SourceVarId> {
Expand Down Expand Up @@ -315,7 +322,7 @@
}
ast::LValue::Dereference(_lv, location) => {
// TODO: this is a dummy statement for now, but we should
// somehow track the derefence and update the pointed to

Check warning on line 325 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (derefence)
// variable
ast::Statement {
kind: ast::StatementKind::Expression(uint_expr(0, *location)),
Expand Down Expand Up @@ -499,8 +506,8 @@
}
}

fn insert_state_set_oracle(&self, module: &mut ParsedModule, n: u32, file: FileId) {
let member_assigns = (1..=n)
fn insert_state_set_oracle(&self, module: &mut ParsedModule, file: FileId) {
let member_assigns = (1..=MAX_MEMBER_ASSIGN_DEPTH)
.map(|i| format!["__debug_member_assign_{i}"])
.collect::<Vec<String>>()
.join(",\n");
Expand Down Expand Up @@ -719,9 +726,9 @@
ast::Pattern::Tuple(patterns, _) => {
stack.extend(patterns.iter().map(|pattern| (pattern, false)));
}
ast::Pattern::Struct(_, pids, _) => {

Check warning on line 729 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (pids)
stack.extend(pids.iter().map(|(_, pattern)| (pattern, is_mut)));

Check warning on line 730 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (pids)
vars.extend(pids.iter().map(|(id, _)| (id.clone(), false)));

Check warning on line 731 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (pids)
}
ast::Pattern::Interned(_, _) => (),
}
Expand All @@ -732,7 +739,7 @@
fn pattern_to_string(pattern: &ast::Pattern) -> String {
match pattern {
ast::Pattern::Identifier(id) => id.to_string(),
ast::Pattern::Mutable(mpat, _, _) => format!("mut {}", pattern_to_string(mpat.as_ref())),

Check warning on line 742 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (mpat)

Check warning on line 742 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (mpat)
ast::Pattern::Tuple(elements, _) => format!(
"({})",
elements.iter().map(pattern_to_string).collect::<Vec<String>>().join(", ")
Expand Down
47 changes: 42 additions & 5 deletions docs/docs/how_to/debugger/debugging_with_the_repl.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Using the REPL Debugger
description:
Step-by-step guide on how to debug your Noir circuits with the REPL Debugger.
Step-by-step guide on how to debug your Noir circuits with the REPL Debugger.
keywords:
[
Nargo,
Expand All @@ -14,7 +14,7 @@ sidebar_position: 1

#### Pre-requisites

In order to use the REPL debugger, first you need to install recent enough versions of Nargo and vscode-noir.
In order to use the REPL debugger, first you need to install recent enough versions of Nargo.

## Debugging a simple circuit

Expand All @@ -38,7 +38,7 @@ At ~/noir-examples/recursion/circuits/main/src/main.nr:1:9
1 -> fn main(x : Field, y : pub Field) {
2 assert(x != y);
3 }
>
>
```

The debugger displays the current Noir code location, and it is now waiting for us to drive it.
Expand Down Expand Up @@ -84,7 +84,7 @@ Some commands operate only for unconstrained functions, such as `memory` and `me
```
> memory
Unconstrained VM memory not available
>
>
```

Before continuing, we can take a look at the initial witness map:
Expand Down Expand Up @@ -115,7 +115,7 @@ _1 = 2
>
```

Now we can inspect the current state of local variables. For that we use the `vars` command.
Now we can inspect the current state of local variables. For that we use the `vars` command.

```
> vars
Expand Down Expand Up @@ -162,3 +162,40 @@ Finished execution
Upon quitting the debugger after a solved circuit, the resulting circuit witness gets saved, equivalent to what would happen if we had run the same circuit with `nargo execute`.

We just went through the basics of debugging using Noir REPL debugger. For a comprehensive reference, check out [the reference page](../../reference/debugger/debugger_repl.md).

## Debugging a test function

Let's debug a simple test:

```rust
#[noir]
fn test_simple_equal() {
let x = 2;
let y = 1 + 1;
assert(x == y, "should be equal");
}
```

To debug a test function using the REPL debugger, navigate to a Noir project directory inside a terminal, and run the `nargo debug` command passing the `--test-name your_test_name_here` argument.

```bash
nargo debug --test-name test_simple_equal
```

After that, the debugger has started and works the same as debugging a main function, you can use any of the above explained commands to control the execution of the test function.

### Test result

The debugger does not end the session automatically. Once you finish debugging the execution of the test function you will notice that the debugger remains in the `Execution finished` state. When you are done debugging the test function you can exit the debugger by using the `quit` command. Once you finish the debugging session you should see the test result.

```text
$ nargo debug --test-name test_simple_equal
[simple_noir_project] Starting debugger
At opcode 0:0 :: BRILLIG CALL func 0: inputs: [], outputs: []
> continue
(Continuing execution...)
Finished execution
> quit
[simple_noir_project] Circuit witness successfully solved
[simple_noir_project] Testing test_simple_equal... ok
```
18 changes: 13 additions & 5 deletions docs/docs/how_to/debugger/debugging_with_vs_code.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ keywords:
sidebar_position: 0
---

This guide will show you how to use VS Code with the vscode-noir extension to debug a Noir project.
This guide will show you how to use VS Code with the vscode-noir extension to debug a Noir project.

#### Pre-requisites

Expand All @@ -23,7 +23,15 @@ This guide will show you how to use VS Code with the vscode-noir extension to de

## Running the debugger

The easiest way to start debugging is to open the file you want to debug, and press `F5`. This will cause the debugger to launch, using your `Prover.toml` file as input.
The easiest way to start debugging is to open the file you want to debug, and click on `Debug` codelens over main functions or `Debug test` over `#[test]` functions

If you don't see the codelens options `Compile|Info|..|Debug` over the `main` function or `Run test| Debug test` over a test function then you probably have the codelens feature disabled. To enable it open the extension configuration page and check the `Enable Code Lens` setting.

![Debugger codelens](@site/static/img/debugger/debugger-codelens.png)

Another way of starting the debugger is to press `F5` on the file you want to debug. This will cause the debugger to launch, using your `Prover.toml` file as input.

Once the debugger has started you should see something like this:

You should see something like this:

Expand All @@ -37,11 +45,11 @@ You will now see two categories of variables: Locals and Witness Map.

![Debug pane expanded](@site/static/img/debugger/3-debug-pane.png)

1. **Locals**: variables of your program. At this point in execution this section is empty, but as we step through the code it will get populated by `x`, `result`, `digest`, etc.
1. **Locals**: variables of your program. At this point in execution this section is empty, but as we step through the code it will get populated by `x`, `result`, `digest`, etc.

2. **Witness map**: these are initially populated from your project's `Prover.toml` file. In this example, they will be used to populate `x` and `result` at the beginning of the `main` function.

Most of the time you will probably be focusing mostly on locals, as they represent the high level state of your program.
Most of the time you will probably be focusing mostly on locals, as they represent the high level state of your program.

You might be interested in inspecting the witness map in case you are trying to solve a really low level issue in the compiler or runtime itself, so this concerns mostly advanced or niche users.

Expand All @@ -57,7 +65,7 @@ We can also inspect the values of variables by directly hovering on them on the

![Hover locals](@site/static/img/debugger/6-hover.png)

Let's set a break point at the `keccak256` function, so we can continue execution up to the point when it's first invoked without having to go one step at a time.
Let's set a break point at the `keccak256` function, so we can continue execution up to the point when it's first invoked without having to go one step at a time.

We just need to click to the right of the line number 18. Once the breakpoint appears, we can click the `continue` button or use its corresponding keyboard shortcut (`F5` by default).

Expand Down
42 changes: 28 additions & 14 deletions docs/docs/reference/debugger/debugger_repl.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: REPL Debugger
description:
Noir Debugger REPL options and commands.
Noir Debugger REPL options and commands.
keywords:
[
Nargo,
Expand All @@ -20,21 +20,30 @@ Runs the Noir REPL debugger. If a `WITNESS_NAME` is provided the debugger writes

### Options

| Option | Description |
| --------------------- | ------------------------------------------------------------ |
| Option | Description |
| --------------------------------- | ----------------------------------------------------------------------------------- |
| `-p, --prover-name <PROVER_NAME>` | The name of the toml file which contains the inputs for the prover [default: Prover]|
| `--package <PACKAGE>` | The name of the package to debug |
| `--print-acir` | Display the ACIR for compiled circuit |
| `--deny-warnings` | Treat all warnings as errors |
| `--silence-warnings` | Suppress warnings |
| `-h, --help` | Print help |
| `--package <PACKAGE>` | The name of the package to debug |
| `--print-acir` | Display the ACIR for compiled circuit |
| `--test-name <TEST_NAME>` | The name (or substring) of the test function to debug |
| `--oracle-resolver <RESOLVER_URL>`| JSON RPC url to solve oracle calls |
| `-h, --help` | Print help |

None of these options are required.

:::note
Since the debugger starts by compiling the target package, all Noir compiler options are also available. Check out the [compiler reference](../nargo_commands.md#nargo-compile) to learn more about the compiler options.
:::

:::note
If the `--test-name` option is provided the debugger will debug the matching function instead of the package `main` function.
This argument must only match one function. If the given name matches with more than one test function the debugger will not start.
:::

:::note
For debugging aztec-contract tests that interact with the TXE ([see further details here](https://docs.aztec.network/developers/guides/smart_contracts/testing)), a JSON RPC server URL must be provided by setting the `--oracle-resolver` option
:::

## REPL commands

Once the debugger is running, it accepts the following commands.
Expand All @@ -53,6 +62,7 @@ Available commands:
out step until a new source location is reached
and the current stack frame is finished
break LOCATION:OpcodeLocation add a breakpoint at an opcode location
break line:i64 add a breakpoint at an opcode associated to the given source code line
over step until a new source location is reached
without diving into function calls
restart restart the debugging session
Expand Down Expand Up @@ -94,7 +104,7 @@ Step until the next Noir source code location. While other commands, such as [`i
```


Using `next` here would cause the debugger to jump to the definition of `deep_entry_point` (if available).
Using `next` here would cause the debugger to jump to the definition of `deep_entry_point` (if available).

If you want to step over `deep_entry_point` and go straight to line 8, use [the `over` command](#over) instead.

Expand Down Expand Up @@ -129,11 +139,11 @@ Step until the end of the current function call. For example:
7 -> assert(deep_entry_point(x) == 4);
8 multiple_values_entry_point(x);
9 }
10
10
11 unconstrained fn returns_multiple_values(x: u32) -> (u32, u32, u32, u32) {
12 ...
...
55
55
56 unconstrained fn deep_entry_point(x: u32) -> u32 {
57 -> level_1(x + 1)
58 }
Expand Down Expand Up @@ -180,7 +190,7 @@ Steps into the next opcode. A compiled Noir program is a sequence of ACIR opcode
...
1.43 | Return
2 EXPR [ (1, _1) -2 ]
```
```

The `->` here shows the debugger paused at an ACIR opcode: `BRILLIG`, at index 1, which denotes an unconstrained code block is about to start.

Expand Down Expand Up @@ -249,6 +259,10 @@ In this example, issuing a `break 1.2` command adds break on opcode 1.2, as deno

Running [the `continue` command](#continue-c) at this point would cause the debugger to execute the program until opcode 1.2.

#### `break [line]` (or shorthand `b [line]`)

Similar to `break [opcode]`, but instead of selecting the opcode by index selects the opcode location by matching the source code location

#### `delete [Opcode]` (or shorthand `d [Opcode]`)

Deletes a breakpoint at an opcode location. Usage is analogous to [the `break` command](#).
Expand All @@ -260,7 +274,7 @@ Deletes a breakpoint at an opcode location. Usage is analogous to [the `break` c
Show variable values available at this point in execution.

:::note
The ability to inspect variable values from the debugger depends on compilation to be run in a special debug instrumentation mode. This instrumentation weaves variable tracing code with the original source code.
The ability to inspect variable values from the debugger depends on compilation to be run in a special debug instrumentation mode. This instrumentation weaves variable tracing code with the original source code.

So variable value inspection comes at the expense of making the resulting ACIR bytecode bigger and harder to understand and optimize.

Expand Down Expand Up @@ -357,4 +371,4 @@ Update a memory cell with the given value. For example:

:::note
This command is only functional while the debugger is executing unconstrained code.
:::
:::
Loading
Loading