rsCpuExecutable.cpp revision a16bfb513347e424bd919135a653de275362f0bb
1#include "rsCpuExecutable.h"
2#include "rsCppUtils.h"
3
4#include <fstream>
5#include <set>
6#include <memory>
7
8#include <sys/stat.h>
9
10#ifdef RS_COMPATIBILITY_LIB
11#include <stdio.h>
12#include <unistd.h>
13#else
14#include "bcc/Config.h"
15#endif
16
17#include <dlfcn.h>
18#include <sys/stat.h>
19
20namespace android {
21namespace renderscript {
22
23namespace {
24
25// Check if a path exists and attempt to create it if it doesn't.
26static bool ensureCacheDirExists(const char *path) {
27    if (access(path, R_OK | W_OK | X_OK) == 0) {
28        // Done if we can rwx the directory
29        return true;
30    }
31    if (mkdir(path, 0700) == 0) {
32        return true;
33    }
34    return false;
35}
36
37// Copy the file named \p srcFile to \p dstFile.
38// Return 0 on success and -1 if anything wasn't copied.
39static int copyFile(const char *dstFile, const char *srcFile) {
40    std::ifstream srcStream(srcFile);
41    if (!srcStream) {
42        ALOGE("Could not verify or read source file: %s", srcFile);
43        return -1;
44    }
45    std::ofstream dstStream(dstFile);
46    if (!dstStream) {
47        ALOGE("Could not verify or write destination file: %s", dstFile);
48        return -1;
49    }
50    dstStream << srcStream.rdbuf();
51    if (!dstStream) {
52        ALOGE("Could not write destination file: %s", dstFile);
53        return -1;
54    }
55
56    srcStream.close();
57    dstStream.close();
58
59    return 0;
60}
61
62static std::string findSharedObjectName(const char *cacheDir,
63                                        const char *resName) {
64    std::string scriptSOName(cacheDir);
65#if defined(RS_COMPATIBILITY_LIB) && !defined(__LP64__)
66    size_t cutPos = scriptSOName.rfind("cache");
67    if (cutPos != std::string::npos) {
68        scriptSOName.erase(cutPos);
69    } else {
70        ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir);
71    }
72    scriptSOName.append("/lib/librs.");
73#else
74    scriptSOName.append("/librs.");
75#endif // RS_COMPATIBILITY_LIB
76    scriptSOName.append(resName);
77    scriptSOName.append(".so");
78
79    return scriptSOName;
80}
81
82}  // anonymous namespace
83
84const char* SharedLibraryUtils::LD_EXE_PATH = "/system/bin/ld.mc";
85const char* SharedLibraryUtils::RS_CACHE_DIR = "com.android.renderscript.cache";
86
87#ifndef RS_COMPATIBILITY_LIB
88
89bool SharedLibraryUtils::createSharedLibrary(const char *driverName,
90                                             const char *cacheDir,
91                                             const char *resName) {
92    std::string sharedLibName = findSharedObjectName(cacheDir, resName);
93    std::string objFileName = cacheDir;
94    objFileName.append("/");
95    objFileName.append(resName);
96    objFileName.append(".o");
97    // Should be something like "libRSDriver.so".
98    std::string linkDriverName = driverName;
99    // Remove ".so" and replace "lib" with "-l".
100    // This will leave us with "-lRSDriver" instead.
101    linkDriverName.erase(linkDriverName.length() - 3);
102    linkDriverName.replace(0, 3, "-l");
103
104    const char *compiler_rt = SYSLIBPATH"/libcompiler_rt.so";
105    const char *mTriple = "-mtriple=" DEFAULT_TARGET_TRIPLE_STRING;
106    const char *libPath = "--library-path=" SYSLIBPATH;
107    const char *vendorLibPath = "--library-path=" SYSLIBPATH_VENDOR;
108
109    std::vector<const char *> args = {
110        LD_EXE_PATH,
111        "-shared",
112        "-nostdlib",
113        compiler_rt, mTriple, vendorLibPath, libPath,
114        linkDriverName.c_str(), "-lm", "-lc",
115        objFileName.c_str(),
116        "-o", sharedLibName.c_str(),
117        nullptr
118    };
119
120    return rsuExecuteCommand(LD_EXE_PATH, args.size()-1, args.data());
121
122}
123
124#endif  // RS_COMPATIBILITY_LIB
125
126const char* RsdCpuScriptImpl::BCC_EXE_PATH = "/system/bin/bcc";
127
128void* SharedLibraryUtils::loadSharedLibrary(const char *cacheDir,
129                                            const char *resName,
130                                            const char *nativeLibDir,
131                                            bool* alreadyLoaded) {
132    void *loaded = nullptr;
133
134#if defined(RS_COMPATIBILITY_LIB) && defined(__LP64__)
135    std::string scriptSOName = findSharedObjectName(nativeLibDir, resName);
136#else
137    std::string scriptSOName = findSharedObjectName(cacheDir, resName);
138#endif
139
140    // We should check if we can load the library from the standard app
141    // location for shared libraries first.
142    loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName, alreadyLoaded);
143
144    if (loaded == nullptr) {
145        ALOGE("Unable to open shared library (%s): %s",
146              scriptSOName.c_str(), dlerror());
147
148#ifdef RS_COMPATIBILITY_LIB
149        // One final attempt to find the library in "/system/lib".
150        // We do this to allow bundled applications to use the compatibility
151        // library fallback path. Those applications don't have a private
152        // library path, so they need to install to the system directly.
153        // Note that this is really just a testing path.
154        std::string scriptSONameSystem("/system/lib/librs.");
155        scriptSONameSystem.append(resName);
156        scriptSONameSystem.append(".so");
157        loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir,
158                              resName);
159        if (loaded == nullptr) {
160            ALOGE("Unable to open system shared library (%s): %s",
161                  scriptSONameSystem.c_str(), dlerror());
162        }
163#endif
164    }
165
166    return loaded;
167}
168
169std::string SharedLibraryUtils::getRandomString(size_t len) {
170    char buf[len + 1];
171    for (size_t i = 0; i < len; i++) {
172        uint32_t r = arc4random() & 0xffff;
173        r %= 62;
174        if (r < 26) {
175            // lowercase
176            buf[i] = 'a' + r;
177        } else if (r < 52) {
178            // uppercase
179            buf[i] = 'A' + (r - 26);
180        } else {
181            // Use a number
182            buf[i] = '0' + (r - 52);
183        }
184    }
185    buf[len] = '\0';
186    return std::string(buf);
187}
188
189void* SharedLibraryUtils::loadSOHelper(const char *origName, const char *cacheDir,
190                                       const char *resName, bool *alreadyLoaded) {
191    // Keep track of which .so libraries have been loaded. Once a library is
192    // in the set (per-process granularity), we must instead make a copy of
193    // the original shared object (randomly named .so file) and load that one
194    // instead. If we don't do this, we end up aliasing global data between
195    // the various Script instances (which are supposed to be completely
196    // independent).
197    static std::set<std::string> LoadedLibraries;
198
199    void *loaded = nullptr;
200
201    // Skip everything if we don't even have the original library available.
202    if (access(origName, F_OK) != 0) {
203        return nullptr;
204    }
205
206    // Common path is that we have not loaded this Script/library before.
207    if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
208        if (alreadyLoaded != nullptr) {
209            *alreadyLoaded = false;
210        }
211        loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
212        if (loaded) {
213            LoadedLibraries.insert(origName);
214        }
215        return loaded;
216    }
217
218    if (alreadyLoaded != nullptr) {
219        *alreadyLoaded = true;
220    }
221
222    std::string newName(cacheDir);
223
224    // Append RS_CACHE_DIR only if it is not found in cacheDir
225    // In driver mode, RS_CACHE_DIR is already appended to cacheDir.
226    if (newName.find(RS_CACHE_DIR) == std::string::npos) {
227        newName.append("/");
228        newName.append(RS_CACHE_DIR);
229        newName.append("/");
230    }
231
232    if (!ensureCacheDirExists(newName.c_str())) {
233        ALOGE("Could not verify or create cache dir: %s", cacheDir);
234        return nullptr;
235    }
236
237    // Construct an appropriately randomized filename for the copy.
238    newName.append("librs.");
239    newName.append(resName);
240    newName.append("#");
241    newName.append(getRandomString(6).c_str());  // 62^6 potential filename variants.
242    newName.append(".so");
243
244    int r = copyFile(newName.c_str(), origName);
245    if (r != 0) {
246        ALOGE("Could not create copy %s -> %s", origName, newName.c_str());
247        return nullptr;
248    }
249    loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
250    r = unlink(newName.c_str());
251    if (r != 0) {
252        ALOGE("Could not unlink copy %s", newName.c_str());
253    }
254    if (loaded) {
255        LoadedLibraries.insert(newName.c_str());
256    }
257
258    return loaded;
259}
260
261// MAXLINESTR must be compatible with operator '#' in C macro.
262#define MAXLINESTR 499
263// MAXLINE must be (MAXLINESTR + 1), representing the size of a C string
264// containing MAXLINESTR non-null chars plus a null.
265#define MAXLINE (MAXLINESTR + 1)
266#define MAKE_STR_HELPER(S) #S
267#define MAKE_STR(S) MAKE_STR_HELPER(S)
268#define EXPORT_VAR_STR "exportVarCount: "
269#define EXPORT_FUNC_STR "exportFuncCount: "
270#define EXPORT_FOREACH_STR "exportForEachCount: "
271#define EXPORT_REDUCE_STR "exportReduceCount: "
272#define OBJECT_SLOT_STR "objectSlotCount: "
273#define PRAGMA_STR "pragmaCount: "
274#define THREADABLE_STR "isThreadable: "
275#define CHECKSUM_STR "buildChecksum: "
276#define VERSIONINFO_STR "versionInfo: "
277
278// Copy up to a newline or size chars from str -> s, updating str
279// Returns s when successful and nullptr when '\0' is finally reached.
280static char* strgets(char *s, int size, const char **ppstr) {
281    if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
282        return nullptr;
283    }
284
285    int i;
286    for (i = 0; i < (size - 1); i++) {
287        s[i] = **ppstr;
288        (*ppstr)++;
289        if (s[i] == '\0') {
290            return s;
291        } else if (s[i] == '\n') {
292            s[i+1] = '\0';
293            return s;
294        }
295    }
296
297    // size has been exceeded.
298    s[i] = '\0';
299
300    return s;
301}
302
303// Creates a duplicate of a string. The new string is as small as possible,
304// only including characters up to and including the first null-terminator;
305// otherwise, the new string will be the same size as the input string.
306// The code that calls duplicateString is responsible for the new string's
307// lifetime, and is responsible for freeing it when it is no longer needed.
308static char* duplicateString(const char *str, size_t length) {
309    const size_t newLen = strnlen(str, length-1) + 1;
310    char *newStr = new char[newLen];
311    strlcpy(newStr, str, newLen);
312    return newStr;
313}
314
315ScriptExecutable* ScriptExecutable::createFromSharedObject(
316    void* sharedObj, uint32_t expectedChecksum) {
317    char line[MAXLINE];
318
319    size_t varCount = 0;
320    size_t funcCount = 0;
321    size_t forEachCount = 0;
322    size_t reduceCount = 0;
323    size_t objectSlotCount = 0;
324    size_t pragmaCount = 0;
325    bool isThreadable = true;
326
327    void** fieldAddress = nullptr;
328    bool* fieldIsObject = nullptr;
329    char** fieldName = nullptr;
330    InvokeFunc_t* invokeFunctions = nullptr;
331    ForEachFunc_t* forEachFunctions = nullptr;
332    uint32_t* forEachSignatures = nullptr;
333    ReduceDescription* reduceDescriptions = nullptr;
334    const char ** pragmaKeys = nullptr;
335    const char ** pragmaValues = nullptr;
336    uint32_t checksum = 0;
337
338    const char *rsInfo = (const char *) dlsym(sharedObj, kRsInfo);
339    int numEntries = 0;
340    const int *rsGlobalEntries = (const int *) dlsym(sharedObj, kRsGlobalEntries);
341    const char **rsGlobalNames = (const char **) dlsym(sharedObj, kRsGlobalNames);
342    const void **rsGlobalAddresses = (const void **) dlsym(sharedObj, kRsGlobalAddresses);
343    const size_t *rsGlobalSizes = (const size_t *) dlsym(sharedObj, kRsGlobalSizes);
344    const uint32_t *rsGlobalProperties = (const uint32_t *) dlsym(sharedObj, kRsGlobalProperties);
345
346    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
347        return nullptr;
348    }
349    if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
350        ALOGE("Invalid export var count!: %s", line);
351        return nullptr;
352    }
353
354    fieldAddress = new void*[varCount];
355    if (fieldAddress == nullptr) {
356        return nullptr;
357    }
358
359    fieldIsObject = new bool[varCount];
360    if (fieldIsObject == nullptr) {
361        goto error;
362    }
363
364    fieldName = new char*[varCount];
365    if (fieldName == nullptr) {
366        goto error;
367    }
368
369    for (size_t i = 0; i < varCount; ++i) {
370        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
371            goto error;
372        }
373        char *c = strrchr(line, '\n');
374        if (c) {
375            *c = '\0';
376        }
377        void* addr = dlsym(sharedObj, line);
378        if (addr == nullptr) {
379            ALOGE("Failed to find variable address for %s: %s",
380                  line, dlerror());
381            // Not a critical error if we don't find a global variable.
382        }
383        fieldAddress[i] = addr;
384        fieldIsObject[i] = false;
385        fieldName[i] = duplicateString(line, sizeof(line));
386    }
387
388    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
389        goto error;
390    }
391    if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
392        ALOGE("Invalid export func count!: %s", line);
393        goto error;
394    }
395
396    invokeFunctions = new InvokeFunc_t[funcCount];
397    if (invokeFunctions == nullptr) {
398        goto error;
399    }
400
401    for (size_t i = 0; i < funcCount; ++i) {
402        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
403            goto error;
404        }
405        char *c = strrchr(line, '\n');
406        if (c) {
407            *c = '\0';
408        }
409
410        invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line);
411        if (invokeFunctions[i] == nullptr) {
412            ALOGE("Failed to get function address for %s(): %s",
413                  line, dlerror());
414            goto error;
415        }
416    }
417
418    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
419        goto error;
420    }
421    if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
422        ALOGE("Invalid export forEach count!: %s", line);
423        goto error;
424    }
425
426    forEachFunctions = new ForEachFunc_t[forEachCount];
427    if (forEachFunctions == nullptr) {
428        goto error;
429    }
430
431    forEachSignatures = new uint32_t[forEachCount];
432    if (forEachSignatures == nullptr) {
433        goto error;
434    }
435
436    for (size_t i = 0; i < forEachCount; ++i) {
437        unsigned int tmpSig = 0;
438        char tmpName[MAXLINE];
439
440        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
441            goto error;
442        }
443        if (sscanf(line, "%u - %" MAKE_STR(MAXLINESTR) "s",
444                   &tmpSig, tmpName) != 2) {
445          ALOGE("Invalid export forEach!: %s", line);
446          goto error;
447        }
448
449        // Lookup the expanded ForEach kernel.
450        strncat(tmpName, ".expand", MAXLINESTR-strlen(tmpName));
451        forEachSignatures[i] = tmpSig;
452        forEachFunctions[i] =
453            (ForEachFunc_t) dlsym(sharedObj, tmpName);
454        if (i != 0 && forEachFunctions[i] == nullptr &&
455            strcmp(tmpName, "root.expand")) {
456            // Ignore missing root.expand functions.
457            // root() is always specified at location 0.
458            ALOGE("Failed to find forEach function address for %s(): %s",
459                  tmpName, dlerror());
460            goto error;
461        }
462    }
463
464    // Read general reduce kernels
465    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
466        goto error;
467    }
468    if (sscanf(line, EXPORT_REDUCE_STR "%zu", &reduceCount) != 1) {
469        ALOGE("Invalid export reduce new count!: %s", line);
470        goto error;
471    }
472
473    reduceDescriptions = new ReduceDescription[reduceCount];
474    if (reduceDescriptions == nullptr) {
475        goto error;
476    }
477
478    for (size_t i = 0; i < reduceCount; ++i) {
479        static const char kNoName[] = ".";
480
481        unsigned int tmpSig = 0;
482        size_t tmpSize = 0;
483        char tmpNameReduce[MAXLINE];
484        char tmpNameInitializer[MAXLINE];
485        char tmpNameAccumulator[MAXLINE];
486        char tmpNameCombiner[MAXLINE];
487        char tmpNameOutConverter[MAXLINE];
488        char tmpNameHalter[MAXLINE];
489
490        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
491            goto error;
492        }
493#define DELIMNAME " - %" MAKE_STR(MAXLINESTR) "s"
494        if (sscanf(line, "%u - %zu" DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME,
495                   &tmpSig, &tmpSize, tmpNameReduce, tmpNameInitializer, tmpNameAccumulator,
496                   tmpNameCombiner, tmpNameOutConverter, tmpNameHalter) != 8) {
497            ALOGE("Invalid export reduce new!: %s", line);
498            goto error;
499        }
500#undef DELIMNAME
501
502        // For now, we expect
503        // - Reduce and Accumulator names
504        // - optional Initializer, Combiner, and OutConverter name
505        // - no Halter name
506        if (!strcmp(tmpNameReduce, kNoName) ||
507            !strcmp(tmpNameAccumulator, kNoName)) {
508            ALOGE("Expected reduce and accumulator names!: %s", line);
509            goto error;
510        }
511        if (strcmp(tmpNameHalter, kNoName)) {
512            ALOGE("Did not expect halter name!: %s", line);
513            goto error;
514        }
515
516        // The current implementation does not use the signature
517        // or reduce name.
518
519        reduceDescriptions[i].accumSize = tmpSize;
520
521        // Process the (optional) initializer.
522        if (strcmp(tmpNameInitializer, kNoName)) {
523          // Lookup the original user-written initializer.
524          if (!(reduceDescriptions[i].initFunc =
525                (ReduceInitializerFunc_t) dlsym(sharedObj, tmpNameInitializer))) {
526            ALOGE("Failed to find initializer function address for %s(): %s",
527                  tmpNameInitializer, dlerror());
528            goto error;
529          }
530        } else {
531          reduceDescriptions[i].initFunc = nullptr;
532        }
533
534        // Lookup the expanded accumulator.
535        strncat(tmpNameAccumulator, ".expand", MAXLINESTR-strlen(tmpNameAccumulator));
536        if (!(reduceDescriptions[i].accumFunc =
537              (ReduceAccumulatorFunc_t) dlsym(sharedObj, tmpNameAccumulator))) {
538            ALOGE("Failed to find accumulator function address for %s(): %s",
539                  tmpNameAccumulator, dlerror());
540            goto error;
541        }
542
543        // Process the (optional) combiner.
544        if (strcmp(tmpNameCombiner, kNoName)) {
545          // Lookup the original user-written combiner.
546          if (!(reduceDescriptions[i].combFunc =
547                (ReduceCombinerFunc_t) dlsym(sharedObj, tmpNameCombiner))) {
548            ALOGE("Failed to find combiner function address for %s(): %s",
549                  tmpNameCombiner, dlerror());
550            goto error;
551          }
552        } else {
553          reduceDescriptions[i].combFunc = nullptr;
554        }
555
556        // Process the (optional) outconverter.
557        if (strcmp(tmpNameOutConverter, kNoName)) {
558          // Lookup the original user-written outconverter.
559          if (!(reduceDescriptions[i].outFunc =
560                (ReduceOutConverterFunc_t) dlsym(sharedObj, tmpNameOutConverter))) {
561            ALOGE("Failed to find outconverter function address for %s(): %s",
562                  tmpNameOutConverter, dlerror());
563            goto error;
564          }
565        } else {
566          reduceDescriptions[i].outFunc = nullptr;
567        }
568    }
569
570    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
571        goto error;
572    }
573    if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
574        ALOGE("Invalid object slot count!: %s", line);
575        goto error;
576    }
577
578    for (size_t i = 0; i < objectSlotCount; ++i) {
579        uint32_t varNum = 0;
580        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
581            goto error;
582        }
583        if (sscanf(line, "%u", &varNum) != 1) {
584            ALOGE("Invalid object slot!: %s", line);
585            goto error;
586        }
587
588        if (varNum < varCount) {
589            fieldIsObject[varNum] = true;
590        }
591    }
592
593#ifndef RS_COMPATIBILITY_LIB
594    // Do not attempt to read pragmas or isThreadable flag in compat lib path.
595    // Neither is applicable for compat lib
596
597    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
598        goto error;
599    }
600
601    if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) {
602        ALOGE("Invalid pragma count!: %s", line);
603        goto error;
604    }
605
606    pragmaKeys = new const char*[pragmaCount];
607    if (pragmaKeys == nullptr) {
608        goto error;
609    }
610
611    pragmaValues = new const char*[pragmaCount];
612    if (pragmaValues == nullptr) {
613        goto error;
614    }
615
616    bzero(pragmaKeys, sizeof(char*) * pragmaCount);
617    bzero(pragmaValues, sizeof(char*) * pragmaCount);
618
619    for (size_t i = 0; i < pragmaCount; ++i) {
620        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
621            ALOGE("Unable to read pragma at index %zu!", i);
622            goto error;
623        }
624        char key[MAXLINE];
625        char value[MAXLINE] = ""; // initialize in case value is empty
626
627        // pragmas can just have a key and no value.  Only check to make sure
628        // that the key is not empty
629        if (sscanf(line, "%" MAKE_STR(MAXLINESTR) "s - %" MAKE_STR(MAXLINESTR) "s",
630                   key, value) == 0 ||
631            strlen(key) == 0)
632        {
633            ALOGE("Invalid pragma value!: %s", line);
634
635            goto error;
636        }
637
638        pragmaKeys[i] = duplicateString(key, sizeof(key));
639        pragmaValues[i] = duplicateString(value, sizeof(value));
640        //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue);
641    }
642
643    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
644        goto error;
645    }
646
647    char tmpFlag[4];
648    if (sscanf(line, THREADABLE_STR "%3s", tmpFlag) != 1) {
649        ALOGE("Invalid threadable flag!: %s", line);
650        goto error;
651    }
652    if (strcmp(tmpFlag, "yes") == 0) {
653        isThreadable = true;
654    } else if (strcmp(tmpFlag, "no") == 0) {
655        isThreadable = false;
656    } else {
657        ALOGE("Invalid threadable flag!: %s", tmpFlag);
658        goto error;
659    }
660
661    if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
662        if (sscanf(line, CHECKSUM_STR "%08x", &checksum) != 1) {
663            ALOGE("Invalid checksum flag!: %s", line);
664            goto error;
665        }
666    } else {
667        ALOGE("Missing checksum in shared obj file");
668        goto error;
669    }
670
671    if (expectedChecksum != 0 && checksum != expectedChecksum) {
672        ALOGE("Found invalid checksum.  Expected %08x, got %08x\n",
673              expectedChecksum, checksum);
674        goto error;
675    }
676
677    {
678      // Parse the version info string, but ignore its contents as it's only
679      // used by the debugger
680      size_t nLines = 0;
681      if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
682        if (sscanf(line, VERSIONINFO_STR "%zu", &nLines) != 1) {
683          ALOGE("invalid versionInfo count");
684          goto error;
685        } else {
686          // skip the versionInfo packet as libRs doesn't use it
687          while (nLines--) {
688            if (strgets(line, MAXLINE, &rsInfo) == nullptr)
689              goto error;
690          }
691        }
692      } else {
693        ALOGE(".rs.info is missing versionInfo section");
694      }
695    }
696
697#endif  // RS_COMPATIBILITY_LIB
698
699    // Read in information about mutable global variables provided by bcc's
700    // RSGlobalInfoPass
701    if (rsGlobalEntries) {
702        numEntries = *rsGlobalEntries;
703        if (numEntries > 0) {
704            rsAssert(rsGlobalNames);
705            rsAssert(rsGlobalAddresses);
706            rsAssert(rsGlobalSizes);
707            rsAssert(rsGlobalProperties);
708        }
709    }
710
711    return new ScriptExecutable(
712        fieldAddress, fieldIsObject, fieldName, varCount,
713        invokeFunctions, funcCount,
714        forEachFunctions, forEachSignatures, forEachCount,
715        reduceDescriptions, reduceCount,
716        pragmaKeys, pragmaValues, pragmaCount,
717        rsGlobalNames, rsGlobalAddresses, rsGlobalSizes, rsGlobalProperties,
718        numEntries, isThreadable, checksum);
719
720error:
721
722#ifndef RS_COMPATIBILITY_LIB
723
724    if (pragmaKeys) {
725        for (size_t idx = 0; idx < pragmaCount; ++idx) {
726            delete [] pragmaKeys[idx];
727        }
728    }
729
730    if (pragmaValues) {
731        for (size_t idx = 0; idx < pragmaCount; ++idx) {
732            delete [] pragmaValues[idx];
733        }
734    }
735
736    delete[] pragmaValues;
737    delete[] pragmaKeys;
738#endif  // RS_COMPATIBILITY_LIB
739
740    delete[] reduceDescriptions;
741
742    delete[] forEachSignatures;
743    delete[] forEachFunctions;
744
745    delete[] invokeFunctions;
746
747    for (size_t i = 0; i < varCount; i++) {
748        delete[] fieldName[i];
749    }
750    delete[] fieldName;
751    delete[] fieldIsObject;
752    delete[] fieldAddress;
753
754    return nullptr;
755}
756
757void* ScriptExecutable::getFieldAddress(const char* name) const {
758    // TODO: improve this by using a hash map.
759    for (size_t i = 0; i < mExportedVarCount; i++) {
760        if (strcmp(name, mFieldName[i]) == 0) {
761            return mFieldAddress[i];
762        }
763    }
764    return nullptr;
765}
766
767bool ScriptExecutable::dumpGlobalInfo() const {
768    ALOGE("Globals: %p %p %p", mGlobalAddresses, mGlobalSizes, mGlobalNames);
769    ALOGE("P   - Pointer");
770    ALOGE(" C  - Constant");
771    ALOGE("  S - Static");
772    for (int i = 0; i < mGlobalEntries; i++) {
773        ALOGE("Global[%d]: %p %zu %s", i, mGlobalAddresses[i], mGlobalSizes[i],
774              mGlobalNames[i]);
775        uint32_t properties = mGlobalProperties[i];
776        ALOGE("%c%c%c Type: %u",
777              isGlobalPointer(properties)  ? 'P' : ' ',
778              isGlobalConstant(properties) ? 'C' : ' ',
779              isGlobalStatic(properties)   ? 'S' : ' ',
780              getGlobalRsType(properties));
781    }
782    return true;
783}
784
785}  // namespace renderscript
786}  // namespace android
787