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