blob: b670838a899f5d08b35028c5cdd3782de16f3733 [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
Miao Wang82e135c2017-02-27 23:35:35 -0800168std::string SharedLibraryUtils::getRandomString(size_t len) {
Yang Ni1efae292015-06-27 15:45:18 -0700169 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';
Miao Wang82e135c2017-02-27 23:35:35 -0800185 return std::string(buf);
Yang Ni1efae292015-06-27 15:45:18 -0700186}
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("#");
Miao Wang82e135c2017-02-27 23:35:35 -0800240 newName.append(getRandomString(6).c_str()); // 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: "
Luke Drummond341f3062016-12-15 12:40:55 +0000275#define VERSIONINFO_STR "versionInfo: "
Yang Ni2abfcc62015-02-17 16:05:19 -0800276
277// Copy up to a newline or size chars from str -> s, updating str
278// Returns s when successful and nullptr when '\0' is finally reached.
279static char* strgets(char *s, int size, const char **ppstr) {
280 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
281 return nullptr;
282 }
283
284 int i;
285 for (i = 0; i < (size - 1); i++) {
286 s[i] = **ppstr;
287 (*ppstr)++;
288 if (s[i] == '\0') {
289 return s;
290 } else if (s[i] == '\n') {
291 s[i+1] = '\0';
292 return s;
293 }
294 }
295
296 // size has been exceeded.
297 s[i] = '\0';
298
299 return s;
300}
301
Michael Butler2a1576f2017-04-19 18:47:55 -0700302// Creates a duplicate of a string. The new string is as small as possible,
303// only including characters up to and including the first null-terminator;
304// otherwise, the new string will be the same size as the input string.
305// The code that calls duplicateString is responsible for the new string's
306// lifetime, and is responsible for freeing it when it is no longer needed.
307static char* duplicateString(const char *str, size_t length) {
308 const size_t newLen = strnlen(str, length-1) + 1;
309 char *newStr = new char[newLen];
310 strlcpy(newStr, str, newLen);
311 return newStr;
312}
313
Yang Ni2abfcc62015-02-17 16:05:19 -0800314ScriptExecutable* ScriptExecutable::createFromSharedObject(
Yang Ni5e480022016-04-06 09:34:34 -0700315 void* sharedObj, uint32_t expectedChecksum) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800316 char line[MAXLINE];
317
318 size_t varCount = 0;
319 size_t funcCount = 0;
320 size_t forEachCount = 0;
Matt Wala14ce0072015-07-30 17:30:25 -0700321 size_t reduceCount = 0;
Yang Ni2abfcc62015-02-17 16:05:19 -0800322 size_t objectSlotCount = 0;
323 size_t pragmaCount = 0;
324 bool isThreadable = true;
325
326 void** fieldAddress = nullptr;
327 bool* fieldIsObject = nullptr;
Yang Ni062c2872015-02-20 15:20:00 -0800328 char** fieldName = nullptr;
Yang Ni2abfcc62015-02-17 16:05:19 -0800329 InvokeFunc_t* invokeFunctions = nullptr;
330 ForEachFunc_t* forEachFunctions = nullptr;
331 uint32_t* forEachSignatures = nullptr;
David Grossae2ec3f2016-06-01 14:45:47 -0700332 ReduceDescription* reduceDescriptions = nullptr;
Yang Ni2abfcc62015-02-17 16:05:19 -0800333 const char ** pragmaKeys = nullptr;
334 const char ** pragmaValues = nullptr;
Yang Nicb170152015-04-16 10:27:02 -0700335 uint32_t checksum = 0;
Yang Ni2abfcc62015-02-17 16:05:19 -0800336
Stephen Hines5aa018c2015-05-20 18:09:57 -0700337 const char *rsInfo = (const char *) dlsym(sharedObj, kRsInfo);
Stephen Hines8409d642015-04-28 18:49:56 -0700338 int numEntries = 0;
Stephen Hines5aa018c2015-05-20 18:09:57 -0700339 const int *rsGlobalEntries = (const int *) dlsym(sharedObj, kRsGlobalEntries);
340 const char **rsGlobalNames = (const char **) dlsym(sharedObj, kRsGlobalNames);
341 const void **rsGlobalAddresses = (const void **) dlsym(sharedObj, kRsGlobalAddresses);
342 const size_t *rsGlobalSizes = (const size_t *) dlsym(sharedObj, kRsGlobalSizes);
343 const uint32_t *rsGlobalProperties = (const uint32_t *) dlsym(sharedObj, kRsGlobalProperties);
Yang Ni2abfcc62015-02-17 16:05:19 -0800344
345 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
346 return nullptr;
347 }
348 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
349 ALOGE("Invalid export var count!: %s", line);
350 return nullptr;
351 }
352
353 fieldAddress = new void*[varCount];
354 if (fieldAddress == nullptr) {
355 return nullptr;
356 }
357
358 fieldIsObject = new bool[varCount];
359 if (fieldIsObject == nullptr) {
360 goto error;
361 }
362
Yang Ni062c2872015-02-20 15:20:00 -0800363 fieldName = new char*[varCount];
364 if (fieldName == nullptr) {
365 goto error;
366 }
367
Yang Ni2abfcc62015-02-17 16:05:19 -0800368 for (size_t i = 0; i < varCount; ++i) {
369 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
370 goto error;
371 }
372 char *c = strrchr(line, '\n');
373 if (c) {
374 *c = '\0';
375 }
376 void* addr = dlsym(sharedObj, line);
377 if (addr == nullptr) {
378 ALOGE("Failed to find variable address for %s: %s",
379 line, dlerror());
380 // Not a critical error if we don't find a global variable.
381 }
382 fieldAddress[i] = addr;
383 fieldIsObject[i] = false;
Michael Butler2a1576f2017-04-19 18:47:55 -0700384 fieldName[i] = duplicateString(line, sizeof(line));
Yang Ni2abfcc62015-02-17 16:05:19 -0800385 }
386
387 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
388 goto error;
389 }
390 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
391 ALOGE("Invalid export func count!: %s", line);
392 goto error;
393 }
394
395 invokeFunctions = new InvokeFunc_t[funcCount];
396 if (invokeFunctions == nullptr) {
397 goto error;
398 }
399
400 for (size_t i = 0; i < funcCount; ++i) {
401 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
402 goto error;
403 }
404 char *c = strrchr(line, '\n');
405 if (c) {
406 *c = '\0';
407 }
408
409 invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line);
410 if (invokeFunctions[i] == nullptr) {
411 ALOGE("Failed to get function address for %s(): %s",
412 line, dlerror());
413 goto error;
414 }
415 }
416
417 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
418 goto error;
419 }
420 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
421 ALOGE("Invalid export forEach count!: %s", line);
422 goto error;
423 }
424
425 forEachFunctions = new ForEachFunc_t[forEachCount];
426 if (forEachFunctions == nullptr) {
427 goto error;
428 }
429
430 forEachSignatures = new uint32_t[forEachCount];
431 if (forEachSignatures == nullptr) {
432 goto error;
433 }
434
435 for (size_t i = 0; i < forEachCount; ++i) {
436 unsigned int tmpSig = 0;
437 char tmpName[MAXLINE];
438
439 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
440 goto error;
441 }
Miao Wangd4848102016-04-27 15:49:47 -0700442 if (sscanf(line, "%u - %" MAKE_STR(MAXLINESTR) "s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800443 &tmpSig, tmpName) != 2) {
444 ALOGE("Invalid export forEach!: %s", line);
445 goto error;
446 }
447
448 // Lookup the expanded ForEach kernel.
Miao Wangd4848102016-04-27 15:49:47 -0700449 strncat(tmpName, ".expand", MAXLINESTR-strlen(tmpName));
Yang Ni2abfcc62015-02-17 16:05:19 -0800450 forEachSignatures[i] = tmpSig;
451 forEachFunctions[i] =
452 (ForEachFunc_t) dlsym(sharedObj, tmpName);
Yang Ni062c2872015-02-20 15:20:00 -0800453 if (i != 0 && forEachFunctions[i] == nullptr &&
454 strcmp(tmpName, "root.expand")) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800455 // Ignore missing root.expand functions.
456 // root() is always specified at location 0.
Matt Wala14ce0072015-07-30 17:30:25 -0700457 ALOGE("Failed to find forEach function address for %s(): %s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800458 tmpName, dlerror());
459 goto error;
460 }
461 }
462
David Gross6c1876b2016-01-15 11:52:14 -0800463 // Read general reduce kernels
David Gross46c93e42016-01-09 16:23:37 -0800464 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
465 goto error;
466 }
David Grossae2ec3f2016-06-01 14:45:47 -0700467 if (sscanf(line, EXPORT_REDUCE_STR "%zu", &reduceCount) != 1) {
David Gross46c93e42016-01-09 16:23:37 -0800468 ALOGE("Invalid export reduce new count!: %s", line);
469 goto error;
470 }
David Gross6c1876b2016-01-15 11:52:14 -0800471
David Grossae2ec3f2016-06-01 14:45:47 -0700472 reduceDescriptions = new ReduceDescription[reduceCount];
473 if (reduceDescriptions == nullptr) {
David Gross46c93e42016-01-09 16:23:37 -0800474 goto error;
475 }
476
David Grossae2ec3f2016-06-01 14:45:47 -0700477 for (size_t i = 0; i < reduceCount; ++i) {
David Gross6c1876b2016-01-15 11:52:14 -0800478 static const char kNoName[] = ".";
479
480 unsigned int tmpSig = 0;
481 size_t tmpSize = 0;
482 char tmpNameReduce[MAXLINE];
483 char tmpNameInitializer[MAXLINE];
484 char tmpNameAccumulator[MAXLINE];
485 char tmpNameCombiner[MAXLINE];
486 char tmpNameOutConverter[MAXLINE];
487 char tmpNameHalter[MAXLINE];
488
489 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
490 goto error;
491 }
Miao Wangd4848102016-04-27 15:49:47 -0700492#define DELIMNAME " - %" MAKE_STR(MAXLINESTR) "s"
David Gross6c1876b2016-01-15 11:52:14 -0800493 if (sscanf(line, "%u - %zu" DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME,
494 &tmpSig, &tmpSize, tmpNameReduce, tmpNameInitializer, tmpNameAccumulator,
495 tmpNameCombiner, tmpNameOutConverter, tmpNameHalter) != 8) {
496 ALOGE("Invalid export reduce new!: %s", line);
497 goto error;
498 }
499#undef DELIMNAME
500
501 // For now, we expect
502 // - Reduce and Accumulator names
503 // - optional Initializer, Combiner, and OutConverter name
504 // - no Halter name
505 if (!strcmp(tmpNameReduce, kNoName) ||
506 !strcmp(tmpNameAccumulator, kNoName)) {
507 ALOGE("Expected reduce and accumulator names!: %s", line);
508 goto error;
509 }
510 if (strcmp(tmpNameHalter, kNoName)) {
511 ALOGE("Did not expect halter name!: %s", line);
512 goto error;
513 }
514
David Gross10adb0c2016-03-29 13:48:41 -0700515 // The current implementation does not use the signature
516 // or reduce name.
David Gross6c1876b2016-01-15 11:52:14 -0800517
David Grossae2ec3f2016-06-01 14:45:47 -0700518 reduceDescriptions[i].accumSize = tmpSize;
David Gross6c1876b2016-01-15 11:52:14 -0800519
520 // Process the (optional) initializer.
521 if (strcmp(tmpNameInitializer, kNoName)) {
522 // Lookup the original user-written initializer.
David Grossae2ec3f2016-06-01 14:45:47 -0700523 if (!(reduceDescriptions[i].initFunc =
524 (ReduceInitializerFunc_t) dlsym(sharedObj, tmpNameInitializer))) {
David Gross6c1876b2016-01-15 11:52:14 -0800525 ALOGE("Failed to find initializer function address for %s(): %s",
526 tmpNameInitializer, dlerror());
527 goto error;
528 }
529 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700530 reduceDescriptions[i].initFunc = nullptr;
David Gross6c1876b2016-01-15 11:52:14 -0800531 }
532
533 // Lookup the expanded accumulator.
Miao Wangd4848102016-04-27 15:49:47 -0700534 strncat(tmpNameAccumulator, ".expand", MAXLINESTR-strlen(tmpNameAccumulator));
David Grossae2ec3f2016-06-01 14:45:47 -0700535 if (!(reduceDescriptions[i].accumFunc =
536 (ReduceAccumulatorFunc_t) dlsym(sharedObj, tmpNameAccumulator))) {
David Gross6c1876b2016-01-15 11:52:14 -0800537 ALOGE("Failed to find accumulator function address for %s(): %s",
538 tmpNameAccumulator, dlerror());
539 goto error;
540 }
541
David Gross10adb0c2016-03-29 13:48:41 -0700542 // Process the (optional) combiner.
543 if (strcmp(tmpNameCombiner, kNoName)) {
544 // Lookup the original user-written combiner.
David Grossae2ec3f2016-06-01 14:45:47 -0700545 if (!(reduceDescriptions[i].combFunc =
546 (ReduceCombinerFunc_t) dlsym(sharedObj, tmpNameCombiner))) {
David Gross10adb0c2016-03-29 13:48:41 -0700547 ALOGE("Failed to find combiner function address for %s(): %s",
548 tmpNameCombiner, dlerror());
549 goto error;
550 }
551 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700552 reduceDescriptions[i].combFunc = nullptr;
David Gross10adb0c2016-03-29 13:48:41 -0700553 }
554
David Gross6c1876b2016-01-15 11:52:14 -0800555 // Process the (optional) outconverter.
556 if (strcmp(tmpNameOutConverter, kNoName)) {
557 // Lookup the original user-written outconverter.
David Grossae2ec3f2016-06-01 14:45:47 -0700558 if (!(reduceDescriptions[i].outFunc =
559 (ReduceOutConverterFunc_t) dlsym(sharedObj, tmpNameOutConverter))) {
David Gross6c1876b2016-01-15 11:52:14 -0800560 ALOGE("Failed to find outconverter function address for %s(): %s",
561 tmpNameOutConverter, dlerror());
562 goto error;
563 }
564 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700565 reduceDescriptions[i].outFunc = nullptr;
David Gross6c1876b2016-01-15 11:52:14 -0800566 }
567 }
568
Yang Ni2abfcc62015-02-17 16:05:19 -0800569 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
570 goto error;
571 }
572 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
573 ALOGE("Invalid object slot count!: %s", line);
574 goto error;
575 }
576
577 for (size_t i = 0; i < objectSlotCount; ++i) {
578 uint32_t varNum = 0;
579 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
580 goto error;
581 }
582 if (sscanf(line, "%u", &varNum) != 1) {
583 ALOGE("Invalid object slot!: %s", line);
584 goto error;
585 }
586
587 if (varNum < varCount) {
588 fieldIsObject[varNum] = true;
589 }
590 }
591
592#ifndef RS_COMPATIBILITY_LIB
593 // Do not attempt to read pragmas or isThreadable flag in compat lib path.
594 // Neither is applicable for compat lib
595
596 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
597 goto error;
598 }
599
600 if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) {
601 ALOGE("Invalid pragma count!: %s", line);
602 goto error;
603 }
604
605 pragmaKeys = new const char*[pragmaCount];
606 if (pragmaKeys == nullptr) {
607 goto error;
608 }
609
610 pragmaValues = new const char*[pragmaCount];
611 if (pragmaValues == nullptr) {
612 goto error;
613 }
614
615 bzero(pragmaKeys, sizeof(char*) * pragmaCount);
616 bzero(pragmaValues, sizeof(char*) * pragmaCount);
617
618 for (size_t i = 0; i < pragmaCount; ++i) {
619 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
620 ALOGE("Unable to read pragma at index %zu!", i);
621 goto error;
622 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800623 char key[MAXLINE];
624 char value[MAXLINE] = ""; // initialize in case value is empty
625
626 // pragmas can just have a key and no value. Only check to make sure
627 // that the key is not empty
Miao Wangd4848102016-04-27 15:49:47 -0700628 if (sscanf(line, "%" MAKE_STR(MAXLINESTR) "s - %" MAKE_STR(MAXLINESTR) "s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800629 key, value) == 0 ||
630 strlen(key) == 0)
631 {
632 ALOGE("Invalid pragma value!: %s", line);
633
634 goto error;
635 }
636
Michael Butler2a1576f2017-04-19 18:47:55 -0700637 pragmaKeys[i] = duplicateString(key, sizeof(key));
638 pragmaValues[i] = duplicateString(value, sizeof(value));
Yang Ni2abfcc62015-02-17 16:05:19 -0800639 //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue);
640 }
641
642 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
643 goto error;
644 }
645
646 char tmpFlag[4];
Miao Wangd4848102016-04-27 15:49:47 -0700647 if (sscanf(line, THREADABLE_STR "%3s", tmpFlag) != 1) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800648 ALOGE("Invalid threadable flag!: %s", line);
649 goto error;
650 }
651 if (strcmp(tmpFlag, "yes") == 0) {
652 isThreadable = true;
653 } else if (strcmp(tmpFlag, "no") == 0) {
654 isThreadable = false;
655 } else {
656 ALOGE("Invalid threadable flag!: %s", tmpFlag);
657 goto error;
658 }
659
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800660 if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
Yang Nicb170152015-04-16 10:27:02 -0700661 if (sscanf(line, CHECKSUM_STR "%08x", &checksum) != 1) {
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800662 ALOGE("Invalid checksum flag!: %s", line);
663 goto error;
664 }
Yang Ni062c2872015-02-20 15:20:00 -0800665 } else {
666 ALOGE("Missing checksum in shared obj file");
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800667 goto error;
668 }
669
Yang Nicb170152015-04-16 10:27:02 -0700670 if (expectedChecksum != 0 && checksum != expectedChecksum) {
671 ALOGE("Found invalid checksum. Expected %08x, got %08x\n",
672 expectedChecksum, checksum);
673 goto error;
674 }
675
Luke Drummond341f3062016-12-15 12:40:55 +0000676 {
677 // Parse the version info string, but ignore its contents as it's only
678 // used by the debugger
679 size_t nLines = 0;
680 if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
681 if (sscanf(line, VERSIONINFO_STR "%zu", &nLines) != 1) {
682 ALOGE("invalid versionInfo count");
683 goto error;
684 } else {
685 // skip the versionInfo packet as libRs doesn't use it
686 while (nLines--) {
687 if (strgets(line, MAXLINE, &rsInfo) == nullptr)
688 goto error;
689 }
690 }
691 } else {
692 ALOGE(".rs.info is missing versionInfo section");
693 }
694 }
695
Yang Ni2abfcc62015-02-17 16:05:19 -0800696#endif // RS_COMPATIBILITY_LIB
697
Stephen Hines8409d642015-04-28 18:49:56 -0700698 // Read in information about mutable global variables provided by bcc's
699 // RSGlobalInfoPass
700 if (rsGlobalEntries) {
701 numEntries = *rsGlobalEntries;
702 if (numEntries > 0) {
703 rsAssert(rsGlobalNames);
704 rsAssert(rsGlobalAddresses);
705 rsAssert(rsGlobalSizes);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700706 rsAssert(rsGlobalProperties);
Stephen Hines8409d642015-04-28 18:49:56 -0700707 }
Stephen Hines8409d642015-04-28 18:49:56 -0700708 }
709
Yang Ni2abfcc62015-02-17 16:05:19 -0800710 return new ScriptExecutable(
Yang Ni5e480022016-04-06 09:34:34 -0700711 fieldAddress, fieldIsObject, fieldName, varCount,
Yang Ni2abfcc62015-02-17 16:05:19 -0800712 invokeFunctions, funcCount,
713 forEachFunctions, forEachSignatures, forEachCount,
David Grossae2ec3f2016-06-01 14:45:47 -0700714 reduceDescriptions, reduceCount,
Yang Ni2abfcc62015-02-17 16:05:19 -0800715 pragmaKeys, pragmaValues, pragmaCount,
Stephen Hines5aa018c2015-05-20 18:09:57 -0700716 rsGlobalNames, rsGlobalAddresses, rsGlobalSizes, rsGlobalProperties,
717 numEntries, isThreadable, checksum);
Yang Ni2abfcc62015-02-17 16:05:19 -0800718
719error:
720
721#ifndef RS_COMPATIBILITY_LIB
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800722
Ting-Yuan Huanga824b7c2016-11-22 16:58:51 -0800723 if (pragmaKeys) {
724 for (size_t idx = 0; idx < pragmaCount; ++idx) {
725 delete [] pragmaKeys[idx];
726 }
727 }
728
729 if (pragmaValues) {
730 for (size_t idx = 0; idx < pragmaCount; ++idx) {
731 delete [] pragmaValues[idx];
732 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800733 }
734
735 delete[] pragmaValues;
736 delete[] pragmaKeys;
737#endif // RS_COMPATIBILITY_LIB
738
Ting-Yuan Huanga824b7c2016-11-22 16:58:51 -0800739 delete[] reduceDescriptions;
740
Yang Ni2abfcc62015-02-17 16:05:19 -0800741 delete[] forEachSignatures;
742 delete[] forEachFunctions;
Yang Ni062c2872015-02-20 15:20:00 -0800743
Yang Ni2abfcc62015-02-17 16:05:19 -0800744 delete[] invokeFunctions;
Yang Ni062c2872015-02-20 15:20:00 -0800745
746 for (size_t i = 0; i < varCount; i++) {
747 delete[] fieldName[i];
748 }
749 delete[] fieldName;
Yang Ni2abfcc62015-02-17 16:05:19 -0800750 delete[] fieldIsObject;
751 delete[] fieldAddress;
752
753 return nullptr;
754}
755
Yang Ni062c2872015-02-20 15:20:00 -0800756void* ScriptExecutable::getFieldAddress(const char* name) const {
757 // TODO: improve this by using a hash map.
758 for (size_t i = 0; i < mExportedVarCount; i++) {
759 if (strcmp(name, mFieldName[i]) == 0) {
760 return mFieldAddress[i];
761 }
762 }
763 return nullptr;
764}
765
Stephen Hines8409d642015-04-28 18:49:56 -0700766bool ScriptExecutable::dumpGlobalInfo() const {
767 ALOGE("Globals: %p %p %p", mGlobalAddresses, mGlobalSizes, mGlobalNames);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700768 ALOGE("P - Pointer");
769 ALOGE(" C - Constant");
770 ALOGE(" S - Static");
Stephen Hines8409d642015-04-28 18:49:56 -0700771 for (int i = 0; i < mGlobalEntries; i++) {
772 ALOGE("Global[%d]: %p %zu %s", i, mGlobalAddresses[i], mGlobalSizes[i],
773 mGlobalNames[i]);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700774 uint32_t properties = mGlobalProperties[i];
775 ALOGE("%c%c%c Type: %u",
776 isGlobalPointer(properties) ? 'P' : ' ',
777 isGlobalConstant(properties) ? 'C' : ' ',
778 isGlobalStatic(properties) ? 'S' : ' ',
779 getGlobalRsType(properties));
Stephen Hines8409d642015-04-28 18:49:56 -0700780 }
781 return true;
782}
783
Yang Ni2abfcc62015-02-17 16:05:19 -0800784} // namespace renderscript
785} // namespace android