Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
debugger.cpp
Go to the documentation of this file.
2
3// We only build the debugger conditionally.
4#ifdef AVM_INCLUDE_DEBUGGER
5
6#include <iostream>
7#include <optional>
8#include <regex>
9#include <string>
10#include <vector>
11
14
21
22// We'll instantiate all debug relation impls in this cpp, and not in each relation cpp.
24
25namespace bb::avm2 {
26namespace {
27
28std::vector<std::string> get_command()
29{
30 std::string line;
32 // Split the line into words.
33 return bb::detail::split_and_trim(line, ' ');
34}
35
36std::string str_replace(const std::string& s, const std::string& search, const std::string& replace)
37{
38 size_t pos = 0;
39 std::string res = s;
40 while ((pos = res.find(search, pos)) != std::string::npos) {
41 res.replace(pos, search.length(), replace);
42 pos += replace.length();
43 }
44 return res;
45}
46
47std::string to_binary(uint64_t n, bool leading_zeroes = true)
48{
49 std::string result;
50 for (int i = 0; i < 64; ++i) {
51 result = ((n & 1) ? "1" : "0") + result;
52 n >>= 1;
53 }
54 if (!leading_zeroes) {
55 size_t first_one = result.find('1');
56 if (first_one != std::string::npos) {
57 result = result.substr(first_one);
58 } else {
59 result = "0";
60 }
61 }
62 return result;
63}
64
65void help()
66{
67 std::cout << "Commands:" << std::endl;
68 std::cout << " ' - increment row" << std::endl;
69 std::cout << " , - decrement row" << std::endl;
70 std::cout << " @<row> - jump to row" << std::endl;
71 std::cout << " .<column_regex> [...column_regex] - print column values" << std::endl;
72 std::cout << " /set <column> <value> - set column" << std::endl;
73 std::cout << " /prefix <column_prefix> - set column prefix" << std::endl;
74 std::cout << " /noprefix - clear column prefix" << std::endl;
75 std::cout << " /testrelation <relation_name> [subrelation_name_or_number] - test relation" << std::endl;
76 std::cout << " exit, e, q - exit" << std::endl;
77}
78
79} // namespace
80
81void InteractiveDebugger::run(uint32_t starting_row)
82{
83 row = starting_row;
84 std::cout << "Entering interactive debugging mode at row " << row << "..." << std::endl;
85 while (true) {
86 // Print prompt with current row.
87 std::cout << this->row << "> ";
88 auto command = get_command();
89 if (command.empty()) {
90 continue;
91 }
92 if (command[0] == "'") {
93 row++;
94 } else if (command[0] == ",") {
95 if (row > 0) {
96 row--;
97 } else {
98 std::cout << "Cannot decrement row below 0." << std::endl;
99 }
100 } else if (command[0].starts_with("@")) {
101 row = static_cast<uint32_t>(std::stoi(command[0].substr(1)));
102 } else if (command[0] == "exit" || command[0] == "e" || command[0] == "q") {
103 break;
104 } else if (command[0] == "/set" || command[0] == "/s") {
105 if (command.size() != 3) {
106 std::cout << "Usage: /set <column> <value>" << std::endl;
107 } else {
108 set_column(command[1], command[2]);
109 }
110 } else if (command[0] == "/prefix" || command[0] == "/p") {
111 if (command.size() != 2) {
112 std::cout << "Usage: /prefix <column_prefix>" << std::endl;
113 } else {
114 prefix = command[1];
115 }
116 } else if (command[0] == "/noprefix" || command[0] == "/np") {
117 prefix = "";
118 } else if (command[0] == "/testrelation" || command[0] == "/tr") {
119 if (command.size() != 2 && command.size() != 3) {
120 std::cout << "Usage: /testrelation <relation_name> [subrelation_name_or_number]" << std::endl;
121 } else {
122 test_relation(command[1], command.size() == 3 ? std::make_optional(command[2]) : std::nullopt);
123 }
124 } else if (command[0].starts_with(".")) {
125 // Remove dot from first column name.
126 command[0].erase(0, 1);
127 // Print columns.
128 print_columns(command);
129 } else {
130 help();
131 }
132 }
133}
134
135void InteractiveDebugger::print_columns(const std::vector<std::string>& regexes)
136{
137 bool found = false;
138 std::string joined_regex;
139 for (const auto& str : regexes) {
140 joined_regex += prefix + str_replace(str, "'", "_shift") + "|";
141 }
142 joined_regex.pop_back(); // Remove trailing '|'.
143 std::regex re;
144 try {
145 re.assign(joined_regex);
146 } catch (std::regex_error& e) {
147 std::cout << "Invalid regex: " << e.what() << std::endl;
148 return;
149 }
150 for (size_t i = 0; i < COLUMN_NAMES.size(); ++i) {
151 if (std::regex_match(COLUMN_NAMES[i], re)) {
152 auto val = trace.get_column_or_shift(static_cast<ColumnAndShifts>(i), row);
153 std::cout << COLUMN_NAMES[i] << ": " << field_to_string(val);
154 // If the value is small enough, print it as decimal and binary.
155 if (val == FF(static_cast<uint64_t>(val))) {
156 uint64_t n = static_cast<uint64_t>(val);
157 std::cout << " (" << n << ", " << to_binary(n, /*leading_zeroes=*/false) << "b)";
158 }
160 found = true;
161 }
162 }
163 if (!found) {
164 std::cout << "No columns matched: " << joined_regex << std::endl;
165 }
166}
167
168void InteractiveDebugger::set_column(const std::string& column_name, const std::string& value)
169{
170 std::string final_name = prefix + column_name;
171 for (size_t i = 0; i < COLUMN_NAMES.size(); ++i) {
172 // We match both names, for copy-pasting ease.
173 if (COLUMN_NAMES[i] == final_name || COLUMN_NAMES[i] == column_name) {
174 trace.set(static_cast<Column>(i), row, std::stoi(value));
175 std::cout << "Column " << COLUMN_NAMES[i] << " set to value " << value << std::endl;
176 return;
177 }
178 }
179 std::cout << "Column " << column_name << " not found." << std::endl;
180}
181
182void InteractiveDebugger::test_relation(const std::string& relation_name, std::optional<std::string> subrelation_name)
183{
184 bool found = false;
185 bool failed = false;
186
187 bb::constexpr_for<0, std::tuple_size_v<typename AvmFlavor::MainRelations>, 1>([&]<size_t i>() {
189
190 if (Relation::NAME != relation_name) {
191 return;
192 }
193 found = true;
194
195 // TODO(fcarreiro): use check_relation.
197 Relation::accumulate(result, tracegen::get_full_row(trace, row), {}, 1);
198 for (size_t j = 0; j < result.size(); ++j) {
199 if (!result[j].is_zero() &&
200 (!subrelation_name || Relation::get_subrelation_label(j) == *subrelation_name)) {
201 std::cout << format("Relation ",
202 Relation::NAME,
203 ", subrelation ",
204 Relation::get_subrelation_label(j),
205 " failed at row ",
206 row)
207 << std::endl;
208 failed = true;
209 return;
210 }
211 }
212 });
213
214 if (!found) {
215 std::cout << "Relation " << relation_name << " not found." << std::endl;
216 } else if (!failed) {
217 std::cout << "Relation " << relation_name << " ("
218 << (subrelation_name.has_value() ? *subrelation_name : "all subrelations") << ")"
219 << " passed!" << std::endl;
220 }
221}
222
223} // namespace bb::avm2
224#endif
ArrayOfValues< FF, RelationImpl::SUBRELATION_PARTIAL_LENGTHS > SumcheckArrayOfValuesOverSubrelations
void run(uint32_t starting_row=0)
tracegen::TraceContainer & trace
Definition debugger.hpp:35
void print_columns(const std::vector< std::string > &regex)
void test_relation(const std::string &relation_name, std::optional< std::string > subrelation_name)
void set_column(const std::string &column_name, const std::string &value)
const FF & get_column_or_shift(ColumnAndShifts col, uint32_t row) const
void set(Column col, uint32_t row, const FF &value, bool use_atomic_limbs=false)
std::string format(Args... args)
Definition log.hpp:23
AvmFullRow get_full_row(const TraceContainer &trace, uint32_t row)
const std::vector< std::string > & COLUMN_NAMES
Definition columns.cpp:26
AvmFlavorSettings::FF FF
Definition field.hpp:10
ColumnAndShifts
Definition columns.hpp:35
std::string field_to_string(const FF &ff)
Definition stringify.cpp:5
std::vector< std::string > split_and_trim(const std::string &str, char delimiter)
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
VectorField result