Skip to content

Commit faf0a61

Browse files
authored
Merge pull request #4592 from JohnDumbell/jd/enhancement/symex_step_debug
Add symex debugging print-out
2 parents f4fff94 + 12b1270 commit faf0a61

File tree

6 files changed

+146
-7
lines changed

6 files changed

+146
-7
lines changed

jbmc/src/jbmc/jbmc_parse_options.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ void jbmc_parse_optionst::set_default_options(optionst &options)
113113
options.set_option("simple-slice", true);
114114
options.set_option("simplify", true);
115115
options.set_option("simplify-if", true);
116+
options.set_option("show-goto-symex-steps", false);
116117

117118
// Other default
118119
options.set_option("arrays-uf", "auto");
@@ -415,6 +416,9 @@ void jbmc_parse_optionst::get_command_line_options(optionst &options)
415416
// code.
416417
if(cmdline.isset("java-threading"))
417418
options.set_option("allow-pointer-unsoundness", true);
419+
420+
if(cmdline.isset("show-goto-symex-steps"))
421+
options.set_option("show-goto-symex-steps", true);
418422
}
419423

420424
/// invoke main modules

src/cbmc/cbmc_parse_options.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ void cbmc_parse_optionst::set_default_options(optionst &options)
118118
options.set_option("simple-slice", true);
119119
options.set_option("simplify", true);
120120
options.set_option("simplify-if", true);
121+
options.set_option("show-goto-symex-steps", false);
121122

122123
// Other default
123124
options.set_option("arrays-uf", "auto");
@@ -442,6 +443,9 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
442443
options.set_option("validate-goto-model", true);
443444
}
444445

446+
if(cmdline.isset("show-goto-symex-steps"))
447+
options.set_option("show-goto-symex-steps", true);
448+
445449
PARSE_OPTIONS_GOTO_TRACE(cmdline, options);
446450
}
447451

src/goto-checker/bmc_util.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ void run_property_decider(
175175
"(program-only)" \
176176
"(show-loops)" \
177177
"(show-vcc)" \
178+
"(show-goto-symex-steps)" \
178179
"(slice-formula)" \
179180
"(unwinding-assertions)" \
180181
"(no-unwinding-assertions)" \
@@ -192,6 +193,8 @@ void run_property_decider(
192193
#define HELP_BMC \
193194
" --paths [strategy] explore paths one at a time\n" \
194195
" --show-symex-strategies list strategies for use with --paths\n" \
196+
" --show-goto-symex-steps show which steps symex travels, includes " \
197+
" diagnostic information\n" \
195198
" --program-only only show program expression\n" \
196199
" --show-loops show the loops in the program\n" \
197200
" --depth nr limit search depth\n" \

src/goto-symex/goto_symex.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ struct symex_configt final
6464
/// executed in the goto_symex_statet (in the assignment method).
6565
bool run_validation_checks;
6666

67+
/// \brief Prints out the path that symex is actively taking during execution,
68+
/// includes diagnostic information about call stack and guard size.
69+
bool show_symex_steps;
70+
6771
/// \brief Construct a symex_configt using options specified in an
6872
/// \ref optionst
6973
explicit symex_configt(const optionst &options);
@@ -224,6 +228,13 @@ class goto_symext
224228
virtual void
225229
symex_step(const get_goto_functiont &get_goto_function, statet &state);
226230

231+
/// Prints the route of symex as it walks through the code. Used for
232+
/// debugging.
233+
void print_symex_step(statet &state);
234+
235+
messaget::mstreamt &
236+
print_callstack_entry(const symex_targett::sourcet &target);
237+
227238
public:
228239

229240
/// language_mode: ID_java, ID_C or another language identifier

src/goto-symex/symex_main.cpp

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ Author: Daniel Kroening, [email protected]
2626
#include <util/string2int.h>
2727
#include <util/symbol_table.h>
2828

29+
#include <util/format.h>
30+
#include <util/format_expr.h>
31+
#include <util/format_type.h>
32+
#include <util/std_types.h>
33+
2934
symex_configt::symex_configt(const optionst &options)
3035
: max_depth(options.get_unsigned_int_option("depth")),
3136
doing_path_exploration(options.is_set("paths")),
@@ -38,7 +43,8 @@ symex_configt::symex_configt(const optionst &options)
3843
unwinding_assertions(options.get_bool_option("unwinding-assertions")),
3944
partial_loops(options.get_bool_option("partial-loops")),
4045
debug_level(unsafe_string2int(options.get_option("debug-level"))),
41-
run_validation_checks(options.get_bool_option("validate-ssa-equation"))
46+
run_validation_checks(options.get_bool_option("validate-ssa-equation")),
47+
show_symex_steps(options.get_bool_option("show-goto-symex-steps"))
4248
{
4349
}
4450

@@ -409,17 +415,103 @@ goto_symext::get_goto_function(abstract_goto_modelt &goto_model)
409415
};
410416
}
411417

418+
messaget::mstreamt &
419+
goto_symext::print_callstack_entry(const symex_targett::sourcet &source)
420+
{
421+
log.status() << source.function_id
422+
<< " location number: " << source.pc->location_number;
423+
424+
return log.status();
425+
}
426+
427+
void goto_symext::print_symex_step(statet &state)
428+
{
429+
// If we're showing the route, begin outputting debug info, and don't print
430+
// instructions we don't run.
431+
432+
// We also skip dead instructions as they don't add much to step-based
433+
// debugging and if there's no code block at this point.
434+
if(
435+
!symex_config.show_symex_steps || state.guard.is_false() ||
436+
state.source.pc->type == DEAD ||
437+
(state.source.pc->code.is_nil() && state.source.pc->type != END_FUNCTION))
438+
{
439+
return;
440+
}
441+
442+
if(state.source.pc->code.is_not_nil())
443+
{
444+
auto guard_expression = state.guard.as_expr();
445+
std::size_t size = 0;
446+
for(auto it = guard_expression.depth_begin();
447+
it != guard_expression.depth_end();
448+
++it)
449+
{
450+
size++;
451+
}
452+
453+
log.status() << "[Guard size: " << size << "] "
454+
<< format(state.source.pc->code);
455+
456+
if(
457+
state.source.pc->source_location.is_not_nil() &&
458+
!state.source.pc->source_location.get_java_bytecode_index().empty())
459+
{
460+
log.status()
461+
<< " bytecode index: "
462+
<< state.source.pc->source_location.get_java_bytecode_index();
463+
}
464+
465+
log.status() << messaget::eom;
466+
}
467+
468+
// Print the method we're returning too.
469+
const auto &call_stack = state.threads[state.source.thread_nr].call_stack;
470+
if(state.source.pc->type == END_FUNCTION)
471+
{
472+
log.status() << messaget::eom;
473+
474+
if(!call_stack.empty())
475+
{
476+
log.status() << "Returning to: ";
477+
print_callstack_entry(call_stack.back().calling_location)
478+
<< messaget::eom;
479+
}
480+
481+
log.status() << messaget::eom;
482+
}
483+
484+
// On a function call print the entire call stack.
485+
if(state.source.pc->type == FUNCTION_CALL)
486+
{
487+
log.status() << messaget::eom;
488+
489+
if(!call_stack.empty())
490+
{
491+
log.status() << "Call stack:" << messaget::eom;
492+
493+
for(auto &frame : call_stack)
494+
{
495+
print_callstack_entry(frame.calling_location) << messaget::eom;
496+
}
497+
498+
print_callstack_entry(state.source) << messaget::eom;
499+
500+
// Add the method we're about to enter with no location number.
501+
log.status() << format(
502+
to_code_function_call(state.source.pc->code).function())
503+
<< messaget::eom << messaget::eom;
504+
}
505+
}
506+
}
507+
412508
/// do just one step
413509
void goto_symext::symex_step(
414510
const get_goto_functiont &get_goto_function,
415511
statet &state)
416512
{
417-
#if 0
418-
std::cout << "\ninstruction type is " << state.source.pc->type << '\n';
419-
std::cout << "Location: " << state.source.pc->source_location << '\n';
420-
std::cout << "Guard: " << format(state.guard.as_expr()) << '\n';
421-
std::cout << "Code: " << format(state.source.pc->code) << '\n';
422-
#endif
513+
// Print debug statements if they've been enabled.
514+
print_symex_step(state);
423515

424516
PRECONDITION(!state.threads.empty());
425517
PRECONDITION(!state.call_stack().empty());

src/util/format_expr.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,31 @@ std::ostream &format_rec(std::ostream &os, const exprt &expr)
324324
os << ' ' << format(s);
325325
return os << " }";
326326
}
327+
else if(statement == ID_dead)
328+
{
329+
return os << "dead " << format(to_code_dead(code).symbol()) << ";";
330+
}
331+
else if(statement == ID_decl)
332+
{
333+
const auto &declaration_symb = to_code_decl(code).symbol();
334+
return os << "decl " << format(declaration_symb.type()) << " "
335+
<< format(declaration_symb) << ";";
336+
}
337+
else if(statement == ID_function_call)
338+
{
339+
const auto &func_call = to_code_function_call(code);
340+
os << to_symbol_expr(func_call.function()).get_identifier() << "(";
341+
342+
// Join all our arguments together.
343+
join_strings(
344+
os,
345+
func_call.arguments().begin(),
346+
func_call.arguments().end(),
347+
", ",
348+
[](const exprt &expr) { return format(expr); });
349+
350+
return os << ");";
351+
}
327352
else
328353
return fallback_format_rec(os, expr);
329354
}

0 commit comments

Comments
 (0)