• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 <dlfcn.h>
18 #include <cctype>
19 #include <cmath>
20 #include <cstring>
21 
22 #include "chre/platform/shared/nanoapp_loader.h"
23 
24 #include "chre.h"
25 #include "chre/platform/assert.h"
26 #include "chre/platform/fatal_error.h"
27 #include "chre/platform/shared/debug_dump.h"
28 #include "chre/platform/shared/memory.h"
29 #include "chre/target_platform/platform_cache_management.h"
30 #include "chre/util/dynamic_vector.h"
31 #include "chre/util/macros.h"
32 
33 #ifdef CHREX_SYMBOL_EXTENSIONS
34 #include "chre/extensions/platform/symbol_list.h"
35 #endif
36 
37 #ifndef CHRE_LOADER_ARCH
38 #define CHRE_LOADER_ARCH EM_ARM
39 #endif  // CHRE_LOADER_ARCH
40 
41 namespace chre {
42 namespace {
43 
44 using ElfHeader = ElfW(Ehdr);
45 using ProgramHeader = ElfW(Phdr);
46 
47 struct ExportedData {
48   void *data;
49   const char *dataName;
50 };
51 
52 //! If non-null, a nanoapp is currently being loaded. This allows certain C
53 //! functions to access the nanoapp if called during static init.
54 NanoappLoader *gCurrentlyLoadingNanoapp = nullptr;
55 //! Indicates whether a failure occurred during static initialization.
56 bool gStaticInitFailure = false;
57 
atexitInternal(struct AtExitCallback & cb)58 int atexitInternal(struct AtExitCallback &cb) {
59   if (gCurrentlyLoadingNanoapp == nullptr) {
60     CHRE_ASSERT_LOG(false,
61                     "atexit is only supported during static initialization.");
62     return -1;
63   }
64 
65   gCurrentlyLoadingNanoapp->registerAtexitFunction(cb);
66   return 0;
67 }
68 
69 // atexit is used to register functions that must be called when a binary is
70 // removed from the system. The call back function has an arg (void *)
cxaAtexitOverride(void (* func)(void *),void * arg,void * dso)71 int cxaAtexitOverride(void (*func)(void *), void *arg, void *dso) {
72   LOGV("__cxa_atexit invoked with %p, %p, %p", func, arg, dso);
73   struct AtExitCallback cb(func, arg);
74   atexitInternal(cb);
75   return 0;
76 }
77 
78 // The call back function has no arg.
atexitOverride(void (* func)(void))79 int atexitOverride(void (*func)(void)) {
80   LOGV("atexit invoked with %p", func);
81   struct AtExitCallback cb(func);
82   atexitInternal(cb);
83   return 0;
84 }
85 
86 // The following functions from the cmath header need to be overridden, since
87 // they're overloaded functions, and we need to specify explicit types of the
88 // template for the compiler.
frexpOverride(double value,int * exp)89 double frexpOverride(double value, int *exp) {
90   return frexp(value, exp);
91 }
92 
fmaxOverride(double x,double y)93 double fmaxOverride(double x, double y) {
94   return fmax(x, y);
95 }
96 
fminOverride(double x,double y)97 double fminOverride(double x, double y) {
98   return fmin(x, y);
99 }
100 
floorOverride(double value)101 double floorOverride(double value) {
102   return floor(value);
103 }
104 
sinOverride(double rad)105 double sinOverride(double rad) {
106   return sin(rad);
107 }
108 
asinOverride(double val)109 double asinOverride(double val) {
110   return asin(val);
111 }
112 
atan2Override(double y,double x)113 double atan2Override(double y, double x) {
114   return atan2(y, x);
115 }
116 
cosOverride(double rad)117 double cosOverride(double rad) {
118   return cos(rad);
119 }
120 
sqrtOverride(float val)121 float sqrtOverride(float val) {
122   return sqrt(val);
123 }
124 
roundOverride(double val)125 double roundOverride(double val) {
126   return round(val);
127 }
128 
129 // This function is required to be exposed to nanoapps to handle errors from
130 // invoking virtual functions.
__cxa_pure_virtual(void)131 void __cxa_pure_virtual(void) {
132   chreAbort(CHRE_ERROR /* abortCode */);
133 }
134 
135 // TODO(karthikmb/stange): While this array was hand-coded for simple
136 // "hello-world" prototyping, the list of exported symbols must be
137 // generated to minimize runtime errors and build breaks.
138 // clang-format off
139 // Disable deprecation warning so that deprecated symbols in the array
140 // can be exported for older nanoapps and tests.
141 CHRE_DEPRECATED_PREAMBLE
142 const ExportedData kExportedData[] = {
143     /* libmath overrides and symbols */
144     ADD_EXPORTED_SYMBOL(asinOverride, "asin"),
145     ADD_EXPORTED_SYMBOL(atan2Override, "atan2"),
146     ADD_EXPORTED_SYMBOL(cosOverride, "cos"),
147     ADD_EXPORTED_SYMBOL(floorOverride, "floor"),
148     ADD_EXPORTED_SYMBOL(fmaxOverride, "fmax"),
149     ADD_EXPORTED_SYMBOL(fminOverride, "fmin"),
150     ADD_EXPORTED_SYMBOL(frexpOverride, "frexp"),
151     ADD_EXPORTED_SYMBOL(roundOverride, "round"),
152     ADD_EXPORTED_SYMBOL(sinOverride, "sin"),
153     ADD_EXPORTED_SYMBOL(sqrtOverride, "sqrt"),
154     ADD_EXPORTED_C_SYMBOL(acosf),
155     ADD_EXPORTED_C_SYMBOL(asinf),
156     ADD_EXPORTED_C_SYMBOL(atan2f),
157     ADD_EXPORTED_C_SYMBOL(ceilf),
158     ADD_EXPORTED_C_SYMBOL(cosf),
159     ADD_EXPORTED_C_SYMBOL(expf),
160     ADD_EXPORTED_C_SYMBOL(fabsf),
161     ADD_EXPORTED_C_SYMBOL(floorf),
162     ADD_EXPORTED_C_SYMBOL(fmaxf),
163     ADD_EXPORTED_C_SYMBOL(fminf),
164     ADD_EXPORTED_C_SYMBOL(fmodf),
165     ADD_EXPORTED_C_SYMBOL(log10f),
166     ADD_EXPORTED_C_SYMBOL(log1pf),
167     ADD_EXPORTED_C_SYMBOL(log2f),
168     ADD_EXPORTED_C_SYMBOL(logf),
169     ADD_EXPORTED_C_SYMBOL(lrintf),
170     ADD_EXPORTED_C_SYMBOL(lroundf),
171     ADD_EXPORTED_C_SYMBOL(powf),
172     ADD_EXPORTED_C_SYMBOL(remainderf),
173     ADD_EXPORTED_C_SYMBOL(roundf),
174     ADD_EXPORTED_C_SYMBOL(sinf),
175     ADD_EXPORTED_C_SYMBOL(sqrtf),
176     ADD_EXPORTED_C_SYMBOL(tanf),
177     ADD_EXPORTED_C_SYMBOL(tanhf),
178     /* libc overrides and symbols */
179     ADD_EXPORTED_C_SYMBOL(__cxa_pure_virtual),
180     ADD_EXPORTED_SYMBOL(cxaAtexitOverride, "__cxa_atexit"),
181     ADD_EXPORTED_SYMBOL(atexitOverride, "atexit"),
182     ADD_EXPORTED_C_SYMBOL(dlsym),
183     ADD_EXPORTED_C_SYMBOL(isgraph),
184     ADD_EXPORTED_C_SYMBOL(memcmp),
185     ADD_EXPORTED_C_SYMBOL(memcpy),
186     ADD_EXPORTED_C_SYMBOL(memmove),
187     ADD_EXPORTED_C_SYMBOL(memset),
188     ADD_EXPORTED_C_SYMBOL(snprintf),
189     ADD_EXPORTED_C_SYMBOL(strcmp),
190     ADD_EXPORTED_C_SYMBOL(strlen),
191     ADD_EXPORTED_C_SYMBOL(strncmp),
192     ADD_EXPORTED_C_SYMBOL(tolower),
193     /* CHRE symbols */
194     ADD_EXPORTED_C_SYMBOL(chreAbort),
195     ADD_EXPORTED_C_SYMBOL(chreAudioConfigureSource),
196     ADD_EXPORTED_C_SYMBOL(chreAudioGetSource),
197     ADD_EXPORTED_C_SYMBOL(chreBleGetCapabilities),
198     ADD_EXPORTED_C_SYMBOL(chreBleGetFilterCapabilities),
199     ADD_EXPORTED_C_SYMBOL(chreBleFlushAsync),
200     ADD_EXPORTED_C_SYMBOL(chreBleStartScanAsync),
201     ADD_EXPORTED_C_SYMBOL(chreBleStopScanAsync),
202     ADD_EXPORTED_C_SYMBOL(chreBleReadRssiAsync),
203     ADD_EXPORTED_C_SYMBOL(chreBleGetScanStatus),
204     ADD_EXPORTED_C_SYMBOL(chreConfigureDebugDumpEvent),
205     ADD_EXPORTED_C_SYMBOL(chreConfigureHostSleepStateEvents),
206     ADD_EXPORTED_C_SYMBOL(chreConfigureNanoappInfoEvents),
207     ADD_EXPORTED_C_SYMBOL(chreDebugDumpLog),
208     ADD_EXPORTED_C_SYMBOL(chreGetApiVersion),
209     ADD_EXPORTED_C_SYMBOL(chreGetAppId),
210     ADD_EXPORTED_C_SYMBOL(chreGetInstanceId),
211     ADD_EXPORTED_C_SYMBOL(chreGetEstimatedHostTimeOffset),
212     ADD_EXPORTED_C_SYMBOL(chreGetNanoappInfoByAppId),
213     ADD_EXPORTED_C_SYMBOL(chreGetNanoappInfoByInstanceId),
214     ADD_EXPORTED_C_SYMBOL(chreGetPlatformId),
215     ADD_EXPORTED_C_SYMBOL(chreGetSensorInfo),
216     ADD_EXPORTED_C_SYMBOL(chreGetSensorSamplingStatus),
217     ADD_EXPORTED_C_SYMBOL(chreGetTime),
218     ADD_EXPORTED_C_SYMBOL(chreGetVersion),
219     ADD_EXPORTED_C_SYMBOL(chreGnssConfigurePassiveLocationListener),
220     ADD_EXPORTED_C_SYMBOL(chreGnssGetCapabilities),
221     ADD_EXPORTED_C_SYMBOL(chreGnssLocationSessionStartAsync),
222     ADD_EXPORTED_C_SYMBOL(chreGnssLocationSessionStopAsync),
223     ADD_EXPORTED_C_SYMBOL(chreGnssMeasurementSessionStartAsync),
224     ADD_EXPORTED_C_SYMBOL(chreGnssMeasurementSessionStopAsync),
225     ADD_EXPORTED_C_SYMBOL(chreHeapAlloc),
226     ADD_EXPORTED_C_SYMBOL(chreHeapFree),
227     ADD_EXPORTED_C_SYMBOL(chreIsHostAwake),
228     ADD_EXPORTED_C_SYMBOL(chreLog),
229     ADD_EXPORTED_C_SYMBOL(chreSendEvent),
230     ADD_EXPORTED_C_SYMBOL(chreSendMessageToHost),
231     ADD_EXPORTED_C_SYMBOL(chreSendMessageToHostEndpoint),
232     ADD_EXPORTED_C_SYMBOL(chreSendMessageWithPermissions),
233     ADD_EXPORTED_C_SYMBOL(chreSensorConfigure),
234     ADD_EXPORTED_C_SYMBOL(chreSensorConfigureBiasEvents),
235     ADD_EXPORTED_C_SYMBOL(chreSensorFind),
236     ADD_EXPORTED_C_SYMBOL(chreSensorFindDefault),
237     ADD_EXPORTED_C_SYMBOL(chreSensorFlushAsync),
238     ADD_EXPORTED_C_SYMBOL(chreSensorGetThreeAxisBias),
239     ADD_EXPORTED_C_SYMBOL(chreTimerCancel),
240     ADD_EXPORTED_C_SYMBOL(chreTimerSet),
241     ADD_EXPORTED_C_SYMBOL(chreUserSettingConfigureEvents),
242     ADD_EXPORTED_C_SYMBOL(chreUserSettingGetState),
243     ADD_EXPORTED_C_SYMBOL(chreWifiConfigureScanMonitorAsync),
244     ADD_EXPORTED_C_SYMBOL(chreWifiGetCapabilities),
245     ADD_EXPORTED_C_SYMBOL(chreWifiRequestScanAsync),
246     ADD_EXPORTED_C_SYMBOL(chreWifiRequestRangingAsync),
247     ADD_EXPORTED_C_SYMBOL(chreWifiNanRequestRangingAsync),
248     ADD_EXPORTED_C_SYMBOL(chreWifiNanSubscribe),
249     ADD_EXPORTED_C_SYMBOL(chreWifiNanSubscribeCancel),
250     ADD_EXPORTED_C_SYMBOL(chreWwanGetCapabilities),
251     ADD_EXPORTED_C_SYMBOL(chreWwanGetCellInfoAsync),
252     ADD_EXPORTED_C_SYMBOL(platform_chreDebugDumpVaLog),
253     ADD_EXPORTED_C_SYMBOL(chreConfigureHostEndpointNotifications),
254     ADD_EXPORTED_C_SYMBOL(chrePublishRpcServices),
255     ADD_EXPORTED_C_SYMBOL(chreGetHostEndpointInfo),
256 };
257 CHRE_DEPRECATED_EPILOGUE
258 // clang-format on
259 
260 }  // namespace
261 
create(void * elfInput,bool mapIntoTcm)262 void *NanoappLoader::create(void *elfInput, bool mapIntoTcm) {
263   void *instance = nullptr;
264   NanoappLoader *loader = memoryAllocDram<NanoappLoader>(elfInput, mapIntoTcm);
265   if (loader != nullptr) {
266     if (loader->open()) {
267       instance = loader;
268     } else {
269       memoryFreeDram(loader);
270     }
271   } else {
272     LOG_OOM();
273   }
274 
275   return instance;
276 }
277 
destroy(NanoappLoader * loader)278 void NanoappLoader::destroy(NanoappLoader *loader) {
279   loader->close();
280   // TODO(b/151847750): Modify utilities to support free'ing from regions other
281   // than SRAM.
282   loader->~NanoappLoader();
283   memoryFreeDram(loader);
284 }
285 
findExportedSymbol(const char * name)286 void *NanoappLoader::findExportedSymbol(const char *name) {
287   size_t nameLen = strlen(name);
288   for (size_t i = 0; i < ARRAY_SIZE(kExportedData); i++) {
289     if (nameLen == strlen(kExportedData[i].dataName) &&
290         strncmp(name, kExportedData[i].dataName, nameLen) == 0) {
291       return kExportedData[i].data;
292     }
293   }
294 
295 #ifdef CHREX_SYMBOL_EXTENSIONS
296   for (size_t i = 0; i < ARRAY_SIZE(kVendorExportedData); i++) {
297     if (nameLen == strlen(kVendorExportedData[i].dataName) &&
298         strncmp(name, kVendorExportedData[i].dataName, nameLen) == 0) {
299       return kVendorExportedData[i].data;
300     }
301   }
302 #endif
303 
304   return nullptr;
305 }
306 
open()307 bool NanoappLoader::open() {
308   bool success = false;
309   if (mBinary != nullptr) {
310     if (!copyAndVerifyHeaders()) {
311       LOGE("Failed to verify headers");
312     } else if (!createMappings()) {
313       LOGE("Failed to create mappings");
314     } else if (!fixRelocations()) {
315       LOGE("Failed to fix relocations");
316     } else if (!resolveGot()) {
317       LOGE("Failed to resolve GOT");
318     } else {
319       // Wipe caches before calling init array to ensure initializers are not in
320       // the data cache.
321       wipeSystemCaches(reinterpret_cast<uintptr_t>(mMapping), mMemorySpan);
322       if (!callInitArray()) {
323         LOGE("Failed to perform static init");
324       } else {
325         success = true;
326       }
327     }
328   }
329 
330   if (!success) {
331     freeAllocatedData();
332   }
333 
334   return success;
335 }
336 
close()337 void NanoappLoader::close() {
338   callAtexitFunctions();
339   callTerminatorArray();
340   freeAllocatedData();
341 }
342 
findSymbolByName(const char * name)343 void *NanoappLoader::findSymbolByName(const char *name) {
344   for (size_t offset = 0; offset < mSymbolTableSize; offset += sizeof(ElfSym)) {
345     ElfSym *currSym = reinterpret_cast<ElfSym *>(mSymbolTablePtr + offset);
346     const char *symbolName = &mStringTablePtr[currSym->st_name];
347 
348     if (strncmp(symbolName, name, strlen(name)) == 0) {
349       return getSymbolTarget(currSym);
350     }
351   }
352   return nullptr;
353 }
354 
registerAtexitFunction(struct AtExitCallback & cb)355 void NanoappLoader::registerAtexitFunction(struct AtExitCallback &cb) {
356   if (!mAtexitFunctions.push_back(cb)) {
357     LOG_OOM();
358     gStaticInitFailure = true;
359   }
360 }
361 
mapBss(const ProgramHeader * hdr)362 void NanoappLoader::mapBss(const ProgramHeader *hdr) {
363   // if the memory size of this segment exceeds the file size zero fill the
364   // difference.
365   LOGV("Program Hdr mem sz: %u file size: %u", hdr->p_memsz, hdr->p_filesz);
366   if (hdr->p_memsz > hdr->p_filesz) {
367     ElfAddr endOfFile = hdr->p_vaddr + hdr->p_filesz + mLoadBias;
368     ElfAddr endOfMem = hdr->p_vaddr + hdr->p_memsz + mLoadBias;
369     if (endOfMem > endOfFile) {
370       auto deltaMem = endOfMem - endOfFile;
371       LOGV("Zeroing out %u from page %x", deltaMem, endOfFile);
372       memset(reinterpret_cast<void *>(endOfFile), 0, deltaMem);
373     }
374   }
375 }
376 
callInitArray()377 bool NanoappLoader::callInitArray() {
378   bool success = true;
379   // Sets global variable used by atexit in case it's invoked as part of
380   // initializing static data.
381   gCurrentlyLoadingNanoapp = this;
382 
383   // TODO(b/151847750): ELF can have other sections like .init, .preinit, .fini
384   // etc. Be sure to look for those if they end up being something that should
385   // be supported for nanoapps.
386   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
387     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
388     if (strncmp(name, kInitArrayName, strlen(kInitArrayName)) == 0) {
389       LOGV("Invoking init function");
390       uintptr_t initArray =
391           static_cast<uintptr_t>(mLoadBias + mSectionHeadersPtr[i].sh_addr);
392       uintptr_t offset = 0;
393       while (offset < mSectionHeadersPtr[i].sh_size) {
394         ElfAddr *funcPtr = reinterpret_cast<ElfAddr *>(initArray + offset);
395         uintptr_t initFunction = static_cast<uintptr_t>(*funcPtr);
396         ((void (*)())initFunction)();
397         offset += sizeof(initFunction);
398         if (gStaticInitFailure) {
399           success = false;
400           break;
401         }
402       }
403       break;
404     }
405   }
406 
407   //! Reset global state so it doesn't leak into the next load.
408   gCurrentlyLoadingNanoapp = nullptr;
409   gStaticInitFailure = false;
410   return success;
411 }
412 
roundDownToAlign(uintptr_t virtualAddr,size_t alignment)413 uintptr_t NanoappLoader::roundDownToAlign(uintptr_t virtualAddr,
414                                           size_t alignment) {
415   return alignment == 0 ? virtualAddr : virtualAddr & -alignment;
416 }
417 
freeAllocatedData()418 void NanoappLoader::freeAllocatedData() {
419   if (mIsTcmBinary) {
420     nanoappBinaryFree(mMapping);
421   } else {
422     nanoappBinaryDramFree(mMapping);
423   }
424   memoryFreeDram(mSectionHeadersPtr);
425   memoryFreeDram(mSectionNamesPtr);
426   memoryFreeDram(mSymbolTablePtr);
427   memoryFreeDram(mStringTablePtr);
428 }
429 
verifyElfHeader()430 bool NanoappLoader::verifyElfHeader() {
431   bool success = false;
432   ElfHeader *elfHeader = getElfHeader();
433   if (elfHeader != nullptr && (elfHeader->e_ident[EI_MAG0] == ELFMAG0) &&
434       (elfHeader->e_ident[EI_MAG1] == ELFMAG1) &&
435       (elfHeader->e_ident[EI_MAG2] == ELFMAG2) &&
436       (elfHeader->e_ident[EI_MAG3] == ELFMAG3) &&
437       (elfHeader->e_ehsize == sizeof(ElfHeader)) &&
438       (elfHeader->e_phentsize == sizeof(ProgramHeader)) &&
439       (elfHeader->e_shentsize == sizeof(SectionHeader)) &&
440       (elfHeader->e_shstrndx < elfHeader->e_shnum) &&
441       (elfHeader->e_version == EV_CURRENT) &&
442       (elfHeader->e_machine == CHRE_LOADER_ARCH) &&
443       (elfHeader->e_type == ET_DYN)) {
444     success = true;
445   }
446   return success;
447 }
448 
verifyProgramHeaders()449 bool NanoappLoader::verifyProgramHeaders() {
450   // This is a minimal check for now -
451   // there should be at least one load segment.
452   bool success = false;
453   for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
454     if (getProgramHeaderArray()[i].p_type == PT_LOAD) {
455       success = true;
456       break;
457     }
458   }
459   return success;
460 }
461 
getSectionHeaderName(size_t headerOffset)462 const char *NanoappLoader::getSectionHeaderName(size_t headerOffset) {
463   if (headerOffset == 0) {
464     return "";
465   }
466 
467   return &mSectionNamesPtr[headerOffset];
468 }
469 
getSectionHeader(const char * headerName)470 NanoappLoader::SectionHeader *NanoappLoader::getSectionHeader(
471     const char *headerName) {
472   SectionHeader *rv = nullptr;
473   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
474     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
475     if (strncmp(name, headerName, strlen(headerName)) == 0) {
476       rv = &mSectionHeadersPtr[i];
477       break;
478     }
479   }
480   return rv;
481 }
482 
getElfHeader()483 ElfHeader *NanoappLoader::getElfHeader() {
484   return reinterpret_cast<ElfHeader *>(mBinary);
485 }
486 
getProgramHeaderArray()487 ProgramHeader *NanoappLoader::getProgramHeaderArray() {
488   ElfHeader *elfHeader = getElfHeader();
489   ProgramHeader *programHeader = nullptr;
490   if (elfHeader != nullptr) {
491     programHeader =
492         reinterpret_cast<ProgramHeader *>(mBinary + elfHeader->e_phoff);
493   }
494 
495   return programHeader;
496 }
497 
getProgramHeaderArraySize()498 size_t NanoappLoader::getProgramHeaderArraySize() {
499   ElfHeader *elfHeader = getElfHeader();
500   size_t arraySize = 0;
501   if (elfHeader != nullptr) {
502     arraySize = elfHeader->e_phnum;
503   }
504 
505   return arraySize;
506 }
507 
getDynamicStringTable()508 char *NanoappLoader::getDynamicStringTable() {
509   char *table = nullptr;
510 
511   SectionHeader *dynamicStringTablePtr = getSectionHeader(".dynstr");
512   CHRE_ASSERT(dynamicStringTablePtr != nullptr);
513   if (dynamicStringTablePtr != nullptr && mBinary != nullptr) {
514     table =
515         reinterpret_cast<char *>(mBinary + dynamicStringTablePtr->sh_offset);
516   }
517 
518   return table;
519 }
520 
getDynamicSymbolTable()521 uint8_t *NanoappLoader::getDynamicSymbolTable() {
522   uint8_t *table = nullptr;
523 
524   SectionHeader *dynamicSymbolTablePtr = getSectionHeader(".dynsym");
525   CHRE_ASSERT(dynamicSymbolTablePtr != nullptr);
526   if (dynamicSymbolTablePtr != nullptr && mBinary != nullptr) {
527     table = (mBinary + dynamicSymbolTablePtr->sh_offset);
528   }
529 
530   return table;
531 }
532 
getDynamicSymbolTableSize()533 size_t NanoappLoader::getDynamicSymbolTableSize() {
534   size_t tableSize = 0;
535 
536   SectionHeader *dynamicSymbolTablePtr = getSectionHeader(".dynsym");
537   CHRE_ASSERT(dynamicSymbolTablePtr != nullptr);
538   if (dynamicSymbolTablePtr != nullptr) {
539     tableSize = dynamicSymbolTablePtr->sh_size;
540   }
541 
542   return tableSize;
543 }
544 
verifySectionHeaders()545 bool NanoappLoader::verifySectionHeaders() {
546   bool foundSymbolTableHeader = false;
547   bool foundStringTableHeader = false;
548 
549   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
550     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
551 
552     if (strncmp(name, kSymTableName, strlen(kSymTableName)) == 0) {
553       foundSymbolTableHeader = true;
554     } else if (strncmp(name, kStrTableName, strlen(kStrTableName)) == 0) {
555       foundStringTableHeader = true;
556     }
557   }
558 
559   return foundSymbolTableHeader && foundStringTableHeader;
560 }
561 
copyAndVerifyHeaders()562 bool NanoappLoader::copyAndVerifyHeaders() {
563   size_t offset = 0;
564   bool success = false;
565   uint8_t *pDataBytes = mBinary;
566 
567   // Verify the ELF Header
568   ElfHeader *elfHeader = getElfHeader();
569   success = verifyElfHeader();
570 
571   LOGV("Verified ELF header %d", success);
572 
573   // Verify Program Headers
574   if (success) {
575     success = verifyProgramHeaders();
576   }
577 
578   LOGV("Verified Program headers %d", success);
579 
580   // Load Section Headers
581   if (success) {
582     offset = elfHeader->e_shoff;
583     size_t sectionHeaderSizeBytes = sizeof(SectionHeader) * elfHeader->e_shnum;
584     mSectionHeadersPtr =
585         static_cast<SectionHeader *>(memoryAllocDram(sectionHeaderSizeBytes));
586     if (mSectionHeadersPtr == nullptr) {
587       success = false;
588       LOG_OOM();
589     } else {
590       memcpy(mSectionHeadersPtr, (pDataBytes + offset), sectionHeaderSizeBytes);
591       mNumSectionHeaders = elfHeader->e_shnum;
592     }
593   }
594 
595   LOGV("Loaded section headers %d", success);
596 
597   // Load section header names
598   if (success) {
599     SectionHeader &stringSection = mSectionHeadersPtr[elfHeader->e_shstrndx];
600     size_t sectionSize = stringSection.sh_size;
601     mSectionNamesPtr = static_cast<char *>(memoryAllocDram(sectionSize));
602     if (mSectionNamesPtr == nullptr) {
603       LOG_OOM();
604       success = false;
605     } else {
606       memcpy(mSectionNamesPtr, mBinary + stringSection.sh_offset, sectionSize);
607     }
608   }
609 
610   LOGV("Loaded section header names %d", success);
611 
612   success = verifySectionHeaders();
613   LOGV("Verified Section headers %d", success);
614 
615   // Load symbol table
616   if (success) {
617     SectionHeader *symbolTableHeader = getSectionHeader(kSymTableName);
618     mSymbolTableSize = symbolTableHeader->sh_size;
619     if (mSymbolTableSize == 0) {
620       LOGE("No symbols to resolve");
621       success = false;
622     } else {
623       mSymbolTablePtr =
624           static_cast<uint8_t *>(memoryAllocDram(mSymbolTableSize));
625       if (mSymbolTablePtr == nullptr) {
626         LOG_OOM();
627         success = false;
628       } else {
629         memcpy(mSymbolTablePtr, mBinary + symbolTableHeader->sh_offset,
630                mSymbolTableSize);
631       }
632     }
633   }
634 
635   LOGV("Loaded symbol table %d", success);
636 
637   // Load string table
638   if (success) {
639     SectionHeader *stringTableHeader = getSectionHeader(kStrTableName);
640     size_t stringTableSize = stringTableHeader->sh_size;
641     if (mSymbolTableSize == 0) {
642       LOGE("No string table corresponding to symbols");
643       success = false;
644     } else {
645       mStringTablePtr = static_cast<char *>(memoryAllocDram(stringTableSize));
646       if (mStringTablePtr == nullptr) {
647         LOG_OOM();
648         success = false;
649       } else {
650         memcpy(mStringTablePtr, mBinary + stringTableHeader->sh_offset,
651                stringTableSize);
652       }
653     }
654   }
655 
656   LOGV("Loaded string table %d", success);
657 
658   return success;
659 }
660 
createMappings()661 bool NanoappLoader::createMappings() {
662   // ELF needs pt_load segments to be in contiguous ascending order of
663   // virtual addresses. So the first and last segs can be used to
664   // calculate the entire address span of the image.
665   ElfHeader *elfHeader = getElfHeader();
666   ProgramHeader *programHeaderArray = getProgramHeaderArray();
667   size_t numProgramHeaders = getProgramHeaderArraySize();
668   const ProgramHeader *first = &programHeaderArray[0];
669   const ProgramHeader *last = &programHeaderArray[numProgramHeaders - 1];
670 
671   // Find first load segment
672   while (first->p_type != PT_LOAD && first <= last) {
673     ++first;
674   }
675 
676   bool success = false;
677   if (first->p_type != PT_LOAD) {
678     LOGE("Unable to find any load segments in the binary");
679   } else {
680     // Verify that the first load segment has a program header
681     // first byte of a valid load segment can't be greater than the
682     // program header offset
683     bool valid =
684         (first->p_offset < elfHeader->e_phoff) &&
685         (first->p_filesz >=
686          (elfHeader->e_phoff + (numProgramHeaders * sizeof(ProgramHeader))));
687     if (!valid) {
688       LOGE("Load segment program header validation failed");
689     } else {
690       // Get the last load segment
691       while (last > first && last->p_type != PT_LOAD) --last;
692 
693       size_t alignment = first->p_align;
694       size_t memorySpan = last->p_vaddr + last->p_memsz - first->p_vaddr;
695       LOGV("Nanoapp image Memory Span: %zu", memorySpan);
696 
697       if (mIsTcmBinary) {
698         mMapping =
699             static_cast<uint8_t *>(nanoappBinaryAlloc(memorySpan, alignment));
700       } else {
701         mMapping = static_cast<uint8_t *>(
702             nanoappBinaryDramAlloc(memorySpan, alignment));
703       }
704 
705       if (mMapping == nullptr) {
706         LOG_OOM();
707       } else {
708         LOGV("Starting location of mappings %p", mMapping);
709         mMemorySpan = memorySpan;
710 
711         // Calculate the load bias using the first load segment.
712         uintptr_t adjustedFirstLoadSegAddr =
713             roundDownToAlign(first->p_vaddr, alignment);
714         mLoadBias =
715             reinterpret_cast<uintptr_t>(mMapping) - adjustedFirstLoadSegAddr;
716         LOGV("Load bias is %lu", static_cast<long unsigned int>(mLoadBias));
717 
718         success = true;
719       }
720     }
721   }
722 
723   if (success) {
724     // Map the remaining segments
725     for (const ProgramHeader *ph = first; ph <= last; ++ph) {
726       if (ph->p_type == PT_LOAD) {
727         ElfAddr segStart = ph->p_vaddr + mLoadBias;
728         void *startPage = reinterpret_cast<void *>(segStart);
729         void *binaryStartPage = mBinary + ph->p_offset;
730         size_t segmentLen = ph->p_filesz;
731 
732         LOGV("Mapping start page %p from %p with length %zu", startPage,
733              binaryStartPage, segmentLen);
734         memcpy(startPage, binaryStartPage, segmentLen);
735         mapBss(ph);
736       } else {
737         LOGE("Non-load segment found between load segments");
738         success = false;
739         break;
740       }
741     }
742   }
743 
744   return success;
745 }
746 
getDynamicSymbol(size_t posInSymbolTable)747 NanoappLoader::ElfSym *NanoappLoader::getDynamicSymbol(
748     size_t posInSymbolTable) {
749   size_t sectionSize = getDynamicSymbolTableSize();
750   uint8_t *dynamicSymbolTable = getDynamicSymbolTable();
751   size_t numElements = sectionSize / sizeof(ElfSym);
752   CHRE_ASSERT(posInSymbolTable < numElements);
753   if (posInSymbolTable < numElements) {
754     return reinterpret_cast<ElfSym *>(
755         &dynamicSymbolTable[posInSymbolTable * sizeof(ElfSym)]);
756   }
757   return nullptr;
758 }
759 
getDataName(const ElfSym * symbol)760 const char *NanoappLoader::getDataName(const ElfSym *symbol) {
761   return symbol == nullptr ? nullptr
762                            : &getDynamicStringTable()[symbol->st_name];
763 }
764 
getSymbolTarget(const ElfSym * symbol)765 void *NanoappLoader::getSymbolTarget(const ElfSym *symbol) {
766   if (symbol == nullptr || symbol->st_shndx == SHN_UNDEF) {
767     return nullptr;
768   }
769 
770   return mMapping + symbol->st_value;
771 }
772 
resolveData(size_t posInSymbolTable)773 void *NanoappLoader::resolveData(size_t posInSymbolTable) {
774   const ElfSym *symbol = getDynamicSymbol(posInSymbolTable);
775   const char *dataName = getDataName(symbol);
776   void *target = nullptr;
777 
778   if (dataName != nullptr) {
779     LOGV("Resolving %s", dataName);
780     target = findExportedSymbol(dataName);
781     if (target == nullptr) {
782       target = getSymbolTarget(symbol);
783     }
784     if (target == nullptr) {
785       LOGE("Unable to find %s", dataName);
786     }
787   }
788 
789   return target;
790 }
791 
getDynamicHeader()792 NanoappLoader::DynamicHeader *NanoappLoader::getDynamicHeader() {
793   DynamicHeader *dyn = nullptr;
794   ProgramHeader *programHeaders = getProgramHeaderArray();
795   for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
796     if (programHeaders[i].p_type == PT_DYNAMIC) {
797       dyn = reinterpret_cast<DynamicHeader *>(programHeaders[i].p_offset +
798                                               mBinary);
799       break;
800     }
801   }
802   return dyn;
803 }
804 
getFirstRoSegHeader()805 NanoappLoader::ProgramHeader *NanoappLoader::getFirstRoSegHeader() {
806   // return the first read only segment found
807   ProgramHeader *ro = nullptr;
808   ProgramHeader *programHeaders = getProgramHeaderArray();
809   for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
810     if (!(programHeaders[i].p_flags & PF_W)) {
811       ro = &programHeaders[i];
812       break;
813     }
814   }
815   return ro;
816 }
817 
getDynEntry(DynamicHeader * dyn,int field)818 NanoappLoader::ElfWord NanoappLoader::getDynEntry(DynamicHeader *dyn,
819                                                   int field) {
820   ElfWord rv = 0;
821 
822   while (dyn->d_tag != DT_NULL) {
823     if (dyn->d_tag == field) {
824       rv = dyn->d_un.d_val;
825       break;
826     }
827     ++dyn;
828   }
829 
830   return rv;
831 }
832 
fixRelocations()833 bool NanoappLoader::fixRelocations() {
834   DynamicHeader *dyn = getDynamicHeader();
835   ProgramHeader *roSeg = getFirstRoSegHeader();
836 
837   bool success = false;
838   if ((dyn == nullptr) || (roSeg == nullptr)) {
839     LOGE("Mandatory headers missing from shared object, aborting load");
840   }
841 
842   // Must return true if it table is not required or is empty. If
843   // the entry is present when not expected, this must return false.
844   success = relocateTable(dyn, DT_RELA);
845   if (success) {
846     success = relocateTable(dyn, DT_REL);
847   }
848 
849   if (!success) {
850     LOGE("Unable to resolve all symbols in the binary");
851   }
852 
853   return success;
854 }
855 
callAtexitFunctions()856 void NanoappLoader::callAtexitFunctions() {
857   while (!mAtexitFunctions.empty()) {
858     struct AtExitCallback cb = mAtexitFunctions.back();
859     if (cb.arg.has_value()) {
860       LOGV("Calling __cxa_atexit at %p, arg %p", cb.func1, cb.arg.value());
861       cb.func1(cb.arg.value());
862     } else {
863       LOGV("Calling atexit at %p", cb.func0);
864       cb.func0();
865     }
866     mAtexitFunctions.pop_back();
867   }
868 }
869 
callTerminatorArray()870 void NanoappLoader::callTerminatorArray() {
871   for (size_t i = 0; i < mNumSectionHeaders; ++i) {
872     const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
873     if (strncmp(name, kFiniArrayName, strlen(kFiniArrayName)) == 0) {
874       uintptr_t finiArray =
875           static_cast<uintptr_t>(mLoadBias + mSectionHeadersPtr[i].sh_addr);
876       uintptr_t offset = 0;
877       while (offset < mSectionHeadersPtr[i].sh_size) {
878         ElfAddr *funcPtr = reinterpret_cast<ElfAddr *>(finiArray + offset);
879         uintptr_t finiFunction = static_cast<uintptr_t>(*funcPtr);
880         ((void (*)())finiFunction)();
881         offset += sizeof(finiFunction);
882       }
883       break;
884     }
885   }
886 }
887 
888 }  // namespace chre
889