blob: ad45eba959175153c8ecf4938f3e05889c5f7ccb [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
302ScriptExecutable* ScriptExecutable::createFromSharedObject(
Yang Ni5e480022016-04-06 09:34:34 -0700303 void* sharedObj, uint32_t expectedChecksum) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800304 char line[MAXLINE];
305
306 size_t varCount = 0;
307 size_t funcCount = 0;
308 size_t forEachCount = 0;
Matt Wala14ce0072015-07-30 17:30:25 -0700309 size_t reduceCount = 0;
Yang Ni2abfcc62015-02-17 16:05:19 -0800310 size_t objectSlotCount = 0;
311 size_t pragmaCount = 0;
312 bool isThreadable = true;
313
314 void** fieldAddress = nullptr;
315 bool* fieldIsObject = nullptr;
Yang Ni062c2872015-02-20 15:20:00 -0800316 char** fieldName = nullptr;
Yang Ni2abfcc62015-02-17 16:05:19 -0800317 InvokeFunc_t* invokeFunctions = nullptr;
318 ForEachFunc_t* forEachFunctions = nullptr;
319 uint32_t* forEachSignatures = nullptr;
David Grossae2ec3f2016-06-01 14:45:47 -0700320 ReduceDescription* reduceDescriptions = nullptr;
Yang Ni2abfcc62015-02-17 16:05:19 -0800321 const char ** pragmaKeys = nullptr;
322 const char ** pragmaValues = nullptr;
Yang Nicb170152015-04-16 10:27:02 -0700323 uint32_t checksum = 0;
Yang Ni2abfcc62015-02-17 16:05:19 -0800324
Stephen Hines5aa018c2015-05-20 18:09:57 -0700325 const char *rsInfo = (const char *) dlsym(sharedObj, kRsInfo);
Stephen Hines8409d642015-04-28 18:49:56 -0700326 int numEntries = 0;
Stephen Hines5aa018c2015-05-20 18:09:57 -0700327 const int *rsGlobalEntries = (const int *) dlsym(sharedObj, kRsGlobalEntries);
328 const char **rsGlobalNames = (const char **) dlsym(sharedObj, kRsGlobalNames);
329 const void **rsGlobalAddresses = (const void **) dlsym(sharedObj, kRsGlobalAddresses);
330 const size_t *rsGlobalSizes = (const size_t *) dlsym(sharedObj, kRsGlobalSizes);
331 const uint32_t *rsGlobalProperties = (const uint32_t *) dlsym(sharedObj, kRsGlobalProperties);
Yang Ni2abfcc62015-02-17 16:05:19 -0800332
333 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
334 return nullptr;
335 }
336 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
337 ALOGE("Invalid export var count!: %s", line);
338 return nullptr;
339 }
340
341 fieldAddress = new void*[varCount];
342 if (fieldAddress == nullptr) {
343 return nullptr;
344 }
345
346 fieldIsObject = new bool[varCount];
347 if (fieldIsObject == nullptr) {
348 goto error;
349 }
350
Yang Ni062c2872015-02-20 15:20:00 -0800351 fieldName = new char*[varCount];
352 if (fieldName == nullptr) {
353 goto error;
354 }
355
Yang Ni2abfcc62015-02-17 16:05:19 -0800356 for (size_t i = 0; i < varCount; ++i) {
357 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
358 goto error;
359 }
360 char *c = strrchr(line, '\n');
361 if (c) {
362 *c = '\0';
363 }
364 void* addr = dlsym(sharedObj, line);
365 if (addr == nullptr) {
366 ALOGE("Failed to find variable address for %s: %s",
367 line, dlerror());
368 // Not a critical error if we don't find a global variable.
369 }
370 fieldAddress[i] = addr;
371 fieldIsObject[i] = false;
Yang Ni062c2872015-02-20 15:20:00 -0800372 fieldName[i] = new char[strlen(line)+1];
373 strcpy(fieldName[i], line);
Yang Ni2abfcc62015-02-17 16:05:19 -0800374 }
375
376 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
377 goto error;
378 }
379 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
380 ALOGE("Invalid export func count!: %s", line);
381 goto error;
382 }
383
384 invokeFunctions = new InvokeFunc_t[funcCount];
385 if (invokeFunctions == nullptr) {
386 goto error;
387 }
388
389 for (size_t i = 0; i < funcCount; ++i) {
390 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
391 goto error;
392 }
393 char *c = strrchr(line, '\n');
394 if (c) {
395 *c = '\0';
396 }
397
398 invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line);
399 if (invokeFunctions[i] == nullptr) {
400 ALOGE("Failed to get function address for %s(): %s",
401 line, dlerror());
402 goto error;
403 }
404 }
405
406 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
407 goto error;
408 }
409 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
410 ALOGE("Invalid export forEach count!: %s", line);
411 goto error;
412 }
413
414 forEachFunctions = new ForEachFunc_t[forEachCount];
415 if (forEachFunctions == nullptr) {
416 goto error;
417 }
418
419 forEachSignatures = new uint32_t[forEachCount];
420 if (forEachSignatures == nullptr) {
421 goto error;
422 }
423
424 for (size_t i = 0; i < forEachCount; ++i) {
425 unsigned int tmpSig = 0;
426 char tmpName[MAXLINE];
427
428 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
429 goto error;
430 }
Miao Wangd4848102016-04-27 15:49:47 -0700431 if (sscanf(line, "%u - %" MAKE_STR(MAXLINESTR) "s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800432 &tmpSig, tmpName) != 2) {
433 ALOGE("Invalid export forEach!: %s", line);
434 goto error;
435 }
436
437 // Lookup the expanded ForEach kernel.
Miao Wangd4848102016-04-27 15:49:47 -0700438 strncat(tmpName, ".expand", MAXLINESTR-strlen(tmpName));
Yang Ni2abfcc62015-02-17 16:05:19 -0800439 forEachSignatures[i] = tmpSig;
440 forEachFunctions[i] =
441 (ForEachFunc_t) dlsym(sharedObj, tmpName);
Yang Ni062c2872015-02-20 15:20:00 -0800442 if (i != 0 && forEachFunctions[i] == nullptr &&
443 strcmp(tmpName, "root.expand")) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800444 // Ignore missing root.expand functions.
445 // root() is always specified at location 0.
Matt Wala14ce0072015-07-30 17:30:25 -0700446 ALOGE("Failed to find forEach function address for %s(): %s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800447 tmpName, dlerror());
448 goto error;
449 }
450 }
451
David Gross6c1876b2016-01-15 11:52:14 -0800452 // Read general reduce kernels
David Gross46c93e42016-01-09 16:23:37 -0800453 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
454 goto error;
455 }
David Grossae2ec3f2016-06-01 14:45:47 -0700456 if (sscanf(line, EXPORT_REDUCE_STR "%zu", &reduceCount) != 1) {
David Gross46c93e42016-01-09 16:23:37 -0800457 ALOGE("Invalid export reduce new count!: %s", line);
458 goto error;
459 }
David Gross6c1876b2016-01-15 11:52:14 -0800460
David Grossae2ec3f2016-06-01 14:45:47 -0700461 reduceDescriptions = new ReduceDescription[reduceCount];
462 if (reduceDescriptions == nullptr) {
David Gross46c93e42016-01-09 16:23:37 -0800463 goto error;
464 }
465
David Grossae2ec3f2016-06-01 14:45:47 -0700466 for (size_t i = 0; i < reduceCount; ++i) {
David Gross6c1876b2016-01-15 11:52:14 -0800467 static const char kNoName[] = ".";
468
469 unsigned int tmpSig = 0;
470 size_t tmpSize = 0;
471 char tmpNameReduce[MAXLINE];
472 char tmpNameInitializer[MAXLINE];
473 char tmpNameAccumulator[MAXLINE];
474 char tmpNameCombiner[MAXLINE];
475 char tmpNameOutConverter[MAXLINE];
476 char tmpNameHalter[MAXLINE];
477
478 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
479 goto error;
480 }
Miao Wangd4848102016-04-27 15:49:47 -0700481#define DELIMNAME " - %" MAKE_STR(MAXLINESTR) "s"
David Gross6c1876b2016-01-15 11:52:14 -0800482 if (sscanf(line, "%u - %zu" DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME,
483 &tmpSig, &tmpSize, tmpNameReduce, tmpNameInitializer, tmpNameAccumulator,
484 tmpNameCombiner, tmpNameOutConverter, tmpNameHalter) != 8) {
485 ALOGE("Invalid export reduce new!: %s", line);
486 goto error;
487 }
488#undef DELIMNAME
489
490 // For now, we expect
491 // - Reduce and Accumulator names
492 // - optional Initializer, Combiner, and OutConverter name
493 // - no Halter name
494 if (!strcmp(tmpNameReduce, kNoName) ||
495 !strcmp(tmpNameAccumulator, kNoName)) {
496 ALOGE("Expected reduce and accumulator names!: %s", line);
497 goto error;
498 }
499 if (strcmp(tmpNameHalter, kNoName)) {
500 ALOGE("Did not expect halter name!: %s", line);
501 goto error;
502 }
503
David Gross10adb0c2016-03-29 13:48:41 -0700504 // The current implementation does not use the signature
505 // or reduce name.
David Gross6c1876b2016-01-15 11:52:14 -0800506
David Grossae2ec3f2016-06-01 14:45:47 -0700507 reduceDescriptions[i].accumSize = tmpSize;
David Gross6c1876b2016-01-15 11:52:14 -0800508
509 // Process the (optional) initializer.
510 if (strcmp(tmpNameInitializer, kNoName)) {
511 // Lookup the original user-written initializer.
David Grossae2ec3f2016-06-01 14:45:47 -0700512 if (!(reduceDescriptions[i].initFunc =
513 (ReduceInitializerFunc_t) dlsym(sharedObj, tmpNameInitializer))) {
David Gross6c1876b2016-01-15 11:52:14 -0800514 ALOGE("Failed to find initializer function address for %s(): %s",
515 tmpNameInitializer, dlerror());
516 goto error;
517 }
518 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700519 reduceDescriptions[i].initFunc = nullptr;
David Gross6c1876b2016-01-15 11:52:14 -0800520 }
521
522 // Lookup the expanded accumulator.
Miao Wangd4848102016-04-27 15:49:47 -0700523 strncat(tmpNameAccumulator, ".expand", MAXLINESTR-strlen(tmpNameAccumulator));
David Grossae2ec3f2016-06-01 14:45:47 -0700524 if (!(reduceDescriptions[i].accumFunc =
525 (ReduceAccumulatorFunc_t) dlsym(sharedObj, tmpNameAccumulator))) {
David Gross6c1876b2016-01-15 11:52:14 -0800526 ALOGE("Failed to find accumulator function address for %s(): %s",
527 tmpNameAccumulator, dlerror());
528 goto error;
529 }
530
David Gross10adb0c2016-03-29 13:48:41 -0700531 // Process the (optional) combiner.
532 if (strcmp(tmpNameCombiner, kNoName)) {
533 // Lookup the original user-written combiner.
David Grossae2ec3f2016-06-01 14:45:47 -0700534 if (!(reduceDescriptions[i].combFunc =
535 (ReduceCombinerFunc_t) dlsym(sharedObj, tmpNameCombiner))) {
David Gross10adb0c2016-03-29 13:48:41 -0700536 ALOGE("Failed to find combiner function address for %s(): %s",
537 tmpNameCombiner, dlerror());
538 goto error;
539 }
540 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700541 reduceDescriptions[i].combFunc = nullptr;
David Gross10adb0c2016-03-29 13:48:41 -0700542 }
543
David Gross6c1876b2016-01-15 11:52:14 -0800544 // Process the (optional) outconverter.
545 if (strcmp(tmpNameOutConverter, kNoName)) {
546 // Lookup the original user-written outconverter.
David Grossae2ec3f2016-06-01 14:45:47 -0700547 if (!(reduceDescriptions[i].outFunc =
548 (ReduceOutConverterFunc_t) dlsym(sharedObj, tmpNameOutConverter))) {
David Gross6c1876b2016-01-15 11:52:14 -0800549 ALOGE("Failed to find outconverter function address for %s(): %s",
550 tmpNameOutConverter, dlerror());
551 goto error;
552 }
553 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700554 reduceDescriptions[i].outFunc = nullptr;
David Gross6c1876b2016-01-15 11:52:14 -0800555 }
556 }
557
Yang Ni2abfcc62015-02-17 16:05:19 -0800558 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
559 goto error;
560 }
561 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
562 ALOGE("Invalid object slot count!: %s", line);
563 goto error;
564 }
565
566 for (size_t i = 0; i < objectSlotCount; ++i) {
567 uint32_t varNum = 0;
568 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
569 goto error;
570 }
571 if (sscanf(line, "%u", &varNum) != 1) {
572 ALOGE("Invalid object slot!: %s", line);
573 goto error;
574 }
575
576 if (varNum < varCount) {
577 fieldIsObject[varNum] = true;
578 }
579 }
580
581#ifndef RS_COMPATIBILITY_LIB
582 // Do not attempt to read pragmas or isThreadable flag in compat lib path.
583 // Neither is applicable for compat lib
584
585 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
586 goto error;
587 }
588
589 if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) {
590 ALOGE("Invalid pragma count!: %s", line);
591 goto error;
592 }
593
594 pragmaKeys = new const char*[pragmaCount];
595 if (pragmaKeys == nullptr) {
596 goto error;
597 }
598
599 pragmaValues = new const char*[pragmaCount];
600 if (pragmaValues == nullptr) {
601 goto error;
602 }
603
604 bzero(pragmaKeys, sizeof(char*) * pragmaCount);
605 bzero(pragmaValues, sizeof(char*) * pragmaCount);
606
607 for (size_t i = 0; i < pragmaCount; ++i) {
608 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
609 ALOGE("Unable to read pragma at index %zu!", i);
610 goto error;
611 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800612 char key[MAXLINE];
613 char value[MAXLINE] = ""; // initialize in case value is empty
614
615 // pragmas can just have a key and no value. Only check to make sure
616 // that the key is not empty
Miao Wangd4848102016-04-27 15:49:47 -0700617 if (sscanf(line, "%" MAKE_STR(MAXLINESTR) "s - %" MAKE_STR(MAXLINESTR) "s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800618 key, value) == 0 ||
619 strlen(key) == 0)
620 {
621 ALOGE("Invalid pragma value!: %s", line);
622
623 goto error;
624 }
625
626 char *pKey = new char[strlen(key)+1];
627 strcpy(pKey, key);
628 pragmaKeys[i] = pKey;
629
630 char *pValue = new char[strlen(value)+1];
631 strcpy(pValue, value);
632 pragmaValues[i] = pValue;
633 //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue);
634 }
635
636 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
637 goto error;
638 }
639
640 char tmpFlag[4];
Miao Wangd4848102016-04-27 15:49:47 -0700641 if (sscanf(line, THREADABLE_STR "%3s", tmpFlag) != 1) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800642 ALOGE("Invalid threadable flag!: %s", line);
643 goto error;
644 }
645 if (strcmp(tmpFlag, "yes") == 0) {
646 isThreadable = true;
647 } else if (strcmp(tmpFlag, "no") == 0) {
648 isThreadable = false;
649 } else {
650 ALOGE("Invalid threadable flag!: %s", tmpFlag);
651 goto error;
652 }
653
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800654 if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
Yang Nicb170152015-04-16 10:27:02 -0700655 if (sscanf(line, CHECKSUM_STR "%08x", &checksum) != 1) {
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800656 ALOGE("Invalid checksum flag!: %s", line);
657 goto error;
658 }
Yang Ni062c2872015-02-20 15:20:00 -0800659 } else {
660 ALOGE("Missing checksum in shared obj file");
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800661 goto error;
662 }
663
Yang Nicb170152015-04-16 10:27:02 -0700664 if (expectedChecksum != 0 && checksum != expectedChecksum) {
665 ALOGE("Found invalid checksum. Expected %08x, got %08x\n",
666 expectedChecksum, checksum);
667 goto error;
668 }
669
Luke Drummond341f3062016-12-15 12:40:55 +0000670 {
671 // Parse the version info string, but ignore its contents as it's only
672 // used by the debugger
673 size_t nLines = 0;
674 if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
675 if (sscanf(line, VERSIONINFO_STR "%zu", &nLines) != 1) {
676 ALOGE("invalid versionInfo count");
677 goto error;
678 } else {
679 // skip the versionInfo packet as libRs doesn't use it
680 while (nLines--) {
681 if (strgets(line, MAXLINE, &rsInfo) == nullptr)
682 goto error;
683 }
684 }
685 } else {
686 ALOGE(".rs.info is missing versionInfo section");
687 }
688 }
689
Yang Ni2abfcc62015-02-17 16:05:19 -0800690#endif // RS_COMPATIBILITY_LIB
691
Stephen Hines8409d642015-04-28 18:49:56 -0700692 // Read in information about mutable global variables provided by bcc's
693 // RSGlobalInfoPass
694 if (rsGlobalEntries) {
695 numEntries = *rsGlobalEntries;
696 if (numEntries > 0) {
697 rsAssert(rsGlobalNames);
698 rsAssert(rsGlobalAddresses);
699 rsAssert(rsGlobalSizes);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700700 rsAssert(rsGlobalProperties);
Stephen Hines8409d642015-04-28 18:49:56 -0700701 }
Stephen Hines8409d642015-04-28 18:49:56 -0700702 }
703
Yang Ni2abfcc62015-02-17 16:05:19 -0800704 return new ScriptExecutable(
Yang Ni5e480022016-04-06 09:34:34 -0700705 fieldAddress, fieldIsObject, fieldName, varCount,
Yang Ni2abfcc62015-02-17 16:05:19 -0800706 invokeFunctions, funcCount,
707 forEachFunctions, forEachSignatures, forEachCount,
David Grossae2ec3f2016-06-01 14:45:47 -0700708 reduceDescriptions, reduceCount,
Yang Ni2abfcc62015-02-17 16:05:19 -0800709 pragmaKeys, pragmaValues, pragmaCount,
Stephen Hines5aa018c2015-05-20 18:09:57 -0700710 rsGlobalNames, rsGlobalAddresses, rsGlobalSizes, rsGlobalProperties,
711 numEntries, isThreadable, checksum);
Yang Ni2abfcc62015-02-17 16:05:19 -0800712
713error:
714
715#ifndef RS_COMPATIBILITY_LIB
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800716
Ting-Yuan Huanga824b7c2016-11-22 16:58:51 -0800717 if (pragmaKeys) {
718 for (size_t idx = 0; idx < pragmaCount; ++idx) {
719 delete [] pragmaKeys[idx];
720 }
721 }
722
723 if (pragmaValues) {
724 for (size_t idx = 0; idx < pragmaCount; ++idx) {
725 delete [] pragmaValues[idx];
726 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800727 }
728
729 delete[] pragmaValues;
730 delete[] pragmaKeys;
731#endif // RS_COMPATIBILITY_LIB
732
Ting-Yuan Huanga824b7c2016-11-22 16:58:51 -0800733 delete[] reduceDescriptions;
734
Yang Ni2abfcc62015-02-17 16:05:19 -0800735 delete[] forEachSignatures;
736 delete[] forEachFunctions;
Yang Ni062c2872015-02-20 15:20:00 -0800737
Yang Ni2abfcc62015-02-17 16:05:19 -0800738 delete[] invokeFunctions;
Yang Ni062c2872015-02-20 15:20:00 -0800739
740 for (size_t i = 0; i < varCount; i++) {
741 delete[] fieldName[i];
742 }
743 delete[] fieldName;
Yang Ni2abfcc62015-02-17 16:05:19 -0800744 delete[] fieldIsObject;
745 delete[] fieldAddress;
746
747 return nullptr;
748}
749
Yang Ni062c2872015-02-20 15:20:00 -0800750void* ScriptExecutable::getFieldAddress(const char* name) const {
751 // TODO: improve this by using a hash map.
752 for (size_t i = 0; i < mExportedVarCount; i++) {
753 if (strcmp(name, mFieldName[i]) == 0) {
754 return mFieldAddress[i];
755 }
756 }
757 return nullptr;
758}
759
Stephen Hines8409d642015-04-28 18:49:56 -0700760bool ScriptExecutable::dumpGlobalInfo() const {
761 ALOGE("Globals: %p %p %p", mGlobalAddresses, mGlobalSizes, mGlobalNames);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700762 ALOGE("P - Pointer");
763 ALOGE(" C - Constant");
764 ALOGE(" S - Static");
Stephen Hines8409d642015-04-28 18:49:56 -0700765 for (int i = 0; i < mGlobalEntries; i++) {
766 ALOGE("Global[%d]: %p %zu %s", i, mGlobalAddresses[i], mGlobalSizes[i],
767 mGlobalNames[i]);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700768 uint32_t properties = mGlobalProperties[i];
769 ALOGE("%c%c%c Type: %u",
770 isGlobalPointer(properties) ? 'P' : ' ',
771 isGlobalConstant(properties) ? 'C' : ' ',
772 isGlobalStatic(properties) ? 'S' : ' ',
773 getGlobalRsType(properties));
Stephen Hines8409d642015-04-28 18:49:56 -0700774 }
775 return true;
776}
777
Yang Ni2abfcc62015-02-17 16:05:19 -0800778} // namespace renderscript
779} // namespace android