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