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
22 namespace panda::ecmascript {
Save(const std::string &filename, Triple triple)23 bool 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
LoadInternal(const std::string &filename)46 bool 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
Load(const std::string &filename)77 bool 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)
Load(const std::string &filename, [[maybe_unused]] std::function<bool (std::string fileName, uint8_t **buff, size_t *buffSize)> ReadAOTCallBack)95 bool 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
TryRemoveAnFile(const char *filename)122 void 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
ParseFunctionEntrySection(ModuleSectionDes &des)132 void 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
UpdateFuncEntries()143 void 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
GetDumpSectionNames()161 const 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
Destroy()174 void AnFileInfo::Destroy()
175 {
176 mainEntryMap_.clear();
177 isLoad_ = false;
178 curTextSecOffset_ = 0;
179 AOTFileInfo::Destroy();
180 }
181
Dump() const182 void 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
IsLoadMain(uint32_t fileIndex, const JSPandaFile *jsPandaFile, const CString &entry) const198 bool 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
AddFuncEntrySec()208 void 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
GenerateMethodToEntryIndexMap()217 void 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