1 /*
2 * copyright 2010-2012, the android open source project
3 *
4 * licensed under the apache license, version 2.0 (the "license");
5 * you may not use this file except in compliance with the license.
6 * you may obtain a copy of the license at
7 *
8 * http://www.apache.org/licenses/license-2.0
9 *
10 * unless required by applicable law or agreed to in writing, software
11 * distributed under the license is distributed on an "as is" basis,
12 * without warranties or conditions of any kind, either express or implied.
13 * see the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 #include "Script.h"
18
19 #include "Config.h"
20 #include "bcinfo/BitcodeWrapper.h"
21
22 #include "MCCacheReader.h"
23 #include "MCCacheWriter.h"
24 #include "CompilerOption.h"
25
26 #include "DebugHelper.h"
27 #include "FileHandle.h"
28 #include "GDBJITRegistrar.h"
29 #include "ScriptCompiled.h"
30 #include "ScriptCached.h"
31 #include "Sha1Helper.h"
32 #include "SourceInfo.h"
33
34 #include <errno.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38
39 #include <new>
40 #include <string.h>
41 #include <cutils/properties.h>
42
43 namespace {
44
getBooleanProp(const char * str)45 bool getBooleanProp(const char *str) {
46 char buf[PROPERTY_VALUE_MAX];
47 property_get(str, buf, "0");
48 return strcmp(buf, "0") != 0;
49 }
50
51 } // namespace anonymous
52
53 namespace bcc {
54
~Script()55 Script::~Script() {
56 switch (mStatus) {
57 case ScriptStatus::Compiled:
58 delete mCompiled;
59 break;
60
61 case ScriptStatus::Cached:
62 delete mCached;
63 break;
64
65 default:
66 break;
67 }
68
69 for (size_t i = 0; i < 2; ++i) {
70 delete mSourceList[i];
71 }
72 }
73
74
addSourceBC(size_t idx,char const * resName,const char * bitcode,size_t bitcodeSize,unsigned long flags)75 int Script::addSourceBC(size_t idx,
76 char const *resName,
77 const char *bitcode,
78 size_t bitcodeSize,
79 unsigned long flags) {
80
81 if (!resName) {
82 mErrorCode = BCC_INVALID_VALUE;
83 ALOGE("Invalid argument: resName = NULL\n");
84 return 1;
85 }
86
87 if (mStatus != ScriptStatus::Unknown) {
88 mErrorCode = BCC_INVALID_OPERATION;
89 ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
90 return 1;
91 }
92
93 if (!bitcode) {
94 mErrorCode = BCC_INVALID_VALUE;
95 ALOGE("Invalid argument: bitcode = NULL\n");
96 return 1;
97 }
98
99 bcinfo::BitcodeWrapper wrapper(bitcode, bitcodeSize);
100
101 mSourceList[idx] = SourceInfo::createFromBuffer(resName,
102 bitcode, bitcodeSize,
103 flags);
104
105 if (!mSourceList[idx]) {
106 mErrorCode = BCC_OUT_OF_MEMORY;
107 ALOGE("Out of memory while adding source bitcode\n");
108 return 1;
109 }
110
111 return 0;
112 }
113
114
addSourceModule(size_t idx,llvm::Module * module,unsigned long flags)115 int Script::addSourceModule(size_t idx,
116 llvm::Module *module,
117 unsigned long flags) {
118 if (mStatus != ScriptStatus::Unknown) {
119 mErrorCode = BCC_INVALID_OPERATION;
120 ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
121 return 1;
122 }
123
124 if (!module) {
125 mErrorCode = BCC_INVALID_VALUE;
126 ALOGE("Invalid argument: module = NULL\n");
127 return 1;
128 }
129
130 mSourceList[idx] = SourceInfo::createFromModule(module, flags);
131
132 if (!mSourceList[idx]) {
133 mErrorCode = BCC_OUT_OF_MEMORY;
134 ALOGE("Out of memory when add source module\n");
135 return 1;
136 }
137
138 return 0;
139 }
140
141
addSourceFile(size_t idx,char const * path,unsigned long flags)142 int Script::addSourceFile(size_t idx,
143 char const *path,
144 unsigned long flags) {
145 if (mStatus != ScriptStatus::Unknown) {
146 mErrorCode = BCC_INVALID_OPERATION;
147 ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
148 return 1;
149 }
150
151 if (!path) {
152 mErrorCode = BCC_INVALID_VALUE;
153 ALOGE("Invalid argument: path = NULL\n");
154 return 1;
155 }
156
157 struct stat sb;
158 if (stat(path, &sb) != 0) {
159 mErrorCode = BCC_INVALID_VALUE;
160 ALOGE("File not found: %s\n", path);
161 return 1;
162 }
163
164 mSourceList[idx] = SourceInfo::createFromFile(path, flags);
165
166 if (!mSourceList[idx]) {
167 mErrorCode = BCC_OUT_OF_MEMORY;
168 ALOGE("Out of memory while adding source file\n");
169 return 1;
170 }
171
172 return 0;
173 }
174
prepareRelocatable(char const * objPath,llvm::Reloc::Model RelocModel,unsigned long flags)175 int Script::prepareRelocatable(char const *objPath,
176 llvm::Reloc::Model RelocModel,
177 unsigned long flags) {
178 CompilerOption option;
179 option.RelocModelOpt = RelocModel;
180 option.LoadAfterCompile = false;
181
182 int status = internalCompile(option);
183 if (status != 0) {
184 ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
185 return status;
186 }
187
188 FileHandle objFile;
189 if (objFile.open(objPath, OpenMode::Write) < 0) {
190 ALOGE("Failed to open %s for write.\n", objPath);
191 return 1;
192 }
193
194 if (static_cast<size_t>(objFile.write(getELF(),
195 getELFSize())) != getELFSize()) {
196 objFile.close();
197 ::unlink(objPath);
198 ALOGE("Unable to write ELF to file %s.\n", objPath);
199 return false;
200 }
201
202 mObjectType = ScriptObject::Relocatable;
203
204 return 0;
205 }
206
207
prepareSharedObject(char const * objPath,char const * dsoPath,unsigned long flags)208 int Script::prepareSharedObject(char const *objPath,
209 char const *dsoPath,
210 unsigned long flags) {
211 // TODO: Support cached shared object.
212 return 1;
213 }
214
215
prepareExecutable(char const * cacheDir,char const * cacheName,unsigned long flags)216 int Script::prepareExecutable(char const *cacheDir,
217 char const *cacheName,
218 unsigned long flags) {
219 if (mStatus != ScriptStatus::Unknown) {
220 mErrorCode = BCC_INVALID_OPERATION;
221 ALOGE("Invalid operation: %s\n", __func__);
222 return 1;
223 }
224
225 int status = internalLoadCache(cacheDir, cacheName, /* checkOnly */ false);
226
227 if (status != 0) {
228 CompilerOption option;
229 status = internalCompile(option);
230
231 if (status != 0) {
232 ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
233 return status;
234 }
235
236 status = writeCache();
237 if (status != 0) {
238 ALOGE("Failed to write the cache for %s\n", cacheName);
239 return status;
240 }
241 }
242
243 // FIXME: Registration can be conditional on the presence of debug metadata
244 registerObjectWithGDB(getELF(), getELFSize()); // thread-safe registration
245
246 mObjectType = ScriptObject::Executable;
247
248 return status;
249 }
250
internalLoadCache(char const * cacheDir,char const * cacheName,bool checkOnly)251 int Script::internalLoadCache(char const *cacheDir, char const *cacheName,
252 bool checkOnly) {
253 if ((cacheDir == NULL) || (cacheName == NULL)) {
254 return 1;
255 }
256
257 // Set cache file Name
258 mCacheName = cacheName;
259
260 // Santize mCacheDir. Ensure that mCacheDir ends with '/'.
261 mCacheDir = cacheDir;
262 if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
263 mCacheDir.push_back('/');
264 }
265
266 if (!isCacheable()) {
267 return 1;
268 }
269
270 std::string objPath = getCachedObjectPath();
271 std::string infoPath = getCacheInfoPath();
272
273 FileHandle objFile;
274 if (objFile.open(objPath.c_str(), OpenMode::Read) < 0) {
275 // Unable to open the executable file in read mode.
276 return 1;
277 }
278
279 FileHandle infoFile;
280 if (infoFile.open(infoPath.c_str(), OpenMode::Read) < 0) {
281 // Unable to open the metadata information file in read mode.
282 return 1;
283 }
284
285 MCCacheReader reader;
286
287 // Register symbol lookup function
288 if (mpExtSymbolLookupFn) {
289 reader.registerSymbolCallback(mpExtSymbolLookupFn,
290 mpExtSymbolLookupFnContext);
291 }
292
293 // Dependencies
294 reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
295 reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
296
297 for (size_t i = 0; i < 2; ++i) {
298 if (mSourceList[i]) {
299 mSourceList[i]->introDependency(reader);
300 }
301 }
302
303 if (checkOnly)
304 return !reader.checkCacheFile(&objFile, &infoFile, this);
305
306 // Read cache file
307 ScriptCached *cached = reader.readCacheFile(&objFile, &infoFile, this);
308
309 if (!cached) {
310 mIsContextSlotNotAvail = reader.isContextSlotNotAvail();
311 return 1;
312 }
313
314 mCached = cached;
315 mStatus = ScriptStatus::Cached;
316
317 // Dirty hack for libRS.
318 // TODO(all): This dirty hack should be removed in the future.
319 if (!cached->isLibRSThreadable() && mpExtSymbolLookupFn) {
320 mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable");
321 }
322
323 return 0;
324 }
325
internalCompile(const CompilerOption & option)326 int Script::internalCompile(const CompilerOption &option) {
327 // Create the ScriptCompiled object
328 mCompiled = new (std::nothrow) ScriptCompiled(this);
329
330 if (!mCompiled) {
331 mErrorCode = BCC_OUT_OF_MEMORY;
332 ALOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
333 return 1;
334 }
335
336 mStatus = ScriptStatus::Compiled;
337
338 // Register symbol lookup function
339 if (mpExtSymbolLookupFn) {
340 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
341 mpExtSymbolLookupFnContext);
342 }
343
344 if (!mSourceList[0]) {
345 ALOGE("Source bitcode is not set.\n");
346 return 1;
347 }
348
349 // Parse Source bitcode file (if necessary)
350 if (mSourceList[0]->prepareModule() != 0) {
351 ALOGE("Unable to setup source module\n");
352 return 1;
353 }
354
355 // Parse Library bitcode file (if necessary)
356 if (mSourceList[1]) {
357 if (mSourceList[1]->prepareModule(mSourceList[0]->getContext()) != 0) {
358 ALOGE("Unable to setup library module\n");
359 return 1;
360 }
361 }
362
363 // Set the main source module
364 if (mCompiled->readModule(mSourceList[0]->getModule()) != 0) {
365 ALOGE("Unable to read source module\n");
366 return 1;
367 }
368
369 // Link the source module with the library module
370 if (mSourceList[1]) {
371 if (mCompiled->linkModule(mSourceList[1]->getModule()) != 0) {
372 ALOGE("Unable to link library module\n");
373 return 1;
374 }
375 }
376
377 // Compile and JIT the code
378 if (mCompiled->compile(option) != 0) {
379 ALOGE("Unable to compile.\n");
380 return 1;
381 }
382
383 return 0;
384 }
385
writeCache()386 int Script::writeCache() {
387 // Not compiled script or encountered error during the compilation.
388 if ((mStatus != ScriptStatus::Compiled) ||
389 (getCompilerErrorMessage() == NULL))
390 return 1;
391
392 // Note: If we re-compile the script because the cached context slot not
393 // available, then we don't have to write the cache.
394
395 // Note: If the address of the context is not in the context slot, then
396 // we don't have to cache it.
397
398 if (isCacheable()) {
399
400 std::string objPath = getCachedObjectPath();
401 std::string infoPath = getCacheInfoPath();
402
403 // Remove the file if it already exists before writing the new file.
404 // The old file may still be mapped elsewhere in memory and we do not want
405 // to modify its contents. (The same script may be running concurrently in
406 // the same process or a different process!)
407 ::unlink(objPath.c_str());
408 ::unlink(infoPath.c_str());
409
410 FileHandle objFile;
411 FileHandle infoFile;
412
413 if (objFile.open(objPath.c_str(), OpenMode::Write) >= 0 &&
414 infoFile.open(infoPath.c_str(), OpenMode::Write) >= 0) {
415
416 MCCacheWriter writer;
417
418 #ifdef TARGET_BUILD
419 // Dependencies
420 writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
421 writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
422 #endif
423
424 for (size_t i = 0; i < 2; ++i) {
425 if (mSourceList[i]) {
426 mSourceList[i]->introDependency(writer);
427 }
428 }
429
430 // libRS is threadable dirty hack
431 // TODO: This should be removed in the future
432 uint32_t libRS_threadable = 0;
433 if (mpExtSymbolLookupFn) {
434 libRS_threadable =
435 (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
436 "__isThreadable");
437 }
438
439 if (!writer.writeCacheFile(&objFile, &infoFile, this, libRS_threadable)) {
440 objFile.truncate();
441 objFile.close();
442
443 if (unlink(objPath.c_str()) != 0) {
444 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
445 objPath.c_str(), strerror(errno));
446 }
447
448 infoFile.truncate();
449 infoFile.close();
450
451 if (unlink(infoPath.c_str()) != 0) {
452 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
453 infoPath.c_str(), strerror(errno));
454 }
455 }
456 }
457 }
458
459 return 0;
460 }
461
462
getCompilerErrorMessage()463 char const *Script::getCompilerErrorMessage() {
464 if (mStatus != ScriptStatus::Compiled) {
465 mErrorCode = BCC_INVALID_OPERATION;
466 return NULL;
467 }
468
469 return mCompiled->getCompilerErrorMessage();
470 }
471
472
lookup(const char * name)473 void *Script::lookup(const char *name) {
474 switch (mStatus) {
475 case ScriptStatus::Compiled: {
476 return mCompiled->lookup(name);
477 }
478
479 case ScriptStatus::Cached: {
480 return mCached->lookup(name);
481 }
482
483 default: {
484 mErrorCode = BCC_INVALID_OPERATION;
485 return NULL;
486 }
487 }
488 }
489
490
getExportVarCount() const491 size_t Script::getExportVarCount() const {
492 switch (mStatus) {
493 case ScriptStatus::Compiled: {
494 return mCompiled->getExportVarCount();
495 }
496
497 case ScriptStatus::Cached: {
498 return mCached->getExportVarCount();
499 }
500
501 default: {
502 return 0;
503 }
504 }
505 }
506
507
getExportFuncCount() const508 size_t Script::getExportFuncCount() const {
509 switch (mStatus) {
510 case ScriptStatus::Compiled: {
511 return mCompiled->getExportFuncCount();
512 }
513
514 case ScriptStatus::Cached: {
515 return mCached->getExportFuncCount();
516 }
517
518 default: {
519 return 0;
520 }
521 }
522 }
523
524
getExportForEachCount() const525 size_t Script::getExportForEachCount() const {
526 switch (mStatus) {
527 case ScriptStatus::Compiled: {
528 return mCompiled->getExportForEachCount();
529 }
530
531 case ScriptStatus::Cached: {
532 return mCached->getExportForEachCount();
533 }
534
535 default: {
536 return 0;
537 }
538 }
539 }
540
541
getPragmaCount() const542 size_t Script::getPragmaCount() const {
543 switch (mStatus) {
544 case ScriptStatus::Compiled: {
545 return mCompiled->getPragmaCount();
546 }
547
548 case ScriptStatus::Cached: {
549 return mCached->getPragmaCount();
550 }
551
552 default: {
553 return 0;
554 }
555 }
556 }
557
558
getFuncCount() const559 size_t Script::getFuncCount() const {
560 switch (mStatus) {
561 case ScriptStatus::Compiled: {
562 return mCompiled->getFuncCount();
563 }
564
565 case ScriptStatus::Cached: {
566 return mCached->getFuncCount();
567 }
568
569 default: {
570 return 0;
571 }
572 }
573 }
574
575
getObjectSlotCount() const576 size_t Script::getObjectSlotCount() const {
577 switch (mStatus) {
578 case ScriptStatus::Compiled: {
579 return mCompiled->getObjectSlotCount();
580 }
581
582 case ScriptStatus::Cached: {
583 return mCached->getObjectSlotCount();
584 }
585
586 default: {
587 return 0;
588 }
589 }
590 }
591
592
getExportVarList(size_t varListSize,void ** varList)593 void Script::getExportVarList(size_t varListSize, void **varList) {
594 switch (mStatus) {
595 #define DELEGATE(STATUS) \
596 case ScriptStatus::STATUS: \
597 m##STATUS->getExportVarList(varListSize, varList); \
598 break;
599
600 DELEGATE(Cached);
601
602 DELEGATE(Compiled);
603 #undef DELEGATE
604
605 default: {
606 mErrorCode = BCC_INVALID_OPERATION;
607 }
608 }
609 }
610
getExportVarNameList(std::vector<std::string> & varList)611 void Script::getExportVarNameList(std::vector<std::string> &varList) {
612 switch (mStatus) {
613 case ScriptStatus::Compiled: {
614 return mCompiled->getExportVarNameList(varList);
615 }
616
617 default: {
618 mErrorCode = BCC_INVALID_OPERATION;
619 }
620 }
621 }
622
623
getExportFuncList(size_t funcListSize,void ** funcList)624 void Script::getExportFuncList(size_t funcListSize, void **funcList) {
625 switch (mStatus) {
626 #define DELEGATE(STATUS) \
627 case ScriptStatus::STATUS: \
628 m##STATUS->getExportFuncList(funcListSize, funcList); \
629 break;
630
631 DELEGATE(Cached);
632
633 DELEGATE(Compiled);
634 #undef DELEGATE
635
636 default: {
637 mErrorCode = BCC_INVALID_OPERATION;
638 }
639 }
640 }
641
getExportFuncNameList(std::vector<std::string> & funcList)642 void Script::getExportFuncNameList(std::vector<std::string> &funcList) {
643 switch (mStatus) {
644 case ScriptStatus::Compiled: {
645 return mCompiled->getExportFuncNameList(funcList);
646 }
647
648 default: {
649 mErrorCode = BCC_INVALID_OPERATION;
650 }
651 }
652 }
653
getExportForEachList(size_t funcListSize,void ** funcList)654 void Script::getExportForEachList(size_t funcListSize, void **funcList) {
655 switch (mStatus) {
656 #define DELEGATE(STATUS) \
657 case ScriptStatus::STATUS: \
658 m##STATUS->getExportForEachList(funcListSize, funcList); \
659 break;
660
661 DELEGATE(Cached);
662
663 DELEGATE(Compiled);
664 #undef DELEGATE
665
666 default: {
667 mErrorCode = BCC_INVALID_OPERATION;
668 }
669 }
670 }
671
getExportForEachNameList(std::vector<std::string> & forEachList)672 void Script::getExportForEachNameList(std::vector<std::string> &forEachList) {
673 switch (mStatus) {
674 case ScriptStatus::Compiled: {
675 return mCompiled->getExportForEachNameList(forEachList);
676 }
677
678 default: {
679 mErrorCode = BCC_INVALID_OPERATION;
680 }
681 }
682 }
683
getPragmaList(size_t pragmaListSize,char const ** keyList,char const ** valueList)684 void Script::getPragmaList(size_t pragmaListSize,
685 char const **keyList,
686 char const **valueList) {
687 switch (mStatus) {
688 #define DELEGATE(STATUS) \
689 case ScriptStatus::STATUS: \
690 m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
691 break;
692
693 DELEGATE(Cached);
694
695 DELEGATE(Compiled);
696 #undef DELEGATE
697
698 default: {
699 mErrorCode = BCC_INVALID_OPERATION;
700 }
701 }
702 }
703
704
getFuncInfoList(size_t funcInfoListSize,FuncInfo * funcInfoList)705 void Script::getFuncInfoList(size_t funcInfoListSize,
706 FuncInfo *funcInfoList) {
707 switch (mStatus) {
708 #define DELEGATE(STATUS) \
709 case ScriptStatus::STATUS: \
710 m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
711 break;
712
713 DELEGATE(Cached);
714
715 DELEGATE(Compiled);
716 #undef DELEGATE
717
718 default: {
719 mErrorCode = BCC_INVALID_OPERATION;
720 }
721 }
722 }
723
724
getObjectSlotList(size_t objectSlotListSize,uint32_t * objectSlotList)725 void Script::getObjectSlotList(size_t objectSlotListSize,
726 uint32_t *objectSlotList) {
727 switch (mStatus) {
728 #define DELEGATE(STATUS) \
729 case ScriptStatus::STATUS: \
730 m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
731 break;
732
733 DELEGATE(Cached);
734
735 DELEGATE(Compiled);
736 #undef DELEGATE
737
738 default: {
739 mErrorCode = BCC_INVALID_OPERATION;
740 }
741 }
742 }
743
744
registerSymbolCallback(BCCSymbolLookupFn pFn,void * pContext)745 int Script::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
746 mpExtSymbolLookupFn = pFn;
747 mpExtSymbolLookupFnContext = pContext;
748
749 if (mStatus != ScriptStatus::Unknown) {
750 mErrorCode = BCC_INVALID_OPERATION;
751 ALOGE("Invalid operation: %s\n", __func__);
752 return 1;
753 }
754 return 0;
755 }
756
isCacheable() const757 bool Script::isCacheable() const {
758 if (getBooleanProp("debug.bcc.nocache")) {
759 // Android system environment property: Disables the cache mechanism by
760 // setting "debug.bcc.nocache". So we will not load the cache file any
761 // way.
762 return false;
763 }
764
765 if (mCacheDir.empty() || mCacheName.empty()) {
766 // The application developer has not specified the cachePath, so
767 // we don't know where to open the cache file.
768 return false;
769 }
770
771 return true;
772 }
773
getELFSize() const774 size_t Script::getELFSize() const {
775 switch (mStatus) {
776 case ScriptStatus::Compiled: {
777 return mCompiled->getELFSize();
778 }
779
780 case ScriptStatus::Cached: {
781 return mCached->getELFSize();
782 }
783
784 default: {
785 return 0;
786 }
787 }
788 }
789
getELF() const790 const char *Script::getELF() const {
791 switch (mStatus) {
792 case ScriptStatus::Compiled: {
793 return mCompiled->getELF();
794 }
795
796 case ScriptStatus::Cached: {
797 return mCached->getELF();
798 }
799
800 default: {
801 return NULL;
802 }
803 }
804 }
805
806 } // namespace bcc
807