blob: d223eee34c0f71cc5fecab51a37bda6bdabef97d [file] [log] [blame]
Zonr Chang19218c02012-04-05 10:44:53 +08001/*
2 * Copyright 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
Stephen Hines4a68b1c2012-05-03 12:28:14 -070017#include "Script.h"
Zonr Chang19218c02012-04-05 10:44:53 +080018
Stephen Hines4a68b1c2012-05-03 12:28:14 -070019#include <errno.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <unistd.h>
23
24#include <new>
Stephen Hines7dfc4d82012-05-03 12:25:21 -070025#include <cstring>
26
27#include <llvm/ADT/STLExtras.h>
28
Stephen Hines4a68b1c2012-05-03 12:28:14 -070029#include <cutils/properties.h>
Zonr Chang19218c02012-04-05 10:44:53 +080030
Stephen Hines4a68b1c2012-05-03 12:28:14 -070031#include "Config.h"
32
33#include "MCCacheReader.h"
34#include "MCCacheWriter.h"
35#include "CompilerOption.h"
36
37#include "DebugHelper.h"
38#include "FileMutex.h"
39#include "GDBJITRegistrar.h"
40#include "InputFile.h"
41#include "OutputFile.h"
42#include "ScriptCompiled.h"
43#include "ScriptCached.h"
44#include "Sha1Helper.h"
45#include "Source.h"
46
47namespace {
48
49bool getBooleanProp(const char *str) {
50 char buf[PROPERTY_VALUE_MAX];
51 property_get(str, buf, "0");
52 return strcmp(buf, "0") != 0;
53}
54
55} // namespace anonymous
56
57namespace bcc {
Zonr Chang19218c02012-04-05 10:44:53 +080058
Stephen Hines0f6b1d32012-05-03 12:29:33 -070059RSScript::SourceDependency::SourceDependency(MCO_ResourceType pSourceType,
60 const std::string &pSourceName,
Stephen Hines7dfc4d82012-05-03 12:25:21 -070061 const uint8_t *pSHA1)
Stephen Hines0f6b1d32012-05-03 12:29:33 -070062 : mSourceType(pSourceType), mSourceName(pSourceName) {
Stephen Hines7dfc4d82012-05-03 12:25:21 -070063 ::memcpy(mSHA1, pSHA1, sizeof(mSHA1));
64 return;
65}
66
Zonr Chang19218c02012-04-05 10:44:53 +080067RSScript::RSScript(Source &pSource)
Stephen Hines4a68b1c2012-05-03 12:28:14 -070068 : Script(pSource),
69 mpExtSymbolLookupFn(NULL),
70 mpExtSymbolLookupFnContext(NULL) {
71 resetState();
72 return;
73}
Zonr Chang19218c02012-04-05 10:44:53 +080074
Stephen Hines7dfc4d82012-05-03 12:25:21 -070075RSScript::~RSScript() {
Stephen Hines4a68b1c2012-05-03 12:28:14 -070076 switch (mStatus) {
77 case ScriptStatus::Compiled:
78 delete mCompiled;
79 break;
80
81 case ScriptStatus::Cached:
82 delete mCached;
83 break;
84
85 default:
86 break;
87 }
Stephen Hines7dfc4d82012-05-03 12:25:21 -070088 llvm::DeleteContainerPointers(mSourceDependencies);
89}
90
Stephen Hines4a68b1c2012-05-03 12:28:14 -070091void RSScript::resetState() {
92 mErrorCode = BCC_NO_ERROR;
93 mStatus = ScriptStatus::Unknown;
94 mObjectType = ScriptObject::Unknown;
95 mIsContextSlotNotAvail = false;
96 // FIXME: mpExtSymbolLookupFn and mpExtSymbolLookupFnContext should be assign
97 // to NULL during state resetting.
98 //mpExtSymbolLookupFn = NULL;
99 //mpExtSymbolLookupFnContext = NULL;
Stephen Hines7dfc4d82012-05-03 12:25:21 -0700100 llvm::DeleteContainerPointers(mSourceDependencies);
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700101 return;
102}
103
104bool RSScript::doReset() {
105 resetState();
Stephen Hines7dfc4d82012-05-03 12:25:21 -0700106 return true;
107}
108
Stephen Hines0f6b1d32012-05-03 12:29:33 -0700109bool RSScript::addSourceDependency(MCO_ResourceType pSourceType,
110 const std::string &pSourceName,
Stephen Hines7dfc4d82012-05-03 12:25:21 -0700111 const uint8_t *pSHA1) {
112 SourceDependency *source_dep =
Stephen Hines0f6b1d32012-05-03 12:29:33 -0700113 new (std::nothrow) SourceDependency(pSourceType, pSourceName, pSHA1);
Stephen Hines7dfc4d82012-05-03 12:25:21 -0700114 if (source_dep == NULL) {
115 ALOGE("Out of memory when record dependency information of `%s'!",
116 pSourceName.c_str());
117 return false;
118 }
119
120 mSourceDependencies.push_back(source_dep);
Zonr Chang19218c02012-04-05 10:44:53 +0800121 return true;
122}
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700123
124int RSScript::prepareRelocatable(char const *objPath,
125 llvm::Reloc::Model RelocModel,
126 unsigned long flags) {
127 CompilerOption option;
128 option.RelocModelOpt = RelocModel;
129 option.LoadAfterCompile = false;
130
131 int status = internalCompile(option);
132 if (status != 0) {
133 ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
134 return status;
135 }
136
137 OutputFile objFile(objPath);
138 if (objFile.hasError()) {
139 ALOGE("Failed to open %s for write. (%s)", objPath,
140 objFile.getErrorMessage().c_str());
141 return 1;
142 }
143
144 if (static_cast<size_t>(objFile.write(getELF(),
145 getELFSize())) != getELFSize()) {
146 objFile.close();
147 ::unlink(objPath);
148 ALOGE("Unable to write ELF to file %s.\n", objPath);
149 return false;
150 }
151
152 mObjectType = ScriptObject::Relocatable;
153
154 return 0;
155}
156
157
158int RSScript::prepareSharedObject(char const *objPath,
159 char const *dsoPath,
160 unsigned long flags) {
161 // TODO: Support cached shared object.
162 return 1;
163}
164
165
166int RSScript::prepareExecutable(char const *cacheDir,
167 char const *cacheName,
168 unsigned long flags) {
169 if (mStatus != ScriptStatus::Unknown) {
170 mErrorCode = BCC_INVALID_OPERATION;
171 ALOGE("Invalid operation: %s\n", __func__);
172 return 1;
173 }
174
175 int status = internalLoadCache(cacheDir, cacheName, /* checkOnly */ false);
176
177 if (status != 0) {
178 CompilerOption option;
179 status = internalCompile(option);
180
181 if (status != 0) {
182 ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
183 return status;
184 }
185
186 status = writeCache();
187 if (status != 0) {
188 ALOGE("Failed to write the cache for %s\n", cacheName);
189 return status;
190 }
191 }
192
193 // FIXME: Registration can be conditional on the presence of debug metadata
194 registerObjectWithGDB(getELF(), getELFSize()); // thread-safe registration
195
196 mObjectType = ScriptObject::Executable;
197
198 return status;
199}
200
201int RSScript::internalLoadCache(char const *cacheDir, char const *cacheName,
202 bool checkOnly) {
203 if ((cacheDir == NULL) || (cacheName == NULL)) {
204 return 1;
205 }
206
207 // Set cache file Name
208 mCacheName = cacheName;
209
210 // Santize mCacheDir. Ensure that mCacheDir ends with '/'.
211 mCacheDir = cacheDir;
212 if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
213 mCacheDir.push_back('/');
214 }
215
216 if (!isCacheable()) {
217 return 1;
218 }
219
220 std::string objPath = getCachedObjectPath();
221 std::string infoPath = getCacheInfoPath();
222
223 // Locks for reading object file and info file.
224 FileMutex<FileBase::kReadLock> objFileMutex(objPath);
225 FileMutex<FileBase::kReadLock> infoFileMutex(infoPath);
226
227 // Aquire read lock for object file.
228 if (objFileMutex.hasError() || !objFileMutex.lock()) {
229 ALOGE("Unable to acquire the lock for %s! (%s)", objPath.c_str(),
230 objFileMutex.getErrorMessage().c_str());
231 return 1;
232 }
233
234 // Aquire read lock for info file.
235 if (infoFileMutex.hasError() || !infoFileMutex.lock()) {
236 ALOGE("Unable to acquire the lock for %s! (%s)", infoPath.c_str(),
237 infoFileMutex.getErrorMessage().c_str());
238 return 1;
239 }
240
241 // Open the object file and info file
242 InputFile objFile(objPath);
243 InputFile infoFile(infoPath);
244
245 if (objFile.hasError()) {
246 ALOGE("Unable to open %s for reading! (%s)", objPath.c_str(),
247 objFile.getErrorMessage().c_str());
248 return 1;
249 }
250
251 if (infoFile.hasError()) {
252 ALOGE("Unable to open %s for reading! (%s)", infoPath.c_str(),
253 infoFile.getErrorMessage().c_str());
254 return 1;
255 }
256
257 MCCacheReader reader;
258
259 // Register symbol lookup function
260 if (mpExtSymbolLookupFn) {
261 reader.registerSymbolCallback(mpExtSymbolLookupFn,
262 mpExtSymbolLookupFnContext);
263 }
264
265 // Dependencies
Stephen Hines0f6b1d32012-05-03 12:29:33 -0700266 reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
267 reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700268
269 for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
270 const SourceDependency *source_dep = mSourceDependencies[i];
Stephen Hines0f6b1d32012-05-03 12:29:33 -0700271 reader.addDependency(source_dep->getSourceType(),
272 source_dep->getSourceName(),
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700273 source_dep->getSHA1Checksum());
274 }
275
276 if (checkOnly)
277 return !reader.checkCacheFile(objFile, infoFile, this);
278
279 // Read cache file
280 ScriptCached *cached = reader.readCacheFile(objFile, infoFile, this);
281
282 if (!cached) {
283 mIsContextSlotNotAvail = reader.isContextSlotNotAvail();
284 return 1;
285 }
286
287 mCached = cached;
288 mStatus = ScriptStatus::Cached;
289
290 // Dirty hack for libRS.
291 // TODO(all): This dirty hack should be removed in the future.
292 if (!cached->isLibRSThreadable() && mpExtSymbolLookupFn) {
293 mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable");
294 }
295
296 return 0;
297}
298
299int RSScript::internalCompile(const CompilerOption &option) {
300 // Create the ScriptCompiled object
301 mCompiled = new (std::nothrow) ScriptCompiled(this);
302
303 if (!mCompiled) {
304 mErrorCode = BCC_OUT_OF_MEMORY;
305 ALOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
306 return 1;
307 }
308
309 mStatus = ScriptStatus::Compiled;
310
311 // Register symbol lookup function
312 if (mpExtSymbolLookupFn) {
313 mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
314 mpExtSymbolLookupFnContext);
315 }
316
317 // Set the main source module
318 if (mCompiled->readModule(getSource().getModule()) != 0) {
319 ALOGE("Unable to read source module\n");
320 return 1;
321 }
322
323 // Compile and JIT the code
324 if (mCompiled->compile(option) != 0) {
325 ALOGE("Unable to compile.\n");
326 return 1;
327 }
328
329 return 0;
330}
331
332int RSScript::writeCache() {
333 // Not compiled script or encountered error during the compilation.
334 if ((mStatus != ScriptStatus::Compiled) ||
335 (getCompilerErrorMessage() == NULL))
336 return 1;
337
338 // Note: If we re-compile the script because the cached context slot not
339 // available, then we don't have to write the cache.
340
341 // Note: If the address of the context is not in the context slot, then
342 // we don't have to cache it.
343
344 if (isCacheable()) {
345 std::string objPath = getCachedObjectPath();
346 std::string infoPath = getCacheInfoPath();
347
348 // Locks for writing object file and info file.
349 FileMutex<FileBase::kWriteLock> objFileMutex(objPath);
350 FileMutex<FileBase::kWriteLock> infoFileMutex(infoPath);
351
352 // Aquire write lock for object file.
353 if (objFileMutex.hasError() || !objFileMutex.lock()) {
354 ALOGE("Unable to acquire the lock for %s! (%s)", objPath.c_str(),
355 objFileMutex.getErrorMessage().c_str());
356 return 1;
357 }
358
359 // Aquire write lock for info file.
360 if (infoFileMutex.hasError() || !infoFileMutex.lock()) {
361 ALOGE("Unable to acquire the lock for %s! (%s)", infoPath.c_str(),
362 infoFileMutex.getErrorMessage().c_str());
363 return 1;
364 }
365
366 // Open the object file and info file
367 OutputFile objFile(objPath);
368 OutputFile infoFile(infoPath);
369
370 if (objFile.hasError()) {
371 ALOGE("Unable to open %s for writing! (%s)", objPath.c_str(),
372 objFile.getErrorMessage().c_str());
373 return 1;
374 }
375
376 if (infoFile.hasError()) {
377 ALOGE("Unable to open %s for writing! (%s)", infoPath.c_str(),
378 infoFile.getErrorMessage().c_str());
379 return 1;
380 }
381
382 MCCacheWriter writer;
383
384#ifdef TARGET_BUILD
385 // Dependencies
Stephen Hines0f6b1d32012-05-03 12:29:33 -0700386 writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
387 writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700388#endif
389
390 for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
391 const SourceDependency *source_dep = mSourceDependencies[i];
Stephen Hines0f6b1d32012-05-03 12:29:33 -0700392 writer.addDependency(source_dep->getSourceType(),
393 source_dep->getSourceName(),
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700394 source_dep->getSHA1Checksum());
395 }
396
397
398 // libRS is threadable dirty hack
399 // TODO: This should be removed in the future
400 uint32_t libRS_threadable = 0;
401 if (mpExtSymbolLookupFn) {
402 libRS_threadable =
403 (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
404 "__isThreadable");
405 }
406
407 if (!writer.writeCacheFile(objFile, infoFile, this, libRS_threadable)) {
408 // Erase the file contents.
409 objFile.truncate();
410 infoFile.truncate();
411
412 // Close the file such that we can removed it from the filesystem.
413 objFile.close();
414 infoFile.close();
415
416 if (::unlink(objPath.c_str()) != 0) {
417 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
418 objPath.c_str(), ::strerror(errno));
419 }
420
421 if (::unlink(infoPath.c_str()) != 0) {
422 ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
423 infoPath.c_str(), ::strerror(errno));
424 }
425 }
426 } // isCacheable()
427
428 return 0;
429}
430
431char const *RSScript::getCompilerErrorMessage() {
432 if (mStatus != ScriptStatus::Compiled) {
433 mErrorCode = BCC_INVALID_OPERATION;
434 return NULL;
435 }
436
437 return mCompiled->getCompilerErrorMessage();
438}
439
440
441void *RSScript::lookup(const char *name) {
442 switch (mStatus) {
443 case ScriptStatus::Compiled: {
444 return mCompiled->lookup(name);
445 }
446
447 case ScriptStatus::Cached: {
448 return mCached->lookup(name);
449 }
450
451 default: {
452 mErrorCode = BCC_INVALID_OPERATION;
453 return NULL;
454 }
455 }
456}
457
458
459size_t RSScript::getExportVarCount() const {
460 switch (mStatus) {
461 case ScriptStatus::Compiled: {
462 return mCompiled->getExportVarCount();
463 }
464
465 case ScriptStatus::Cached: {
466 return mCached->getExportVarCount();
467 }
468
469 default: {
470 return 0;
471 }
472 }
473}
474
475
476size_t RSScript::getExportFuncCount() const {
477 switch (mStatus) {
478 case ScriptStatus::Compiled: {
479 return mCompiled->getExportFuncCount();
480 }
481
482 case ScriptStatus::Cached: {
483 return mCached->getExportFuncCount();
484 }
485
486 default: {
487 return 0;
488 }
489 }
490}
491
492
493size_t RSScript::getExportForEachCount() const {
494 switch (mStatus) {
495 case ScriptStatus::Compiled: {
496 return mCompiled->getExportForEachCount();
497 }
498
499 case ScriptStatus::Cached: {
500 return mCached->getExportForEachCount();
501 }
502
503 default: {
504 return 0;
505 }
506 }
507}
508
509
510size_t RSScript::getPragmaCount() const {
511 switch (mStatus) {
512 case ScriptStatus::Compiled: {
513 return mCompiled->getPragmaCount();
514 }
515
516 case ScriptStatus::Cached: {
517 return mCached->getPragmaCount();
518 }
519
520 default: {
521 return 0;
522 }
523 }
524}
525
526
527size_t RSScript::getFuncCount() const {
528 switch (mStatus) {
529 case ScriptStatus::Compiled: {
530 return mCompiled->getFuncCount();
531 }
532
533 case ScriptStatus::Cached: {
534 return mCached->getFuncCount();
535 }
536
537 default: {
538 return 0;
539 }
540 }
541}
542
543
544size_t RSScript::getObjectSlotCount() const {
545 switch (mStatus) {
546 case ScriptStatus::Compiled: {
547 return mCompiled->getObjectSlotCount();
548 }
549
550 case ScriptStatus::Cached: {
551 return mCached->getObjectSlotCount();
552 }
553
554 default: {
555 return 0;
556 }
557 }
558}
559
560
561void RSScript::getExportVarList(size_t varListSize, void **varList) {
562 switch (mStatus) {
563#define DELEGATE(STATUS) \
564 case ScriptStatus::STATUS: \
565 m##STATUS->getExportVarList(varListSize, varList); \
566 break;
567
568 DELEGATE(Cached);
569
570 DELEGATE(Compiled);
571#undef DELEGATE
572
573 default: {
574 mErrorCode = BCC_INVALID_OPERATION;
575 }
576 }
577}
578
579void RSScript::getExportVarNameList(std::vector<std::string> &varList) {
580 switch (mStatus) {
581 case ScriptStatus::Compiled: {
582 return mCompiled->getExportVarNameList(varList);
583 }
584
585 default: {
586 mErrorCode = BCC_INVALID_OPERATION;
587 }
588 }
589}
590
591
592void RSScript::getExportFuncList(size_t funcListSize, void **funcList) {
593 switch (mStatus) {
594#define DELEGATE(STATUS) \
595 case ScriptStatus::STATUS: \
596 m##STATUS->getExportFuncList(funcListSize, funcList); \
597 break;
598
599 DELEGATE(Cached);
600
601 DELEGATE(Compiled);
602#undef DELEGATE
603
604 default: {
605 mErrorCode = BCC_INVALID_OPERATION;
606 }
607 }
608}
609
610void RSScript::getExportFuncNameList(std::vector<std::string> &funcList) {
611 switch (mStatus) {
612 case ScriptStatus::Compiled: {
613 return mCompiled->getExportFuncNameList(funcList);
614 }
615
616 default: {
617 mErrorCode = BCC_INVALID_OPERATION;
618 }
619 }
620}
621
622void RSScript::getExportForEachList(size_t funcListSize, void **funcList) {
623 switch (mStatus) {
624#define DELEGATE(STATUS) \
625 case ScriptStatus::STATUS: \
626 m##STATUS->getExportForEachList(funcListSize, funcList); \
627 break;
628
629 DELEGATE(Cached);
630
631 DELEGATE(Compiled);
632#undef DELEGATE
633
634 default: {
635 mErrorCode = BCC_INVALID_OPERATION;
636 }
637 }
638}
639
640void RSScript::getExportForEachNameList(std::vector<std::string> &forEachList) {
641 switch (mStatus) {
642 case ScriptStatus::Compiled: {
643 return mCompiled->getExportForEachNameList(forEachList);
644 }
645
646 default: {
647 mErrorCode = BCC_INVALID_OPERATION;
648 }
649 }
650}
651
652void RSScript::getPragmaList(size_t pragmaListSize,
653 char const **keyList,
654 char const **valueList) {
655 switch (mStatus) {
656#define DELEGATE(STATUS) \
657 case ScriptStatus::STATUS: \
658 m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
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
672
673void RSScript::getFuncInfoList(size_t funcInfoListSize,
674 FuncInfo *funcInfoList) {
675 switch (mStatus) {
676#define DELEGATE(STATUS) \
677 case ScriptStatus::STATUS: \
678 m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
679 break;
680
681 DELEGATE(Cached);
682
683 DELEGATE(Compiled);
684#undef DELEGATE
685
686 default: {
687 mErrorCode = BCC_INVALID_OPERATION;
688 }
689 }
690}
691
692
693void RSScript::getObjectSlotList(size_t objectSlotListSize,
694 uint32_t *objectSlotList) {
695 switch (mStatus) {
696#define DELEGATE(STATUS) \
697 case ScriptStatus::STATUS: \
698 m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
699 break;
700
701 DELEGATE(Cached);
702
703 DELEGATE(Compiled);
704#undef DELEGATE
705
706 default: {
707 mErrorCode = BCC_INVALID_OPERATION;
708 }
709 }
710}
711
712
713int RSScript::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
714 mpExtSymbolLookupFn = pFn;
715 mpExtSymbolLookupFnContext = pContext;
716
717 if (mStatus != ScriptStatus::Unknown) {
718 mErrorCode = BCC_INVALID_OPERATION;
719 ALOGE("Invalid operation: %s\n", __func__);
720 return 1;
721 }
722 return 0;
723}
724
725bool RSScript::isCacheable() const {
726 if (getBooleanProp("debug.bcc.nocache")) {
727 // Android system environment property: Disables the cache mechanism by
728 // setting "debug.bcc.nocache". So we will not load the cache file any
729 // way.
730 return false;
731 }
732
733 if (mCacheDir.empty() || mCacheName.empty()) {
734 // The application developer has not specified the cachePath, so
735 // we don't know where to open the cache file.
736 return false;
737 }
738
739 return true;
740}
741
742size_t RSScript::getELFSize() const {
743 switch (mStatus) {
744 case ScriptStatus::Compiled: {
745 return mCompiled->getELFSize();
746 }
747
748 case ScriptStatus::Cached: {
749 return mCached->getELFSize();
750 }
751
752 default: {
753 return 0;
754 }
755 }
756}
757
758const char *RSScript::getELF() const {
759 switch (mStatus) {
760 case ScriptStatus::Compiled: {
761 return mCompiled->getELF();
762 }
763
764 case ScriptStatus::Cached: {
765 return mCached->getELF();
766 }
767
768 default: {
769 return NULL;
770 }
771 }
772}
773
774} // namespace bcc