blob: 82e3738fc72775cc22fcaa6a7db63c691c63ceae [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#else
Jean-Luc Brouillet03fab682017-02-16 21:07:20 -080013#include "bcc/Config.h"
Yang Ni2abfcc62015-02-17 16:05:19 -080014#endif
15
Jiyong Park316ffa52017-08-10 20:37:20 +090016#include <unistd.h>
Yang Ni2abfcc62015-02-17 16:05:19 -080017#include <dlfcn.h>
Nick Kralevichb7ca6d02018-12-10 13:03:02 -080018#include <android/dlext.h>
Mathias Agopian2536d3f2017-03-01 18:16:10 -080019#include <sys/stat.h>
Yang Ni2abfcc62015-02-17 16:05:19 -080020
21namespace android {
22namespace renderscript {
23
24namespace {
25
Yang Ni2abfcc62015-02-17 16:05:19 -080026// Check if a path exists and attempt to create it if it doesn't.
Nick Kralevichb7ca6d02018-12-10 13:03:02 -080027[[maybe_unused]]
Yang Ni2abfcc62015-02-17 16:05:19 -080028static bool ensureCacheDirExists(const char *path) {
29 if (access(path, R_OK | W_OK | X_OK) == 0) {
30 // Done if we can rwx the directory
31 return true;
32 }
33 if (mkdir(path, 0700) == 0) {
34 return true;
35 }
36 return false;
37}
38
39// Copy the file named \p srcFile to \p dstFile.
40// Return 0 on success and -1 if anything wasn't copied.
Nick Kralevichb7ca6d02018-12-10 13:03:02 -080041[[maybe_unused]]
Yang Ni2abfcc62015-02-17 16:05:19 -080042static int copyFile(const char *dstFile, const char *srcFile) {
43 std::ifstream srcStream(srcFile);
44 if (!srcStream) {
45 ALOGE("Could not verify or read source file: %s", srcFile);
46 return -1;
47 }
48 std::ofstream dstStream(dstFile);
49 if (!dstStream) {
50 ALOGE("Could not verify or write destination file: %s", dstFile);
51 return -1;
52 }
53 dstStream << srcStream.rdbuf();
54 if (!dstStream) {
55 ALOGE("Could not write destination file: %s", dstFile);
56 return -1;
57 }
58
59 srcStream.close();
60 dstStream.close();
61
62 return 0;
63}
64
65static std::string findSharedObjectName(const char *cacheDir,
Yang Nia845c352017-05-01 15:53:23 -070066 const char *resName,
67 const bool reuse = true) {
Yang Ni2abfcc62015-02-17 16:05:19 -080068 std::string scriptSOName(cacheDir);
69#if defined(RS_COMPATIBILITY_LIB) && !defined(__LP64__)
70 size_t cutPos = scriptSOName.rfind("cache");
71 if (cutPos != std::string::npos) {
72 scriptSOName.erase(cutPos);
73 } else {
74 ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir);
75 }
76 scriptSOName.append("/lib/librs.");
77#else
78 scriptSOName.append("/librs.");
79#endif // RS_COMPATIBILITY_LIB
Yang Ni2abfcc62015-02-17 16:05:19 -080080 scriptSOName.append(resName);
Yang Nia845c352017-05-01 15:53:23 -070081 if (!reuse) {
82 // If the generated shared library is not reused, e.g., with a debug
83 // context or forced by a system property, multiple threads may read
84 // and write the shared library at the same time. To avoid the race
85 // on the generated shared library, delete it before finishing script
86 // initialization. To avoid deleting a file generated by a regular
87 // context, use a special suffix here.
88 // Because the script initialization is guarded by a lock from the Java
89 // API, it is safe to name this file with a consistent name and suffix
90 // and delete it after loading. The same lock has also prevented write-
91 // write races on the .so during script initialization even if reuse is
92 // true.
93 scriptSOName.append("#delete_after_load");
94 }
Yang Ni2abfcc62015-02-17 16:05:19 -080095 scriptSOName.append(".so");
96
97 return scriptSOName;
98}
99
Jiyong Parkda43d582017-06-16 10:42:10 +0900100#ifndef RS_COMPATIBILITY_LIB
101static bool isRunningInVndkNamespace() {
102 static bool result = []() {
103 Dl_info info;
104 if (dladdr(reinterpret_cast<const void*>(&isRunningInVndkNamespace), &info) != 0) {
105 std::string filename = std::string(info.dli_fname);
Jooyung Handc42cee2020-03-25 21:46:54 +0900106 return filename.find("/apex/com.android.vndk") != std::string::npos;
Jiyong Parkda43d582017-06-16 10:42:10 +0900107 } else {
108 ALOGW("Can't determine whether this lib is running in vndk namespace or not. Assuming it is in vndk namespace.");
109 }
110 return true;
111 }();
112 return result;
113}
114#endif
115
Yang Ni2abfcc62015-02-17 16:05:19 -0800116} // anonymous namespace
117
118const char* SharedLibraryUtils::LD_EXE_PATH = "/system/bin/ld.mc";
119const char* SharedLibraryUtils::RS_CACHE_DIR = "com.android.renderscript.cache";
120
121#ifndef RS_COMPATIBILITY_LIB
122
Stephen Hines4c368af2015-05-06 00:43:02 -0700123bool SharedLibraryUtils::createSharedLibrary(const char *driverName,
124 const char *cacheDir,
Yang Nia845c352017-05-01 15:53:23 -0700125 const char *resName,
126 const bool reuse,
127 std::string *fullPath) {
128 std::string sharedLibName = findSharedObjectName(cacheDir, resName, reuse);
129 if (fullPath) {
130 *fullPath = sharedLibName;
131 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800132 std::string objFileName = cacheDir;
133 objFileName.append("/");
134 objFileName.append(resName);
135 objFileName.append(".o");
Stephen Hines4c368af2015-05-06 00:43:02 -0700136 // Should be something like "libRSDriver.so".
137 std::string linkDriverName = driverName;
138 // Remove ".so" and replace "lib" with "-l".
139 // This will leave us with "-lRSDriver" instead.
140 linkDriverName.erase(linkDriverName.length() - 3);
141 linkDriverName.replace(0, 3, "-l");
Yang Ni2abfcc62015-02-17 16:05:19 -0800142
Justin Yune0f1e2e2017-12-05 18:42:57 +0900143 static const std::string vndkLibCompilerRt =
144 getVndkSysLibPath() + "/libcompiler_rt.so";
Jiyong Parkda43d582017-06-16 10:42:10 +0900145 const char *compiler_rt = isRunningInVndkNamespace() ?
Justin Yune0f1e2e2017-12-05 18:42:57 +0900146 vndkLibCompilerRt.c_str() : SYSLIBPATH "/libcompiler_rt.so";
Pirama Arumuga Nainarc2be4132015-04-21 15:25:53 -0700147 const char *mTriple = "-mtriple=" DEFAULT_TARGET_TRIPLE_STRING;
148 const char *libPath = "--library-path=" SYSLIBPATH;
Jiyong Parkda43d582017-06-16 10:42:10 +0900149 // vndk path is only added when RS framework is running in vndk namespace.
150 // If we unconditionally add the vndk path to the library path, then RS
151 // driver in the vndk-sp directory will always be used even for CPU fallback
152 // case, where RS framework is loaded from the default namespace.
Justin Yune0f1e2e2017-12-05 18:42:57 +0900153 static const std::string vndkLibPathString =
154 "--library-path=" + getVndkSysLibPath();
Jiyong Parkda43d582017-06-16 10:42:10 +0900155 const char *vndkLibPath = isRunningInVndkNamespace() ?
Justin Yune0f1e2e2017-12-05 18:42:57 +0900156 vndkLibPathString.c_str() : "";
Pirama Arumuga Nainar682672e2015-05-07 15:52:48 -0700157 const char *vendorLibPath = "--library-path=" SYSLIBPATH_VENDOR;
Pirama Arumuga Nainarc2be4132015-04-21 15:25:53 -0700158
Jiyong Parkda43d582017-06-16 10:42:10 +0900159 // The search path order should be vendor -> vndk -> system
Yang Ni2abfcc62015-02-17 16:05:19 -0800160 std::vector<const char *> args = {
161 LD_EXE_PATH,
162 "-shared",
163 "-nostdlib",
Jiyong Parkda43d582017-06-16 10:42:10 +0900164 compiler_rt, mTriple, vendorLibPath, vndkLibPath, libPath,
Stephen Hines4c368af2015-05-06 00:43:02 -0700165 linkDriverName.c_str(), "-lm", "-lc",
Yang Ni2abfcc62015-02-17 16:05:19 -0800166 objFileName.c_str(),
167 "-o", sharedLibName.c_str(),
168 nullptr
169 };
170
Pirama Arumuga Nainar2fa8a232015-03-25 17:21:40 -0700171 return rsuExecuteCommand(LD_EXE_PATH, args.size()-1, args.data());
Yang Ni2abfcc62015-02-17 16:05:19 -0800172
Yang Ni2abfcc62015-02-17 16:05:19 -0800173}
174
175#endif // RS_COMPATIBILITY_LIB
176
177const char* RsdCpuScriptImpl::BCC_EXE_PATH = "/system/bin/bcc";
178
Yang Nia845c352017-05-01 15:53:23 -0700179void* SharedLibraryUtils::loadAndDeleteSharedLibrary(const char *fullPath) {
180 void *loaded = dlopen(fullPath, RTLD_NOW | RTLD_LOCAL);
181 if (loaded == nullptr) {
182 ALOGE("Unable to open shared library (%s): %s", fullPath, dlerror());
183 return nullptr;
184 }
185
186 int r = unlink(fullPath);
187 if (r != 0) {
188 ALOGE("Could not unlink copy %s", fullPath);
189 return nullptr;
190 }
191 return loaded;
192}
193
Yang Ni2abfcc62015-02-17 16:05:19 -0800194void* SharedLibraryUtils::loadSharedLibrary(const char *cacheDir,
195 const char *resName,
Yang Ni1efae292015-06-27 15:45:18 -0700196 const char *nativeLibDir,
197 bool* alreadyLoaded) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800198 void *loaded = nullptr;
199
200#if defined(RS_COMPATIBILITY_LIB) && defined(__LP64__)
201 std::string scriptSOName = findSharedObjectName(nativeLibDir, resName);
202#else
203 std::string scriptSOName = findSharedObjectName(cacheDir, resName);
204#endif
205
206 // We should check if we can load the library from the standard app
207 // location for shared libraries first.
Yang Ni1efae292015-06-27 15:45:18 -0700208 loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName, alreadyLoaded);
Yang Ni2abfcc62015-02-17 16:05:19 -0800209
Miao Wang0140ccb2019-09-10 17:28:47 -0700210 if (loaded != nullptr) {
211 return loaded;
212 }
213 ALOGE("Unable to open shared library (%s): %s", scriptSOName.c_str(), dlerror());
Yang Ni2abfcc62015-02-17 16:05:19 -0800214
215#ifdef RS_COMPATIBILITY_LIB
Miao Wang0140ccb2019-09-10 17:28:47 -0700216 // Re-trying without absolute path.
217 // For RS support lib, the shared object may not be extracted from the apk.
218 // In order to access that, we need to load the library without specifying
219 // the absolute path.
220 std::string scriptSONameApk("librs.");
221 scriptSONameApk.append(resName);
222 scriptSONameApk.append(".so");
223 loaded = loadSOHelper(scriptSONameApk.c_str(), cacheDir, resName);
224 if (loaded != nullptr) {
225 return loaded;
Yang Ni2abfcc62015-02-17 16:05:19 -0800226 }
Miao Wang0140ccb2019-09-10 17:28:47 -0700227 ALOGE("Unable to open APK shared library (%s): %s", scriptSONameApk.c_str(), dlerror());
228
229 // One final attempt to find the library in "/system/lib".
230 // We do this to allow bundled applications to use the compatibility
231 // library fallback path. Those applications don't have a private
232 // library path, so they need to install to the system directly.
233 // Note that this is really just a testing path.
234 std::string scriptSONameSystem("/system/lib/librs.");
235 scriptSONameSystem.append(resName);
236 scriptSONameSystem.append(".so");
237 loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir, resName);
238 if (loaded == nullptr) {
239 ALOGE("Unable to open system shared library (%s): %s",
240 scriptSONameSystem.c_str(), dlerror());
241 }
242#endif
Yang Ni2abfcc62015-02-17 16:05:19 -0800243
244 return loaded;
245}
246
Miao Wang82e135c2017-02-27 23:35:35 -0800247std::string SharedLibraryUtils::getRandomString(size_t len) {
Yang Ni1efae292015-06-27 15:45:18 -0700248 char buf[len + 1];
249 for (size_t i = 0; i < len; i++) {
250 uint32_t r = arc4random() & 0xffff;
251 r %= 62;
252 if (r < 26) {
253 // lowercase
254 buf[i] = 'a' + r;
255 } else if (r < 52) {
256 // uppercase
257 buf[i] = 'A' + (r - 26);
258 } else {
259 // Use a number
260 buf[i] = '0' + (r - 52);
261 }
262 }
263 buf[len] = '\0';
Miao Wang82e135c2017-02-27 23:35:35 -0800264 return std::string(buf);
Yang Ni1efae292015-06-27 15:45:18 -0700265}
266
Nick Kralevichb7ca6d02018-12-10 13:03:02 -0800267static void* loadAsCopy(const char *origName, std::string newName) {
268 void *loaded = nullptr;
269#ifndef RS_COMPATIBILITY_LIB
270 int fd = TEMP_FAILURE_RETRY(open(origName, O_RDONLY | O_CLOEXEC));
271 if (fd == -1) {
272 ALOGE("Unable to open original file %s: %s", origName, strerror(errno));
273 return nullptr;
274 }
275
276 android_dlextinfo extinfo;
277 memset(&extinfo, 0, sizeof(extinfo));
278 extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_FORCE_LOAD;
279 extinfo.library_fd = fd;
280
281 loaded = android_dlopen_ext(newName.c_str(), RTLD_NOW | RTLD_LOCAL, &extinfo);
282 close(fd);
283#else
284 int r = copyFile(newName.c_str(), origName);
285 if (r != 0) {
286 ALOGE("Could not create copy %s -> %s", origName, newName.c_str());
287 return nullptr;
288 }
289 loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
290 r = unlink(newName.c_str());
291 if (r != 0) {
292 ALOGE("Could not unlink copy %s", newName.c_str());
293 }
294#endif // RS_COMPATIBILITY_LIB
295 return loaded;
296}
297
Yang Ni2abfcc62015-02-17 16:05:19 -0800298void* SharedLibraryUtils::loadSOHelper(const char *origName, const char *cacheDir,
Yang Ni1efae292015-06-27 15:45:18 -0700299 const char *resName, bool *alreadyLoaded) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800300 // Keep track of which .so libraries have been loaded. Once a library is
301 // in the set (per-process granularity), we must instead make a copy of
302 // the original shared object (randomly named .so file) and load that one
303 // instead. If we don't do this, we end up aliasing global data between
304 // the various Script instances (which are supposed to be completely
305 // independent).
306 static std::set<std::string> LoadedLibraries;
307
308 void *loaded = nullptr;
309
Miao Wang0140ccb2019-09-10 17:28:47 -0700310#ifndef RS_COMPATIBILITY_LIB
Yang Ni2abfcc62015-02-17 16:05:19 -0800311 // Skip everything if we don't even have the original library available.
312 if (access(origName, F_OK) != 0) {
313 return nullptr;
314 }
Miao Wang0140ccb2019-09-10 17:28:47 -0700315#endif // RS_COMPATIBILITY_LIB
Yang Ni2abfcc62015-02-17 16:05:19 -0800316
317 // Common path is that we have not loaded this Script/library before.
318 if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
Yang Ni1efae292015-06-27 15:45:18 -0700319 if (alreadyLoaded != nullptr) {
320 *alreadyLoaded = false;
321 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800322 loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
323 if (loaded) {
324 LoadedLibraries.insert(origName);
325 }
326 return loaded;
327 }
328
Yang Ni1efae292015-06-27 15:45:18 -0700329 if (alreadyLoaded != nullptr) {
330 *alreadyLoaded = true;
331 }
332
Yang Ni2abfcc62015-02-17 16:05:19 -0800333 std::string newName(cacheDir);
334
335 // Append RS_CACHE_DIR only if it is not found in cacheDir
336 // In driver mode, RS_CACHE_DIR is already appended to cacheDir.
337 if (newName.find(RS_CACHE_DIR) == std::string::npos) {
338 newName.append("/");
339 newName.append(RS_CACHE_DIR);
340 newName.append("/");
341 }
342
343 if (!ensureCacheDirExists(newName.c_str())) {
344 ALOGE("Could not verify or create cache dir: %s", cacheDir);
345 return nullptr;
346 }
347
348 // Construct an appropriately randomized filename for the copy.
349 newName.append("librs.");
350 newName.append(resName);
351 newName.append("#");
Miao Wang82e135c2017-02-27 23:35:35 -0800352 newName.append(getRandomString(6).c_str()); // 62^6 potential filename variants.
Yang Ni2abfcc62015-02-17 16:05:19 -0800353 newName.append(".so");
354
Nick Kralevichb7ca6d02018-12-10 13:03:02 -0800355 loaded = loadAsCopy(origName, newName);
356
Yang Ni2abfcc62015-02-17 16:05:19 -0800357 if (loaded) {
358 LoadedLibraries.insert(newName.c_str());
359 }
360
361 return loaded;
362}
363
Miao Wangd4848102016-04-27 15:49:47 -0700364// MAXLINESTR must be compatible with operator '#' in C macro.
365#define MAXLINESTR 499
366// MAXLINE must be (MAXLINESTR + 1), representing the size of a C string
367// containing MAXLINESTR non-null chars plus a null.
368#define MAXLINE (MAXLINESTR + 1)
Yang Ni2abfcc62015-02-17 16:05:19 -0800369#define MAKE_STR_HELPER(S) #S
370#define MAKE_STR(S) MAKE_STR_HELPER(S)
371#define EXPORT_VAR_STR "exportVarCount: "
372#define EXPORT_FUNC_STR "exportFuncCount: "
373#define EXPORT_FOREACH_STR "exportForEachCount: "
Matt Wala14ce0072015-07-30 17:30:25 -0700374#define EXPORT_REDUCE_STR "exportReduceCount: "
Yang Ni2abfcc62015-02-17 16:05:19 -0800375#define OBJECT_SLOT_STR "objectSlotCount: "
376#define PRAGMA_STR "pragmaCount: "
377#define THREADABLE_STR "isThreadable: "
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800378#define CHECKSUM_STR "buildChecksum: "
Luke Drummond3bc02c52016-12-15 12:40:55 +0000379#define VERSIONINFO_STR "versionInfo: "
Yang Ni2abfcc62015-02-17 16:05:19 -0800380
381// Copy up to a newline or size chars from str -> s, updating str
382// Returns s when successful and nullptr when '\0' is finally reached.
383static char* strgets(char *s, int size, const char **ppstr) {
384 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
385 return nullptr;
386 }
387
388 int i;
389 for (i = 0; i < (size - 1); i++) {
390 s[i] = **ppstr;
391 (*ppstr)++;
392 if (s[i] == '\0') {
393 return s;
394 } else if (s[i] == '\n') {
395 s[i+1] = '\0';
396 return s;
397 }
398 }
399
400 // size has been exceeded.
401 s[i] = '\0';
402
403 return s;
404}
405
Michael Butlerca451c32017-04-19 18:47:55 -0700406// Creates a duplicate of a string. The new string is as small as possible,
407// only including characters up to and including the first null-terminator;
408// otherwise, the new string will be the same size as the input string.
409// The code that calls duplicateString is responsible for the new string's
410// lifetime, and is responsible for freeing it when it is no longer needed.
411static char* duplicateString(const char *str, size_t length) {
412 const size_t newLen = strnlen(str, length-1) + 1;
413 char *newStr = new char[newLen];
414 strlcpy(newStr, str, newLen);
415 return newStr;
416}
417
Yang Ni2abfcc62015-02-17 16:05:19 -0800418ScriptExecutable* ScriptExecutable::createFromSharedObject(
Yang Ni5e480022016-04-06 09:34:34 -0700419 void* sharedObj, uint32_t expectedChecksum) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800420 char line[MAXLINE];
421
422 size_t varCount = 0;
423 size_t funcCount = 0;
424 size_t forEachCount = 0;
Matt Wala14ce0072015-07-30 17:30:25 -0700425 size_t reduceCount = 0;
Yang Ni2abfcc62015-02-17 16:05:19 -0800426 size_t objectSlotCount = 0;
427 size_t pragmaCount = 0;
428 bool isThreadable = true;
429
430 void** fieldAddress = nullptr;
431 bool* fieldIsObject = nullptr;
Yang Ni062c2872015-02-20 15:20:00 -0800432 char** fieldName = nullptr;
Yang Ni2abfcc62015-02-17 16:05:19 -0800433 InvokeFunc_t* invokeFunctions = nullptr;
434 ForEachFunc_t* forEachFunctions = nullptr;
435 uint32_t* forEachSignatures = nullptr;
David Grossae2ec3f2016-06-01 14:45:47 -0700436 ReduceDescription* reduceDescriptions = nullptr;
Yang Ni2abfcc62015-02-17 16:05:19 -0800437 const char ** pragmaKeys = nullptr;
438 const char ** pragmaValues = nullptr;
Yang Nicb170152015-04-16 10:27:02 -0700439 uint32_t checksum = 0;
Yang Ni2abfcc62015-02-17 16:05:19 -0800440
Stephen Hines5aa018c2015-05-20 18:09:57 -0700441 const char *rsInfo = (const char *) dlsym(sharedObj, kRsInfo);
Stephen Hines8409d642015-04-28 18:49:56 -0700442 int numEntries = 0;
Stephen Hines5aa018c2015-05-20 18:09:57 -0700443 const int *rsGlobalEntries = (const int *) dlsym(sharedObj, kRsGlobalEntries);
444 const char **rsGlobalNames = (const char **) dlsym(sharedObj, kRsGlobalNames);
445 const void **rsGlobalAddresses = (const void **) dlsym(sharedObj, kRsGlobalAddresses);
446 const size_t *rsGlobalSizes = (const size_t *) dlsym(sharedObj, kRsGlobalSizes);
447 const uint32_t *rsGlobalProperties = (const uint32_t *) dlsym(sharedObj, kRsGlobalProperties);
Yang Ni2abfcc62015-02-17 16:05:19 -0800448
449 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
450 return nullptr;
451 }
452 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
453 ALOGE("Invalid export var count!: %s", line);
454 return nullptr;
455 }
456
457 fieldAddress = new void*[varCount];
458 if (fieldAddress == nullptr) {
459 return nullptr;
460 }
461
462 fieldIsObject = new bool[varCount];
463 if (fieldIsObject == nullptr) {
464 goto error;
465 }
466
Yang Ni062c2872015-02-20 15:20:00 -0800467 fieldName = new char*[varCount];
468 if (fieldName == nullptr) {
469 goto error;
470 }
471
Yang Ni2abfcc62015-02-17 16:05:19 -0800472 for (size_t i = 0; i < varCount; ++i) {
473 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
474 goto error;
475 }
476 char *c = strrchr(line, '\n');
477 if (c) {
478 *c = '\0';
479 }
480 void* addr = dlsym(sharedObj, line);
481 if (addr == nullptr) {
482 ALOGE("Failed to find variable address for %s: %s",
483 line, dlerror());
484 // Not a critical error if we don't find a global variable.
485 }
486 fieldAddress[i] = addr;
487 fieldIsObject[i] = false;
Michael Butlerca451c32017-04-19 18:47:55 -0700488 fieldName[i] = duplicateString(line, sizeof(line));
Yang Ni2abfcc62015-02-17 16:05:19 -0800489 }
490
491 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
492 goto error;
493 }
494 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
495 ALOGE("Invalid export func count!: %s", line);
496 goto error;
497 }
498
499 invokeFunctions = new InvokeFunc_t[funcCount];
500 if (invokeFunctions == nullptr) {
501 goto error;
502 }
503
504 for (size_t i = 0; i < funcCount; ++i) {
505 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
506 goto error;
507 }
508 char *c = strrchr(line, '\n');
509 if (c) {
510 *c = '\0';
511 }
512
513 invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line);
514 if (invokeFunctions[i] == nullptr) {
515 ALOGE("Failed to get function address for %s(): %s",
516 line, dlerror());
517 goto error;
518 }
519 }
520
521 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
522 goto error;
523 }
524 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
525 ALOGE("Invalid export forEach count!: %s", line);
526 goto error;
527 }
528
529 forEachFunctions = new ForEachFunc_t[forEachCount];
530 if (forEachFunctions == nullptr) {
531 goto error;
532 }
533
534 forEachSignatures = new uint32_t[forEachCount];
535 if (forEachSignatures == nullptr) {
536 goto error;
537 }
538
539 for (size_t i = 0; i < forEachCount; ++i) {
540 unsigned int tmpSig = 0;
541 char tmpName[MAXLINE];
542
543 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
544 goto error;
545 }
Miao Wangd4848102016-04-27 15:49:47 -0700546 if (sscanf(line, "%u - %" MAKE_STR(MAXLINESTR) "s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800547 &tmpSig, tmpName) != 2) {
548 ALOGE("Invalid export forEach!: %s", line);
549 goto error;
550 }
551
552 // Lookup the expanded ForEach kernel.
Miao Wangd4848102016-04-27 15:49:47 -0700553 strncat(tmpName, ".expand", MAXLINESTR-strlen(tmpName));
Yang Ni2abfcc62015-02-17 16:05:19 -0800554 forEachSignatures[i] = tmpSig;
555 forEachFunctions[i] =
556 (ForEachFunc_t) dlsym(sharedObj, tmpName);
Yang Ni062c2872015-02-20 15:20:00 -0800557 if (i != 0 && forEachFunctions[i] == nullptr &&
558 strcmp(tmpName, "root.expand")) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800559 // Ignore missing root.expand functions.
560 // root() is always specified at location 0.
Matt Wala14ce0072015-07-30 17:30:25 -0700561 ALOGE("Failed to find forEach function address for %s(): %s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800562 tmpName, dlerror());
563 goto error;
564 }
565 }
566
David Gross6c1876b2016-01-15 11:52:14 -0800567 // Read general reduce kernels
David Gross46c93e42016-01-09 16:23:37 -0800568 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
569 goto error;
570 }
David Grossae2ec3f2016-06-01 14:45:47 -0700571 if (sscanf(line, EXPORT_REDUCE_STR "%zu", &reduceCount) != 1) {
David Gross46c93e42016-01-09 16:23:37 -0800572 ALOGE("Invalid export reduce new count!: %s", line);
573 goto error;
574 }
David Gross6c1876b2016-01-15 11:52:14 -0800575
David Grossae2ec3f2016-06-01 14:45:47 -0700576 reduceDescriptions = new ReduceDescription[reduceCount];
577 if (reduceDescriptions == nullptr) {
David Gross46c93e42016-01-09 16:23:37 -0800578 goto error;
579 }
580
David Grossae2ec3f2016-06-01 14:45:47 -0700581 for (size_t i = 0; i < reduceCount; ++i) {
David Gross6c1876b2016-01-15 11:52:14 -0800582 static const char kNoName[] = ".";
583
584 unsigned int tmpSig = 0;
585 size_t tmpSize = 0;
586 char tmpNameReduce[MAXLINE];
587 char tmpNameInitializer[MAXLINE];
588 char tmpNameAccumulator[MAXLINE];
589 char tmpNameCombiner[MAXLINE];
590 char tmpNameOutConverter[MAXLINE];
591 char tmpNameHalter[MAXLINE];
592
593 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
594 goto error;
595 }
Miao Wangd4848102016-04-27 15:49:47 -0700596#define DELIMNAME " - %" MAKE_STR(MAXLINESTR) "s"
David Gross6c1876b2016-01-15 11:52:14 -0800597 if (sscanf(line, "%u - %zu" DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME,
598 &tmpSig, &tmpSize, tmpNameReduce, tmpNameInitializer, tmpNameAccumulator,
599 tmpNameCombiner, tmpNameOutConverter, tmpNameHalter) != 8) {
600 ALOGE("Invalid export reduce new!: %s", line);
601 goto error;
602 }
603#undef DELIMNAME
604
605 // For now, we expect
606 // - Reduce and Accumulator names
607 // - optional Initializer, Combiner, and OutConverter name
608 // - no Halter name
609 if (!strcmp(tmpNameReduce, kNoName) ||
610 !strcmp(tmpNameAccumulator, kNoName)) {
611 ALOGE("Expected reduce and accumulator names!: %s", line);
612 goto error;
613 }
614 if (strcmp(tmpNameHalter, kNoName)) {
615 ALOGE("Did not expect halter name!: %s", line);
616 goto error;
617 }
618
David Gross10adb0c2016-03-29 13:48:41 -0700619 // The current implementation does not use the signature
620 // or reduce name.
David Gross6c1876b2016-01-15 11:52:14 -0800621
David Grossae2ec3f2016-06-01 14:45:47 -0700622 reduceDescriptions[i].accumSize = tmpSize;
David Gross6c1876b2016-01-15 11:52:14 -0800623
624 // Process the (optional) initializer.
625 if (strcmp(tmpNameInitializer, kNoName)) {
626 // Lookup the original user-written initializer.
David Grossae2ec3f2016-06-01 14:45:47 -0700627 if (!(reduceDescriptions[i].initFunc =
628 (ReduceInitializerFunc_t) dlsym(sharedObj, tmpNameInitializer))) {
David Gross6c1876b2016-01-15 11:52:14 -0800629 ALOGE("Failed to find initializer function address for %s(): %s",
630 tmpNameInitializer, dlerror());
631 goto error;
632 }
633 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700634 reduceDescriptions[i].initFunc = nullptr;
David Gross6c1876b2016-01-15 11:52:14 -0800635 }
636
637 // Lookup the expanded accumulator.
Miao Wangd4848102016-04-27 15:49:47 -0700638 strncat(tmpNameAccumulator, ".expand", MAXLINESTR-strlen(tmpNameAccumulator));
David Grossae2ec3f2016-06-01 14:45:47 -0700639 if (!(reduceDescriptions[i].accumFunc =
640 (ReduceAccumulatorFunc_t) dlsym(sharedObj, tmpNameAccumulator))) {
David Gross6c1876b2016-01-15 11:52:14 -0800641 ALOGE("Failed to find accumulator function address for %s(): %s",
642 tmpNameAccumulator, dlerror());
643 goto error;
644 }
645
David Gross10adb0c2016-03-29 13:48:41 -0700646 // Process the (optional) combiner.
647 if (strcmp(tmpNameCombiner, kNoName)) {
648 // Lookup the original user-written combiner.
David Grossae2ec3f2016-06-01 14:45:47 -0700649 if (!(reduceDescriptions[i].combFunc =
650 (ReduceCombinerFunc_t) dlsym(sharedObj, tmpNameCombiner))) {
David Gross10adb0c2016-03-29 13:48:41 -0700651 ALOGE("Failed to find combiner function address for %s(): %s",
652 tmpNameCombiner, dlerror());
653 goto error;
654 }
655 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700656 reduceDescriptions[i].combFunc = nullptr;
David Gross10adb0c2016-03-29 13:48:41 -0700657 }
658
David Gross6c1876b2016-01-15 11:52:14 -0800659 // Process the (optional) outconverter.
660 if (strcmp(tmpNameOutConverter, kNoName)) {
661 // Lookup the original user-written outconverter.
David Grossae2ec3f2016-06-01 14:45:47 -0700662 if (!(reduceDescriptions[i].outFunc =
663 (ReduceOutConverterFunc_t) dlsym(sharedObj, tmpNameOutConverter))) {
David Gross6c1876b2016-01-15 11:52:14 -0800664 ALOGE("Failed to find outconverter function address for %s(): %s",
665 tmpNameOutConverter, dlerror());
666 goto error;
667 }
668 } else {
David Grossae2ec3f2016-06-01 14:45:47 -0700669 reduceDescriptions[i].outFunc = nullptr;
David Gross6c1876b2016-01-15 11:52:14 -0800670 }
671 }
672
Yang Ni2abfcc62015-02-17 16:05:19 -0800673 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
674 goto error;
675 }
676 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
677 ALOGE("Invalid object slot count!: %s", line);
678 goto error;
679 }
680
681 for (size_t i = 0; i < objectSlotCount; ++i) {
682 uint32_t varNum = 0;
683 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
684 goto error;
685 }
686 if (sscanf(line, "%u", &varNum) != 1) {
687 ALOGE("Invalid object slot!: %s", line);
688 goto error;
689 }
690
691 if (varNum < varCount) {
692 fieldIsObject[varNum] = true;
693 }
694 }
695
696#ifndef RS_COMPATIBILITY_LIB
697 // Do not attempt to read pragmas or isThreadable flag in compat lib path.
698 // Neither is applicable for compat lib
699
700 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
701 goto error;
702 }
703
704 if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) {
705 ALOGE("Invalid pragma count!: %s", line);
706 goto error;
707 }
708
709 pragmaKeys = new const char*[pragmaCount];
710 if (pragmaKeys == nullptr) {
711 goto error;
712 }
713
714 pragmaValues = new const char*[pragmaCount];
715 if (pragmaValues == nullptr) {
716 goto error;
717 }
718
719 bzero(pragmaKeys, sizeof(char*) * pragmaCount);
720 bzero(pragmaValues, sizeof(char*) * pragmaCount);
721
722 for (size_t i = 0; i < pragmaCount; ++i) {
723 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
724 ALOGE("Unable to read pragma at index %zu!", i);
725 goto error;
726 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800727 char key[MAXLINE];
728 char value[MAXLINE] = ""; // initialize in case value is empty
729
730 // pragmas can just have a key and no value. Only check to make sure
731 // that the key is not empty
Miao Wangd4848102016-04-27 15:49:47 -0700732 if (sscanf(line, "%" MAKE_STR(MAXLINESTR) "s - %" MAKE_STR(MAXLINESTR) "s",
Yang Ni2abfcc62015-02-17 16:05:19 -0800733 key, value) == 0 ||
734 strlen(key) == 0)
735 {
736 ALOGE("Invalid pragma value!: %s", line);
737
738 goto error;
739 }
740
Michael Butlerca451c32017-04-19 18:47:55 -0700741 pragmaKeys[i] = duplicateString(key, sizeof(key));
742 pragmaValues[i] = duplicateString(value, sizeof(value));
Yang Ni2abfcc62015-02-17 16:05:19 -0800743 //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue);
744 }
745
746 if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
747 goto error;
748 }
749
750 char tmpFlag[4];
Miao Wangd4848102016-04-27 15:49:47 -0700751 if (sscanf(line, THREADABLE_STR "%3s", tmpFlag) != 1) {
Yang Ni2abfcc62015-02-17 16:05:19 -0800752 ALOGE("Invalid threadable flag!: %s", line);
753 goto error;
754 }
755 if (strcmp(tmpFlag, "yes") == 0) {
756 isThreadable = true;
757 } else if (strcmp(tmpFlag, "no") == 0) {
758 isThreadable = false;
759 } else {
760 ALOGE("Invalid threadable flag!: %s", tmpFlag);
761 goto error;
762 }
763
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800764 if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
Yang Nicb170152015-04-16 10:27:02 -0700765 if (sscanf(line, CHECKSUM_STR "%08x", &checksum) != 1) {
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800766 ALOGE("Invalid checksum flag!: %s", line);
767 goto error;
768 }
Yang Ni062c2872015-02-20 15:20:00 -0800769 } else {
770 ALOGE("Missing checksum in shared obj file");
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800771 goto error;
772 }
773
Yang Nicb170152015-04-16 10:27:02 -0700774 if (expectedChecksum != 0 && checksum != expectedChecksum) {
775 ALOGE("Found invalid checksum. Expected %08x, got %08x\n",
776 expectedChecksum, checksum);
777 goto error;
778 }
779
Luke Drummond3bc02c52016-12-15 12:40:55 +0000780 {
781 // Parse the version info string, but ignore its contents as it's only
782 // used by the debugger
783 size_t nLines = 0;
784 if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
785 if (sscanf(line, VERSIONINFO_STR "%zu", &nLines) != 1) {
786 ALOGE("invalid versionInfo count");
787 goto error;
788 } else {
789 // skip the versionInfo packet as libRs doesn't use it
Ivan Lozano90016ca2017-12-12 09:24:37 -0800790 while (nLines) {
791 --nLines;
Luke Drummond3bc02c52016-12-15 12:40:55 +0000792 if (strgets(line, MAXLINE, &rsInfo) == nullptr)
793 goto error;
794 }
795 }
796 } else {
797 ALOGE(".rs.info is missing versionInfo section");
798 }
799 }
800
Yang Ni2abfcc62015-02-17 16:05:19 -0800801#endif // RS_COMPATIBILITY_LIB
802
Stephen Hines8409d642015-04-28 18:49:56 -0700803 // Read in information about mutable global variables provided by bcc's
804 // RSGlobalInfoPass
805 if (rsGlobalEntries) {
806 numEntries = *rsGlobalEntries;
807 if (numEntries > 0) {
808 rsAssert(rsGlobalNames);
809 rsAssert(rsGlobalAddresses);
810 rsAssert(rsGlobalSizes);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700811 rsAssert(rsGlobalProperties);
Stephen Hines8409d642015-04-28 18:49:56 -0700812 }
Stephen Hines8409d642015-04-28 18:49:56 -0700813 }
814
Yang Ni2abfcc62015-02-17 16:05:19 -0800815 return new ScriptExecutable(
Yang Ni5e480022016-04-06 09:34:34 -0700816 fieldAddress, fieldIsObject, fieldName, varCount,
Yang Ni2abfcc62015-02-17 16:05:19 -0800817 invokeFunctions, funcCount,
818 forEachFunctions, forEachSignatures, forEachCount,
David Grossae2ec3f2016-06-01 14:45:47 -0700819 reduceDescriptions, reduceCount,
Yang Ni2abfcc62015-02-17 16:05:19 -0800820 pragmaKeys, pragmaValues, pragmaCount,
Stephen Hines5aa018c2015-05-20 18:09:57 -0700821 rsGlobalNames, rsGlobalAddresses, rsGlobalSizes, rsGlobalProperties,
822 numEntries, isThreadable, checksum);
Yang Ni2abfcc62015-02-17 16:05:19 -0800823
824error:
825
826#ifndef RS_COMPATIBILITY_LIB
Pirama Arumuga Nainaraa6757f2015-02-13 20:02:50 -0800827
Ting-Yuan Huanga824b7c2016-11-22 16:58:51 -0800828 if (pragmaKeys) {
829 for (size_t idx = 0; idx < pragmaCount; ++idx) {
830 delete [] pragmaKeys[idx];
831 }
832 }
833
834 if (pragmaValues) {
835 for (size_t idx = 0; idx < pragmaCount; ++idx) {
836 delete [] pragmaValues[idx];
837 }
Yang Ni2abfcc62015-02-17 16:05:19 -0800838 }
839
840 delete[] pragmaValues;
841 delete[] pragmaKeys;
842#endif // RS_COMPATIBILITY_LIB
843
Ting-Yuan Huanga824b7c2016-11-22 16:58:51 -0800844 delete[] reduceDescriptions;
845
Yang Ni2abfcc62015-02-17 16:05:19 -0800846 delete[] forEachSignatures;
847 delete[] forEachFunctions;
Yang Ni062c2872015-02-20 15:20:00 -0800848
Yang Ni2abfcc62015-02-17 16:05:19 -0800849 delete[] invokeFunctions;
Yang Ni062c2872015-02-20 15:20:00 -0800850
851 for (size_t i = 0; i < varCount; i++) {
852 delete[] fieldName[i];
853 }
854 delete[] fieldName;
Yang Ni2abfcc62015-02-17 16:05:19 -0800855 delete[] fieldIsObject;
856 delete[] fieldAddress;
857
858 return nullptr;
859}
860
Yang Ni062c2872015-02-20 15:20:00 -0800861void* ScriptExecutable::getFieldAddress(const char* name) const {
862 // TODO: improve this by using a hash map.
863 for (size_t i = 0; i < mExportedVarCount; i++) {
864 if (strcmp(name, mFieldName[i]) == 0) {
865 return mFieldAddress[i];
866 }
867 }
868 return nullptr;
869}
870
Stephen Hines8409d642015-04-28 18:49:56 -0700871bool ScriptExecutable::dumpGlobalInfo() const {
872 ALOGE("Globals: %p %p %p", mGlobalAddresses, mGlobalSizes, mGlobalNames);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700873 ALOGE("P - Pointer");
874 ALOGE(" C - Constant");
875 ALOGE(" S - Static");
Stephen Hines8409d642015-04-28 18:49:56 -0700876 for (int i = 0; i < mGlobalEntries; i++) {
877 ALOGE("Global[%d]: %p %zu %s", i, mGlobalAddresses[i], mGlobalSizes[i],
878 mGlobalNames[i]);
Stephen Hines5aa018c2015-05-20 18:09:57 -0700879 uint32_t properties = mGlobalProperties[i];
880 ALOGE("%c%c%c Type: %u",
881 isGlobalPointer(properties) ? 'P' : ' ',
882 isGlobalConstant(properties) ? 'C' : ' ',
883 isGlobalStatic(properties) ? 'S' : ' ',
884 getGlobalRsType(properties));
Stephen Hines8409d642015-04-28 18:49:56 -0700885 }
886 return true;
887}
888
Yang Ni2abfcc62015-02-17 16:05:19 -0800889} // namespace renderscript
890} // namespace android