aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib
diff options
context:
space:
mode:
authorDan Liew <daniel.liew@imperial.ac.uk>2016-03-18 13:31:30 +0000
committerDan Liew <delcypher@gmail.com>2017-06-01 11:36:09 +0100
commit66e3b6b3dcbf38f5cb4bed7aba57e89ff296c468 (patch)
tree21d24ad079a682ce995469bd774e1159ce57bc49 /lib
parent31e75fdf1e277bbf961287706b06eab8136c6cd0 (diff)
downloadklee-66e3b6b3dcbf38f5cb4bed7aba57e89ff296c468.tar.gz
[Z3] Add the `-debug-z3-dump-queries=<path>` command line option. This
is useful for getting access to the constraints being stored in the Z3 solver in the SMT-LIBv2.5 format.
Diffstat (limited to 'lib')
-rw-r--r--lib/Solver/Z3Solver.cpp37
1 files changed, 36 insertions, 1 deletions
diff --git a/lib/Solver/Z3Solver.cpp b/lib/Solver/Z3Solver.cpp
index 06179f9c..311dbd12 100644
--- a/lib/Solver/Z3Solver.cpp
+++ b/lib/Solver/Z3Solver.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "klee/Config/config.h"
#include "klee/Internal/Support/ErrorHandling.h"
+#include "klee/Internal/Support/FileHandling.h"
#ifdef ENABLE_Z3
#include "Z3Builder.h"
#include "klee/Constraints.h"
@@ -15,6 +16,14 @@
#include "klee/SolverImpl.h"
#include "klee/util/Assignment.h"
#include "klee/util/ExprUtil.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace {
+llvm::cl::opt<std::string> Z3QueryDumpFile(
+ "debug-z3-dump-queries", llvm::cl::init(""),
+ llvm::cl::desc("Dump Z3's representation of the query to the specified path"));
+}
#include "llvm/Support/ErrorHandling.h"
@@ -25,6 +34,7 @@ private:
Z3Builder *builder;
double timeout;
SolverRunStatus runStatusCode;
+ llvm::raw_fd_ostream* dumpedQueriesFile;
::Z3_params solverParameters;
// Parameter symbols
::Z3_symbol timeoutParamStrSymbol;
@@ -66,17 +76,32 @@ public:
Z3SolverImpl::Z3SolverImpl()
: builder(new Z3Builder(/*autoClearConstructCache=*/false)), timeout(0.0),
- runStatusCode(SOLVER_RUN_STATUS_FAILURE) {
+ runStatusCode(SOLVER_RUN_STATUS_FAILURE), dumpedQueriesFile(0) {
assert(builder && "unable to create Z3Builder");
solverParameters = Z3_mk_params(builder->ctx);
Z3_params_inc_ref(builder->ctx, solverParameters);
timeoutParamStrSymbol = Z3_mk_string_symbol(builder->ctx, "timeout");
setCoreSolverTimeout(timeout);
+
+ if (!Z3QueryDumpFile.empty()) {
+ std::string error;
+ dumpedQueriesFile = klee_open_output_file(Z3QueryDumpFile, error);
+ if (!error.empty()) {
+ klee_error("Error creating file for dumping Z3 queries: %s",
+ error.c_str());
+ }
+ klee_message("Dumping Z3 queries to \"%s\"", Z3QueryDumpFile.c_str());
+ }
}
Z3SolverImpl::~Z3SolverImpl() {
Z3_params_dec_ref(builder->ctx, solverParameters);
delete builder;
+
+ if (dumpedQueriesFile) {
+ dumpedQueriesFile->close();
+ delete dumpedQueriesFile;
+ }
}
Z3Solver::Z3Solver() : Solver(new Z3SolverImpl()) {}
@@ -165,6 +190,7 @@ bool Z3SolverImpl::computeInitialValues(
bool Z3SolverImpl::internalRunSolver(
const Query &query, const std::vector<const Array *> *objects,
std::vector<std::vector<unsigned char> > *values, bool &hasSolution) {
+
TimerStatIncrementer t(stats::queryTime);
// TODO: Does making a new solver for each query have a performance
// impact vs making one global solver and using push and pop?
@@ -197,6 +223,15 @@ bool Z3SolverImpl::internalRunSolver(
builder->ctx, theSolver,
Z3ASTHandle(Z3_mk_not(builder->ctx, z3QueryExpr), builder->ctx));
+ if (dumpedQueriesFile) {
+ *dumpedQueriesFile << "; start Z3 query\n";
+ *dumpedQueriesFile << Z3_solver_to_string(builder->ctx, theSolver);
+ *dumpedQueriesFile << "(check-sat)\n";
+ *dumpedQueriesFile << "(reset)\n";
+ *dumpedQueriesFile << "; end Z3 query\n\n";
+ dumpedQueriesFile->flush();
+ }
+
::Z3_lbool satisfiable = Z3_solver_check(builder->ctx, theSolver);
runStatusCode = handleSolverResponse(theSolver, satisfiable, objects, values,
hasSolution);