MCCacheWriter.cpp revision 5e3e0ce19d80c9a42b89ca95f22d98fbbe6ffb14
1/* 2 * Copyright 2010, 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 "MCCacheWriter.h" 18 19#include "ContextManager.h" 20#include "DebugHelper.h" 21#include "FileHandle.h" 22#include "Script.h" 23 24#include <map> 25#include <string> 26#include <vector> 27#include <utility> 28 29#include <stdint.h> 30#include <stdlib.h> 31#include <string.h> 32 33using namespace std; 34 35#if USE_MCJIT 36namespace bcc { 37 38MCCacheWriter::~MCCacheWriter() { 39#define CHECK_AND_FREE(VAR) if (VAR) { free(VAR); } 40 41 CHECK_AND_FREE(mpHeaderSection); 42 CHECK_AND_FREE(mpStringPoolSection); 43 CHECK_AND_FREE(mpDependencyTableSection); 44 CHECK_AND_FREE(mpExportVarListSection); 45 CHECK_AND_FREE(mpExportFuncListSection); 46 CHECK_AND_FREE(mpPragmaListSection); 47 CHECK_AND_FREE(mpFuncTableSection); 48 CHECK_AND_FREE(mpObjectSlotSection); 49 50#undef CHECK_AND_FREE 51} 52 53bool MCCacheWriter::writeCacheFile(FileHandle *objFile, FileHandle *infoFile, 54 Script *S, uint32_t libRS_threadable) { 55 if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) { 56 return false; 57 } 58 59 mObjFile = objFile; 60 mInfoFile = infoFile; 61 mpOwner = S; 62 63 bool result = prepareHeader(libRS_threadable) 64 && prepareDependencyTable() 65 && prepareFuncTable() 66 && preparePragmaList() 67 && prepareStringPool() 68 && prepareExportVarList() 69 && prepareExportFuncList() 70 && prepareObjectSlotList() 71 && calcSectionOffset() 72 && writeAll() 73 ; 74 75 return result; 76} 77 78 79bool MCCacheWriter::prepareHeader(uint32_t libRS_threadable) { 80 MCO_Header *header = (MCO_Header *)malloc(sizeof(MCO_Header)); 81 82 if (!header) { 83 LOGE("Unable to allocate for header.\n"); 84 return false; 85 } 86 87 mpHeaderSection = header; 88 89 // Initialize 90 memset(header, '\0', sizeof(MCO_Header)); 91 92 // Magic word and version 93 memcpy(header->magic, OBCC_MAGIC, 4); 94 memcpy(header->version, OBCC_VERSION, 4); 95 memcpy(header->libbcc_build_time, libbcc_build_time, 24); 96 97 // Machine Integer Type 98 uint32_t number = 0x00000001; 99 header->endianness = (*reinterpret_cast<char *>(&number) == 1) ? 'e' : 'E'; 100 header->sizeof_off_t = sizeof(off_t); 101 header->sizeof_size_t = sizeof(size_t); 102 header->sizeof_ptr_t = sizeof(void *); 103 104 header->root_base_addr = mpOwner->lookup("root"); 105 106 LOGD("Lookup root() address [%p]", header->root_base_addr); 107 108 // libRS is threadable dirty hack 109 // TODO: This should be removed in the future 110 header->libRS_threadable = libRS_threadable; 111 112 return true; 113} 114 115 116bool MCCacheWriter::prepareDependencyTable() { 117 size_t tableSize = sizeof(OBCC_DependencyTable) + 118 sizeof(OBCC_Dependency) * mDependencies.size(); 119 120 OBCC_DependencyTable *tab = (OBCC_DependencyTable *)malloc(tableSize); 121 122 if (!tab) { 123 LOGE("Unable to allocate for dependency table section.\n"); 124 return false; 125 } 126 127 mpDependencyTableSection = tab; 128 mpHeaderSection->depend_tab_size = tableSize; 129 130 tab->count = mDependencies.size(); 131 132 size_t i = 0; 133 for (map<string, pair<uint32_t, unsigned char const *> >::iterator 134 I = mDependencies.begin(), E = mDependencies.end(); I != E; ++I, ++i) { 135 OBCC_Dependency *dep = &tab->table[i]; 136 137 dep->res_name_strp_index = addString(I->first.c_str(), I->first.size()); 138 dep->res_type = I->second.first; 139 memcpy(dep->sha1, I->second.second, 20); 140 } 141 142 return true; 143} 144 145 146bool MCCacheWriter::prepareFuncTable() { 147 size_t funcCount = mpOwner->getFuncCount(); 148 149 size_t tableSize = sizeof(OBCC_FuncTable) + 150 sizeof(OBCC_FuncInfo) * funcCount; 151 152 OBCC_FuncTable *tab = (OBCC_FuncTable *)malloc(tableSize); 153 154 if (!tab) { 155 LOGE("Unable to allocate for function table section.\n"); 156 return false; 157 } 158 159 mpFuncTableSection = tab; 160 mpHeaderSection->func_table_size = tableSize; 161 162 tab->count = static_cast<size_t>(funcCount); 163 164 // Get the function informations 165 vector<FuncInfo> funcInfoList(funcCount); 166 mpOwner->getFuncInfoList(funcCount, &*funcInfoList.begin()); 167 168 for (size_t i = 0; i < funcCount; ++i) { 169 FuncInfo *info = &funcInfoList[i]; 170 OBCC_FuncInfo *outputInfo = &tab->table[i]; 171 172 outputInfo->name_strp_index = addString(info->name, strlen(info->name)); 173 outputInfo->cached_addr = info->addr; 174 outputInfo->size = info->size; 175 } 176 177 return true; 178} 179 180 181bool MCCacheWriter::preparePragmaList() { 182 size_t pragmaCount = mpOwner->getPragmaCount(); 183 184 size_t listSize = sizeof(OBCC_PragmaList) + 185 sizeof(OBCC_Pragma) * pragmaCount; 186 187 OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize); 188 189 if (!list) { 190 LOGE("Unable to allocate for pragma list\n"); 191 return false; 192 } 193 194 mpPragmaListSection = list; 195 mpHeaderSection->pragma_list_size = listSize; 196 197 list->count = pragmaCount; 198 199 vector<char const *> keyList(pragmaCount); 200 vector<char const *> valueList(pragmaCount); 201 mpOwner->getPragmaList(pragmaCount, &*keyList.begin(), &*valueList.begin()); 202 203 for (size_t i = 0; i < pragmaCount; ++i) { 204 char const *key = keyList[i]; 205 char const *value = valueList[i]; 206 207 size_t keyLen = strlen(key); 208 size_t valueLen = strlen(value); 209 210 OBCC_Pragma *pragma = &list->list[i]; 211 pragma->key_strp_index = addString(key, keyLen); 212 pragma->value_strp_index = addString(value, valueLen); 213 } 214 215 return true; 216} 217 218bool MCCacheWriter::prepareStringPool() { 219 // Calculate string pool size 220 size_t size = sizeof(OBCC_StringPool) + 221 sizeof(OBCC_String) * mStringPool.size(); 222 223 off_t strOffset = size; 224 225 for (size_t i = 0; i < mStringPool.size(); ++i) { 226 size += mStringPool[i].second + 1; 227 } 228 229 // Create string pool 230 OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size); 231 232 if (!pool) { 233 LOGE("Unable to allocate string pool.\n"); 234 return false; 235 } 236 237 mpStringPoolSection = pool; 238 mpHeaderSection->str_pool_size = size; 239 240 pool->count = mStringPool.size(); 241 242 char *strPtr = reinterpret_cast<char *>(pool) + strOffset; 243 244 for (size_t i = 0; i < mStringPool.size(); ++i) { 245 OBCC_String *str = &pool->list[i]; 246 247 str->length = mStringPool[i].second; 248 str->offset = strOffset; 249 memcpy(strPtr, mStringPool[i].first, str->length); 250 251 strPtr += str->length; 252 *strPtr++ = '\0'; 253 254 strOffset += str->length + 1; 255 } 256 257 return true; 258} 259 260 261bool MCCacheWriter::prepareExportVarList() { 262 size_t varCount = mpOwner->getExportVarCount(); 263 size_t listSize = sizeof(OBCC_ExportVarList) + sizeof(void *) * varCount; 264 265 OBCC_ExportVarList *list = (OBCC_ExportVarList *)malloc(listSize); 266 267 if (!list) { 268 LOGE("Unable to allocate for export variable list\n"); 269 return false; 270 } 271 272 mpExportVarListSection = list; 273 mpHeaderSection->export_var_list_size = listSize; 274 275 list->count = static_cast<size_t>(varCount); 276 277 mpOwner->getExportVarList(varCount, list->cached_addr_list); 278 return true; 279} 280 281 282bool MCCacheWriter::prepareExportFuncList() { 283 size_t funcCount = mpOwner->getExportFuncCount(); 284 size_t listSize = sizeof(OBCC_ExportFuncList) + sizeof(void *) * funcCount; 285 286 OBCC_ExportFuncList *list = (OBCC_ExportFuncList *)malloc(listSize); 287 288 if (!list) { 289 LOGE("Unable to allocate for export function list\n"); 290 return false; 291 } 292 293 mpExportFuncListSection = list; 294 mpHeaderSection->export_func_list_size = listSize; 295 296 list->count = static_cast<size_t>(funcCount); 297 298 mpOwner->getExportFuncList(funcCount, list->cached_addr_list); 299 return true; 300} 301 302 303bool MCCacheWriter::prepareObjectSlotList() { 304 size_t objectSlotCount = mpOwner->getObjectSlotCount(); 305 306 size_t listSize = sizeof(OBCC_ObjectSlotList) + 307 sizeof(uint32_t) * objectSlotCount; 308 309 OBCC_ObjectSlotList *list = (OBCC_ObjectSlotList *)malloc(listSize); 310 311 if (!list) { 312 LOGE("Unable to allocate for object slot list\n"); 313 return false; 314 } 315 316 mpObjectSlotSection = list; 317 mpHeaderSection->object_slot_list_size = listSize; 318 319 list->count = objectSlotCount; 320 321 mpOwner->getObjectSlotList(objectSlotCount, list->object_slot_list); 322 return true; 323} 324 325 326bool MCCacheWriter::calcSectionOffset() { 327 size_t offset = sizeof(MCO_Header); 328 329#define OFFSET_INCREASE(NAME) \ 330 do { \ 331 /* Align to a word */ \ 332 size_t rem = offset % sizeof(int); \ 333 if (rem > 0) { \ 334 offset += sizeof(int) - rem; \ 335 } \ 336 \ 337 /* Save the offset and increase it */ \ 338 mpHeaderSection->NAME##_offset = offset; \ 339 offset += mpHeaderSection->NAME##_size; \ 340 } while (0) 341 342 OFFSET_INCREASE(str_pool); 343 OFFSET_INCREASE(depend_tab); 344 OFFSET_INCREASE(export_var_list); 345 OFFSET_INCREASE(export_func_list); 346 OFFSET_INCREASE(pragma_list); 347 OFFSET_INCREASE(func_table); 348 OFFSET_INCREASE(object_slot_list); 349 350#undef OFFSET_INCREASE 351 352 return true; 353} 354 355 356bool MCCacheWriter::writeAll() { 357#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION) \ 358 do { \ 359 if (mInfoFile->seek(OFFSET, SEEK_SET) == -1) { \ 360 LOGE("Unable to seek to " #NAME " section for writing.\n"); \ 361 return false; \ 362 } \ 363 \ 364 if (mInfoFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) != \ 365 static_cast<ssize_t>(SIZE)) { \ 366 LOGE("Unable to write " #NAME " section to cache file.\n"); \ 367 return false; \ 368 } \ 369 } while (0) 370 371#define WRITE_SECTION_SIMPLE(NAME, SECTION) \ 372 WRITE_SECTION(NAME, \ 373 mpHeaderSection->NAME##_offset, \ 374 mpHeaderSection->NAME##_size, \ 375 SECTION) 376 377 WRITE_SECTION(header, 0, sizeof(MCO_Header), mpHeaderSection); 378 379 WRITE_SECTION_SIMPLE(str_pool, mpStringPoolSection); 380 WRITE_SECTION_SIMPLE(depend_tab, mpDependencyTableSection); 381 WRITE_SECTION_SIMPLE(export_var_list, mpExportVarListSection); 382 WRITE_SECTION_SIMPLE(export_func_list, mpExportFuncListSection); 383 WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection); 384 WRITE_SECTION_SIMPLE(func_table, mpFuncTableSection); 385 WRITE_SECTION_SIMPLE(object_slot_list, mpObjectSlotSection); 386 387#undef WRITE_SECTION_SIMPLE 388#undef WRITE_SECTION 389 390 if (static_cast<size_t>(mObjFile->write(mpOwner->getELF(), mpOwner->getELFSize())) 391 != mpOwner->getELFSize()) { 392 LOGE("Unable to write ELF to cache file.\n"); 393 return false; 394 } 395 396 return true; 397} 398 399 400} // namespace bcc 401#endif 402