1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/compiler/aot_file/an_file_info.h" 17 18#include <cerrno> 19#include "ecmascript/compiler/aot_file/elf_builder.h" 20#include "ecmascript/compiler/aot_file/elf_reader.h" 21 22namespace panda::ecmascript { 23bool AnFileInfo::Save(const std::string &filename, Triple triple) 24{ 25 std::string realPath; 26 if (!RealPath(filename, realPath, false)) { 27 return false; 28 } 29 const char *rawPath = realPath.c_str(); 30 TryRemoveAnFile(rawPath); 31 32 std::ofstream file(rawPath, std::ofstream::binary); 33 SetStubNum(entries_.size()); 34 AddFuncEntrySec(); 35 36 ElfBuilder builder(des_, GetDumpSectionNames()); 37 llvm::ELF::Elf64_Ehdr header; 38 builder.PackELFHeader(header, base::FileHeaderBase::ToVersionNumber(AOTFileVersion::AN_VERSION), triple); 39 file.write(reinterpret_cast<char *>(&header), sizeof(llvm::ELF::Elf64_Ehdr)); 40 builder.PackELFSections(file); 41 builder.PackELFSegment(file); 42 file.close(); 43 return true; 44} 45 46bool AnFileInfo::LoadInternal(const std::string &filename) 47{ 48 if (fileMapMem_.GetOriginAddr() == nullptr) { 49 LOG_ECMA(ERROR) << "File mmap failed"; 50 return false; 51 } 52 53 moduleNum_ = 1; 54 des_.resize(moduleNum_); 55 ModuleSectionDes &des = des_[0]; 56 57 ElfReader reader(fileMapMem_); 58 std::vector<ElfSecName> secs = GetDumpSectionNames(); 59 if (!reader.VerifyELFHeader(base::FileHeaderBase::ToVersionNumber(AOTFileVersion::AN_VERSION), 60 AOTFileVersion::AN_STRICT_MATCH)) { 61 return false; 62 } 63 reader.ParseELFSections(des, secs); 64 if (!reader.ParseELFSegment()) { 65 LOG_ECMA(ERROR) << "modify mmap area permission failed"; 66 return false; 67 } 68 ParseFunctionEntrySection(des); 69 70 UpdateFuncEntries(); 71 72 LOG_COMPILER(INFO) << "loaded an file: " << filename.c_str(); 73 isLoad_ = true; 74 return true; 75} 76 77bool AnFileInfo::Load(const std::string &filename) 78{ 79 std::string realPath; 80 if (!RealPath(filename, realPath, false)) { 81 LOG_COMPILER(ERROR) << "Can not load aot file from path [ " << filename << " ], " 82 << "please execute ark_aot_compiler with options --aot-file."; 83 return false; 84 } 85 if (!FileExist(realPath.c_str())) { 86 LOG_ECMA(WARN) << "File not exist. file: " << realPath; 87 return false; 88 } 89 90 fileMapMem_ = FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READ); 91 return LoadInternal(filename); 92} 93 94#if defined(CROSS_PLATFORM) && defined(ANDROID_PLATFORM) 95bool AnFileInfo::Load(const std::string &filename, [[maybe_unused]] std::function<bool 96 (std::string fileName, uint8_t **buff, size_t *buffSize)> ReadAOTCallBack) 97{ 98 std::string fileName = filename; 99 uint8_t *buff = nullptr; 100 size_t buffSize = 0; 101 size_t found = filename.find_last_of("/"); 102 if (found != std::string::npos) { 103 fileName = filename.substr(found + 1); 104 } 105 106 LOG_ECMA(INFO) << "Call JsAotReader to load: " << fileName; 107 if (ReadAOTCallBack(fileName, &buff, &buffSize)) { 108 void* newBuff = nullptr; 109 if (posix_memalign(&newBuff, sysconf(_SC_PAGESIZE), buffSize) != 0) { 110 LOG_ECMA(ERROR) << "posix_memalign failed!"; 111 return false; 112 } 113 std::copy(reinterpret_cast<char*>(buff), reinterpret_cast<char*>(buff) + buffSize, 114 reinterpret_cast<char*>(newBuff)); 115 fileMapMem_ = MemMap(newBuff, buffSize); 116 } 117 118 return LoadInternal(filename); 119} 120#endif 121 122void AnFileInfo::TryRemoveAnFile(const char *filename) 123{ 124 if (!FileExist(filename)) { 125 return; 126 } 127 if (Unlink(filename) == -1) { 128 LOG_COMPILER(ERROR) << "remove " << filename << " failed and errno is " << errno; 129 } 130} 131 132void AnFileInfo::ParseFunctionEntrySection(ModuleSectionDes &des) 133{ 134 uint64_t secAddr = des.GetSecAddr(ElfSecName::ARK_FUNCENTRY); 135 uint32_t secSize = des.GetSecSize(ElfSecName::ARK_FUNCENTRY); 136 FuncEntryDes *entryDes = reinterpret_cast<FuncEntryDes *>(secAddr); 137 entryNum_ = secSize / sizeof(FuncEntryDes); 138 entries_.assign(entryDes, entryDes + entryNum_); 139 des.SetStartIndex(0); 140 des.SetFuncCount(entryNum_); 141} 142 143void AnFileInfo::UpdateFuncEntries() 144{ 145 ModuleSectionDes &des = des_[0]; 146 size_t len = entries_.size(); 147 for (size_t i = 0; i < len; i++) { 148 FuncEntryDes &funcDes = entries_[i]; 149 funcDes.codeAddr_ += des.GetSecAddr(ElfSecName::TEXT); 150 if (funcDes.isMainFunc_) { 151 EntryKey key = std::make_pair(funcDes.abcIndexInAi_, funcDes.indexInKindOrMethodId_); 152 mainEntryMap_[key] = MainFuncEntry { funcDes.codeAddr_, funcDes.fpDeltaPrevFrameSp_, funcDes.isFastCall_ }; 153#ifndef NDEBUG 154 LOG_COMPILER(INFO) << "AnFileInfo Load main method id: " << funcDes.indexInKindOrMethodId_ 155 << " code addr: " << reinterpret_cast<void *>(funcDes.codeAddr_); 156#endif 157 } 158 } 159} 160 161const std::vector<ElfSecName> &AnFileInfo::GetDumpSectionNames() 162{ 163 static const std::vector<ElfSecName> secNames = { 164 ElfSecName::TEXT, 165 ElfSecName::STRTAB, 166 ElfSecName::SYMTAB, 167 ElfSecName::SHSTRTAB, 168 ElfSecName::ARK_STACKMAP, 169 ElfSecName::ARK_FUNCENTRY 170 }; 171 return secNames; 172} 173 174void AnFileInfo::Destroy() 175{ 176 mainEntryMap_.clear(); 177 isLoad_ = false; 178 curTextSecOffset_ = 0; 179 AOTFileInfo::Destroy(); 180} 181 182void AnFileInfo::Dump() const 183{ 184 LOG_COMPILER(INFO) << "An file loading: "; 185 int i = 0; 186 for (const ModuleSectionDes &d : des_) { 187 i++; 188 for (const auto &s : d.GetSectionsInfo()) { 189 std::string name = d.GetSecName(s.first); 190 uint32_t size = d.GetSecSize(s.first); 191 uint64_t addr = d.GetSecAddr(s.first); 192 LOG_COMPILER(INFO) << " - module-" << i << " <" << name << "> [0x" << std::hex << addr << ", 0x" 193 << std::hex << addr + size << "]"; 194 } 195 } 196} 197 198bool AnFileInfo::IsLoadMain(uint32_t fileIndex, const JSPandaFile *jsPandaFile, const CString &entry) const 199{ 200 auto methodId = jsPandaFile->GetMainMethodIndex(entry); 201#ifndef NDEBUG 202 LOG_COMPILER(INFO) << "AnFileInfo IsLoadMain method id: " << methodId << " entry: " << entry; 203#endif 204 auto it = mainEntryMap_.find(std::make_pair(fileIndex, methodId)); 205 return it != mainEntryMap_.end(); 206} 207 208void AnFileInfo::AddFuncEntrySec() 209{ 210 ModuleSectionDes &des = des_[ElfBuilder::FuncEntryModuleDesIndex]; 211 // add section 212 uint64_t funcEntryAddr = reinterpret_cast<uint64_t>(entries_.data()); 213 uint32_t funcEntrySize = sizeof(FuncEntryDes) * entryNum_; 214 des.SetSecAddrAndSize(ElfSecName::ARK_FUNCENTRY, funcEntryAddr, funcEntrySize); 215} 216 217void AnFileInfo::GenerateMethodToEntryIndexMap() 218{ 219 const std::vector<AOTFileInfo::FuncEntryDes> &entries = GetStubs(); 220 uint32_t entriesSize = entries.size(); 221 for (uint32_t i = 0; i < entriesSize; ++i) { 222 const AOTFileInfo::FuncEntryDes &entry = entries[i]; 223 std::string &fileName = entryIdxToFileNameMap_.at(i); 224 auto key = std::make_pair(fileName, entry.indexInKindOrMethodId_); 225 methodToEntryIndexMap_[key] = i; 226 } 227} 228} // namespace panda::ecmascript 229