/* * 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 "ELFObjectLoaderImpl.h" #include <llvm/Support/ELF.h> // The following files are included from librsloader. #include "ELFObject.h" #include "ELFSectionSymTab.h" #include "ELFSymbol.h" #include "utils/serialize.h" #include "bcc/ExecutionEngine/SymbolResolverInterface.h" #include "bcc/Support/Log.h" using namespace bcc; bool ELFObjectLoaderImpl::load(const void *pMem, size_t pMemSize) { ArchiveReaderLE reader(reinterpret_cast<const unsigned char *>(pMem), pMemSize); #ifdef __LP64__ mObject = ELFObject<64>::read(reader); #else mObject = ELFObject<32>::read(reader); #endif if (mObject == NULL) { ALOGE("Unable to load the ELF object!"); return false; } // Retrive the pointer to the symbol table. #ifdef __LP64__ mSymTab = static_cast<ELFSectionSymTab<64> *>( mObject->getSectionByName(".symtab")); #else mSymTab = static_cast<ELFSectionSymTab<32> *>( mObject->getSectionByName(".symtab")); #endif if (mSymTab == NULL) { ALOGW("Object doesn't contain any symbol table."); } return true; } bool ELFObjectLoaderImpl::relocate(SymbolResolverInterface &pResolver) { mObject->relocate(SymbolResolverInterface::LookupFunction, &pResolver); if (mObject->getMissingSymbols()) { ALOGE("Some symbols are found to be undefined during relocation!"); return false; } return true; } bool ELFObjectLoaderImpl::prepareDebugImage(void *pDebugImg, size_t pDebugImgSize) { // Update the value of sh_addr in pDebugImg to its corresponding section in // the mObject. #ifdef __LP64__ llvm::ELF::Elf64_Ehdr *elf_header = reinterpret_cast<llvm::ELF::Elf64_Ehdr *>(pDebugImg); #else llvm::ELF::Elf32_Ehdr *elf_header = reinterpret_cast<llvm::ELF::Elf32_Ehdr *>(pDebugImg); #endif if (elf_header->e_shoff > pDebugImgSize) { #ifdef __LP64__ ALOGE("Invalid section header table offset found! (e_shoff = %ld)", elf_header->e_shoff); #else ALOGE("Invalid section header table offset found! (e_shoff = %d)", elf_header->e_shoff); #endif return false; } if ((elf_header->e_shoff + sizeof(llvm::ELF::Elf32_Shdr) * elf_header->e_shnum) > pDebugImgSize) { #ifdef __LP64__ ALOGE("Invalid image supplied (debug image doesn't contain all the section" "header or corrupted image)! (e_shoff = %ld, e_shnum = %d)", elf_header->e_shoff, elf_header->e_shnum); #else ALOGE("Invalid image supplied (debug image doesn't contain all the section" "header or corrupted image)! (e_shoff = %d, e_shnum = %d)", elf_header->e_shoff, elf_header->e_shnum); #endif return false; } #ifdef __LP64__ llvm::ELF::Elf64_Shdr *section_header_table = reinterpret_cast<llvm::ELF::Elf64_Shdr *>( reinterpret_cast<uint8_t*>(pDebugImg) + elf_header->e_shoff); #else llvm::ELF::Elf32_Shdr *section_header_table = reinterpret_cast<llvm::ELF::Elf32_Shdr *>( reinterpret_cast<uint8_t*>(pDebugImg) + elf_header->e_shoff); #endif for (unsigned i = 0; i < elf_header->e_shnum; i++) { if (section_header_table[i].sh_flags & llvm::ELF::SHF_ALLOC) { #ifdef __LP64__ ELFSectionBits<64> *section = static_cast<ELFSectionBits<64> *>(mObject->getSectionByIndex(i)); #else ELFSectionBits<32> *section = static_cast<ELFSectionBits<32> *>(mObject->getSectionByIndex(i)); #endif if (section != NULL) { uintptr_t address = reinterpret_cast<uintptr_t>(section->getBuffer()); #ifdef __LP64__ LOG_FATAL_IF(address > 0xFFFFFFFFFFFFFFFFu, "Out of bound address for Elf64_Addr"); section_header_table[i].sh_addr = static_cast<llvm::ELF::Elf64_Addr>(address); #else LOG_FATAL_IF(address > 0xFFFFFFFFu, "Out of bound address for Elf32_Addr"); section_header_table[i].sh_addr = static_cast<llvm::ELF::Elf32_Addr>(address); #endif } } } return true; } void *ELFObjectLoaderImpl::getSymbolAddress(const char *pName) const { if (mSymTab == NULL) { return NULL; } #ifdef __LP64__ const ELFSymbol<64> *symbol = mSymTab->getByName(pName); #else const ELFSymbol<32> *symbol = mSymTab->getByName(pName); #endif if (symbol == NULL) { ALOGV("Request symbol '%s' is not found in the object!", pName); return NULL; } return symbol->getAddress(mObject->getHeader()->getMachine(), /* autoAlloc */false); } size_t ELFObjectLoaderImpl::getSymbolSize(const char *pName) const { if (mSymTab == NULL) { return 0; } #ifdef __LP64__ const ELFSymbol<64> *symbol = mSymTab->getByName(pName); #else const ELFSymbol<32> *symbol = mSymTab->getByName(pName); #endif if (symbol == NULL) { ALOGV("Request symbol '%s' is not found in the object!", pName); return 0; } return static_cast<size_t>(symbol->getSize()); } bool ELFObjectLoaderImpl::getSymbolNameList(android::Vector<const char *>& pNameList, ObjectLoader::SymbolType pType) const { if (mSymTab == NULL) { return false; } unsigned elf_type; switch (pType) { case ObjectLoader::kFunctionType: { elf_type = llvm::ELF::STT_FUNC; break; } case ObjectLoader::kUnknownType: { break; } default: { assert(false && "Invalid symbol type given!"); return false; } } for (size_t i = 0, e = mSymTab->size(); i != e; i++) { #ifdef __LP64__ ELFSymbol<64> *symbol = (*mSymTab)[i]; #else ELFSymbol<32> *symbol = (*mSymTab)[i]; #endif if (symbol == NULL) { continue; } if ((pType == ObjectLoader::kUnknownType) || (symbol->getType() == elf_type)) { const char *symbol_name = symbol->getName(); if (symbol_name != NULL) { pNameList.push_back(symbol_name); } } } return true; } ELFObjectLoaderImpl::~ELFObjectLoaderImpl() { delete mObject; return; }