klee
main.cpp
Go to the documentation of this file.
1//===-- main.cpp ------------------------------------------------*- C++ -*-===//
2//
3// The KLEE Symbolic Virtual Machine
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "klee/Config/Version.h"
12#include "klee/Expr/Expr.h"
19#include "klee/Solver/Common.h"
22#include "klee/Solver/Solver.h"
26
27#include "llvm/ADT/StringExtras.h"
28#include "llvm/Support/CommandLine.h"
29#include "llvm/Support/ManagedStatic.h"
30#include "llvm/Support/MemoryBuffer.h"
31#include "llvm/Support/raw_ostream.h"
32
33#include <sys/stat.h>
34#include <unistd.h>
35
36
37#include "llvm/Support/Signals.h"
38
39using namespace llvm;
40using namespace klee;
41using namespace klee::expr;
42
43namespace {
44llvm::cl::opt<std::string> InputFile(llvm::cl::desc("<input query log>"),
45 llvm::cl::Positional, llvm::cl::init("-"),
46 llvm::cl::cat(klee::ExprCat));
47
48enum ToolActions { PrintTokens, PrintAST, PrintSMTLIBv2, Evaluate };
49
50static llvm::cl::opt<ToolActions> ToolAction(
51 llvm::cl::desc("Tool actions:"), llvm::cl::init(Evaluate),
52 llvm::cl::values(clEnumValN(PrintTokens, "print-tokens",
53 "Print tokens from the input file."),
54 clEnumValN(PrintSMTLIBv2, "print-smtlib",
55 "Print parsed input file as SMT-LIBv2 query."),
56 clEnumValN(PrintAST, "print-ast",
57 "Print parsed AST nodes from the input file."),
58 clEnumValN(Evaluate, "evaluate",
59 "Evaluate parsed AST nodes from the input file.")),
60 llvm::cl::cat(klee::SolvingCat));
61
62enum BuilderKinds {
63 DefaultBuilder,
64 ConstantFoldingBuilder,
65 SimplifyingBuilder
66};
67
68static llvm::cl::opt<BuilderKinds> BuilderKind(
69 "builder", llvm::cl::desc("Expression builder:"),
70 llvm::cl::init(DefaultBuilder),
71 llvm::cl::values(clEnumValN(DefaultBuilder, "default",
72 "Default expression construction."),
73 clEnumValN(ConstantFoldingBuilder, "constant-folding",
74 "Fold constant expressions."),
75 clEnumValN(SimplifyingBuilder, "simplify",
76 "Fold constants and simplify expressions.")),
77 llvm::cl::cat(klee::ExprCat));
78
79llvm::cl::opt<std::string> DirectoryToWriteQueryLogs(
80 "query-log-dir",
81 llvm::cl::desc(
82 "The folder to write query logs to (default=current directory)"),
83 llvm::cl::init("."), llvm::cl::cat(klee::ExprCat));
84
85llvm::cl::opt<bool> ClearArrayAfterQuery(
86 "clear-array-decls-after-query",
87 llvm::cl::desc("Discard the previous array declarations after a query "
88 "is performed (default=false)"),
89 llvm::cl::init(false), llvm::cl::cat(klee::ExprCat));
90} // namespace
91
92static std::string getQueryLogPath(const char filename[])
93{
94 //check directoryToWriteLogs exists
95 struct stat s;
96 if( !(stat(DirectoryToWriteQueryLogs.c_str(),&s) == 0 && S_ISDIR(s.st_mode)) )
97 {
98 llvm::errs() << "Directory to log queries \""
99 << DirectoryToWriteQueryLogs << "\" does not exist!"
100 << "\n";
101 exit(1);
102 }
103
104 //check permissions okay
105 if( !( (s.st_mode & S_IWUSR) && getuid() == s.st_uid) &&
106 !( (s.st_mode & S_IWGRP) && getgid() == s.st_gid) &&
107 !( s.st_mode & S_IWOTH)
108 )
109 {
110 llvm::errs() << "Directory to log queries \""
111 << DirectoryToWriteQueryLogs << "\" is not writable!"
112 << "\n";
113 exit(1);
114 }
115
116 std::string path = DirectoryToWriteQueryLogs;
117 path += "/";
118 path += filename;
119 return path;
120}
121
122static std::string escapedString(const char *start, unsigned length) {
123 std::string Str;
124 llvm::raw_string_ostream s(Str);
125 for (unsigned i=0; i<length; ++i) {
126 char c = start[i];
127 if (isprint(c)) {
128 s << c;
129 } else if (c == '\n') {
130 s << "\\n";
131 } else {
132 s << "\\x"
133 << hexdigit(((unsigned char) c >> 4) & 0xF)
134 << hexdigit((unsigned char) c & 0xF);
135 }
136 }
137 return s.str();
138}
139
140static void PrintInputTokens(const MemoryBuffer *MB) {
141 Lexer L(MB);
142 Token T;
143 do {
144 L.Lex(T);
145 llvm::outs() << "(Token \"" << T.getKindName() << "\" "
146 << "\"" << escapedString(T.start, T.length) << "\" "
147 << T.length << " " << T.line << " " << T.column << ")\n";
148 } while (T.kind != Token::EndOfFile);
149}
150
151static bool PrintInputAST(const char *Filename,
152 const MemoryBuffer *MB,
153 ExprBuilder *Builder) {
154 std::vector<Decl*> Decls;
155 Parser *P = Parser::Create(Filename, MB, Builder, ClearArrayAfterQuery);
156 P->SetMaxErrors(20);
157
158 unsigned NumQueries = 0;
159 while (Decl *D = P->ParseTopLevelDecl()) {
160 if (!P->GetNumErrors()) {
161 if (isa<QueryCommand>(D))
162 llvm::outs() << "# Query " << ++NumQueries << "\n";
163
164 D->dump();
165 }
166 Decls.push_back(D);
167 }
168
169 bool success = true;
170 if (unsigned N = P->GetNumErrors()) {
171 llvm::errs() << Filename << ": parse failure: " << N << " errors.\n";
172 success = false;
173 }
174
175 for (std::vector<Decl*>::iterator it = Decls.begin(),
176 ie = Decls.end(); it != ie; ++it)
177 delete *it;
178
179 delete P;
180
181 return success;
182}
183
184static bool EvaluateInputAST(const char *Filename,
185 const MemoryBuffer *MB,
186 ExprBuilder *Builder) {
187 std::vector<Decl*> Decls;
188 Parser *P = Parser::Create(Filename, MB, Builder, ClearArrayAfterQuery);
189 P->SetMaxErrors(20);
190 while (Decl *D = P->ParseTopLevelDecl()) {
191 Decls.push_back(D);
192 }
193
194 bool success = true;
195 if (unsigned N = P->GetNumErrors()) {
196 llvm::errs() << Filename << ": parse failure: " << N << " errors.\n";
197 success = false;
198 }
199
200 if (!success)
201 return false;
202
204
206 const time::Span maxCoreSolverTime(MaxCoreSolverTime);
207 if (maxCoreSolverTime) {
208 coreSolver->setCoreSolverTimeout(maxCoreSolverTime);
209 }
210 }
211
212 Solver *S = constructSolverChain(coreSolver,
217
218 unsigned Index = 0;
219 for (std::vector<Decl*>::iterator it = Decls.begin(),
220 ie = Decls.end(); it != ie; ++it) {
221 Decl *D = *it;
222 if (QueryCommand *QC = dyn_cast<QueryCommand>(D)) {
223 llvm::outs() << "Query " << Index << ":\t";
224
225 assert("FIXME: Support counterexample query commands!");
226 if (QC->Values.empty() && QC->Objects.empty()) {
227 bool result;
228 if (S->mustBeTrue(Query(ConstraintSet(QC->Constraints), QC->Query),
229 result)) {
230 llvm::outs() << (result ? "VALID" : "INVALID");
231 } else {
232 llvm::outs() << "FAIL (reason: "
233 << SolverImpl::getOperationStatusString(S->impl->getOperationStatusCode())
234 << ")";
235 }
236 } else if (!QC->Values.empty()) {
237 assert(QC->Objects.empty() &&
238 "FIXME: Support counterexamples for values and objects!");
239 assert(QC->Values.size() == 1 &&
240 "FIXME: Support counterexamples for multiple values!");
241 assert(QC->Query->isFalse() &&
242 "FIXME: Support counterexamples with non-trivial query!");
243 ref<ConstantExpr> result;
244 if (S->getValue(Query(ConstraintSet(QC->Constraints), QC->Values[0]),
245 result)) {
246 llvm::outs() << "INVALID\n";
247 llvm::outs() << "\tExpr 0:\t" << result;
248 } else {
249 llvm::outs() << "FAIL (reason: "
250 << SolverImpl::getOperationStatusString(S->impl->getOperationStatusCode())
251 << ")";
252 }
253 } else {
254 std::vector< std::vector<unsigned char> > result;
255
256 if (S->getInitialValues(
257 Query(ConstraintSet(QC->Constraints), QC->Query), QC->Objects,
258 result)) {
259 llvm::outs() << "INVALID\n";
260
261 for (unsigned i = 0, e = result.size(); i != e; ++i) {
262 llvm::outs() << "\tArray " << i << ":\t"
263 << QC->Objects[i]->name
264 << "[";
265 for (unsigned j = 0; j != QC->Objects[i]->size; ++j) {
266 llvm::outs() << (unsigned) result[i][j];
267 if (j + 1 != QC->Objects[i]->size)
268 llvm::outs() << ", ";
269 }
270 llvm::outs() << "]";
271 if (i + 1 != e)
272 llvm::outs() << "\n";
273 }
274 } else {
276 if (SolverImpl::SOLVER_RUN_STATUS_TIMEOUT == retCode) {
277 llvm::outs() << " FAIL (reason: "
278 << SolverImpl::getOperationStatusString(retCode)
279 << ")";
280 }
281 else {
282 llvm::outs() << "VALID (counterexample request ignored)";
283 }
284 }
285 }
286
287 llvm::outs() << "\n";
288 ++Index;
289 }
290 }
291
292 for (std::vector<Decl*>::iterator it = Decls.begin(),
293 ie = Decls.end(); it != ie; ++it)
294 delete *it;
295 delete P;
296
297 delete S;
298
299 if (uint64_t queries = *theStatisticManager->getStatisticByName("Queries")) {
300 llvm::outs()
301 << "--\n"
302 << "total queries = " << queries << '\n'
303 << "total query constructs = "
304 << *theStatisticManager->getStatisticByName("QueryConstructs") << '\n'
305 << "valid queries = "
306 << *theStatisticManager->getStatisticByName("QueriesValid") << '\n'
307 << "invalid queries = "
308 << *theStatisticManager->getStatisticByName("QueriesInvalid") << '\n'
309 << "query cex = "
310 << *theStatisticManager->getStatisticByName("QueriesCEX") << '\n';
311 }
312
313 return success;
314}
315
316static bool printInputAsSMTLIBv2(const char *Filename,
317 const MemoryBuffer *MB,
318 ExprBuilder *Builder)
319{
320 //Parse the input file
321 std::vector<Decl*> Decls;
322 Parser *P = Parser::Create(Filename, MB, Builder, ClearArrayAfterQuery);
323 P->SetMaxErrors(20);
324 while (Decl *D = P->ParseTopLevelDecl())
325 {
326 Decls.push_back(D);
327 }
328
329 bool success = true;
330 if (unsigned N = P->GetNumErrors())
331 {
332 llvm::errs() << Filename << ": parse failure: "
333 << N << " errors.\n";
334 success = false;
335 }
336
337 if (!success)
338 return false;
339
340 ExprSMTLIBPrinter printer;
341 printer.setOutput(llvm::outs());
342
343 unsigned int queryNumber = 0;
344 //Loop over the declarations
345 for (std::vector<Decl*>::iterator it = Decls.begin(), ie = Decls.end(); it != ie; ++it)
346 {
347 Decl *D = *it;
348 if (QueryCommand *QC = dyn_cast<QueryCommand>(D))
349 {
350 //print line break to separate from previous query
351 if(queryNumber!=0) llvm::outs() << "\n";
352
353 //Output header for this query as a SMT-LIBv2 comment
354 llvm::outs() << ";SMTLIBv2 Query " << queryNumber << "\n";
355
356 /* Can't pass ConstraintManager constructor directly
357 * as argument to Query object. Like...
358 * query(ConstraintManager(QC->Constraints),QC->Query);
359 *
360 * For some reason if constructed this way the first
361 * constraint in the constraint set is set to NULL and
362 * will later cause a NULL pointer dereference.
363 */
364 ConstraintSet constraintM(QC->Constraints);
365 Query query(constraintM, QC->Query);
366 printer.setQuery(query);
367
368 if(!QC->Objects.empty())
369 printer.setArrayValuesToGet(QC->Objects);
370
371 printer.generateOutput();
372
373
374 queryNumber++;
375 }
376 }
377
378 //Clean up
379 for (std::vector<Decl*>::iterator it = Decls.begin(),
380 ie = Decls.end(); it != ie; ++it)
381 delete *it;
382 delete P;
383
384 return true;
385}
386
387int main(int argc, char **argv) {
388#if LLVM_VERSION_CODE >= LLVM_VERSION(13, 0)
389 KCommandLine::HideOptions(llvm::cl::getGeneralCategory());
390#else
391 KCommandLine::HideOptions(llvm::cl::GeneralCategory);
392#endif
393
394 bool success = true;
395
396 llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
397 llvm::cl::SetVersionPrinter(klee::printVersion);
398 llvm::cl::ParseCommandLineOptions(argc, argv);
399
400 std::string ErrorStr;
401
402 auto MBResult = MemoryBuffer::getFileOrSTDIN(InputFile.c_str());
403 if (!MBResult) {
404 llvm::errs() << argv[0] << ": error: " << MBResult.getError().message()
405 << "\n";
406 return 1;
407 }
408 std::unique_ptr<MemoryBuffer> &MB = *MBResult;
409
410 ExprBuilder *Builder = 0;
411 switch (BuilderKind) {
412 case DefaultBuilder:
413 Builder = createDefaultExprBuilder();
414 break;
415 case ConstantFoldingBuilder:
416 Builder = createDefaultExprBuilder();
417 Builder = createConstantFoldingExprBuilder(Builder);
418 break;
419 case SimplifyingBuilder:
420 Builder = createDefaultExprBuilder();
421 Builder = createConstantFoldingExprBuilder(Builder);
422 Builder = createSimplifyingExprBuilder(Builder);
423 break;
424 }
425
426 switch (ToolAction) {
427 case PrintTokens:
428 PrintInputTokens(MB.get());
429 break;
430 case PrintAST:
431 success = PrintInputAST(InputFile=="-" ? "<stdin>" : InputFile.c_str(), MB.get(),
432 Builder);
433 break;
434 case Evaluate:
435 success = EvaluateInputAST(InputFile=="-" ? "<stdin>" : InputFile.c_str(),
436 MB.get(), Builder);
437 break;
438 case PrintSMTLIBv2:
439 success = printInputAsSMTLIBv2(InputFile=="-"? "<stdin>" : InputFile.c_str(), MB.get(),Builder);
440 break;
441 default:
442 llvm::errs() << argv[0] << ": error: Unknown program action!\n";
443 }
444
445 delete Builder;
446 llvm::llvm_shutdown();
447 return success ? 0 : 1;
448}
ExprBuilder - Base expression builder class.
Definition: ExprBuilder.h:17
void setQuery(const Query &q)
void setOutput(llvm::raw_ostream &output)
void setArrayValuesToGet(const std::vector< const Array * > &a)
virtual SolverRunStatus getOperationStatusCode()=0
getOperationStatusCode - get the status of the last solver operation
bool mustBeTrue(const Query &, bool &result)
Definition: Solver.cpp:49
bool getValue(const Query &, ref< ConstantExpr > &result)
Definition: Solver.cpp:81
SolverImpl * impl
Definition: Solver.h:77
bool getInitialValues(const Query &, const std::vector< const Array * > &objects, std::vector< std::vector< unsigned char > > &result)
Definition: Solver.cpp:98
virtual void setCoreSolverTimeout(time::Span timeout)
Definition: Solver.cpp:33
Statistic * getStatisticByName(const std::string &name) const
Definition: Statistics.cpp:50
Decl - Base class for top level declarations.
Definition: Parser.h:41
Lexer - Interface for lexing tokens from a .kquery language file.
Definition: Lexer.h:78
Token & Lex(Token &Result)
Definition: Lexer.cpp:210
Parser - Public interface for parsing a .kquery language file.
Definition: Parser.h:206
virtual unsigned GetNumErrors() const =0
GetNumErrors - Return the number of encountered errors.
virtual void SetMaxErrors(unsigned N)=0
SetMaxErrors - Suppress anything beyond the first N errors.
virtual Decl * ParseTopLevelDecl()=0
Definition: Ref.h:82
static bool printInputAsSMTLIBv2(const char *Filename, const MemoryBuffer *MB, ExprBuilder *Builder)
Definition: main.cpp:316
static bool EvaluateInputAST(const char *Filename, const MemoryBuffer *MB, ExprBuilder *Builder)
Definition: main.cpp:184
int main(int argc, char **argv)
Definition: main.cpp:387
static std::string getQueryLogPath(const char filename[])
Definition: main.cpp:92
static std::string escapedString(const char *start, unsigned length)
Definition: main.cpp:122
static void PrintInputTokens(const MemoryBuffer *MB)
Definition: main.cpp:140
static bool PrintInputAST(const char *Filename, const MemoryBuffer *MB, ExprBuilder *Builder)
Definition: main.cpp:151
Statistic queries
Definition: main.cpp:291
ExprBuilder * createDefaultExprBuilder()
llvm::cl::opt< CoreSolverType > CoreSolverToUse
ExprBuilder * createConstantFoldingExprBuilder(ExprBuilder *Base)
Solver * constructSolverChain(Solver *coreSolver, std::string querySMT2LogPath, std::string baseSolverQuerySMT2LogPath, std::string queryKQueryLogPath, std::string baseSolverQueryKQueryLogPath)
llvm::cl::opt< std::string > MaxCoreSolverTime
const char ALL_QUERIES_KQUERY_FILE_NAME[]
Definition: Common.h:24
const char SOLVER_QUERIES_SMT2_FILE_NAME[]
Definition: Common.h:23
const char ALL_QUERIES_SMT2_FILE_NAME[]
Definition: Common.h:22
Solver * createCoreSolver(CoreSolverType cst)
Definition: CoreSolver.cpp:25
llvm::cl::OptionCategory SolvingCat
ExprBuilder * createSimplifyingExprBuilder(ExprBuilder *Base)
@ DUMMY_SOLVER
Definition: SolverCmdLine.h:60
llvm::cl::OptionCategory ExprCat
void printVersion(llvm::raw_ostream &OS)
const char SOLVER_QUERIES_KQUERY_FILE_NAME[]
Definition: Common.h:25
StatisticManager * theStatisticManager
Definition: Statistics.cpp:57
const char * start
The token kind.
Definition: Lexer.h:53
unsigned column
The line number of the start of this token.
Definition: Lexer.h:56
unsigned line
The length of the token.
Definition: Lexer.h:55
const char * getKindName() const
getKindName - The name of this token's kind.
Definition: Lexer.cpp:24
unsigned length
The beginning of the token string.
Definition: Lexer.h:54