summaryrefslogtreecommitdiffstats
path: root/lib/ExecutionEngine/ObjectLoader.cpp
blob: ade11ab718483a79c587ca4dea77956630e6def7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
 * Copyright 2012, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "bcc/ExecutionEngine/ObjectLoader.h"

#include <utils/FileMap.h>

#include "bcc/ExecutionEngine/GDBJITRegistrar.h"
#include "bcc/Support/FileBase.h"
#include "bcc/Support/Log.h"

#include "ELFObjectLoaderImpl.h"

using namespace bcc;

ObjectLoader *ObjectLoader::Load(void *pMemStart, size_t pMemSize,
                                 const char *pName,
                                 SymbolResolverInterface &pResolver,
                                 bool pEnableGDBDebug) {
  ObjectLoader *result = NULL;

  // Check parameters.
  if ((pMemStart == NULL) || (pMemSize <= 0)) {
    ALOGE("Invalid memory '%s' was given to load (memory addr: %p, size: %u)",
          pName, pMemStart, static_cast<unsigned>(pMemSize));
    goto bail;
  }

  // Create result object
  result = new (std::nothrow) ObjectLoader();
  if (result == NULL) {
    ALOGE("Out of memory when create object loader for %s!", pName);
    goto bail;
  }

  // Currently, only ELF object loader is supported. Therefore, there's no codes
  // to detect the object file type and to select the one appropriated. Directly
  // try out the ELF object loader.
  result->mImpl = new (std::nothrow) ELFObjectLoaderImpl();
  if (result->mImpl == NULL) {
    ALOGE("Out of memory when create ELF object loader for %s", pName);
    goto bail;
  }

  // Load the object file.
  if (!result->mImpl->load(pMemStart, pMemSize)) {
    ALOGE("Failed to load %s!", pName);
    goto bail;
  }

  // Perform relocation.
  if (!result->mImpl->relocate(pResolver)) {
    ALOGE("Error occurred when performs relocation on %s!", pName);
    goto bail;
  }

  // GDB debugging is enabled. Note that error occurrs during the setup of
  // debugging won't failed the object load. Only a warning is issued to notify
  // that the debugging is disabled due to the failure.
  if (pEnableGDBDebug) {
    // GDB's JIT debugging requires the source object file corresponded to the
    // process image desired to debug with. And some fields in the object file
    // must be updated to record the runtime information after it's loaded into
    // memory. For example, GDB's JIT debugging requires an ELF file with the
    // value of sh_addr in the section header to be the memory address that the
    // section lives in the process image. Therefore, a writable memory with its
    // contents initialized to the contents of pFile is created.
    result->mDebugImage = new (std::nothrow) uint8_t [ pMemSize ];
    if (result->mDebugImage != NULL) {
      ::memcpy(result->mDebugImage, pMemStart, pMemSize);
      if (!result->mImpl->prepareDebugImage(result->mDebugImage, pMemSize)) {
        ALOGW("GDB debug for %s is enabled by the user but won't work due to "
              "failure debug image preparation!", pName);
      } else {
        registerObjectWithGDB(
            reinterpret_cast<const ObjectBuffer *>(result->mDebugImage),
            pMemSize);
      }
    }
  }

  return result;

bail:
  delete result;
  return NULL;
}

ObjectLoader *ObjectLoader::Load(FileBase &pFile,
                                 SymbolResolverInterface &pResolver,
                                 bool pEnableGDBDebug) {
  size_t file_size;
  android::FileMap *file_map = NULL;
  const char *input_filename = pFile.getName().c_str();
  ObjectLoader *result = NULL;

  // Check the inputs.
  if (pFile.hasError()) {
    ALOGE("Input file %s to the object loader is in the invalid state! (%s)",
          input_filename, pFile.getErrorMessage().c_str());
    return NULL;
  }

  // Get the file size.
  file_size = pFile.getSize();
  if (pFile.hasError()) {
    ALOGE("Failed to get size of file %s! (%s)", input_filename,
          pFile.getErrorMessage().c_str());
    return NULL;
  }

  // Abort on empty file.
  if (file_size <= 0) {
    ALOGE("Empty file %s to the object loader.", input_filename);
    return NULL;
  }

  // Create memory map for the input file.
  file_map = pFile.createMap(0, file_size, /* pIsReadOnly */true);
  if ((file_map == NULL) || pFile.hasError())  {
    ALOGE("Failed to map the file %s to the memory! (%s)", input_filename,
          pFile.getErrorMessage().c_str());
    return NULL;
  }

  // Delegate the load request.
  result = Load(file_map->getDataPtr(), file_size, input_filename, pResolver,
                pEnableGDBDebug);

  // No whether the load is successful or not, file_map is no longer needed. On
  // success, there's a copy of the object corresponded to the pFile in the
  // memory. Therefore, file_map can be safely released.
  file_map->release();

  return result;
}

void *ObjectLoader::getSymbolAddress(const char *pName) const {
  return mImpl->getSymbolAddress(pName);
}

size_t ObjectLoader::getSymbolSize(const char *pName) const {
  return mImpl->getSymbolSize(pName);
}

bool ObjectLoader::getSymbolNameList(android::Vector<const char *>& pNameList,
                                     SymbolType pType) const {
  return mImpl->getSymbolNameList(pNameList, pType);
}

ObjectLoader::~ObjectLoader() {
  delete mImpl;
  delete [] reinterpret_cast<uint8_t *>(mDebugImage);
}