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