blob: 426d89e28d0d0566cc0fbcb693f34be22a58b04f [file] [log] [blame]
Yang Ni2abfcc62015-02-17 16:05:19 -08001#include "rsCpuExecutable.h"
2#include "rsCppUtils.h"
3
4#include <fstream>
5#include <set>
6#include <memory>
7
Miao Wang2a611682017-02-27 17:36:40 -08008#include <sys/stat.h>
9
Yang Ni2abfcc62015-02-17 16:05:19 -080010#ifdef RS_COMPATIBILITY_LIB
11#include <stdio.h>
Yang Ni2abfcc62015-02-17 16:05:19 -080012#include <unistd.h>
13#else
Jean-Luc Brouillet03fab682017-02-16 21:07:20 -080014#include "bcc/Config.h"
Yang Ni2abfcc62015-02-17 16:05:19 -080015#endif
16
17#include <dlfcn.h>
18
19namespace android {
20namespace renderscript {
21
22namespace {
23
Yang Ni2abfcc62015-02-17 16:05:19 -080024// Check if a path exists and attempt to create it if it doesn't.
25static bool ensureCacheDirExists(const char *path) {
26 if (access(path, R_OK | W_OK | X_OK) == 0) {
27 // Done if we can rwx the directory
28 return true;
29 }
30 if (mkdir(path, 0700) == 0) {
31 return true;
32 }
33 return false;
34}
35
36// Copy the file named \p srcFile to \p dstFile.
37// Return 0 on success and -1 if anything wasn't copied.
38static int copyFile(const char *dstFile, const char *srcFile) {
39 std::ifstream srcStream(srcFile);
40 if (!srcStream) {
41 ALOGE("Could not verify or read source file: %s", srcFile);
42 return -1;
43 }
44 std::ofstream dstStream(dstFile);
45 if (!dstStream) {
46 ALOGE("Could not verify or write destination file: %s", dstFile);
47 return -1;
48 }
49 dstStream << srcStream.rdbuf();
50 if (!dstStream) {
51 ALOGE("Could not write destination file: %s", dstFile);
52 return -1;
53 }
54
55 srcStream.close();
56 dstStream.close();
57
58 return 0;
59}
60
61static std::string findSharedObjectName(const char *cacheDir,
62 const char *resName) {
Yang Ni2abfcc62015-02-17 16:05:19 -080063 std::string scriptSOName(cacheDir);
64#if defined(RS_COMPATIBILITY_LIB) && !defined(__LP64__)
65 size_t cutPos = scriptSOName.rfind("cache");
66 if (cutPos != std::string::npos) {
67 scriptSOName.erase(cutPos);
68 } else {
69 ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir);
70 }
71 scriptSOName.append("/lib/librs.");
72#else
73 scriptSOName.append("/librs.");
74#endif // RS_COMPATIBILITY_LIB
Yang Ni2abfcc62015-02-17 16:05:19 -080075 scriptSOName.append(resName);
76 scriptSOName.append(".so");
77
78 return scriptSOName;
79}
80
81} // anonymous namespace
82
83const char* SharedLibraryUtils::LD_EXE_PATH = "/system/bin/ld.mc";
84const char* SharedLibraryUtils::RS_CACHE_DIR = "com.android.renderscript.cache";
85
86#ifndef RS_COMPATIBILITY_LIB
87
Stephen Hines4c368af2015-05-06 00:43:02 -070088bool SharedLibraryUtils::createSharedLibrary(const char *driverName,
89 const char *cacheDir,
90 const char *resName) {
Yang Ni2abfcc62015-02-17 16:05:19 -080091 std::string sharedLibName = findSharedObjectName(cacheDir, resName);
92 std::string objFileName = cacheDir;
93 objFileName.append("/");
94 objFileName.append(resName);
95 objFileName.append(".o");
Stephen Hines4c368af2015-05-06 00:43:02 -070096 // Should be something like "libRSDriver.so".
97 std::string linkDriverName = driverName;
98 // Remove ".so" and replace "lib" with "-l".
99 // This will leave us with "-lRSDriver" instead.
100 linkDriverName.erase(linkDriverName.length() - 3);
101 linkDriverName.replace(0, 3, "-l");
Yang Ni2abfcc62015-02-17 16:05:19 -0800102
103 const char *compiler_rt = SYSLIBPATH"/libcompiler_rt.so";
Pirama Arumuga Nainarc2be4132015-04-21 15:25:53 -0700104 const char *mTriple = "-mtriple=" DEFAULT_TARGET_TRIPLE_STRING;
105 const char *libPath = "--library-path=" SYSLIBPATH;
Pirama Arumuga Nainar682672e2015-05-07 15:52:48 -0700106 const char *vendorLibPath = "--library-path=" SYSLIBPATH_VENDOR;
Pirama Arumuga Nainarc2be4132015-04-21 15:25:53 -0700107
Yang Ni2abfcc62015-02-17 16:05:19 -0800108 std::vector<const char *> args = {
109 LD_EXE_PATH,
110 "-shared",
111 "-nostdlib",
Pirama Arumuga Nainar682672e2015-05-07 15:52:48 -0700112 compiler_rt, mTriple, vendorLibPath, libPath,
Stephen Hines4c368af2015-05-06 00:43:02 -0700113 linkDriverName.c_str(), "-lm", "-lc",
Yang Ni2abfcc62015-02-17 16:05:19 -0800114 objFileName.c_str(),
115 "-o", sharedLibName.c_str(),
116 nullptr
117 };
118
Pirama Arumuga Nainar2fa8a232015-03-25 17:21:40 -0700119 return rsuExecuteCommand(LD_EXE_PATH, args.size()-1, args.data());
Yang Ni2abfcc62015-02-17 16:05:19 -0800120
Yang Ni2abfcc62015-02-17 16:05:19 -0800121}
122
123#endif // RS_COMPATIBILITY_LIB
124
125const char* RsdCpuScriptImpl::BCC_EXE_PATH = "/system/bin/bcc";
126
127void* SharedLibraryUtils::loadSharedLibrary(const char *cacheDir,
128 const char *resName,
Yang Ni1efae292015-06-27 15:45:18 -0700129 const char *nativeLibDir,
130 bool* alreadyLoaded) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800131 void *loaded = nullptr;
132
133#if defined(RS_COMPATIBILITY_LIB) && defined(__LP64__)
134 std::string scriptSOName = findSharedObjectName(nativeLibDir, resName);
135#else
136 std::string scriptSOName = findSharedObjectName(cacheDir, resName);
137#endif
138
139 // We should check if we can load the library from the standard app
140 // location for shared libraries first.
Yang Ni1efae292015-06-27 15:45:18 -0700141 loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName, alreadyLoaded);
Yang Ni2abfcc62015-02-17 16:05:19 -0800142
143 if (loaded == nullptr) {
144 ALOGE("Unable to open shared library (%s): %s",
145 scriptSOName.c_str(), dlerror());
146
147#ifdef RS_COMPATIBILITY_LIB
148 // One final attempt to find the library in "/system/lib".
149 // We do this to allow bundled applications to use the compatibility
150 // library fallback path. Those applications don't have a private
151 // library path, so they need to install to the system directly.
152 // Note that this is really just a testing path.
153 std::string scriptSONameSystem("/system/lib/librs.");
154 scriptSONameSystem.append(resName);
155 scriptSONameSystem.append(".so");
156 loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir,
157 resName);
158 if (loaded == nullptr) {
159 ALOGE("Unable to open system shared library (%s): %s",
160 scriptSONameSystem.c_str(), dlerror());
161 }
162#endif
163 }
164
165 return loaded;
166}
167
Yang Ni1efae292015-06-27 15:45:18 -0700168String8 SharedLibraryUtils::getRandomString(size_t len) {
169 char buf[len + 1];
170 for (size_t i = 0; i < len; i++) {
171 uint32_t r = arc4random() & 0xffff;
172 r %= 62;
173 if (r < 26) {
174 // lowercase
175 buf[i] = 'a' + r;
176 } else if (r < 52) {
177 // uppercase
178 buf[i] = 'A' + (r - 26);
179 } else {
180 // Use a number
181 buf[i] = '0' + (r - 52);
182 }
183 }
184 buf[len] = '\0';
185 return String8(buf);
186}
187
Yang Ni2abfcc62015-02-17 16:05:19 -0800188void* SharedLibraryUtils::loadSOHelper(const char *origName, const char *cacheDir,
Yang Ni1efae292015-06-27 15:45:18 -0700189 const char *resName, bool *alreadyLoaded) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800190 // Keep track of which .so libraries have been loaded. Once a library is
191 // in the set (per-process granularity), we must instead make a copy of
192 // the original shared object (randomly named .so file) and load that one
193 // instead. If we don't do this, we end up aliasing global data between
194 // the various Script instances (which are supposed to be completely
195 // independent).
196 static std::set<std::string> LoadedLibraries;
197
198 void *loaded = nullptr;
199
200 // Skip everything if we don't even have the original library available.
201 if (access(origName, F_OK) != 0) {
202 return nullptr;
203 }
204
205 // Common path is that we have not loaded this Script/library before.
206 if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
Yang Ni1efae292015-06-27 15:45:18 -0700207 if (alreadyLoaded != nullptr) {
208 *alreadyLoaded = false;
209 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800210 loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
211 if (loaded) {
212 LoadedLibraries.insert(origName);
213 }
214 return loaded;
215 }
216
Yang Ni1efae292015-06-27 15:45:18 -0700217 if (alreadyLoaded != nullptr) {
218 *alreadyLoaded = true;
219 }
220
Yang Ni2abfcc62015-02-17 16:05:19 -0800221 std::string newName(cacheDir);
222
223 // Append RS_CACHE_DIR only if it is not found in cacheDir
224 // In driver mode, RS_CACHE_DIR is already appended to cacheDir.
225 if (newName.find(RS_CACHE_DIR) == std::string::npos) {
226 newName.append("/");
227 newName.append(RS_CACHE_DIR);
228 newName.append("/");
229 }
230
231 if (!ensureCacheDirExists(newName.c_str())) {
232 ALOGE("Could not verify or create cache dir: %s", cacheDir);
233 return nullptr;
234 }
235
236 // Construct an appropriately randomized filename for the copy.
237 newName.append("librs.");
238 newName.append(resName);
239 newName.append("#");
Yang Ni1efae292015-06-27 15:45:18 -0700240 newName.append(getRandomString(6).string()); // 62^6 potential filename variants.
Yang Ni2abfcc62015-02-17 16:05:19 -0800241 newName.append(".so");
242
243 int r = copyFile(newName.c_str(), origName);
244 if (r != 0) {
245 ALOGE("Could not create copy %s -> %s", origName, newName.c_str());
246 return nullptr;
247 }
248 loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
249 r = unlink(newName.c_str());
250 if (r != 0) {
251 ALOGE("Could not unlink copy %s", newName.c_str());
252 }
253 if (loaded) {
254 LoadedLibraries.insert(newName.c_str());
255 }
256
257 return loaded;
258}
259
Miao Wangd4848102016-04-27 15:49:47 -0700260// MAXLINESTR must be compatible with operator '#' in C macro.
261#define MAXLINESTR 499
262// MAXLINE must be (MAXLINESTR + 1), representing the size of a C string
263// containing MAXLINESTR non-null chars plus a null.
264#define MAXLINE (MAXLINESTR + 1)
Yang Ni2abfcc62015-02-17 16:05:19 -0800265#define MAKE_STR_HELPER(S) #S
266#define MAKE_STR(S) MAKE_STR_HELPER(S)
267#define EXPORT_VAR_STR "exportVarCount: "
268#define EXPORT_FUNC_STR "exportFuncCount: "
269#define EXPORT_FOREACH_STR "exportForEachCount: "
Matt Wala14ce0072015-07-30 17:30:25 -0700270#define EXPORT_REDUCE_STR "exportReduceCount: "
Yang Ni2abfcc62015-02-17 16:05:19 -0800271#define OBJECT_SLOT_STR "objectSlotCount: "
272#define PRAGMA_STR "pragmaCount: "
273#define THREADABLE_STR "isThreadable: "
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800274#define CHECKSUM_STR "buildChecksum: "
Yang Ni2abfcc62015-02-17 16:05:19 -0800275
276// Copy up to a newline or size chars from str -> s, updating str
277// Returns s when successful and nullptr when '\0' is finally reached.
278static char* strgets(char *s, int size, const char **ppstr) {
279 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
280 return nullptr;
281 }
282
283 int i;
284 for (i = 0; i < (size - 1); i++) {
285 s[i] = **ppstr;
286 (*ppstr)++;
287 if (s[i] == '\0') {
288 return s;
289 } else if (s[i] == '\n') {
290 s[i+1] = '\0';
291 return s;
292 }
293 }
294
295 // size has been exceeded.
296 s[i] = '\0';
297
298 return s;
299}
300
301ScriptExecutable* ScriptExecutable::createFromSharedObject(
Yang Ni5e480022016-04-06 09:34:34 -0700302 void* sharedObj, uint32_t expectedChecksum) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800303 char line[MAXLINE];
304
305 size_t varCount = 0;
306 size_t funcCount = 0;
307 size_t forEachCount = 0;
Matt Wala14ce0072015-07-30 17:30:25 -0700308 size_t reduceCount = 0;
Yang Ni2abfcc62015-02-17 16:05:19 -0800309 size_t objectSlotCount = 0;
310 size_t pragmaCount = 0;
311 bool isThreadable = true;
312
313 void** fieldAddress = nullptr;
314 bool* fieldIsObject = nullptr;
Yang Ni062c2872015-02-20 15:20:00 -0800315 char** fieldName = nullptr;
Yang Ni2abfcc62015-02-17 16:05:19 -0800316 InvokeFunc_t* invokeFunctions = nullptr;
317 ForEachFunc_t* forEachFunctions = nullptr;
318 uint32_t* forEachSignatures = nullptr;
David Grossae2ec3f2016-06-01 14:45:47 -0700319 ReduceDescription* reduceDescriptions = nullptr;
Yang Ni2abfcc62015-02-17 16:05:19 -0800320 const char ** pragmaKeys = nullptr;
321 const char ** pragmaValues = nullptr;
Yang Nicb170152015-04-16 10:27:02 -0700322 uint32_t checksum = 0;
Yang Ni2abfcc62015-02-17 16:05:19 -0800323
Stephen Hines5aa018c2015-05-20 18:09:57 -0700324 const char *rsInfo = (const char *) dlsym(sharedObj, kRsInfo);
Stephen Hines8409d642015-04-28 18:49:56 -0700325 int numEntries = 0;
Stephen Hines5aa018c2015-05-20 18:09:57 -0700326 const int *rsGlobalEntries = (const int *) dlsym(sharedObj, kRsGlobalEntries);
327 const char **rsGlobalNames = (const char **) dlsym(sharedObj, kRsGlobalNames);
328 const void **rsGlobalAddresses = (const void **) dlsym(sharedObj, kRsGlobalAddresses);
329 const size_t *rsGlobalSizes = (const size_t *) dlsym(sharedObj, kRsGlobalSizes);
330 const uint32_t *rsGlobalProperties = (const uint32_t *) dlsym(sharedObj, kRsGlobalProperties);
Yang Ni2abfcc62015-02-17 16:05:19 -0800331
332 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
333 return nullptr;
334 }
335 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
336 ALOGE("Invalid export var count!: %s", line);
337 return nullptr;
338 }
339
340 fieldAddress = new void*[varCount];
341 if (fieldAddress == nullptr) {
342 return nullptr;
343 }
344
345 fieldIsObject = new bool[varCount];
346 if (fieldIsObject == nullptr) {
347 goto error;
348 }
349
Yang Ni062c2872015-02-20 15:20:00 -0800350 fieldName = new char*[varCount];
351 if (fieldName == nullptr) {
352 goto error;
353 }
354
Yang Ni2abfcc62015-02-17 16:05:19 -0800355 for (size_t i = 0; i < varCount; ++i) {
356 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
357 goto error;
358 }
359 char *c = strrchr(line, '\n');
360 if (c) {
361 *c = '\0';
362 }
363 void* addr = dlsym(sharedObj, line);
364 if (addr == nullptr) {
365 ALOGE("Failed to find variable address for %s: %s",
366 line, dlerror());
367 // Not a critical error if we don't find a global variable.
368 }
369 fieldAddress[i] = addr;
370 fieldIsObject[i] = false;
Yang Ni062c2872015-02-20 15:20:00 -0800371 fieldName[i] = new char[strlen(line)+1];
372 strcpy(fieldName[i], line);
Yang Ni2abfcc62015-02-17 16:05:19 -0800373 }
374
375 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
376 goto error;
377 }
378 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
379 ALOGE("Invalid export func count!: %s", line);
380 goto error;
381 }
382
383 invokeFunctions = new InvokeFunc_t[funcCount];
384 if (invokeFunctions == nullptr) {
385 goto error;
386 }
387
388 for (size_t i = 0; i < funcCount; ++i) {
389 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
390 goto error;
391 }
392 char *c = strrchr(line, '\n');
393 if (c) {
394 *c = '\0';
395 }
396
397 invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line);
398 if (invokeFunctions[i] == nullptr) {
399 ALOGE("Failed to get function address for %s(): %s",
400 line, dlerror());
401 goto error;
402 }
403 }
404
405 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
406 goto error;
407 }
408 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
409 ALOGE("Invalid export forEach count!: %s", line);
410 goto error;
411 }
412
413 forEachFunctions = new ForEachFunc_t[forEachCount];
414 if (forEachFunctions == nullptr) {
415 goto error;
416 }
417
418 forEachSignatures = new uint32_t[forEachCount];
419 if (forEachSignatures == nullptr) {
420 goto error;
421 }
422
423 for (size_t i = 0; i < forEachCount; ++i) {
424 unsigned int tmpSig = 0;
425 char tmpName[MAXLINE];
426
427 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
428 goto error;
429 }
Miao Wangd4848102016-04-27 15:49:47 -0700430 if (sscanf(line, "%u - %" MAKE_STR(MAXLINESTR) "s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800431 &tmpSig, tmpName) != 2) {
432 ALOGE("Invalid export forEach!: %s", line);
433 goto error;
434 }
435
436 // Lookup the expanded ForEach kernel.
Miao Wangd4848102016-04-27 15:49:47 -0700437 strncat(tmpName, ".expand", MAXLINESTR-strlen(tmpName));
Yang Ni2abfcc62015-02-17 16:05:19 -0800438 forEachSignatures[i] = tmpSig;
439 forEachFunctions[i] =
440 (ForEachFunc_t) dlsym(sharedObj, tmpName);
Yang Ni062c2872015-02-20 15:20:00 -0800441 if (i != 0 && forEachFunctions[i] == nullptr &&
442 strcmp(tmpName, "root.expand")) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800443 // Ignore missing root.expand functions.
444 // root() is always specified at location 0.
Matt Wala14ce0072015-07-30 17:30:25 -0700445 ALOGE("Failed to find forEach function address for %s(): %s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800446 tmpName, dlerror());
447 goto error;
448 }
449 }
450
David Gross6c1876b2016-01-15 11:52:14 -0800451 // Read general reduce kernels
David Gross46c93e42016-01-09 16:23:37 -0800452 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
453 goto error;
454 }
David Grossae2ec3f2016-06-01 14:45:47 -0700455 if (sscanf(line, EXPORT_REDUCE_STR "%zu", &reduceCount) != 1) {
David Gross46c93e42016-01-09 16:23:37 -0800456 ALOGE("Invalid export reduce new count!: %s", line);
457 goto error;
458 }
David Gross6c1876b2016-01-15 11:52:14 -0800459
David Grossae2ec3f2016-06-01 14:45:47 -0700460 reduceDescriptions = new ReduceDescription[reduceCount];
461 if (reduceDescriptions == nullptr) {
David Gross46c93e42016-01-09 16:23:37 -0800462 goto error;
463 }
464
David Grossae2ec3f2016-06-01 14:45:47 -0700465 for (size_t i = 0; i < reduceCount; ++i) {
David Gross6c1876b2016-01-15 11:52:14 -0800466 static const char kNoName[] = ".";
467
468 unsigned int tmpSig = 0;
469 size_t tmpSize = 0;
470 char tmpNameReduce[MAXLINE];
471 char tmpNameInitializer[MAXLINE];
472 char tmpNameAccumulator[MAXLINE];
473 char tmpNameCombiner[MAXLINE];
474 char tmpNameOutConverter[MAXLINE];
475 char tmpNameHalter[MAXLINE];
476
477 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
478 goto error;
479 }
Miao Wangd4848102016-04-27 15:49:47 -0700480#define DELIMNAME " - %" MAKE_STR(MAXLINESTR) "s"
David Gross6c1876b2016-01-15 11:52:14 -0800481 if (sscanf(line, "%u - %zu" DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME,
482 &tmpSig, &tmpSize, tmpNameReduce, tmpNameInitializer, tmpNameAccumulator,
483 tmpNameCombiner, tmpNameOutConverter, tmpNameHalter) != 8) {
484 ALOGE("Invalid export reduce new!: %s", line);
485 goto error;
486 }
487#undef DELIMNAME
488
489 // For now, we expect
490 // - Reduce and Accumulator names
491 // - optional Initializer, Combiner, and OutConverter name
492 // - no Halter name
493 if (!strcmp(tmpNameReduce, kNoName) ||
494 !strcmp(tmpNameAccumulator, kNoName)) {
495 ALOGE("Expected reduce and accumulator names!: %s", line);
496 goto error;
497 }
498 if (strcmp(tmpNameHalter, kNoName)) {
499 ALOGE("Did not expect halter name!: %s", line);
500 goto error;
501 }
502
David Gross10adb0c2016-03-29 13:48:41 -0700503 // The current implementation does not use the signature
504 // or reduce name.
David Gross6c1876b2016-01-15 11:52:14 -0800505
David Grossae2ec3f2016-06-01 14:45:47 -0700506 reduceDescriptions[i].accumSize = tmpSize;
David Gross6c1876b2016-01-15 11:52:14 -0800507
508 // Process the (optional) initializer.
509 if (strcmp(tmpNameInitializer, kNoName)) {
510 // Lookup the original user-written initializer.
David Grossae2ec3f2016-06-01 14:45:47 -0700511 if (!(reduceDescriptions[i].initFunc =
512 (ReduceInitializerFunc_t) dlsym(sharedObj, tmpNameInitializer))) {
David Gross6c1876b2016-01-15 11:52:14 -0800513 ALOGE("Failed to find initializer function address for %s(): %s",
514 tmpNameInitializer, dlerror());
515 goto error;
516 }
517 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700518 reduceDescriptions[i].initFunc = nullptr;
David Gross6c1876b2016-01-15 11:52:14 -0800519 }
520
521 // Lookup the expanded accumulator.
Miao Wangd4848102016-04-27 15:49:47 -0700522 strncat(tmpNameAccumulator, ".expand", MAXLINESTR-strlen(tmpNameAccumulator));
David Grossae2ec3f2016-06-01 14:45:47 -0700523 if (!(reduceDescriptions[i].accumFunc =
524 (ReduceAccumulatorFunc_t) dlsym(sharedObj, tmpNameAccumulator))) {
David Gross6c1876b2016-01-15 11:52:14 -0800525 ALOGE("Failed to find accumulator function address for %s(): %s",
526 tmpNameAccumulator, dlerror());
527 goto error;
528 }
529
David Gross10adb0c2016-03-29 13:48:41 -0700530 // Process the (optional) combiner.
531 if (strcmp(tmpNameCombiner, kNoName)) {
532 // Lookup the original user-written combiner.
David Grossae2ec3f2016-06-01 14:45:47 -0700533 if (!(reduceDescriptions[i].combFunc =
534 (ReduceCombinerFunc_t) dlsym(sharedObj, tmpNameCombiner))) {
David Gross10adb0c2016-03-29 13:48:41 -0700535 ALOGE("Failed to find combiner function address for %s(): %s",
536 tmpNameCombiner, dlerror());
537 goto error;
538 }
539 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700540 reduceDescriptions[i].combFunc = nullptr;
David Gross10adb0c2016-03-29 13:48:41 -0700541 }
542
David Gross6c1876b2016-01-15 11:52:14 -0800543 // Process the (optional) outconverter.
544 if (strcmp(tmpNameOutConverter, kNoName)) {
545 // Lookup the original user-written outconverter.
David Grossae2ec3f2016-06-01 14:45:47 -0700546 if (!(reduceDescriptions[i].outFunc =
547 (ReduceOutConverterFunc_t) dlsym(sharedObj, tmpNameOutConverter))) {
David Gross6c1876b2016-01-15 11:52:14 -0800548 ALOGE("Failed to find outconverter function address for %s(): %s",
549 tmpNameOutConverter, dlerror());
550 goto error;
551 }
552 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700553 reduceDescriptions[i].outFunc = nullptr;
David Gross6c1876b2016-01-15 11:52:14 -0800554 }
555 }
556
Yang Ni2abfcc62015-02-17 16:05:19 -0800557 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
558 goto error;
559 }
560 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
561 ALOGE("Invalid object slot count!: %s", line);
562 goto error;
563 }
564
565 for (size_t i = 0; i < objectSlotCount; ++i) {
566 uint32_t varNum = 0;
567 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
568 goto error;
569 }
570 if (sscanf(line, "%u", &varNum) != 1) {
571 ALOGE("Invalid object slot!: %s", line);
572 goto error;
573 }
574
575 if (varNum < varCount) {
576 fieldIsObject[varNum] = true;
577 }
578 }
579
580#ifndef RS_COMPATIBILITY_LIB
581 // Do not attempt to read pragmas or isThreadable flag in compat lib path.
582 // Neither is applicable for compat lib
583
584 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
585 goto error;
586 }
587
588 if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) {
589 ALOGE("Invalid pragma count!: %s", line);
590 goto error;
591 }
592
593 pragmaKeys = new const char*[pragmaCount];
594 if (pragmaKeys == nullptr) {
595 goto error;
596 }
597
598 pragmaValues = new const char*[pragmaCount];
599 if (pragmaValues == nullptr) {
600 goto error;
601 }
602
603 bzero(pragmaKeys, sizeof(char*) * pragmaCount);
604 bzero(pragmaValues, sizeof(char*) * pragmaCount);
605
606 for (size_t i = 0; i < pragmaCount; ++i) {
607 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
608 ALOGE("Unable to read pragma at index %zu!", i);
609 goto error;
610 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800611 char key[MAXLINE];
612 char value[MAXLINE] = ""; // initialize in case value is empty
613
614 // pragmas can just have a key and no value. Only check to make sure
615 // that the key is not empty
Miao Wangd4848102016-04-27 15:49:47 -0700616 if (sscanf(line, "%" MAKE_STR(MAXLINESTR) "s - %" MAKE_STR(MAXLINESTR) "s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800617 key, value) == 0 ||
618 strlen(key) == 0)
619 {
620 ALOGE("Invalid pragma value!: %s", line);
621
622 goto error;
623 }
624
625 char *pKey = new char[strlen(key)+1];
626 strcpy(pKey, key);
627 pragmaKeys[i] = pKey;
628
629 char *pValue = new char[strlen(value)+1];
630 strcpy(pValue, value);
631 pragmaValues[i] = pValue;
632 //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue);
633 }
634
635 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
636 goto error;
637 }
638
639 char tmpFlag[4];
Miao Wangd4848102016-04-27 15:49:47 -0700640 if (sscanf(line, THREADABLE_STR "%3s", tmpFlag) != 1) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800641 ALOGE("Invalid threadable flag!: %s", line);
642 goto error;
643 }
644 if (strcmp(tmpFlag, "yes") == 0) {
645 isThreadable = true;
646 } else if (strcmp(tmpFlag, "no") == 0) {
647 isThreadable = false;
648 } else {
649 ALOGE("Invalid threadable flag!: %s", tmpFlag);
650 goto error;
651 }
652
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800653 if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
Yang Nicb170152015-04-16 10:27:02 -0700654 if (sscanf(line, CHECKSUM_STR "%08x", &checksum) != 1) {
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800655 ALOGE("Invalid checksum flag!: %s", line);
656 goto error;
657 }
Yang Ni062c2872015-02-20 15:20:00 -0800658 } else {
659 ALOGE("Missing checksum in shared obj file");
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800660 goto error;
661 }
662
Yang Nicb170152015-04-16 10:27:02 -0700663 if (expectedChecksum != 0 && checksum != expectedChecksum) {
664 ALOGE("Found invalid checksum. Expected %08x, got %08x\n",
665 expectedChecksum, checksum);
666 goto error;
667 }
668
Yang Ni2abfcc62015-02-17 16:05:19 -0800669#endif // RS_COMPATIBILITY_LIB
670
Stephen Hines8409d642015-04-28 18:49:56 -0700671 // Read in information about mutable global variables provided by bcc's
672 // RSGlobalInfoPass
673 if (rsGlobalEntries) {
674 numEntries = *rsGlobalEntries;
675 if (numEntries > 0) {
676 rsAssert(rsGlobalNames);
677 rsAssert(rsGlobalAddresses);
678 rsAssert(rsGlobalSizes);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700679 rsAssert(rsGlobalProperties);
Stephen Hines8409d642015-04-28 18:49:56 -0700680 }
Stephen Hines8409d642015-04-28 18:49:56 -0700681 }
682
Yang Ni2abfcc62015-02-17 16:05:19 -0800683 return new ScriptExecutable(
Yang Ni5e480022016-04-06 09:34:34 -0700684 fieldAddress, fieldIsObject, fieldName, varCount,
Yang Ni2abfcc62015-02-17 16:05:19 -0800685 invokeFunctions, funcCount,
686 forEachFunctions, forEachSignatures, forEachCount,
David Grossae2ec3f2016-06-01 14:45:47 -0700687 reduceDescriptions, reduceCount,
Yang Ni2abfcc62015-02-17 16:05:19 -0800688 pragmaKeys, pragmaValues, pragmaCount,
Stephen Hines5aa018c2015-05-20 18:09:57 -0700689 rsGlobalNames, rsGlobalAddresses, rsGlobalSizes, rsGlobalProperties,
690 numEntries, isThreadable, checksum);
Yang Ni2abfcc62015-02-17 16:05:19 -0800691
692error:
693
694#ifndef RS_COMPATIBILITY_LIB
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800695
Ting-Yuan Huanga824b7c2016-11-22 16:58:51 -0800696 if (pragmaKeys) {
697 for (size_t idx = 0; idx < pragmaCount; ++idx) {
698 delete [] pragmaKeys[idx];
699 }
700 }
701
702 if (pragmaValues) {
703 for (size_t idx = 0; idx < pragmaCount; ++idx) {
704 delete [] pragmaValues[idx];
705 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800706 }
707
708 delete[] pragmaValues;
709 delete[] pragmaKeys;
710#endif // RS_COMPATIBILITY_LIB
711
Ting-Yuan Huanga824b7c2016-11-22 16:58:51 -0800712 delete[] reduceDescriptions;
713
Yang Ni2abfcc62015-02-17 16:05:19 -0800714 delete[] forEachSignatures;
715 delete[] forEachFunctions;
Yang Ni062c2872015-02-20 15:20:00 -0800716
Yang Ni2abfcc62015-02-17 16:05:19 -0800717 delete[] invokeFunctions;
Yang Ni062c2872015-02-20 15:20:00 -0800718
719 for (size_t i = 0; i < varCount; i++) {
720 delete[] fieldName[i];
721 }
722 delete[] fieldName;
Yang Ni2abfcc62015-02-17 16:05:19 -0800723 delete[] fieldIsObject;
724 delete[] fieldAddress;
725
726 return nullptr;
727}
728
Yang Ni062c2872015-02-20 15:20:00 -0800729void* ScriptExecutable::getFieldAddress(const char* name) const {
730 // TODO: improve this by using a hash map.
731 for (size_t i = 0; i < mExportedVarCount; i++) {
732 if (strcmp(name, mFieldName[i]) == 0) {
733 return mFieldAddress[i];
734 }
735 }
736 return nullptr;
737}
738
Stephen Hines8409d642015-04-28 18:49:56 -0700739bool ScriptExecutable::dumpGlobalInfo() const {
740 ALOGE("Globals: %p %p %p", mGlobalAddresses, mGlobalSizes, mGlobalNames);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700741 ALOGE("P - Pointer");
742 ALOGE(" C - Constant");
743 ALOGE(" S - Static");
Stephen Hines8409d642015-04-28 18:49:56 -0700744 for (int i = 0; i < mGlobalEntries; i++) {
745 ALOGE("Global[%d]: %p %zu %s", i, mGlobalAddresses[i], mGlobalSizes[i],
746 mGlobalNames[i]);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700747 uint32_t properties = mGlobalProperties[i];
748 ALOGE("%c%c%c Type: %u",
749 isGlobalPointer(properties) ? 'P' : ' ',
750 isGlobalConstant(properties) ? 'C' : ' ',
751 isGlobalStatic(properties) ? 'S' : ' ',
752 getGlobalRsType(properties));
Stephen Hines8409d642015-04-28 18:49:56 -0700753 }
754 return true;
755}
756
Yang Ni2abfcc62015-02-17 16:05:19 -0800757} // namespace renderscript
758} // namespace android