Skip to content

Commit 2e9e1a0

Browse files
committed
Change the way max symbolic variables works + add --stop-at-pc
1 parent dc80a5f commit 2e9e1a0

File tree

4 files changed

+146
-17
lines changed

4 files changed

+146
-17
lines changed

platforms/CLI-Emulator/main.cpp

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "../../src/Utils/macros.h"
2020
#include "../../src/Utils/util.h"
2121
#include "warduino/config.h"
22+
#include "bigint.h"
2223

2324
// Constants
2425
#define MAX_MODULE_SIZE (64 * 1024 * 1024)
@@ -457,6 +458,85 @@ struct Model {
457458
return count;
458459
}
459460

461+
size_t max_fanout() {
462+
size_t max = 0;
463+
if (subpaths.size() > max) {
464+
max = subpaths.size();
465+
}
466+
for (Model path : subpaths) {
467+
max = std::max(path.max_fanout(), max);
468+
}
469+
return max;
470+
}
471+
472+
int min_fanout() {
473+
int min = -1;
474+
if (!subpaths.empty() && (min < 0 || subpaths.size() < min)) {
475+
min = subpaths.size();
476+
}
477+
478+
for (Model path : subpaths) {
479+
int val = path.min_fanout();
480+
if (val > 0) {
481+
min = std::min(val, min);
482+
}
483+
}
484+
return min;
485+
}
486+
487+
BigInt::bigint prim_states(const std::string& prim) {
488+
if (prim == "chip_analog_read") {
489+
return 4096;
490+
}
491+
if (prim == "chip_digital_read") {
492+
return 2;
493+
}
494+
}
495+
496+
BigInt::bigint max_states() {
497+
BigInt::bigint max = 0;
498+
for (auto model : subpaths) {
499+
BigInt::bigint value = model.max_states(0);
500+
if (value > max) {
501+
max = value;
502+
}
503+
}
504+
return max;
505+
}
506+
507+
BigInt::bigint max_states(size_t depth) {
508+
// TODO: Maybe, maybe not, knock lock for example
509+
/*if (subpaths.empty()) {
510+
return 1;
511+
}*/
512+
513+
BigInt::bigint v = prim_states(values["x_" + std::to_string(depth)].primitive_origin);
514+
BigInt::bigint max = v;
515+
for (int i = 0; i < subpaths.size(); i++) {
516+
BigInt::bigint value = v * subpaths[i].max_states(depth + 1); // Might overflow (Gesture-robot)
517+
if (value > max) {
518+
max = value;
519+
}
520+
}
521+
return max;
522+
}
523+
524+
void fanouts(std::vector<size_t> &fanout) {
525+
if (subpaths.empty()) {
526+
return;
527+
}
528+
fanout.emplace_back(subpaths.size());
529+
for (Model path : subpaths) {
530+
path.fanouts(fanout);
531+
}
532+
}
533+
534+
float avg_fanout() {
535+
std::vector<size_t> f;
536+
fanouts(f);
537+
return static_cast<float>(std::reduce(f.begin(), f.end())) / static_cast<float>(f.size());
538+
}
539+
460540
nlohmann::json to_json() {
461541
nlohmann::json graph;
462542
graph["paths"] = to_json(0);
@@ -506,7 +586,8 @@ z3::expr preconditions() {
506586
return primitive_bounds;
507587
}
508588

509-
void run_concolic(const std::vector<std::string>& snapshot_messages, int max_instructions = 50, int max_sym_vars = -1, int max_iterations = -1) {
589+
void run_concolic(const std::vector<std::string>& snapshot_messages, int max_instructions = 50, int max_sym_vars = -1, int max_iterations = -1, int stop_at_pc = -1) {
590+
const auto start{std::chrono::steady_clock::now()};
510591
wac->interpreter = new ConcolicInterpreter();
511592
// Has a big impact on performance, for example if you have a simple program
512593
// with a loop that contains an if statement and, you run the loop 30 times
@@ -516,6 +597,7 @@ void run_concolic(const std::vector<std::string>& snapshot_messages, int max_ins
516597
//wac->max_instructions = 900;
517598
wac->max_instructions = max_instructions;
518599
wac->max_symbolic_variables = max_sym_vars;
600+
wac->stop_at_pc = stop_at_pc;
519601
int total_instructions_executed = 0;
520602

521603
z3::expr global_condition = m->ctx.bool_val(true);
@@ -638,6 +720,8 @@ void run_concolic(const std::vector<std::string>& snapshot_messages, int max_ins
638720
z3_pretty_println(m->path_condition);*/
639721
}
640722

723+
const auto finish{std::chrono::steady_clock::now()};
724+
const std::chrono::duration<double> elapsed_seconds{finish - start};
641725
std::cout << std::endl << "=== FINISHED ===" << std::endl;
642726
/*std::cout << "Models found:" << std::endl;
643727
for (size_t i = 0; i < models.size(); i++) {
@@ -652,7 +736,14 @@ void run_concolic(const std::vector<std::string>& snapshot_messages, int max_ins
652736
std::cout << "Models found:" << std::endl;
653737
std::cout << graph.to_string(0) << std::endl;
654738
std::cout << graph.to_json() << std::endl;
655-
std::cout << "Found " << graph.count_leaf_nodes() << " uniqe paths!" << std::endl;
739+
//std::cout << uint128_to_string(graph.max_states()) << " & " << graph.count_leaf_nodes() << " & " << " & " << graph.max_fanout() << " & " << elapsed_seconds.count() << " \\\\" << std::endl;
740+
std::cout << graph.max_states() << " & " << graph.count_leaf_nodes() << " & " << graph.max_fanout() << " & " <<
741+
(max_instructions < 0 ? "$\\infty$" : std::to_string(max_instructions)) << " & " <<
742+
(max_sym_vars < 0 ? "$\\infty$" : std::to_string(max_sym_vars)) << " & " <<
743+
(max_iterations < 0 ? "$\\infty$" : std::to_string(max_iterations)) << " & " <<
744+
std::fixed << std::setprecision(3) << elapsed_seconds.count() << " \\\\" << std::endl;
745+
//std::cout << uint128_to_string(graph.max_states()) << " & " << graph.count_leaf_nodes() << " & " << graph.min_fanout() << " & " << graph.max_fanout() << " & " << graph.avg_fanout() << " \\\\" << std::endl;
746+
656747
/*for (size_t i = 0; i < x0_models.size(); i++) {
657748
std::cout << "- Model #" << i << ":" << std::endl;
658749
//z3_pretty_println(x0_models[i].path_condition);
@@ -693,6 +784,7 @@ int main(int argc, const char *argv[]) {
693784
const char *max_instructions_str = "50";
694785
const char *max_symbolic_variables_str = "-1";
695786
const char *max_iterations_str = "-1";
787+
const char *stop_at_pc_str = "-1";
696788
bool dump_info = false;
697789

698790
const char *fname = nullptr;
@@ -786,6 +878,8 @@ int main(int argc, const char *argv[]) {
786878
ARGV_GET(max_symbolic_variables_str);
787879
} else if (!strcmp("--max-iterations", arg)) {
788880
ARGV_GET(max_iterations_str);
881+
} else if (!strcmp("--stop-at-pc", arg)) {
882+
ARGV_GET(stop_at_pc_str);
789883
} else if (!strcmp("--dump-info", arg)) {
790884
dump_info = true;
791885
}
@@ -896,7 +990,7 @@ int main(int argc, const char *argv[]) {
896990

897991
// Run Wasm module
898992
if (strcmp(mode, "concolic") == 0) {
899-
run_concolic(snapshot_messages, std::stoi(max_instructions_str), std::stoi(max_symbolic_variables_str), std::stoi(max_iterations_str));
993+
run_concolic(snapshot_messages, std::stoi(max_instructions_str), std::stoi(max_symbolic_variables_str), std::stoi(max_iterations_str), std::stoi(stop_at_pc_str));
900994
}
901995
else {
902996
// TODO: Add option to calculate the choice points and add them as breakpoints from the remote debugger once

src/Interpreter/interp_loop.h

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#pragma once
22

3-
#include "concolic_interpreter.h"
4-
#include "interpreter.h"
3+
#include <iostream>
54

65
#include "../Memory/mem.h"
76
#include "../Utils/macros.h"
@@ -73,6 +72,7 @@ bool interp(Module *m, bool waiting) {
7372
? "module"
7473
: "patch");
7574

75+
m->path_condition = m->path_condition.simplify();
7676
/*std::string symbolic_stack_str = "sym stack : [ ";
7777
std::string stack_str = "stack : [ ";
7878
//for (int i = std::max(0, m->sp - 5); i <= m->sp; i++) {
@@ -89,7 +89,7 @@ bool interp(Module *m, bool waiting) {
8989
}
9090
else {
9191
// None means that there is no symbolic value for the current
92-
thing on the stack, we didn't implement something yet in that case.
92+
//thing on the stack, we didn't implement something yet in that case.
9393
//assert(false);
9494
symbolic_stack_str += "none";
9595
}
@@ -101,25 +101,47 @@ bool interp(Module *m, bool waiting) {
101101
symbolic_stack_str += " ]";
102102
stack_str += " ]";
103103
std::cout << symbolic_stack_str << std::endl;
104-
std::cout << stack_str << std::endl;*/
104+
std::cout << stack_str << std::endl;
105+
106+
z3::solver s(m->ctx);
107+
s.add(m->path_condition);
108+
auto result = s.check();
109+
std::cout << "Path condition: " << m->path_condition.to_string() << std::endl;
110+
assert(result == z3::sat);
111+
112+
std::cout << "Globals: [";
113+
for (int i = 0; i < m->symbolic_globals.size(); i++) {
114+
std::cout << m->symbolic_globals[i].to_string() << ", ";
115+
}
116+
std::cout << std::endl;*/
117+
105118
/*std::cout << "running instr: " << OPERATOR_INFO[opcode]; // <<
106119
std::endl; uint8_t *pc_ptr_tmp = m->pc_ptr; std::cout << " " <<
107120
read_LEB_32(&pc_ptr_tmp) << std::endl;*/
108-
m->instructions_executed++;
109-
if (m->warduino->max_instructions > 0 &&
110-
m->instructions_executed >= m->warduino->max_instructions) {
111-
debug("Max instructions executed\n");
112-
return true;
121+
if (m->warduino->program_state == WARDUINOrun) {
122+
m->instructions_executed++;
123+
if (m->warduino->max_instructions > 0 &&
124+
m->instructions_executed >= m->warduino->max_instructions) {
125+
debug("Max instructions executed\n");
126+
return true;
127+
}
128+
129+
if (m->warduino->stop_at_pc >= 0) {
130+
if (m->pc_ptr == toPhysicalAddress(m->warduino->stop_at_pc, m)) {
131+
debug("Stop pc reached\n");
132+
return true;
133+
}
134+
}
113135
}
114-
if (m->warduino->max_symbolic_variables > 0 && m->symbolic_variable_count >= m->warduino->max_symbolic_variables) {
136+
if (m->warduino->max_symbolic_variables > 0 && m->symbolic_variable_count > m->warduino->max_symbolic_variables) {
115137
return true;
116138
}
117139
T interpreter;
118-
if (std::is_same<T, Interpreter>()) {
140+
/*if (std::is_same<T, Interpreter>()) {
119141
printf("Concrete\n");
120142
} else if (std::is_same<T, ConcolicInterpreter>()) {
121143
printf("Concolic\n");
122-
}
144+
}*/
123145
switch (opcode) {
124146
//
125147
// Control flow operators

src/Primitives/emulated.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,12 @@ def_prim(chip_digital_write, twoToNoneU32) {
414414
def_prim(chip_digital_read, oneToOneU32) {
415415
uint8_t pin = arg0.uint32;
416416
pop_args(1);
417-
pushUInt32(1); // HIGH
417+
//pushUInt32(1); // HIGH
418+
if (m->warduino->max_symbolic_variables > 0 && m->symbolic_variable_count + 1 > m->warduino->max_symbolic_variables) {
419+
m->symbolic_variable_count++;
420+
return true;
421+
}
422+
push_symbolic_int(m, "chip_digital_read", pin);
418423
return true;
419424
}
420425

@@ -425,7 +430,12 @@ def_prim(chip_analog_read, oneToOneI32) {
425430
push_symbolic_int(m, "chip_analog_read", pin);
426431
return true;
427432
}*/
428-
pushInt32(sin(sensor_emu) * 100);
433+
if (m->warduino->max_symbolic_variables > 0 && m->symbolic_variable_count + 1 > m->warduino->max_symbolic_variables) {
434+
m->symbolic_variable_count++;
435+
return true;
436+
}
437+
push_symbolic_int(m, "chip_analog_read", pin);
438+
//pushInt32(sin(sensor_emu) * 100);
429439
sensor_emu += .25;
430440
return true;
431441
}
@@ -437,6 +447,8 @@ def_prim(color_sensor, oneToOneI32) {
437447
push_symbolic_int(m, "color_sensor", pin);
438448
return true;
439449
}*/
450+
push_symbolic_int(m, "color_sensor", pin);
451+
return true;
440452
pushInt32(sin(sensor_emu) * 100);
441453
sensor_emu += .25;
442454
return true;

src/WARDuino.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ class WARDuino {
251251
Interpreter *interpreter;
252252
int max_instructions = -1;
253253
int max_symbolic_variables = -1;
254+
int stop_at_pc = -1;
254255

255256
static WARDuino *instance();
256257

0 commit comments

Comments
 (0)