aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib
diff options
context:
space:
mode:
authorMikhail <mishok2503@mail.ru>2022-06-08 16:36:28 +0300
committerMartinNowack <2443641+MartinNowack@users.noreply.github.com>2022-07-04 22:20:00 +0100
commit99c522b14dbbf6b26be35b6e7bb8da7b29070287 (patch)
tree49fb535d7beda87188b878c053b1b3241e07fc3f /lib
parent3d0033f099c907bcd5d4d2c2a7562037071ec2bf (diff)
downloadklee-99c522b14dbbf6b26be35b6e7bb8da7b29070287.tar.gz
Inline asm external call
Diffstat (limited to 'lib')
-rw-r--r--lib/Core/Executor.cpp47
-rw-r--r--lib/Core/Executor.h3
-rw-r--r--lib/Core/ExternalDispatcher.cpp35
-rw-r--r--lib/Core/ExternalDispatcher.h4
-rw-r--r--lib/Module/KModule.cpp4
5 files changed, 58 insertions, 35 deletions
diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp
index 11ad902e..42405982 100644
--- a/lib/Core/Executor.cpp
+++ b/lib/Core/Executor.cpp
@@ -37,6 +37,7 @@
#include "klee/Expr/ExprUtil.h"
#include "klee/Module/Cell.h"
#include "klee/Module/InstructionInfoTable.h"
+#include "klee/Module/KCallable.h"
#include "klee/Module/KInstruction.h"
#include "klee/Module/KModule.h"
#include "klee/Solver/Common.h"
@@ -59,6 +60,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
@@ -1658,10 +1660,11 @@ void Executor::executeCall(ExecutionState &state, KInstruction *ki, Function *f,
return;
if (f && f->isDeclaration()) {
switch (f->getIntrinsicID()) {
- case Intrinsic::not_intrinsic:
+ case Intrinsic::not_intrinsic: {
// state may be destroyed by this call, cannot touch
- callExternalFunction(state, ki, f, arguments);
+ callExternalFunction(state, ki, kmodule->functionMap[f], arguments);
break;
+ }
case Intrinsic::fabs: {
ref<ConstantExpr> arg =
toConstant(state, arguments[0], "floating point");
@@ -2399,10 +2402,6 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) {
unsigned numArgs = cb.arg_size();
Function *f = getTargetFunction(fp, state);
- if (isa<InlineAsm>(fp)) {
- terminateStateOnExecError(state, "inline assembly is unsupported");
- break;
- }
// evaluate arguments
std::vector< ref<Expr> > arguments;
arguments.reserve(numArgs);
@@ -2410,6 +2409,16 @@ void Executor::executeInstruction(ExecutionState &state, KInstruction *ki) {
for (unsigned j=0; j<numArgs; ++j)
arguments.push_back(eval(ki, j+1, state).value);
+ if (auto* asmValue = dyn_cast<InlineAsm>(fp)) { //TODO: move to `executeCall`
+ if (ExternalCalls != ExternalCallPolicy::None) {
+ KInlineAsm callable(asmValue);
+ callExternalFunction(state, ki, &callable, arguments);
+ } else {
+ terminateStateOnExecError(state, "external calls disallowed (in particular inline asm)");
+ }
+ break;
+ }
+
if (f) {
const FunctionType *fType =
dyn_cast<FunctionType>(cast<PointerType>(f->getType())->getElementType());
@@ -3784,16 +3793,18 @@ static std::set<std::string> okExternals(okExternalsList,
void Executor::callExternalFunction(ExecutionState &state,
KInstruction *target,
- Function *function,
+ KCallable *callable,
std::vector< ref<Expr> > &arguments) {
// check if specialFunctionHandler wants it
- if (specialFunctionHandler->handle(state, function, target, arguments))
- return;
+ if (const auto *func = dyn_cast<KFunction>(callable)) {
+ if (specialFunctionHandler->handle(state, func->function, target, arguments))
+ return;
+ }
if (ExternalCalls == ExternalCallPolicy::None &&
- !okExternals.count(function->getName().str())) {
+ !okExternals.count(callable->getName().str())) {
klee_warning("Disallowed call to external function: %s\n",
- function->getName().str().c_str());
+ callable->getName().str().c_str());
terminateStateOnUserError(state, "external calls disallowed");
return;
}
@@ -3835,7 +3846,7 @@ void Executor::callExternalFunction(ExecutionState &state,
} else {
terminateStateOnExecError(state,
"external call with symbolic argument: " +
- function->getName());
+ callable->getName());
return;
}
}
@@ -3856,7 +3867,7 @@ void Executor::callExternalFunction(ExecutionState &state,
if (!errnoValue) {
terminateStateOnExecError(state,
"external call with errno value symbolic: " +
- function->getName());
+ callable->getName());
return;
}
@@ -3868,7 +3879,7 @@ void Executor::callExternalFunction(ExecutionState &state,
std::string TmpStr;
llvm::raw_string_ostream os(TmpStr);
- os << "calling external: " << function->getName().str() << "(";
+ os << "calling external: " << callable->getName().str() << "(";
for (unsigned i=0; i<arguments.size(); i++) {
os << arguments[i];
if (i != arguments.size()-1)
@@ -3879,12 +3890,12 @@ void Executor::callExternalFunction(ExecutionState &state,
if (AllExternalWarnings)
klee_warning("%s", os.str().c_str());
else
- klee_warning_once(function, "%s", os.str().c_str());
+ klee_warning_once(callable->getValue(), "%s", os.str().c_str());
}
- bool success = externalDispatcher->executeCall(function, target->inst, args);
+ bool success = externalDispatcher->executeCall(callable, target->inst, args);
if (!success) {
- terminateStateOnError(state, "failed external call: " + function->getName(),
+ terminateStateOnError(state, "failed external call: " + callable->getName(),
StateTerminationType::External);
return;
}
@@ -3903,7 +3914,7 @@ void Executor::callExternalFunction(ExecutionState &state,
#endif
Type *resultType = target->inst->getType();
- if (resultType != Type::getVoidTy(function->getContext())) {
+ if (resultType != Type::getVoidTy(kmodule->module->getContext())) {
ref<Expr> e = ConstantExpr::fromMemory((void*) args,
getWidthForLLVMType(resultType));
bindLocal(target, state, e);
diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h
index 7da4f63c..279d8bee 100644
--- a/lib/Core/Executor.h
+++ b/lib/Core/Executor.h
@@ -64,6 +64,7 @@ namespace klee {
class ExternalDispatcher;
class Expr;
class InstructionInfoTable;
+ class KCallable;
struct KFunction;
struct KInstruction;
class KInstIterator;
@@ -240,7 +241,7 @@ private:
void callExternalFunction(ExecutionState &state,
KInstruction *target,
- llvm::Function *function,
+ KCallable *callable,
std::vector< ref<Expr> > &arguments);
ObjectState *bindObjectInState(ExecutionState &state, const MemoryObject *mo,
diff --git a/lib/Core/ExternalDispatcher.cpp b/lib/Core/ExternalDispatcher.cpp
index 13b17337..7a0d8e14 100644
--- a/lib/Core/ExternalDispatcher.cpp
+++ b/lib/Core/ExternalDispatcher.cpp
@@ -9,10 +9,13 @@
#include "ExternalDispatcher.h"
#include "klee/Config/Version.h"
+#include "klee/Module/KCallable.h"
+#include "klee/Module/KModule.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
@@ -45,7 +48,7 @@ class ExternalDispatcherImpl {
private:
typedef std::map<const llvm::Instruction *, llvm::Function *> dispatchers_ty;
dispatchers_ty dispatchers;
- llvm::Function *createDispatcher(llvm::Function *f, llvm::Instruction *i,
+ llvm::Function *createDispatcher(KCallable *target, llvm::Instruction *i,
llvm::Module *module);
llvm::ExecutionEngine *executionEngine;
LLVMContext &ctx;
@@ -59,7 +62,7 @@ private:
public:
ExternalDispatcherImpl(llvm::LLVMContext &ctx);
~ExternalDispatcherImpl();
- bool executeCall(llvm::Function *function, llvm::Instruction *i,
+ bool executeCall(KCallable *callable, llvm::Instruction *i,
uint64_t *args);
void *resolveSymbol(const std::string &name);
int getLastErrno();
@@ -153,7 +156,7 @@ ExternalDispatcherImpl::~ExternalDispatcherImpl() {
// we don't need to delete any of them.
}
-bool ExternalDispatcherImpl::executeCall(Function *f, Instruction *i,
+bool ExternalDispatcherImpl::executeCall(KCallable *callable, Instruction *i,
uint64_t *args) {
dispatchers_ty::iterator it = dispatchers.find(i);
if (it != dispatchers.end()) {
@@ -180,7 +183,7 @@ bool ExternalDispatcherImpl::executeCall(Function *f, Instruction *i,
// The MCJIT generates whole modules at a time so for every call that we
// haven't made before we need to create a new Module.
dispatchModule = new Module(getFreshModuleID(), ctx);
- dispatcher = createDispatcher(f, i, dispatchModule);
+ dispatcher = createDispatcher(callable, i, dispatchModule);
dispatchers.insert(std::make_pair(i, dispatcher));
// Force the JIT execution engine to go ahead and build the function. This
@@ -249,10 +252,10 @@ bool ExternalDispatcherImpl::runProtectedCall(Function *f, uint64_t *args) {
// the special cases that the JIT knows how to directly call. If this is not
// done, then the jit will end up generating a nullary stub just to call our
// stub, for every single function call.
-Function *ExternalDispatcherImpl::createDispatcher(Function *target,
+Function *ExternalDispatcherImpl::createDispatcher(KCallable *target,
Instruction *inst,
Module *module) {
- if (!resolveSymbol(target->getName().str()))
+ if (isa<KFunction>(target) && !resolveSymbol(target->getName().str()))
return 0;
const CallBase &cb = cast<CallBase>(*inst);
@@ -309,10 +312,18 @@ Function *ExternalDispatcherImpl::createDispatcher(Function *target,
idx += ((!!argSize ? argSize : 64) + 63) / 64;
}
- auto dispatchTarget = module->getOrInsertFunction(target->getName(), FTy,
- target->getAttributes());
- auto result = Builder.CreateCall(dispatchTarget,
- llvm::ArrayRef<Value *>(args, args + i));
+ llvm::CallInst *result;
+ if (auto* func = dyn_cast<KFunction>(target)) {
+ auto dispatchTarget = module->getOrInsertFunction(target->getName(), FTy,
+ func->function->getAttributes());
+ result = Builder.CreateCall(dispatchTarget,
+ llvm::ArrayRef<Value *>(args, args + i));
+ } else if (auto* asmValue = dyn_cast<KInlineAsm>(target)) {
+ result = Builder.CreateCall(asmValue->getInlineAsm(),
+ llvm::ArrayRef<Value *>(args, args + i));
+ } else {
+ assert(0 && "Unhandled KCallable derived class");
+ }
if (result->getType() != Type::getVoidTy(ctx)) {
auto resp = Builder.CreateBitCast(
argI64s, PointerType::getUnqual(result->getType()));
@@ -336,9 +347,9 @@ ExternalDispatcher::ExternalDispatcher(llvm::LLVMContext &ctx)
ExternalDispatcher::~ExternalDispatcher() { delete impl; }
-bool ExternalDispatcher::executeCall(llvm::Function *function,
+bool ExternalDispatcher::executeCall(KCallable *callable,
llvm::Instruction *i, uint64_t *args) {
- return impl->executeCall(function, i, args);
+ return impl->executeCall(callable, i, args);
}
void *ExternalDispatcher::resolveSymbol(const std::string &name) {
diff --git a/lib/Core/ExternalDispatcher.h b/lib/Core/ExternalDispatcher.h
index 7730ac4e..72e6faaa 100644
--- a/lib/Core/ExternalDispatcher.h
+++ b/lib/Core/ExternalDispatcher.h
@@ -20,11 +20,11 @@
namespace llvm {
class Instruction;
class LLVMContext;
-class Function;
}
namespace klee {
class ExternalDispatcherImpl;
+class KCallable;
class ExternalDispatcher {
private:
ExternalDispatcherImpl *impl;
@@ -37,7 +37,7 @@ public:
* ci with arguments in args[1], args[2], ... and writing the result
* into args[0].
*/
- bool executeCall(llvm::Function *function, llvm::Instruction *i,
+ bool executeCall(KCallable *callable, llvm::Instruction *i,
uint64_t *args);
void *resolveSymbol(const std::string &name);
diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp
index 294968a3..2e96c68a 100644
--- a/lib/Module/KModule.cpp
+++ b/lib/Module/KModule.cpp
@@ -303,7 +303,6 @@ void KModule::manifest(InterpreterHandler *ih, bool forceSourceOutput) {
for (auto &Function : *module) {
if (Function.isDeclaration()) {
declarations.push_back(&Function);
- continue;
}
auto kf = std::unique_ptr<KFunction>(new KFunction(&Function, this));
@@ -406,7 +405,8 @@ static int getOperandNum(Value *v,
KFunction::KFunction(llvm::Function *_function,
KModule *km)
- : function(_function),
+ : KCallable(CK_Function),
+ function(_function),
numArgs(function->arg_size()),
numInstructions(0),
trackCoverage(true) {