File: | llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp |
Warning: | line 440, column 25 2nd function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- ExternalFunctions.cpp - Implement External Functions --------------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | // | |||
9 | // This file contains both code to deal with invoking "external" functions, but | |||
10 | // also contains code that implements "exported" external functions. | |||
11 | // | |||
12 | // There are currently two mechanisms for handling external functions in the | |||
13 | // Interpreter. The first is to implement lle_* wrapper functions that are | |||
14 | // specific to well-known library functions which manually translate the | |||
15 | // arguments from GenericValues and make the call. If such a wrapper does | |||
16 | // not exist, and libffi is available, then the Interpreter will attempt to | |||
17 | // invoke the function using libffi, after finding its address. | |||
18 | // | |||
19 | //===----------------------------------------------------------------------===// | |||
20 | ||||
21 | #include "Interpreter.h" | |||
22 | #include "llvm/ADT/APInt.h" | |||
23 | #include "llvm/ADT/ArrayRef.h" | |||
24 | #include "llvm/Config/config.h" // Detect libffi | |||
25 | #include "llvm/ExecutionEngine/GenericValue.h" | |||
26 | #include "llvm/IR/DataLayout.h" | |||
27 | #include "llvm/IR/DerivedTypes.h" | |||
28 | #include "llvm/IR/Function.h" | |||
29 | #include "llvm/IR/Type.h" | |||
30 | #include "llvm/Support/Casting.h" | |||
31 | #include "llvm/Support/DynamicLibrary.h" | |||
32 | #include "llvm/Support/ErrorHandling.h" | |||
33 | #include "llvm/Support/ManagedStatic.h" | |||
34 | #include "llvm/Support/Mutex.h" | |||
35 | #include "llvm/Support/raw_ostream.h" | |||
36 | #include <cassert> | |||
37 | #include <cmath> | |||
38 | #include <csignal> | |||
39 | #include <cstdint> | |||
40 | #include <cstdio> | |||
41 | #include <cstring> | |||
42 | #include <map> | |||
43 | #include <mutex> | |||
44 | #include <string> | |||
45 | #include <utility> | |||
46 | #include <vector> | |||
47 | ||||
48 | #ifdef HAVE_FFI_CALL1 | |||
49 | #ifdef HAVE_FFI_H1 | |||
50 | #include <ffi.h> | |||
51 | #define USE_LIBFFI | |||
52 | #elif HAVE_FFI_FFI_H | |||
53 | #include <ffi/ffi.h> | |||
54 | #define USE_LIBFFI | |||
55 | #endif | |||
56 | #endif | |||
57 | ||||
58 | using namespace llvm; | |||
59 | ||||
60 | static ManagedStatic<sys::Mutex> FunctionsLock; | |||
61 | ||||
62 | typedef GenericValue (*ExFunc)(FunctionType *, ArrayRef<GenericValue>); | |||
63 | static ManagedStatic<std::map<const Function *, ExFunc> > ExportedFunctions; | |||
64 | static ManagedStatic<std::map<std::string, ExFunc> > FuncNames; | |||
65 | ||||
66 | #ifdef USE_LIBFFI | |||
67 | typedef void (*RawFunc)(); | |||
68 | static ManagedStatic<std::map<const Function *, RawFunc> > RawFunctions; | |||
69 | #endif | |||
70 | ||||
71 | static Interpreter *TheInterpreter; | |||
72 | ||||
73 | static char getTypeID(Type *Ty) { | |||
74 | switch (Ty->getTypeID()) { | |||
75 | case Type::VoidTyID: return 'V'; | |||
76 | case Type::IntegerTyID: | |||
77 | switch (cast<IntegerType>(Ty)->getBitWidth()) { | |||
78 | case 1: return 'o'; | |||
79 | case 8: return 'B'; | |||
80 | case 16: return 'S'; | |||
81 | case 32: return 'I'; | |||
82 | case 64: return 'L'; | |||
83 | default: return 'N'; | |||
84 | } | |||
85 | case Type::FloatTyID: return 'F'; | |||
86 | case Type::DoubleTyID: return 'D'; | |||
87 | case Type::PointerTyID: return 'P'; | |||
88 | case Type::FunctionTyID:return 'M'; | |||
89 | case Type::StructTyID: return 'T'; | |||
90 | case Type::ArrayTyID: return 'A'; | |||
91 | default: return 'U'; | |||
92 | } | |||
93 | } | |||
94 | ||||
95 | // Try to find address of external function given a Function object. | |||
96 | // Please note, that interpreter doesn't know how to assemble a | |||
97 | // real call in general case (this is JIT job), that's why it assumes, | |||
98 | // that all external functions has the same (and pretty "general") signature. | |||
99 | // The typical example of such functions are "lle_X_" ones. | |||
100 | static ExFunc lookupFunction(const Function *F) { | |||
101 | // Function not found, look it up... start by figuring out what the | |||
102 | // composite function name should be. | |||
103 | std::string ExtName = "lle_"; | |||
104 | FunctionType *FT = F->getFunctionType(); | |||
105 | ExtName += getTypeID(FT->getReturnType()); | |||
106 | for (Type *T : FT->params()) | |||
107 | ExtName += getTypeID(T); | |||
108 | ExtName += ("_" + F->getName()).str(); | |||
109 | ||||
110 | sys::ScopedLock Writer(*FunctionsLock); | |||
111 | ExFunc FnPtr = (*FuncNames)[ExtName]; | |||
112 | if (!FnPtr) | |||
113 | FnPtr = (*FuncNames)[("lle_X_" + F->getName()).str()]; | |||
114 | if (!FnPtr) // Try calling a generic function... if it exists... | |||
115 | FnPtr = (ExFunc)(intptr_t)sys::DynamicLibrary::SearchForAddressOfSymbol( | |||
116 | ("lle_X_" + F->getName()).str()); | |||
117 | if (FnPtr) | |||
118 | ExportedFunctions->insert(std::make_pair(F, FnPtr)); // Cache for later | |||
119 | return FnPtr; | |||
120 | } | |||
121 | ||||
122 | #ifdef USE_LIBFFI | |||
123 | static ffi_type *ffiTypeFor(Type *Ty) { | |||
124 | switch (Ty->getTypeID()) { | |||
125 | case Type::VoidTyID: return &ffi_type_void; | |||
126 | case Type::IntegerTyID: | |||
127 | switch (cast<IntegerType>(Ty)->getBitWidth()) { | |||
128 | case 8: return &ffi_type_sint8; | |||
129 | case 16: return &ffi_type_sint16; | |||
130 | case 32: return &ffi_type_sint32; | |||
131 | case 64: return &ffi_type_sint64; | |||
132 | } | |||
133 | llvm_unreachable("Unhandled integer type bitwidth")::llvm::llvm_unreachable_internal("Unhandled integer type bitwidth" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp" , 133); | |||
134 | case Type::FloatTyID: return &ffi_type_float; | |||
135 | case Type::DoubleTyID: return &ffi_type_double; | |||
136 | case Type::PointerTyID: return &ffi_type_pointer; | |||
137 | default: break; | |||
138 | } | |||
139 | // TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc. | |||
140 | report_fatal_error("Type could not be mapped for use with libffi."); | |||
141 | return NULL__null; | |||
142 | } | |||
143 | ||||
144 | static void *ffiValueFor(Type *Ty, const GenericValue &AV, | |||
145 | void *ArgDataPtr) { | |||
146 | switch (Ty->getTypeID()) { | |||
147 | case Type::IntegerTyID: | |||
148 | switch (cast<IntegerType>(Ty)->getBitWidth()) { | |||
149 | case 8: { | |||
150 | int8_t *I8Ptr = (int8_t *) ArgDataPtr; | |||
151 | *I8Ptr = (int8_t) AV.IntVal.getZExtValue(); | |||
152 | return ArgDataPtr; | |||
153 | } | |||
154 | case 16: { | |||
155 | int16_t *I16Ptr = (int16_t *) ArgDataPtr; | |||
156 | *I16Ptr = (int16_t) AV.IntVal.getZExtValue(); | |||
157 | return ArgDataPtr; | |||
158 | } | |||
159 | case 32: { | |||
160 | int32_t *I32Ptr = (int32_t *) ArgDataPtr; | |||
161 | *I32Ptr = (int32_t) AV.IntVal.getZExtValue(); | |||
162 | return ArgDataPtr; | |||
163 | } | |||
164 | case 64: { | |||
165 | int64_t *I64Ptr = (int64_t *) ArgDataPtr; | |||
166 | *I64Ptr = (int64_t) AV.IntVal.getZExtValue(); | |||
167 | return ArgDataPtr; | |||
168 | } | |||
169 | } | |||
170 | llvm_unreachable("Unhandled integer type bitwidth")::llvm::llvm_unreachable_internal("Unhandled integer type bitwidth" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp" , 170); | |||
171 | case Type::FloatTyID: { | |||
172 | float *FloatPtr = (float *) ArgDataPtr; | |||
173 | *FloatPtr = AV.FloatVal; | |||
174 | return ArgDataPtr; | |||
175 | } | |||
176 | case Type::DoubleTyID: { | |||
177 | double *DoublePtr = (double *) ArgDataPtr; | |||
178 | *DoublePtr = AV.DoubleVal; | |||
179 | return ArgDataPtr; | |||
180 | } | |||
181 | case Type::PointerTyID: { | |||
182 | void **PtrPtr = (void **) ArgDataPtr; | |||
183 | *PtrPtr = GVTOP(AV); | |||
184 | return ArgDataPtr; | |||
185 | } | |||
186 | default: break; | |||
187 | } | |||
188 | // TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc. | |||
189 | report_fatal_error("Type value could not be mapped for use with libffi."); | |||
190 | return NULL__null; | |||
191 | } | |||
192 | ||||
193 | static bool ffiInvoke(RawFunc Fn, Function *F, ArrayRef<GenericValue> ArgVals, | |||
194 | const DataLayout &TD, GenericValue &Result) { | |||
195 | ffi_cif cif; | |||
196 | FunctionType *FTy = F->getFunctionType(); | |||
197 | const unsigned NumArgs = F->arg_size(); | |||
198 | ||||
199 | // TODO: We don't have type information about the remaining arguments, because | |||
200 | // this information is never passed into ExecutionEngine::runFunction(). | |||
201 | if (ArgVals.size() > NumArgs && F->isVarArg()) { | |||
202 | report_fatal_error("Calling external var arg function '" + F->getName() | |||
203 | + "' is not supported by the Interpreter."); | |||
204 | } | |||
205 | ||||
206 | unsigned ArgBytes = 0; | |||
207 | ||||
208 | std::vector<ffi_type*> args(NumArgs); | |||
209 | for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end(); | |||
210 | A != E; ++A) { | |||
211 | const unsigned ArgNo = A->getArgNo(); | |||
212 | Type *ArgTy = FTy->getParamType(ArgNo); | |||
213 | args[ArgNo] = ffiTypeFor(ArgTy); | |||
214 | ArgBytes += TD.getTypeStoreSize(ArgTy); | |||
215 | } | |||
216 | ||||
217 | SmallVector<uint8_t, 128> ArgData; | |||
218 | ArgData.resize(ArgBytes); | |||
219 | uint8_t *ArgDataPtr = ArgData.data(); | |||
220 | SmallVector<void*, 16> values(NumArgs); | |||
221 | for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end(); | |||
222 | A != E; ++A) { | |||
223 | const unsigned ArgNo = A->getArgNo(); | |||
224 | Type *ArgTy = FTy->getParamType(ArgNo); | |||
225 | values[ArgNo] = ffiValueFor(ArgTy, ArgVals[ArgNo], ArgDataPtr); | |||
226 | ArgDataPtr += TD.getTypeStoreSize(ArgTy); | |||
227 | } | |||
228 | ||||
229 | Type *RetTy = FTy->getReturnType(); | |||
230 | ffi_type *rtype = ffiTypeFor(RetTy); | |||
231 | ||||
232 | if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NumArgs, rtype, args.data()) == | |||
233 | FFI_OK) { | |||
234 | SmallVector<uint8_t, 128> ret; | |||
235 | if (RetTy->getTypeID() != Type::VoidTyID) | |||
236 | ret.resize(TD.getTypeStoreSize(RetTy)); | |||
237 | ffi_call(&cif, Fn, ret.data(), values.data()); | |||
238 | switch (RetTy->getTypeID()) { | |||
239 | case Type::IntegerTyID: | |||
240 | switch (cast<IntegerType>(RetTy)->getBitWidth()) { | |||
241 | case 8: Result.IntVal = APInt(8 , *(int8_t *) ret.data()); break; | |||
242 | case 16: Result.IntVal = APInt(16, *(int16_t*) ret.data()); break; | |||
243 | case 32: Result.IntVal = APInt(32, *(int32_t*) ret.data()); break; | |||
244 | case 64: Result.IntVal = APInt(64, *(int64_t*) ret.data()); break; | |||
245 | } | |||
246 | break; | |||
247 | case Type::FloatTyID: Result.FloatVal = *(float *) ret.data(); break; | |||
248 | case Type::DoubleTyID: Result.DoubleVal = *(double*) ret.data(); break; | |||
249 | case Type::PointerTyID: Result.PointerVal = *(void **) ret.data(); break; | |||
250 | default: break; | |||
251 | } | |||
252 | return true; | |||
253 | } | |||
254 | ||||
255 | return false; | |||
256 | } | |||
257 | #endif // USE_LIBFFI | |||
258 | ||||
259 | GenericValue Interpreter::callExternalFunction(Function *F, | |||
260 | ArrayRef<GenericValue> ArgVals) { | |||
261 | TheInterpreter = this; | |||
262 | ||||
263 | std::unique_lock<sys::Mutex> Guard(*FunctionsLock); | |||
264 | ||||
265 | // Do a lookup to see if the function is in our cache... this should just be a | |||
266 | // deferred annotation! | |||
267 | std::map<const Function *, ExFunc>::iterator FI = ExportedFunctions->find(F); | |||
268 | if (ExFunc Fn = (FI == ExportedFunctions->end()) ? lookupFunction(F) | |||
269 | : FI->second) { | |||
270 | Guard.unlock(); | |||
271 | return Fn(F->getFunctionType(), ArgVals); | |||
272 | } | |||
273 | ||||
274 | #ifdef USE_LIBFFI | |||
275 | std::map<const Function *, RawFunc>::iterator RF = RawFunctions->find(F); | |||
276 | RawFunc RawFn; | |||
277 | if (RF == RawFunctions->end()) { | |||
278 | RawFn = (RawFunc)(intptr_t) | |||
279 | sys::DynamicLibrary::SearchForAddressOfSymbol(std::string(F->getName())); | |||
280 | if (!RawFn) | |||
281 | RawFn = (RawFunc)(intptr_t)getPointerToGlobalIfAvailable(F); | |||
282 | if (RawFn != 0) | |||
283 | RawFunctions->insert(std::make_pair(F, RawFn)); // Cache for later | |||
284 | } else { | |||
285 | RawFn = RF->second; | |||
286 | } | |||
287 | ||||
288 | Guard.unlock(); | |||
289 | ||||
290 | GenericValue Result; | |||
291 | if (RawFn != 0 && ffiInvoke(RawFn, F, ArgVals, getDataLayout(), Result)) | |||
292 | return Result; | |||
293 | #endif // USE_LIBFFI | |||
294 | ||||
295 | if (F->getName() == "__main") | |||
296 | errs() << "Tried to execute an unknown external function: " | |||
297 | << *F->getType() << " __main\n"; | |||
298 | else | |||
299 | report_fatal_error("Tried to execute an unknown external function: " + | |||
300 | F->getName()); | |||
301 | #ifndef USE_LIBFFI | |||
302 | errs() << "Recompiling LLVM with --enable-libffi might help.\n"; | |||
303 | #endif | |||
304 | return GenericValue(); | |||
305 | } | |||
306 | ||||
307 | //===----------------------------------------------------------------------===// | |||
308 | // Functions "exported" to the running application... | |||
309 | // | |||
310 | ||||
311 | // void atexit(Function*) | |||
312 | static GenericValue lle_X_atexit(FunctionType *FT, | |||
313 | ArrayRef<GenericValue> Args) { | |||
314 | assert(Args.size() == 1)(static_cast <bool> (Args.size() == 1) ? void (0) : __assert_fail ("Args.size() == 1", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp" , 314, __extension__ __PRETTY_FUNCTION__)); | |||
315 | TheInterpreter->addAtExitHandler((Function*)GVTOP(Args[0])); | |||
316 | GenericValue GV; | |||
317 | GV.IntVal = 0; | |||
318 | return GV; | |||
319 | } | |||
320 | ||||
321 | // void exit(int) | |||
322 | static GenericValue lle_X_exit(FunctionType *FT, ArrayRef<GenericValue> Args) { | |||
323 | TheInterpreter->exitCalled(Args[0]); | |||
324 | return GenericValue(); | |||
325 | } | |||
326 | ||||
327 | // void abort(void) | |||
328 | static GenericValue lle_X_abort(FunctionType *FT, ArrayRef<GenericValue> Args) { | |||
329 | //FIXME: should we report or raise here? | |||
330 | //report_fatal_error("Interpreted program raised SIGABRT"); | |||
331 | raise (SIGABRT6); | |||
332 | return GenericValue(); | |||
333 | } | |||
334 | ||||
335 | // int sprintf(char *, const char *, ...) - a very rough implementation to make | |||
336 | // output useful. | |||
337 | static GenericValue lle_X_sprintf(FunctionType *FT, | |||
338 | ArrayRef<GenericValue> Args) { | |||
339 | char *OutputBuffer = (char *)GVTOP(Args[0]); | |||
340 | const char *FmtStr = (const char *)GVTOP(Args[1]); | |||
341 | unsigned ArgNo = 2; | |||
342 | ||||
343 | // printf should return # chars printed. This is completely incorrect, but | |||
344 | // close enough for now. | |||
345 | GenericValue GV; | |||
346 | GV.IntVal = APInt(32, strlen(FmtStr)); | |||
347 | while (true) { | |||
348 | switch (*FmtStr) { | |||
349 | case 0: return GV; // Null terminator... | |||
350 | default: // Normal nonspecial character | |||
351 | sprintf(OutputBuffer++, "%c", *FmtStr++); | |||
352 | break; | |||
353 | case '\\': { // Handle escape codes | |||
354 | sprintf(OutputBuffer, "%c%c", *FmtStr, *(FmtStr+1)); | |||
355 | FmtStr += 2; OutputBuffer += 2; | |||
356 | break; | |||
357 | } | |||
358 | case '%': { // Handle format specifiers | |||
359 | char FmtBuf[100] = "", Buffer[1000] = ""; | |||
360 | char *FB = FmtBuf; | |||
361 | *FB++ = *FmtStr++; | |||
362 | char Last = *FB++ = *FmtStr++; | |||
363 | unsigned HowLong = 0; | |||
364 | while (Last != 'c' && Last != 'd' && Last != 'i' && Last != 'u' && | |||
365 | Last != 'o' && Last != 'x' && Last != 'X' && Last != 'e' && | |||
366 | Last != 'E' && Last != 'g' && Last != 'G' && Last != 'f' && | |||
367 | Last != 'p' && Last != 's' && Last != '%') { | |||
368 | if (Last == 'l' || Last == 'L') HowLong++; // Keep track of l's | |||
369 | Last = *FB++ = *FmtStr++; | |||
370 | } | |||
371 | *FB = 0; | |||
372 | ||||
373 | switch (Last) { | |||
374 | case '%': | |||
375 | memcpy(Buffer, "%", 2); break; | |||
376 | case 'c': | |||
377 | sprintf(Buffer, FmtBuf, uint32_t(Args[ArgNo++].IntVal.getZExtValue())); | |||
378 | break; | |||
379 | case 'd': case 'i': | |||
380 | case 'u': case 'o': | |||
381 | case 'x': case 'X': | |||
382 | if (HowLong >= 1) { | |||
383 | if (HowLong == 1 && | |||
384 | TheInterpreter->getDataLayout().getPointerSizeInBits() == 64 && | |||
385 | sizeof(long) < sizeof(int64_t)) { | |||
386 | // Make sure we use %lld with a 64 bit argument because we might be | |||
387 | // compiling LLI on a 32 bit compiler. | |||
388 | unsigned Size = strlen(FmtBuf); | |||
389 | FmtBuf[Size] = FmtBuf[Size-1]; | |||
390 | FmtBuf[Size+1] = 0; | |||
391 | FmtBuf[Size-1] = 'l'; | |||
392 | } | |||
393 | sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal.getZExtValue()); | |||
394 | } else | |||
395 | sprintf(Buffer, FmtBuf,uint32_t(Args[ArgNo++].IntVal.getZExtValue())); | |||
396 | break; | |||
397 | case 'e': case 'E': case 'g': case 'G': case 'f': | |||
398 | sprintf(Buffer, FmtBuf, Args[ArgNo++].DoubleVal); break; | |||
399 | case 'p': | |||
400 | sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break; | |||
401 | case 's': | |||
402 | sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break; | |||
403 | default: | |||
404 | errs() << "<unknown printf code '" << *FmtStr << "'!>"; | |||
405 | ArgNo++; break; | |||
406 | } | |||
407 | size_t Len = strlen(Buffer); | |||
408 | memcpy(OutputBuffer, Buffer, Len + 1); | |||
409 | OutputBuffer += Len; | |||
410 | } | |||
411 | break; | |||
412 | } | |||
413 | } | |||
414 | return GV; | |||
415 | } | |||
416 | ||||
417 | // int printf(const char *, ...) - a very rough implementation to make output | |||
418 | // useful. | |||
419 | static GenericValue lle_X_printf(FunctionType *FT, | |||
420 | ArrayRef<GenericValue> Args) { | |||
421 | char Buffer[10000]; | |||
422 | std::vector<GenericValue> NewArgs; | |||
423 | NewArgs.push_back(PTOGV((void*)&Buffer[0])); | |||
424 | llvm::append_range(NewArgs, Args); | |||
425 | GenericValue GV = lle_X_sprintf(FT, NewArgs); | |||
426 | outs() << Buffer; | |||
427 | return GV; | |||
428 | } | |||
429 | ||||
430 | // int sscanf(const char *format, ...); | |||
431 | static GenericValue lle_X_sscanf(FunctionType *FT, | |||
432 | ArrayRef<GenericValue> args) { | |||
433 | assert(args.size() < 10 && "Only handle up to 10 args to sscanf right now!")(static_cast <bool> (args.size() < 10 && "Only handle up to 10 args to sscanf right now!" ) ? void (0) : __assert_fail ("args.size() < 10 && \"Only handle up to 10 args to sscanf right now!\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp" , 433, __extension__ __PRETTY_FUNCTION__)); | |||
| ||||
434 | ||||
435 | char *Args[10]; | |||
436 | for (unsigned i = 0; i < args.size(); ++i) | |||
437 | Args[i] = (char*)GVTOP(args[i]); | |||
438 | ||||
439 | GenericValue GV; | |||
440 | GV.IntVal = APInt(32, sscanf(Args[0], Args[1], Args[2], Args[3], Args[4], | |||
| ||||
441 | Args[5], Args[6], Args[7], Args[8], Args[9])); | |||
442 | return GV; | |||
443 | } | |||
444 | ||||
445 | // int scanf(const char *format, ...); | |||
446 | static GenericValue lle_X_scanf(FunctionType *FT, ArrayRef<GenericValue> args) { | |||
447 | assert(args.size() < 10 && "Only handle up to 10 args to scanf right now!")(static_cast <bool> (args.size() < 10 && "Only handle up to 10 args to scanf right now!" ) ? void (0) : __assert_fail ("args.size() < 10 && \"Only handle up to 10 args to scanf right now!\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp" , 447, __extension__ __PRETTY_FUNCTION__)); | |||
448 | ||||
449 | char *Args[10]; | |||
450 | for (unsigned i = 0; i < args.size(); ++i) | |||
451 | Args[i] = (char*)GVTOP(args[i]); | |||
452 | ||||
453 | GenericValue GV; | |||
454 | GV.IntVal = APInt(32, scanf( Args[0], Args[1], Args[2], Args[3], Args[4], | |||
455 | Args[5], Args[6], Args[7], Args[8], Args[9])); | |||
456 | return GV; | |||
457 | } | |||
458 | ||||
459 | // int fprintf(FILE *, const char *, ...) - a very rough implementation to make | |||
460 | // output useful. | |||
461 | static GenericValue lle_X_fprintf(FunctionType *FT, | |||
462 | ArrayRef<GenericValue> Args) { | |||
463 | assert(Args.size() >= 2)(static_cast <bool> (Args.size() >= 2) ? void (0) : __assert_fail ("Args.size() >= 2", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp" , 463, __extension__ __PRETTY_FUNCTION__)); | |||
464 | char Buffer[10000]; | |||
465 | std::vector<GenericValue> NewArgs; | |||
466 | NewArgs.push_back(PTOGV(Buffer)); | |||
467 | NewArgs.insert(NewArgs.end(), Args.begin()+1, Args.end()); | |||
468 | GenericValue GV = lle_X_sprintf(FT, NewArgs); | |||
469 | ||||
470 | fputs(Buffer, (FILE *) GVTOP(Args[0])); | |||
471 | return GV; | |||
472 | } | |||
473 | ||||
474 | static GenericValue lle_X_memset(FunctionType *FT, | |||
475 | ArrayRef<GenericValue> Args) { | |||
476 | int val = (int)Args[1].IntVal.getSExtValue(); | |||
477 | size_t len = (size_t)Args[2].IntVal.getZExtValue(); | |||
478 | memset((void *)GVTOP(Args[0]), val, len); | |||
479 | // llvm.memset.* returns void, lle_X_* returns GenericValue, | |||
480 | // so here we return GenericValue with IntVal set to zero | |||
481 | GenericValue GV; | |||
482 | GV.IntVal = 0; | |||
483 | return GV; | |||
484 | } | |||
485 | ||||
486 | static GenericValue lle_X_memcpy(FunctionType *FT, | |||
487 | ArrayRef<GenericValue> Args) { | |||
488 | memcpy(GVTOP(Args[0]), GVTOP(Args[1]), | |||
489 | (size_t)(Args[2].IntVal.getLimitedValue())); | |||
490 | ||||
491 | // llvm.memcpy* returns void, lle_X_* returns GenericValue, | |||
492 | // so here we return GenericValue with IntVal set to zero | |||
493 | GenericValue GV; | |||
494 | GV.IntVal = 0; | |||
495 | return GV; | |||
496 | } | |||
497 | ||||
498 | void Interpreter::initializeExternalFunctions() { | |||
499 | sys::ScopedLock Writer(*FunctionsLock); | |||
500 | (*FuncNames)["lle_X_atexit"] = lle_X_atexit; | |||
501 | (*FuncNames)["lle_X_exit"] = lle_X_exit; | |||
502 | (*FuncNames)["lle_X_abort"] = lle_X_abort; | |||
503 | ||||
504 | (*FuncNames)["lle_X_printf"] = lle_X_printf; | |||
505 | (*FuncNames)["lle_X_sprintf"] = lle_X_sprintf; | |||
506 | (*FuncNames)["lle_X_sscanf"] = lle_X_sscanf; | |||
507 | (*FuncNames)["lle_X_scanf"] = lle_X_scanf; | |||
508 | (*FuncNames)["lle_X_fprintf"] = lle_X_fprintf; | |||
509 | (*FuncNames)["lle_X_memset"] = lle_X_memset; | |||
510 | (*FuncNames)["lle_X_memcpy"] = lle_X_memcpy; | |||
511 | } |