diff --git a/include/klee/ExternalDispatcher.h b/include/klee/ExternalDispatcher.h index ee993d3..f48be2e 100644 --- a/include/klee/ExternalDispatcher.h +++ b/include/klee/ExternalDispatcher.h @@ -21,14 +21,17 @@ namespace klee { class ExternalDispatcher { private: public: - typedef uint64_t (*external_fcn_t)(...); typedef llvm::SmallVector Arguments; ExternalDispatcher(); virtual ~ExternalDispatcher(); virtual void *resolveSymbol(const std::string &name); - virtual bool call(external_fcn_t targetFunction, const Arguments &args, uint64_t *result, std::stringstream &err); + virtual bool call(const std::string& targetName, void* targetAddr, const Arguments &args, uint64_t *result, std::stringstream &err); + + uint64_t double_to_rawbits(double value); + + double rawbits_to_double(uint64_t bits); }; } diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index c5b255e..8b92250 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -1697,7 +1697,6 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, } ExternalDispatcher::Arguments cas; - unsigned i = 1; for (std::vector>::iterator ai = arguments.begin(), ae = arguments.end(); ai != ae; ++ai, ++i) { ref arg = state.toUnique(*ai); @@ -1742,13 +1741,11 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, os << ", "; } os << ")" << std::dec; - klee_warning_external(function, "%s", os.str().c_str()); } - - uint64_t result; - external_fcn_t targetFunction = (external_fcn_t) externalDispatcher->resolveSymbol(function->getName()); - if (!targetFunction) { + uint64_t result = 0; + void* targetAddr = externalDispatcher->resolveSymbol(function->getName()); + if (!targetAddr) { std::stringstream ss; ss << "Could not find address of external function " << function->getName().str(); terminateState(state, ss.str()); @@ -1756,14 +1753,13 @@ void Executor::callExternalFunction(ExecutionState &state, KInstruction *target, } std::stringstream ss; - if (!externalDispatcher->call(targetFunction, cas, &result, ss)) { + if (!externalDispatcher->call(function->getName(), targetAddr, cas, &result, ss)) { ss << ": " << function->getName().str(); terminateState(state, ss.str()); return; } Type *resultType = target->inst->getType(); - if (resultType != Type::getVoidTy(function->getContext())) { ref resultExpr; auto resultWidth = getWidthForLLVMType(resultType); diff --git a/lib/Core/ExternalDispatcher.cpp b/lib/Core/ExternalDispatcher.cpp index 9189ba7..28fc72d 100644 --- a/lib/Core/ExternalDispatcher.cpp +++ b/lib/Core/ExternalDispatcher.cpp @@ -8,15 +8,17 @@ //===----------------------------------------------------------------------===// #include +#include #include #include +#include + #include #include -#include +#include namespace klee { - ExternalDispatcher::ExternalDispatcher() { } @@ -39,7 +41,6 @@ void *ExternalDispatcher::resolveSymbol(const std::string &name) { if (addr) { return addr; } - // If it has an asm specifier and starts with an underscore we retry // without the underscore. I (DWD) don't know why. if (name[0] == 1 && str[0] == '_') { @@ -47,46 +48,88 @@ void *ExternalDispatcher::resolveSymbol(const std::string &name) { addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(str); } + if (!addr) { + addr = dlsym(RTLD_DEFAULT, str); + if (addr) { + llvm::sys::DynamicLibrary::AddSymbol(str, addr); + } + } + return addr; } -bool ExternalDispatcher::call(external_fcn_t targetFunction, const Arguments &args, uint64_t *result, - std::stringstream &err) { +extern "C" { + typedef double (*external_fcn_dd_t)(double); + typedef uint32_t (*external_fcn_u32d_t)(double); + typedef double (*external_fcn_ddu32_t)(double, uint32_t); + typedef double (*external_fcn_ddd_t)(double, double); + typedef uint64_t (*external_fcn_t)(...); +} + +uint64_t ExternalDispatcher::double_to_rawbits(double value) { + uint64_t bits = 0; + memcpy(&bits, &value, 8); + return bits; +} + +double ExternalDispatcher::rawbits_to_double(uint64_t bits) { + double value = 0.0; + memcpy(&value, &bits, 8); + return value; +} - switch (args.size()) { - case 0: - *result = targetFunction(); - break; - case 1: - *result = targetFunction(args[0]); - break; - case 2: - *result = targetFunction(args[0], args[1]); - break; - case 3: - *result = targetFunction(args[0], args[1], args[2]); - break; - case 4: - *result = targetFunction(args[0], args[1], args[2], args[3]); - break; - case 5: - *result = targetFunction(args[0], args[1], args[2], args[3], args[4]); - break; - case 6: - *result = targetFunction(args[0], args[1], args[2], args[3], args[4], args[5]); - break; - case 7: - *result = targetFunction(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - break; - case 8: - *result = targetFunction(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); - break; - default: { - err << "External function has too many parameters"; - return false; +bool ExternalDispatcher::call(const std::string& targetName, void *targetAddr, const Arguments &args, uint64_t *result, + std::stringstream &err) { + if (targetName == "exp2" || targetName == "log" || targetName == "tan" || + targetName == "rint" || targetName == "fabs" || targetName == "floor" || + targetName == "ceil" || targetName == "sin" || targetName == "cos") { // double func(double) + auto targetFunc = (external_fcn_dd_t) targetAddr; + *result = double_to_rawbits(targetFunc(rawbits_to_double(args[0]))); + } else if (targetName == "isinf" || targetName == "isnan") { // uint32_t func(double) + auto targetFunc = (external_fcn_u32d_t) targetAddr; + *result = targetFunc(rawbits_to_double(args[0])); + } else if (targetName == "ldexp") { // double func(double, uint32_t) + auto targetFunc = (external_fcn_ddu32_t) targetAddr; + *result = double_to_rawbits(targetFunc(rawbits_to_double(args[0]), args[1])); + } else if (targetName == "atan2") { // double func(double, double) + auto targetFunc = (external_fcn_ddd_t) targetAddr; + *result = double_to_rawbits(targetFunc(rawbits_to_double(args[0]), rawbits_to_double(args[1]))); + } else { + auto targetFunc = (external_fcn_t) targetAddr; + switch (args.size()) { + case 0: + *result = targetFunc(); + break; + case 1: + *result = targetFunc(args[0]); + break; + case 2: + *result = targetFunc(args[0], args[1]); + break; + case 3: + *result = targetFunc(args[0], args[1], args[2]); + break; + case 4: + *result = targetFunc(args[0], args[1], args[2], args[3]); + break; + case 5: + *result = targetFunc(args[0], args[1], args[2], args[3], args[4]); + break; + case 6: + *result = targetFunc(args[0], args[1], args[2], args[3], args[4], args[5]); + break; + case 7: + *result = targetFunc(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + break; + case 8: + *result = targetFunc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); + break; + default: { + err << "External function has too many parameters"; + return false; + } } } - return true; -} + } }