2002-04-07 20:49:59 +00:00
|
|
|
//===-- ExternalFunctions.cpp - Implement External Functions --------------===//
|
2005-04-21 22:43:08 +00:00
|
|
|
//
|
2003-10-20 19:43:21 +00:00
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 20:36:04 +00:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2005-04-21 22:43:08 +00:00
|
|
|
//
|
2003-10-20 19:43:21 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2005-04-21 22:43:08 +00:00
|
|
|
//
|
2002-04-07 20:49:59 +00:00
|
|
|
// This file contains both code to deal with invoking "external" functions, but
|
|
|
|
// also contains code that implements "exported" external functions.
|
2001-09-10 04:50:17 +00:00
|
|
|
//
|
2009-02-04 06:26:47 +00:00
|
|
|
// There are currently two mechanisms for handling external functions in the
|
|
|
|
// Interpreter. The first is to implement lle_* wrapper functions that are
|
|
|
|
// specific to well-known library functions which manually translate the
|
|
|
|
// arguments from GenericValues and make the call. If such a wrapper does
|
|
|
|
// not exist, and libffi is available, then the Interpreter will attempt to
|
|
|
|
// invoke the function using libffi, after finding its address.
|
2001-09-10 04:50:17 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Interpreter.h"
|
|
|
|
#include "llvm/DerivedTypes.h"
|
2003-10-14 21:42:11 +00:00
|
|
|
#include "llvm/Module.h"
|
2009-02-04 06:26:47 +00:00
|
|
|
#include "llvm/Config/config.h" // Detect libffi
|
2009-07-11 13:10:19 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2004-11-29 14:11:29 +00:00
|
|
|
#include "llvm/System/DynamicLibrary.h"
|
2002-10-02 21:12:13 +00:00
|
|
|
#include "llvm/Target/TargetData.h"
|
2007-07-27 18:26:35 +00:00
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
2009-06-22 22:30:56 +00:00
|
|
|
#include "llvm/System/Mutex.h"
|
2003-11-05 01:18:49 +00:00
|
|
|
#include <csignal>
|
2008-10-08 07:23:46 +00:00
|
|
|
#include <cstdio>
|
2003-10-14 21:42:11 +00:00
|
|
|
#include <map>
|
2006-12-02 02:22:01 +00:00
|
|
|
#include <cmath>
|
2008-02-20 11:08:44 +00:00
|
|
|
#include <cstring>
|
2007-12-12 06:16:47 +00:00
|
|
|
|
2009-04-13 04:26:06 +00:00
|
|
|
#ifdef HAVE_FFI_CALL
|
2009-02-04 06:26:47 +00:00
|
|
|
#ifdef HAVE_FFI_H
|
|
|
|
#include <ffi.h>
|
2009-04-13 04:26:06 +00:00
|
|
|
#define USE_LIBFFI
|
2009-02-04 06:26:47 +00:00
|
|
|
#elif HAVE_FFI_FFI_H
|
|
|
|
#include <ffi/ffi.h>
|
2009-04-13 04:26:06 +00:00
|
|
|
#define USE_LIBFFI
|
2009-02-04 06:26:47 +00:00
|
|
|
#endif
|
2007-12-12 06:16:47 +00:00
|
|
|
#endif
|
2009-01-22 20:09:20 +00:00
|
|
|
|
2003-12-14 23:25:48 +00:00
|
|
|
using namespace llvm;
|
2003-11-11 22:41:34 +00:00
|
|
|
|
2009-06-22 22:30:56 +00:00
|
|
|
static ManagedStatic<sys::Mutex> FunctionsLock;
|
|
|
|
|
2009-02-04 06:26:47 +00:00
|
|
|
typedef GenericValue (*ExFunc)(const FunctionType *,
|
|
|
|
const std::vector<GenericValue> &);
|
|
|
|
static ManagedStatic<std::map<const Function *, ExFunc> > ExportedFunctions;
|
2002-01-20 22:54:45 +00:00
|
|
|
static std::map<std::string, ExFunc> FuncNames;
|
2001-09-10 04:50:17 +00:00
|
|
|
|
2009-04-13 04:26:06 +00:00
|
|
|
#ifdef USE_LIBFFI
|
2009-08-12 22:10:57 +00:00
|
|
|
typedef void (*RawFunc)();
|
2009-02-04 06:26:47 +00:00
|
|
|
static ManagedStatic<std::map<const Function *, RawFunc> > RawFunctions;
|
|
|
|
#endif
|
|
|
|
|
2001-10-27 04:15:57 +00:00
|
|
|
static Interpreter *TheInterpreter;
|
|
|
|
|
2001-09-10 04:50:17 +00:00
|
|
|
static char getTypeID(const Type *Ty) {
|
2004-06-17 18:19:28 +00:00
|
|
|
switch (Ty->getTypeID()) {
|
2001-09-10 04:50:17 +00:00
|
|
|
case Type::VoidTyID: return 'V';
|
For PR1064:
Implement the arbitrary bit-width integer feature. The feature allows
integers of any bitwidth (up to 64) to be defined instead of just 1, 8,
16, 32, and 64 bit integers.
This change does several things:
1. Introduces a new Derived Type, IntegerType, to represent the number of
bits in an integer. The Type classes SubclassData field is used to
store the number of bits. This allows 2^23 bits in an integer type.
2. Removes the five integer Type::TypeID values for the 1, 8, 16, 32 and
64-bit integers. These are replaced with just IntegerType which is not
a primitive any more.
3. Adjust the rest of LLVM to account for this change.
Note that while this incremental change lays the foundation for arbitrary
bit-width integers, LLVM has not yet been converted to actually deal with
them in any significant way. Most optimization passes, for example, will
still only deal with the byte-width integer types. Future increments
will rectify this situation.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@33113 91177308-0d34-0410-b5e6-96231b3b80d8
2007-01-12 07:05:14 +00:00
|
|
|
case Type::IntegerTyID:
|
|
|
|
switch (cast<IntegerType>(Ty)->getBitWidth()) {
|
|
|
|
case 1: return 'o';
|
|
|
|
case 8: return 'B';
|
|
|
|
case 16: return 'S';
|
|
|
|
case 32: return 'I';
|
|
|
|
case 64: return 'L';
|
|
|
|
default: return 'N';
|
|
|
|
}
|
2001-09-10 04:50:17 +00:00
|
|
|
case Type::FloatTyID: return 'F';
|
|
|
|
case Type::DoubleTyID: return 'D';
|
|
|
|
case Type::PointerTyID: return 'P';
|
2006-12-31 05:51:36 +00:00
|
|
|
case Type::FunctionTyID:return 'M';
|
2001-09-10 04:50:17 +00:00
|
|
|
case Type::StructTyID: return 'T';
|
|
|
|
case Type::ArrayTyID: return 'A';
|
|
|
|
case Type::OpaqueTyID: return 'O';
|
|
|
|
default: return 'U';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-30 23:03:25 +00:00
|
|
|
// Try to find address of external function given a Function object.
|
|
|
|
// Please note, that interpreter doesn't know how to assemble a
|
|
|
|
// real call in general case (this is JIT job), that's why it assumes,
|
|
|
|
// that all external functions has the same (and pretty "general") signature.
|
|
|
|
// The typical example of such functions are "lle_X_" ones.
|
2003-10-10 17:03:10 +00:00
|
|
|
static ExFunc lookupFunction(const Function *F) {
|
2001-09-10 04:50:17 +00:00
|
|
|
// Function not found, look it up... start by figuring out what the
|
|
|
|
// composite function name should be.
|
2002-01-20 22:54:45 +00:00
|
|
|
std::string ExtName = "lle_";
|
2003-10-10 17:03:10 +00:00
|
|
|
const FunctionType *FT = F->getFunctionType();
|
|
|
|
for (unsigned i = 0, e = FT->getNumContainedTypes(); i != e; ++i)
|
|
|
|
ExtName += getTypeID(FT->getContainedType(i));
|
2009-07-24 08:24:36 +00:00
|
|
|
ExtName + "_" + F->getNameStr();
|
2001-09-10 04:50:17 +00:00
|
|
|
|
2009-07-07 18:33:04 +00:00
|
|
|
sys::ScopedLock Writer(*FunctionsLock);
|
2001-10-30 20:28:00 +00:00
|
|
|
ExFunc FnPtr = FuncNames[ExtName];
|
|
|
|
if (FnPtr == 0)
|
2009-07-24 08:24:36 +00:00
|
|
|
FnPtr = FuncNames["lle_X_" + F->getNameStr()];
|
2001-09-10 04:50:17 +00:00
|
|
|
if (FnPtr == 0) // Try calling a generic function... if it exists...
|
2009-07-22 21:10:12 +00:00
|
|
|
FnPtr = (ExFunc)(intptr_t)
|
2009-07-24 08:24:36 +00:00
|
|
|
sys::DynamicLibrary::SearchForAddressOfSymbol("lle_X_"+F->getNameStr());
|
2001-09-10 04:50:17 +00:00
|
|
|
if (FnPtr != 0)
|
2009-02-04 06:26:47 +00:00
|
|
|
ExportedFunctions->insert(std::make_pair(F, FnPtr)); // Cache for later
|
2001-09-10 04:50:17 +00:00
|
|
|
return FnPtr;
|
|
|
|
}
|
|
|
|
|
2009-04-13 04:26:06 +00:00
|
|
|
#ifdef USE_LIBFFI
|
2009-02-04 06:26:47 +00:00
|
|
|
static ffi_type *ffiTypeFor(const Type *Ty) {
|
|
|
|
switch (Ty->getTypeID()) {
|
|
|
|
case Type::VoidTyID: return &ffi_type_void;
|
|
|
|
case Type::IntegerTyID:
|
|
|
|
switch (cast<IntegerType>(Ty)->getBitWidth()) {
|
|
|
|
case 8: return &ffi_type_sint8;
|
|
|
|
case 16: return &ffi_type_sint16;
|
|
|
|
case 32: return &ffi_type_sint32;
|
|
|
|
case 64: return &ffi_type_sint64;
|
|
|
|
}
|
|
|
|
case Type::FloatTyID: return &ffi_type_float;
|
|
|
|
case Type::DoubleTyID: return &ffi_type_double;
|
|
|
|
case Type::PointerTyID: return &ffi_type_pointer;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
// TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc.
|
2009-07-11 13:10:19 +00:00
|
|
|
llvm_report_error("Type could not be mapped for use with libffi.");
|
2009-02-04 06:26:47 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *ffiValueFor(const Type *Ty, const GenericValue &AV,
|
|
|
|
void *ArgDataPtr) {
|
|
|
|
switch (Ty->getTypeID()) {
|
|
|
|
case Type::IntegerTyID:
|
|
|
|
switch (cast<IntegerType>(Ty)->getBitWidth()) {
|
|
|
|
case 8: {
|
|
|
|
int8_t *I8Ptr = (int8_t *) ArgDataPtr;
|
|
|
|
*I8Ptr = (int8_t) AV.IntVal.getZExtValue();
|
|
|
|
return ArgDataPtr;
|
|
|
|
}
|
|
|
|
case 16: {
|
|
|
|
int16_t *I16Ptr = (int16_t *) ArgDataPtr;
|
|
|
|
*I16Ptr = (int16_t) AV.IntVal.getZExtValue();
|
|
|
|
return ArgDataPtr;
|
|
|
|
}
|
|
|
|
case 32: {
|
|
|
|
int32_t *I32Ptr = (int32_t *) ArgDataPtr;
|
|
|
|
*I32Ptr = (int32_t) AV.IntVal.getZExtValue();
|
|
|
|
return ArgDataPtr;
|
|
|
|
}
|
|
|
|
case 64: {
|
|
|
|
int64_t *I64Ptr = (int64_t *) ArgDataPtr;
|
|
|
|
*I64Ptr = (int64_t) AV.IntVal.getZExtValue();
|
|
|
|
return ArgDataPtr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case Type::FloatTyID: {
|
|
|
|
float *FloatPtr = (float *) ArgDataPtr;
|
|
|
|
*FloatPtr = AV.DoubleVal;
|
|
|
|
return ArgDataPtr;
|
|
|
|
}
|
|
|
|
case Type::DoubleTyID: {
|
|
|
|
double *DoublePtr = (double *) ArgDataPtr;
|
|
|
|
*DoublePtr = AV.DoubleVal;
|
|
|
|
return ArgDataPtr;
|
|
|
|
}
|
|
|
|
case Type::PointerTyID: {
|
|
|
|
void **PtrPtr = (void **) ArgDataPtr;
|
|
|
|
*PtrPtr = GVTOP(AV);
|
|
|
|
return ArgDataPtr;
|
|
|
|
}
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
// TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc.
|
2009-07-11 13:10:19 +00:00
|
|
|
llvm_report_error("Type value could not be mapped for use with libffi.");
|
2009-02-04 06:26:47 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ffiInvoke(RawFunc Fn, Function *F,
|
|
|
|
const std::vector<GenericValue> &ArgVals,
|
|
|
|
const TargetData *TD, GenericValue &Result) {
|
|
|
|
ffi_cif cif;
|
|
|
|
const FunctionType *FTy = F->getFunctionType();
|
|
|
|
const unsigned NumArgs = F->arg_size();
|
|
|
|
|
|
|
|
// TODO: We don't have type information about the remaining arguments, because
|
|
|
|
// this information is never passed into ExecutionEngine::runFunction().
|
|
|
|
if (ArgVals.size() > NumArgs && F->isVarArg()) {
|
2009-07-11 13:10:19 +00:00
|
|
|
llvm_report_error("Calling external var arg function '" + F->getName()
|
|
|
|
+ "' is not supported by the Interpreter.");
|
2009-02-04 06:26:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ArgBytes = 0;
|
|
|
|
|
|
|
|
std::vector<ffi_type*> args(NumArgs);
|
|
|
|
for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end();
|
|
|
|
A != E; ++A) {
|
|
|
|
const unsigned ArgNo = A->getArgNo();
|
|
|
|
const Type *ArgTy = FTy->getParamType(ArgNo);
|
|
|
|
args[ArgNo] = ffiTypeFor(ArgTy);
|
|
|
|
ArgBytes += TD->getTypeStoreSize(ArgTy);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *ArgData = (uint8_t*) alloca(ArgBytes);
|
|
|
|
uint8_t *ArgDataPtr = ArgData;
|
|
|
|
std::vector<void*> values(NumArgs);
|
|
|
|
for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end();
|
|
|
|
A != E; ++A) {
|
|
|
|
const unsigned ArgNo = A->getArgNo();
|
|
|
|
const Type *ArgTy = FTy->getParamType(ArgNo);
|
|
|
|
values[ArgNo] = ffiValueFor(ArgTy, ArgVals[ArgNo], ArgDataPtr);
|
|
|
|
ArgDataPtr += TD->getTypeStoreSize(ArgTy);
|
|
|
|
}
|
|
|
|
|
|
|
|
const Type *RetTy = FTy->getReturnType();
|
|
|
|
ffi_type *rtype = ffiTypeFor(RetTy);
|
|
|
|
|
|
|
|
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NumArgs, rtype, &args[0]) == FFI_OK) {
|
|
|
|
void *ret = NULL;
|
|
|
|
if (RetTy->getTypeID() != Type::VoidTyID)
|
|
|
|
ret = alloca(TD->getTypeStoreSize(RetTy));
|
|
|
|
ffi_call(&cif, Fn, ret, &values[0]);
|
|
|
|
switch (RetTy->getTypeID()) {
|
|
|
|
case Type::IntegerTyID:
|
|
|
|
switch (cast<IntegerType>(RetTy)->getBitWidth()) {
|
|
|
|
case 8: Result.IntVal = APInt(8 , *(int8_t *) ret); break;
|
|
|
|
case 16: Result.IntVal = APInt(16, *(int16_t*) ret); break;
|
|
|
|
case 32: Result.IntVal = APInt(32, *(int32_t*) ret); break;
|
|
|
|
case 64: Result.IntVal = APInt(64, *(int64_t*) ret); break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Type::FloatTyID: Result.FloatVal = *(float *) ret; break;
|
|
|
|
case Type::DoubleTyID: Result.DoubleVal = *(double*) ret; break;
|
|
|
|
case Type::PointerTyID: Result.PointerVal = *(void **) ret; break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2009-04-13 04:26:06 +00:00
|
|
|
#endif // USE_LIBFFI
|
2009-02-04 06:26:47 +00:00
|
|
|
|
2005-01-21 19:59:37 +00:00
|
|
|
GenericValue Interpreter::callExternalFunction(Function *F,
|
2003-05-14 14:21:30 +00:00
|
|
|
const std::vector<GenericValue> &ArgVals) {
|
2001-10-27 04:15:57 +00:00
|
|
|
TheInterpreter = this;
|
|
|
|
|
2009-06-22 22:30:56 +00:00
|
|
|
FunctionsLock->acquire();
|
|
|
|
|
2002-04-07 20:49:59 +00:00
|
|
|
// Do a lookup to see if the function is in our cache... this should just be a
|
2003-10-10 17:42:19 +00:00
|
|
|
// deferred annotation!
|
2009-02-04 06:26:47 +00:00
|
|
|
std::map<const Function *, ExFunc>::iterator FI = ExportedFunctions->find(F);
|
|
|
|
if (ExFunc Fn = (FI == ExportedFunctions->end()) ? lookupFunction(F)
|
2009-06-22 22:30:56 +00:00
|
|
|
: FI->second) {
|
|
|
|
FunctionsLock->release();
|
2009-02-04 06:26:47 +00:00
|
|
|
return Fn(F->getFunctionType(), ArgVals);
|
2009-06-22 22:30:56 +00:00
|
|
|
}
|
2009-02-04 06:26:47 +00:00
|
|
|
|
2009-04-13 04:26:06 +00:00
|
|
|
#ifdef USE_LIBFFI
|
2009-02-04 06:26:47 +00:00
|
|
|
std::map<const Function *, RawFunc>::iterator RF = RawFunctions->find(F);
|
|
|
|
RawFunc RawFn;
|
|
|
|
if (RF == RawFunctions->end()) {
|
|
|
|
RawFn = (RawFunc)(intptr_t)
|
|
|
|
sys::DynamicLibrary::SearchForAddressOfSymbol(F->getName());
|
|
|
|
if (RawFn != 0)
|
|
|
|
RawFunctions->insert(std::make_pair(F, RawFn)); // Cache for later
|
|
|
|
} else {
|
|
|
|
RawFn = RF->second;
|
2001-09-10 04:50:17 +00:00
|
|
|
}
|
2009-06-22 22:30:56 +00:00
|
|
|
|
|
|
|
FunctionsLock->release();
|
2001-09-10 04:50:17 +00:00
|
|
|
|
2009-02-04 06:26:47 +00:00
|
|
|
GenericValue Result;
|
|
|
|
if (RawFn != 0 && ffiInvoke(RawFn, F, ArgVals, getTargetData(), Result))
|
|
|
|
return Result;
|
2009-04-13 04:26:06 +00:00
|
|
|
#endif // USE_LIBFFI
|
2009-02-04 06:26:47 +00:00
|
|
|
|
2009-07-11 13:10:19 +00:00
|
|
|
if (F->getName() == "__main")
|
2009-08-23 08:43:55 +00:00
|
|
|
errs() << "Tried to execute an unknown external function: "
|
2009-07-11 13:10:19 +00:00
|
|
|
<< F->getType()->getDescription() << " __main\n";
|
|
|
|
else
|
|
|
|
llvm_report_error("Tried to execute an unknown external function: " +
|
|
|
|
F->getType()->getDescription() + " " +F->getName());
|
2009-02-04 06:26:47 +00:00
|
|
|
return GenericValue();
|
2001-09-10 04:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
2002-03-29 03:57:15 +00:00
|
|
|
// Functions "exported" to the running application...
|
2001-09-10 04:50:17 +00:00
|
|
|
//
|
2009-08-07 20:50:09 +00:00
|
|
|
|
|
|
|
// Visual Studio warns about returning GenericValue in extern "C" linkage
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(disable : 4190)
|
|
|
|
#endif
|
|
|
|
|
2001-09-10 04:50:17 +00:00
|
|
|
extern "C" { // Don't add C++ manglings to llvm mangling :)
|
|
|
|
|
2003-05-14 14:21:30 +00:00
|
|
|
// void atexit(Function*)
|
2009-02-04 06:26:47 +00:00
|
|
|
GenericValue lle_X_atexit(const FunctionType *FT,
|
|
|
|
const std::vector<GenericValue> &Args) {
|
2003-05-14 14:21:30 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
TheInterpreter->addAtExitHandler((Function*)GVTOP(Args[0]));
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = 0;
|
2003-05-14 14:21:30 +00:00
|
|
|
return GV;
|
2001-10-18 21:55:32 +00:00
|
|
|
}
|
|
|
|
|
2002-10-02 21:12:13 +00:00
|
|
|
// void exit(int)
|
2009-02-04 06:26:47 +00:00
|
|
|
GenericValue lle_X_exit(const FunctionType *FT,
|
|
|
|
const std::vector<GenericValue> &Args) {
|
2001-10-27 04:15:57 +00:00
|
|
|
TheInterpreter->exitCalled(Args[0]);
|
|
|
|
return GenericValue();
|
|
|
|
}
|
|
|
|
|
2002-10-02 21:12:13 +00:00
|
|
|
// void abort(void)
|
2009-02-04 06:26:47 +00:00
|
|
|
GenericValue lle_X_abort(const FunctionType *FT,
|
|
|
|
const std::vector<GenericValue> &Args) {
|
2009-07-11 13:10:19 +00:00
|
|
|
//FIXME: should we report or raise here?
|
|
|
|
//llvm_report_error("Interpreted program raised SIGABRT");
|
2003-11-05 01:18:49 +00:00
|
|
|
raise (SIGABRT);
|
2002-05-20 21:17:16 +00:00
|
|
|
return GenericValue();
|
|
|
|
}
|
|
|
|
|
2009-02-04 06:26:47 +00:00
|
|
|
// int sprintf(char *, const char *, ...) - a very rough implementation to make
|
2001-12-13 00:43:47 +00:00
|
|
|
// output useful.
|
2009-02-04 06:26:47 +00:00
|
|
|
GenericValue lle_X_sprintf(const FunctionType *FT,
|
|
|
|
const std::vector<GenericValue> &Args) {
|
2003-01-13 00:59:47 +00:00
|
|
|
char *OutputBuffer = (char *)GVTOP(Args[0]);
|
|
|
|
const char *FmtStr = (const char *)GVTOP(Args[1]);
|
2001-12-13 00:43:47 +00:00
|
|
|
unsigned ArgNo = 2;
|
2001-10-29 20:27:45 +00:00
|
|
|
|
|
|
|
// printf should return # chars printed. This is completely incorrect, but
|
|
|
|
// close enough for now.
|
2007-03-06 03:08:12 +00:00
|
|
|
GenericValue GV;
|
|
|
|
GV.IntVal = APInt(32, strlen(FmtStr));
|
2001-10-29 20:27:45 +00:00
|
|
|
while (1) {
|
|
|
|
switch (*FmtStr) {
|
|
|
|
case 0: return GV; // Null terminator...
|
|
|
|
default: // Normal nonspecial character
|
2001-12-13 00:43:47 +00:00
|
|
|
sprintf(OutputBuffer++, "%c", *FmtStr++);
|
2001-10-29 20:27:45 +00:00
|
|
|
break;
|
|
|
|
case '\\': { // Handle escape codes
|
2001-12-13 00:43:47 +00:00
|
|
|
sprintf(OutputBuffer, "%c%c", *FmtStr, *(FmtStr+1));
|
|
|
|
FmtStr += 2; OutputBuffer += 2;
|
2001-10-29 20:27:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '%': { // Handle format specifiers
|
2001-11-07 19:46:27 +00:00
|
|
|
char FmtBuf[100] = "", Buffer[1000] = "";
|
|
|
|
char *FB = FmtBuf;
|
|
|
|
*FB++ = *FmtStr++;
|
|
|
|
char Last = *FB++ = *FmtStr++;
|
|
|
|
unsigned HowLong = 0;
|
|
|
|
while (Last != 'c' && Last != 'd' && Last != 'i' && Last != 'u' &&
|
|
|
|
Last != 'o' && Last != 'x' && Last != 'X' && Last != 'e' &&
|
|
|
|
Last != 'E' && Last != 'g' && Last != 'G' && Last != 'f' &&
|
|
|
|
Last != 'p' && Last != 's' && Last != '%') {
|
|
|
|
if (Last == 'l' || Last == 'L') HowLong++; // Keep track of l's
|
|
|
|
Last = *FB++ = *FmtStr++;
|
2001-10-29 20:27:45 +00:00
|
|
|
}
|
2001-11-07 19:46:27 +00:00
|
|
|
*FB = 0;
|
2005-04-21 22:43:08 +00:00
|
|
|
|
2001-11-07 19:46:27 +00:00
|
|
|
switch (Last) {
|
|
|
|
case '%':
|
2008-08-05 23:36:35 +00:00
|
|
|
strcpy(Buffer, "%"); break;
|
2001-11-07 19:46:27 +00:00
|
|
|
case 'c':
|
2007-03-06 03:08:12 +00:00
|
|
|
sprintf(Buffer, FmtBuf, uint32_t(Args[ArgNo++].IntVal.getZExtValue()));
|
|
|
|
break;
|
2001-11-07 19:46:27 +00:00
|
|
|
case 'd': case 'i':
|
|
|
|
case 'u': case 'o':
|
|
|
|
case 'x': case 'X':
|
2002-08-02 23:08:32 +00:00
|
|
|
if (HowLong >= 1) {
|
2003-08-24 14:02:47 +00:00
|
|
|
if (HowLong == 1 &&
|
2006-08-16 01:24:12 +00:00
|
|
|
TheInterpreter->getTargetData()->getPointerSizeInBits() == 64 &&
|
2006-05-24 19:21:13 +00:00
|
|
|
sizeof(long) < sizeof(int64_t)) {
|
2002-08-02 23:08:32 +00:00
|
|
|
// Make sure we use %lld with a 64 bit argument because we might be
|
|
|
|
// compiling LLI on a 32 bit compiler.
|
|
|
|
unsigned Size = strlen(FmtBuf);
|
|
|
|
FmtBuf[Size] = FmtBuf[Size-1];
|
|
|
|
FmtBuf[Size+1] = 0;
|
|
|
|
FmtBuf[Size-1] = 'l';
|
|
|
|
}
|
2007-03-06 03:08:12 +00:00
|
|
|
sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal.getZExtValue());
|
2002-08-02 23:08:32 +00:00
|
|
|
} else
|
2007-03-06 03:08:12 +00:00
|
|
|
sprintf(Buffer, FmtBuf,uint32_t(Args[ArgNo++].IntVal.getZExtValue()));
|
|
|
|
break;
|
2001-11-07 19:46:27 +00:00
|
|
|
case 'e': case 'E': case 'g': case 'G': case 'f':
|
|
|
|
sprintf(Buffer, FmtBuf, Args[ArgNo++].DoubleVal); break;
|
|
|
|
case 'p':
|
2003-01-13 00:59:47 +00:00
|
|
|
sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break;
|
2005-04-21 22:43:08 +00:00
|
|
|
case 's':
|
2003-01-13 00:59:47 +00:00
|
|
|
sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break;
|
2009-08-23 08:43:55 +00:00
|
|
|
default:
|
|
|
|
errs() << "<unknown printf code '" << *FmtStr << "'!>";
|
2001-11-07 19:46:27 +00:00
|
|
|
ArgNo++; break;
|
|
|
|
}
|
2001-12-13 00:43:47 +00:00
|
|
|
strcpy(OutputBuffer, Buffer);
|
|
|
|
OutputBuffer += strlen(Buffer);
|
2001-10-29 20:27:45 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-04-21 17:11:45 +00:00
|
|
|
return GV;
|
2001-10-29 20:27:45 +00:00
|
|
|
}
|
|
|
|
|
2009-02-04 06:26:47 +00:00
|
|
|
// int printf(const char *, ...) - a very rough implementation to make output
|
|
|
|
// useful.
|
|
|
|
GenericValue lle_X_printf(const FunctionType *FT,
|
|
|
|
const std::vector<GenericValue> &Args) {
|
2001-12-13 00:43:47 +00:00
|
|
|
char Buffer[10000];
|
2009-02-04 06:26:47 +00:00
|
|
|
std::vector<GenericValue> NewArgs;
|
2007-04-21 17:11:45 +00:00
|
|
|
NewArgs.push_back(PTOGV((void*)&Buffer[0]));
|
2001-12-13 00:43:47 +00:00
|
|
|
NewArgs.insert(NewArgs.end(), Args.begin(), Args.end());
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue GV = lle_X_sprintf(FT, NewArgs);
|
2009-08-23 08:43:55 +00:00
|
|
|
outs() << Buffer;
|
2001-12-13 00:43:47 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2009-08-13 21:58:54 +00:00
|
|
|
static void ByteswapSCANFResults(LLVMContext &C,
|
|
|
|
const char *Fmt, void *Arg0, void *Arg1,
|
2003-03-31 22:12:37 +00:00
|
|
|
void *Arg2, void *Arg3, void *Arg4, void *Arg5,
|
|
|
|
void *Arg6, void *Arg7, void *Arg8) {
|
|
|
|
void *Args[] = { Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, 0 };
|
|
|
|
|
|
|
|
// Loop over the format string, munging read values as appropriate (performs
|
2003-08-18 14:43:39 +00:00
|
|
|
// byteswaps as necessary).
|
2003-03-31 22:12:37 +00:00
|
|
|
unsigned ArgNo = 0;
|
|
|
|
while (*Fmt) {
|
|
|
|
if (*Fmt++ == '%') {
|
|
|
|
// Read any flag characters that may be present...
|
|
|
|
bool Suppress = false;
|
|
|
|
bool Half = false;
|
|
|
|
bool Long = false;
|
|
|
|
bool LongLong = false; // long long or long double
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
switch (*Fmt++) {
|
|
|
|
case '*': Suppress = true; break;
|
|
|
|
case 'a': /*Allocate = true;*/ break; // We don't need to track this
|
|
|
|
case 'h': Half = true; break;
|
|
|
|
case 'l': Long = true; break;
|
|
|
|
case 'q':
|
|
|
|
case 'L': LongLong = true; break;
|
|
|
|
default:
|
|
|
|
if (Fmt[-1] > '9' || Fmt[-1] < '0') // Ignore field width specs
|
|
|
|
goto Out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Out:
|
|
|
|
|
|
|
|
// Read the conversion character
|
|
|
|
if (!Suppress && Fmt[-1] != '%') { // Nothing to do?
|
|
|
|
unsigned Size = 0;
|
|
|
|
const Type *Ty = 0;
|
|
|
|
|
|
|
|
switch (Fmt[-1]) {
|
|
|
|
case 'i': case 'o': case 'u': case 'x': case 'X': case 'n': case 'p':
|
|
|
|
case 'd':
|
|
|
|
if (Long || LongLong) {
|
2009-08-13 21:58:54 +00:00
|
|
|
Size = 8; Ty = Type::getInt64Ty(C);
|
2003-03-31 22:12:37 +00:00
|
|
|
} else if (Half) {
|
2009-08-13 21:58:54 +00:00
|
|
|
Size = 4; Ty = Type::getInt16Ty(C);
|
2003-03-31 22:12:37 +00:00
|
|
|
} else {
|
2009-08-13 21:58:54 +00:00
|
|
|
Size = 4; Ty = Type::getInt32Ty(C);
|
2003-03-31 22:12:37 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'e': case 'g': case 'E':
|
|
|
|
case 'f':
|
|
|
|
if (Long || LongLong) {
|
2009-08-13 21:58:54 +00:00
|
|
|
Size = 8; Ty = Type::getDoubleTy(C);
|
2003-03-31 22:12:37 +00:00
|
|
|
} else {
|
2009-08-13 21:58:54 +00:00
|
|
|
Size = 4; Ty = Type::getFloatTy(C);
|
2003-03-31 22:12:37 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 's': case 'c': case '[': // No byteswap needed
|
|
|
|
Size = 1;
|
2009-08-13 21:58:54 +00:00
|
|
|
Ty = Type::getInt8Ty(C);
|
2003-03-31 22:12:37 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Size) {
|
|
|
|
GenericValue GV;
|
|
|
|
void *Arg = Args[ArgNo++];
|
|
|
|
memcpy(&GV, Arg, Size);
|
|
|
|
TheInterpreter->StoreValueToMemory(GV, (GenericValue*)Arg, Ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-03-08 22:51:07 +00:00
|
|
|
// int sscanf(const char *format, ...);
|
2009-02-04 06:26:47 +00:00
|
|
|
GenericValue lle_X_sscanf(const FunctionType *FT,
|
|
|
|
const std::vector<GenericValue> &args) {
|
2002-03-08 22:51:07 +00:00
|
|
|
assert(args.size() < 10 && "Only handle up to 10 args to sscanf right now!");
|
|
|
|
|
2003-03-31 22:12:37 +00:00
|
|
|
char *Args[10];
|
2002-03-08 22:51:07 +00:00
|
|
|
for (unsigned i = 0; i < args.size(); ++i)
|
2003-03-31 22:12:37 +00:00
|
|
|
Args[i] = (char*)GVTOP(args[i]);
|
2002-03-08 22:51:07 +00:00
|
|
|
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, sscanf(Args[0], Args[1], Args[2], Args[3], Args[4],
|
|
|
|
Args[5], Args[6], Args[7], Args[8], Args[9]));
|
2009-08-13 21:58:54 +00:00
|
|
|
ByteswapSCANFResults(FT->getContext(),
|
|
|
|
Args[1], Args[2], Args[3], Args[4],
|
2003-03-31 22:12:37 +00:00
|
|
|
Args[5], Args[6], Args[7], Args[8], Args[9], 0);
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
|
|
|
// int scanf(const char *format, ...);
|
2009-02-04 06:26:47 +00:00
|
|
|
GenericValue lle_X_scanf(const FunctionType *FT,
|
|
|
|
const std::vector<GenericValue> &args) {
|
2003-03-31 22:12:37 +00:00
|
|
|
assert(args.size() < 10 && "Only handle up to 10 args to scanf right now!");
|
|
|
|
|
|
|
|
char *Args[10];
|
|
|
|
for (unsigned i = 0; i < args.size(); ++i)
|
|
|
|
Args[i] = (char*)GVTOP(args[i]);
|
|
|
|
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, scanf( Args[0], Args[1], Args[2], Args[3], Args[4],
|
|
|
|
Args[5], Args[6], Args[7], Args[8], Args[9]));
|
2009-08-13 21:58:54 +00:00
|
|
|
ByteswapSCANFResults(FT->getContext(),
|
|
|
|
Args[0], Args[1], Args[2], Args[3], Args[4],
|
2003-03-31 22:12:37 +00:00
|
|
|
Args[5], Args[6], Args[7], Args[8], Args[9]);
|
2002-03-08 22:51:07 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2009-02-04 06:26:47 +00:00
|
|
|
// int fprintf(FILE *, const char *, ...) - a very rough implementation to make
|
|
|
|
// output useful.
|
|
|
|
GenericValue lle_X_fprintf(const FunctionType *FT,
|
|
|
|
const std::vector<GenericValue> &Args) {
|
2003-04-21 22:43:20 +00:00
|
|
|
assert(Args.size() >= 2);
|
2002-11-06 23:05:03 +00:00
|
|
|
char Buffer[10000];
|
2009-02-04 06:26:47 +00:00
|
|
|
std::vector<GenericValue> NewArgs;
|
2003-01-13 00:59:47 +00:00
|
|
|
NewArgs.push_back(PTOGV(Buffer));
|
2002-11-06 23:05:03 +00:00
|
|
|
NewArgs.insert(NewArgs.end(), Args.begin()+1, Args.end());
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue GV = lle_X_sprintf(FT, NewArgs);
|
2002-11-06 23:05:03 +00:00
|
|
|
|
2009-02-04 06:26:47 +00:00
|
|
|
fputs(Buffer, (FILE *) GVTOP(Args[0]));
|
2002-11-06 23:05:03 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2001-09-10 04:50:17 +00:00
|
|
|
} // End extern "C"
|
2001-10-30 20:28:00 +00:00
|
|
|
|
2009-08-07 20:50:09 +00:00
|
|
|
// Done with externals; turn the warning back on
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(default: 4190)
|
|
|
|
#endif
|
|
|
|
|
2001-10-30 20:28:00 +00:00
|
|
|
|
2003-05-08 16:18:31 +00:00
|
|
|
void Interpreter::initializeExternalFunctions() {
|
2009-07-07 18:33:04 +00:00
|
|
|
sys::ScopedLock Writer(*FunctionsLock);
|
2009-02-04 06:26:47 +00:00
|
|
|
FuncNames["lle_X_atexit"] = lle_X_atexit;
|
2001-11-03 10:15:32 +00:00
|
|
|
FuncNames["lle_X_exit"] = lle_X_exit;
|
2002-05-20 21:17:16 +00:00
|
|
|
FuncNames["lle_X_abort"] = lle_X_abort;
|
2009-02-04 06:26:47 +00:00
|
|
|
|
2001-11-03 10:15:32 +00:00
|
|
|
FuncNames["lle_X_printf"] = lle_X_printf;
|
2001-12-13 00:43:47 +00:00
|
|
|
FuncNames["lle_X_sprintf"] = lle_X_sprintf;
|
2002-03-08 22:51:07 +00:00
|
|
|
FuncNames["lle_X_sscanf"] = lle_X_sscanf;
|
2003-03-31 22:12:37 +00:00
|
|
|
FuncNames["lle_X_scanf"] = lle_X_scanf;
|
2002-11-06 23:05:03 +00:00
|
|
|
FuncNames["lle_X_fprintf"] = lle_X_fprintf;
|
2001-10-30 20:28:00 +00:00
|
|
|
}
|
2003-11-11 22:41:34 +00:00
|
|
|
|