Home | History | Annotate | Download | only in ExecutionEngine
      1 /*
      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 
     17 #include "bcc/ExecutionEngine/ObjectLoader.h"
     18 
     19 #include <utils/FileMap.h>
     20 
     21 #include "bcc/ExecutionEngine/GDBJITRegistrar.h"
     22 #include "bcc/Support/FileBase.h"
     23 #include "bcc/Support/Log.h"
     24 
     25 #include "ELFObjectLoaderImpl.h"
     26 
     27 using namespace bcc;
     28 
     29 ObjectLoader *ObjectLoader::Load(void *pMemStart, size_t pMemSize,
     30                                  const char *pName,
     31                                  SymbolResolverInterface &pResolver,
     32                                  bool pEnableGDBDebug) {
     33   ObjectLoader *result = NULL;
     34 
     35   // Check parameters.
     36   if ((pMemStart == NULL) || (pMemSize <= 0)) {
     37     ALOGE("Invalid memory '%s' was given to load (memory addr: %p, size: %u)",
     38           pName, pMemStart, static_cast<unsigned>(pMemSize));
     39     goto bail;
     40   }
     41 
     42   // Create result object
     43   result = new (std::nothrow) ObjectLoader();
     44   if (result == NULL) {
     45     ALOGE("Out of memory when create object loader for %s!", pName);
     46     goto bail;
     47   }
     48 
     49   // Currently, only ELF object loader is supported. Therefore, there's no codes
     50   // to detect the object file type and to select the one appropriated. Directly
     51   // try out the ELF object loader.
     52   result->mImpl = new (std::nothrow) ELFObjectLoaderImpl();
     53   if (result->mImpl == NULL) {
     54     ALOGE("Out of memory when create ELF object loader for %s", pName);
     55     goto bail;
     56   }
     57 
     58   // Load the object file.
     59   if (!result->mImpl->load(pMemStart, pMemSize)) {
     60     ALOGE("Failed to load %s!", pName);
     61     goto bail;
     62   }
     63 
     64   // Perform relocation.
     65   if (!result->mImpl->relocate(pResolver)) {
     66     ALOGE("Error occurred when performs relocation on %s!", pName);
     67     goto bail;
     68   }
     69 
     70   // GDB debugging is enabled. Note that error occurrs during the setup of
     71   // debugging won't failed the object load. Only a warning is issued to notify
     72   // that the debugging is disabled due to the failure.
     73   if (pEnableGDBDebug) {
     74     // GDB's JIT debugging requires the source object file corresponded to the
     75     // process image desired to debug with. And some fields in the object file
     76     // must be updated to record the runtime information after it's loaded into
     77     // memory. For example, GDB's JIT debugging requires an ELF file with the
     78     // value of sh_addr in the section header to be the memory address that the
     79     // section lives in the process image. Therefore, a writable memory with its
     80     // contents initialized to the contents of pFile is created.
     81     result->mDebugImage = new (std::nothrow) uint8_t [ pMemSize ];
     82     if (result->mDebugImage != NULL) {
     83       ::memcpy(result->mDebugImage, pMemStart, pMemSize);
     84       if (!result->mImpl->prepareDebugImage(result->mDebugImage, pMemSize)) {
     85         ALOGW("GDB debug for %s is enabled by the user but won't work due to "
     86               "failure debug image preparation!", pName);
     87       } else {
     88         registerObjectWithGDB(
     89             reinterpret_cast<const ObjectBuffer *>(result->mDebugImage),
     90             pMemSize);
     91       }
     92     }
     93   }
     94 
     95   return result;
     96 
     97 bail:
     98   delete result;
     99   return NULL;
    100 }
    101 
    102 ObjectLoader *ObjectLoader::Load(FileBase &pFile,
    103                                  SymbolResolverInterface &pResolver,
    104                                  bool pEnableGDBDebug) {
    105   size_t file_size;
    106   android::FileMap *file_map = NULL;
    107   const char *input_filename = pFile.getName().c_str();
    108   ObjectLoader *result = NULL;
    109 
    110   // Check the inputs.
    111   if (pFile.hasError()) {
    112     ALOGE("Input file %s to the object loader is in the invalid state! (%s)",
    113           input_filename, pFile.getErrorMessage().c_str());
    114     return NULL;
    115   }
    116 
    117   // Get the file size.
    118   file_size = pFile.getSize();
    119   if (pFile.hasError()) {
    120     ALOGE("Failed to get size of file %s! (%s)", input_filename,
    121           pFile.getErrorMessage().c_str());
    122     return NULL;
    123   }
    124 
    125   // Abort on empty file.
    126   if (file_size <= 0) {
    127     ALOGE("Empty file %s to the object loader.", input_filename);
    128     return NULL;
    129   }
    130 
    131   // Create memory map for the input file.
    132   file_map = pFile.createMap(0, file_size, /* pIsReadOnly */true);
    133   if ((file_map == NULL) || pFile.hasError())  {
    134     ALOGE("Failed to map the file %s to the memory! (%s)", input_filename,
    135           pFile.getErrorMessage().c_str());
    136     return NULL;
    137   }
    138 
    139   // Delegate the load request.
    140   result = Load(file_map->getDataPtr(), file_size, input_filename, pResolver,
    141                 pEnableGDBDebug);
    142 
    143   // No whether the load is successful or not, file_map is no longer needed. On
    144   // success, there's a copy of the object corresponded to the pFile in the
    145   // memory. Therefore, file_map can be safely released.
    146   file_map->release();
    147 
    148   return result;
    149 }
    150 
    151 void *ObjectLoader::getSymbolAddress(const char *pName) const {
    152   return mImpl->getSymbolAddress(pName);
    153 }
    154 
    155 size_t ObjectLoader::getSymbolSize(const char *pName) const {
    156   return mImpl->getSymbolSize(pName);
    157 }
    158 
    159 bool ObjectLoader::getSymbolNameList(android::Vector<const char *>& pNameList,
    160                                      SymbolType pType) const {
    161   return mImpl->getSymbolNameList(pNameList, pType);
    162 }
    163 
    164 ObjectLoader::~ObjectLoader() {
    165   delete mImpl;
    166   delete [] reinterpret_cast<uint8_t *>(mDebugImage);
    167 }
    168