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/elf_reader.h"
17
18namespace panda::ecmascript {
19bool ElfReader::VerifyELFHeader(uint32_t version, bool strictMatch)
20{
21    llvm::ELF::Elf64_Ehdr header = *(reinterpret_cast<llvm::ELF::Elf64_Ehdr *>(fileMapMem_.GetOriginAddr()));
22    if (header.e_ident[llvm::ELF::EI_MAG0] != llvm::ELF::ElfMagic[llvm::ELF::EI_MAG0]
23        || header.e_ident[llvm::ELF::EI_MAG1] != llvm::ELF::ElfMagic[llvm::ELF::EI_MAG1]
24        || header.e_ident[llvm::ELF::EI_MAG2] != llvm::ELF::ElfMagic[llvm::ELF::EI_MAG2]
25        || header.e_ident[llvm::ELF::EI_MAG3] != llvm::ELF::ElfMagic[llvm::ELF::EI_MAG3]) {
26        LOG_ECMA(ERROR) << "ELF format error, expected magic is " << llvm::ELF::ElfMagic
27                        << ", but got " << header.e_ident[llvm::ELF::EI_MAG0] << header.e_ident[llvm::ELF::EI_MAG1]
28                        << header.e_ident[llvm::ELF::EI_MAG2] << header.e_ident[llvm::ELF::EI_MAG3];
29        return false;
30    }
31    if (!base::FileHeaderBase::VerifyVersion("Elf", header.e_version, version, strictMatch)) {
32        return false;
33    }
34    if (ElfChecker(fileMapMem_).CheckValidElf() == false) {
35        LOG_ECMA(ERROR) << "ELF file content is not valid";
36        return false;
37    }
38    return true;
39}
40
41ModuleSectionDes::ModuleRegionInfo *ElfReader::GetCurModuleInfo(uint32_t i, llvm::ELF::Elf64_Off offset)
42{
43    uint64_t codeAddress = reinterpret_cast<uint64_t>(fileMapMem_.GetOriginAddr());
44    uint64_t info = codeAddress + offset + i * sizeof(ModuleSectionDes::ModuleRegionInfo);
45    return reinterpret_cast<ModuleSectionDes::ModuleRegionInfo *>(info);
46}
47
48void ElfReader::ParseELFSections(ModuleSectionDes &des, std::vector<ElfSecName> &secs)
49{
50    llvm::ELF::Elf64_Ehdr *ehdr = reinterpret_cast<llvm::ELF::Elf64_Ehdr *>(fileMapMem_.GetOriginAddr());
51    char *addr = reinterpret_cast<char *>(ehdr);
52    llvm::ELF::Elf64_Shdr *shdr = reinterpret_cast<llvm::ELF::Elf64_Shdr *>(addr + ehdr->e_shoff);
53    ASSERT(ehdr->e_shstrndx != static_cast<llvm::ELF::Elf64_Half>(-1));
54    llvm::ELF::Elf64_Shdr strdr = shdr[ehdr->e_shstrndx];
55    for (size_t j = 0; j < secs.size(); ++j) {
56        int secId = -1;
57        ElfSecName sec = secs[j];
58        std::string sectionName = ModuleSectionDes::GetSecName(sec);
59        for (size_t i = 0; i < ehdr->e_shnum; ++i) {
60            llvm::ELF::Elf64_Word shName = shdr[i].sh_name;
61            char *curShName = reinterpret_cast<char *>(addr) + shName + strdr.sh_offset;
62            if (sectionName.compare(curShName) == 0) {
63                secId = static_cast<int>(i);
64                break;
65            }
66        }
67        if (secId == -1) {
68            LOG_COMPILER(DEBUG) << "sectionName: " << sectionName << " not found in strtab";
69            continue;
70        }
71        ASSERT(secId > 0 && secId < ehdr->e_shnum);
72        llvm::ELF::Elf64_Shdr secShdr = shdr[secId];
73        uintptr_t secAddr = reinterpret_cast<uintptr_t>(addr + secShdr.sh_offset);
74        uint32_t secSize = secShdr.sh_size;
75        if (sec == ElfSecName::ARK_FUNCENTRY) {
76            ASSERT((secSize > 0) && (secSize % sizeof(AOTFileInfo::FuncEntryDes) == 0));
77        }
78        if (sec == ElfSecName::ARK_STACKMAP) {
79            des.SetArkStackMapPtr(reinterpret_cast<uint8_t *>(secAddr));
80            des.SetArkStackMapSize(secSize);
81        } else {
82            des.SetSecAddrAndSize(sec, secAddr, secSize);
83        }
84    }
85}
86
87void ElfReader::ParseELFSections(std::vector<ModuleSectionDes> &des, std::vector<ElfSecName> &secs)
88{
89    llvm::ELF::Elf64_Ehdr *ehdr = reinterpret_cast<llvm::ELF::Elf64_Ehdr *>(fileMapMem_.GetOriginAddr());
90    char *addr = reinterpret_cast<char *>(ehdr);
91    llvm::ELF::Elf64_Shdr *shdrs = reinterpret_cast<llvm::ELF::Elf64_Shdr *>(addr + ehdr->e_shoff);
92    ASSERT(ehdr->e_shstrndx != static_cast<llvm::ELF::Elf64_Half>(-1));
93    llvm::ELF::Elf64_Shdr strdr = shdrs[ehdr->e_shstrndx];
94    ASSERT(ehdr->e_flags != static_cast<llvm::ELF::Elf64_Word>(-1));
95    llvm::ELF::Elf64_Shdr moduledr = shdrs[ehdr->e_flags];
96    size_t moduleInfoSize = moduledr.sh_size;
97    uint32_t moduleNum = GetModuleNum(moduleInfoSize);
98    des.resize(moduleNum);
99    std::set<ElfSecName> secSet(secs.begin(), secs.end());
100    for (ElfSecName sec : secSet) {
101        int secId = -1;
102        std::string sectionName = ModuleSectionDes::GetSecName(sec);
103        for (size_t i = 0; i < ehdr->e_shnum; ++i) {
104            llvm::ELF::Elf64_Word shName = shdrs[i].sh_name;
105            char *curShName = reinterpret_cast<char *>(addr) + shName + strdr.sh_offset;
106            if (sectionName.compare(curShName) == 0) {
107                secId = static_cast<int>(i);
108                break;
109            }
110        }
111        if (secId == -1) {
112            LOG_COMPILER(DEBUG) << "sectionName: " << sectionName << " not found in strtab";
113            continue;
114        }
115        ASSERT(secId > 0 && secId < ehdr->e_shnum);
116        llvm::ELF::Elf64_Shdr secShdr = shdrs[secId];
117        uintptr_t secAddr = reinterpret_cast<uintptr_t>(addr + secShdr.sh_offset);
118        uint32_t secSize = secShdr.sh_size;
119        switch (sec) {
120            case ElfSecName::TEXT: {
121                llvm::ELF::Elf64_Off secOffset = 0;
122                SeparateTextSections(des, secAddr, secOffset, moduledr.sh_offset);
123                ASSERT(static_cast<uint32_t>(secOffset) == secSize);
124                break;
125            }
126            case ElfSecName::ARK_STACKMAP: {
127                llvm::ELF::Elf64_Off secOffset = 0;
128                SeparateArkStackMapSections(des, secAddr, secOffset, moduledr.sh_offset);
129                ASSERT(static_cast<uint32_t>(secOffset) == secSize);
130                break;
131            }
132            case ElfSecName::STRTAB: {
133                llvm::ELF::Elf64_Off secOffset = 0;
134                SeparateStrtabSections(des, secAddr, secOffset, moduledr.sh_offset);
135                ASSERT(static_cast<uint32_t>(secOffset) == secSize);
136                break;
137            }
138            case ElfSecName::SYMTAB: {
139                llvm::ELF::Elf64_Off secOffset = 0;
140                SeparateSymtabSections(des, secAddr, secOffset, moduledr.sh_offset);
141                ASSERT(static_cast<uint32_t>(secOffset) == secSize);
142                break;
143            }
144            case ElfSecName::SHSTRTAB:
145            case ElfSecName::ARK_FUNCENTRY:
146            case ElfSecName::ARK_ASMSTUB:
147            case ElfSecName::ARK_MODULEINFO: {
148                if (sec == ElfSecName::ARK_FUNCENTRY) {
149                    ASSERT((secSize > 0) && (secSize % sizeof(AOTFileInfo::FuncEntryDes) == 0));
150                }
151                des[0].SetSecAddrAndSize(sec, secAddr, secSize);
152                break;
153            }
154            default: {
155                LOG_ECMA(FATAL) << "this section should not dump to stub file";
156                break;
157            }
158        }
159    }
160}
161
162void ElfReader::ParseELFSections(BinaryBufferParser &parser,
163                                 std::vector<ModuleSectionDes> &des,
164                                 std::vector<ElfSecName> &secs)
165{
166    ASSERT(des.size() == ASMSTUB_MODULE_NUM);
167    uint64_t codeAddress = reinterpret_cast<uint64_t>(stubsMem_.addr_);
168    llvm::ELF::Elf64_Ehdr ehdr;
169    parser.ParseBuffer(&ehdr, sizeof(ehdr), 0);
170    std::vector<llvm::ELF::Elf64_Shdr> shdrs(ehdr.e_shnum);
171    parser.ParseBuffer(shdrs.data(), sizeof(llvm::ELF::Elf64_Shdr) * ehdr.e_shnum, ehdr.e_shoff);
172
173    ASSERT(ehdr.e_shstrndx != static_cast<llvm::ELF::Elf64_Half>(-1));
174    llvm::ELF::Elf64_Shdr strdr = shdrs[ehdr.e_shstrndx];
175    ASSERT(ehdr.e_flags != static_cast<llvm::ELF::Elf64_Word>(-1));
176    llvm::ELF::Elf64_Shdr moduledr = shdrs[ehdr.e_flags];
177    [[maybe_unused]] size_t moduleInfoSize = moduledr.sh_size;
178    uint32_t moduleNum = GetModuleNum(moduleInfoSize);
179    ASSERT(moduleNum == ASMSTUB_MODULE_NUM);
180    moduleInfo_.resize(moduleNum);
181    parser.ParseBuffer(moduleInfo_.data(), moduleInfoSize, moduledr.sh_offset);
182    std::set<ElfSecName> secSet(secs.begin(), secs.end());
183    for (ElfSecName sec : secSet) {
184        int secId = -1;
185        std::string sectionName = ModuleSectionDes::GetSecName(sec);
186        for (size_t i = 0; i < ehdr.e_shnum; ++i) {
187            llvm::ELF::Elf64_Word shName = shdrs[i].sh_name;
188            char *curShName = reinterpret_cast<char *>(parser.GetAddr()) + shName + strdr.sh_offset;
189            if (sectionName.compare(curShName) == 0) {
190                secId = static_cast<int>(i);
191                break;
192            }
193        }
194        if (secId == -1) {
195            LOG_COMPILER(DEBUG) << "sectionName: " << sectionName << " not found in strtab";
196            continue;
197        }
198        ASSERT(secId > 0 && secId < ehdr.e_shnum);
199        llvm::ELF::Elf64_Shdr secShdr = shdrs[secId];
200        uint64_t secAddr = static_cast<uint64_t>(codeAddress + secShdr.sh_offset);
201        uint32_t secSize = secShdr.sh_size;
202        switch (sec) {
203            case ElfSecName::TEXT: {
204                llvm::ELF::Elf64_Off secOffset = 0;
205                SeparateTextSections(parser, des, secAddr, secOffset, secShdr.sh_offset);
206                ASSERT(static_cast<uint32_t>(secOffset) == secSize);
207                break;
208            }
209            case ElfSecName::ARK_STACKMAP: {
210                llvm::ELF::Elf64_Off secOffset = 0;
211                SeparateArkStackMapSections(parser, des, secAddr, secOffset, secShdr.sh_offset);
212                ASSERT(static_cast<uint32_t>(secOffset) == secSize);
213                break;
214            }
215            case ElfSecName::STRTAB: {
216                llvm::ELF::Elf64_Off secOffset = 0;
217                SeparateStrtabSections(parser, des, secAddr, secOffset, secShdr.sh_offset);
218                ASSERT(static_cast<uint32_t>(secOffset) == secSize);
219                break;
220            }
221            case ElfSecName::SYMTAB: {
222                llvm::ELF::Elf64_Off secOffset = 0;
223                SeparateSymtabSections(parser, des, secAddr, secOffset, secShdr.sh_offset);
224                ASSERT(static_cast<uint32_t>(secOffset) == secSize);
225                break;
226            }
227            case ElfSecName::SHSTRTAB:
228            case ElfSecName::ARK_FUNCENTRY:
229            case ElfSecName::ARK_ASMSTUB:
230            case ElfSecName::ARK_MODULEINFO: {
231                if (sec == ElfSecName::ARK_FUNCENTRY) {
232                    ASSERT((secSize > 0) && (secSize % sizeof(AOTFileInfo::FuncEntryDes) == 0));
233                }
234                parser.ParseBuffer(reinterpret_cast<void *>(secAddr), secSize, secShdr.sh_offset);
235                des[0].SetSecAddrAndSize(sec, secAddr, secSize);
236                break;
237            }
238            default: {
239                LOG_ECMA(FATAL) << "this section should not dump to stub file";
240                break;
241            }
242        }
243    }
244}
245
246bool ElfReader::ParseELFSegment()
247{
248    if (fileMapMem_.GetOriginAddr() == nullptr) {
249        return false;
250    }
251    char *addr = reinterpret_cast<char *>(fileMapMem_.GetOriginAddr());
252    llvm::ELF::Elf64_Ehdr *ehdr = reinterpret_cast<llvm::ELF::Elf64_Ehdr *>(fileMapMem_.GetOriginAddr());
253    llvm::ELF::Elf64_Phdr *phdr = reinterpret_cast<llvm::ELF::Elf64_Phdr *>(addr + ehdr->e_phoff);
254    for (int i = 0; i < ehdr->e_phnum; ++i) {
255        if (phdr[i].p_type != llvm::ELF::PT_LOAD) {
256            continue;
257        }
258        if (phdr[i].p_filesz > phdr[i].p_memsz) {
259            LOG_COMPILER(ERROR) << " p_filesz:0x" << std::hex << phdr[i].p_filesz << " > p_memsz:0x"
260                << phdr[i].p_memsz;
261            return false;
262        }
263        if (!phdr[i].p_filesz) {
264            continue;
265        }
266        unsigned char *virtualAddr = reinterpret_cast<unsigned char *>(addr + phdr[i].p_vaddr);
267        ASSERT(phdr[i].p_offset % PageSize() == 0);
268        if ((phdr[i].p_flags & llvm::ELF::PF_X) != 0) {
269            ASSERT(reinterpret_cast<uintptr_t>(virtualAddr) % PageSize() == 0);
270            if (!PageProtect(virtualAddr, phdr[i].p_memsz, PAGE_PROT_EXEC_READ)) {
271                return false;
272            }
273        }
274    }
275    return true;
276}
277
278void ElfReader::SeparateTextSections(std::vector<ModuleSectionDes> &des,
279                                     const uintptr_t &secAddr,
280                                     llvm::ELF::Elf64_Off &secOffset,
281                                     const llvm::ELF::Elf64_Off &moduleInfoOffset)
282{
283    for (size_t i = 0; i < des.size(); ++i) {
284        auto moduleInfo = GetCurModuleInfo(i, moduleInfoOffset);
285        secOffset = AlignUp(secOffset, AOTFileInfo::PAGE_ALIGN);
286        uint32_t rodataSizeBeforeText = moduleInfo->rodataSizeBeforeText;
287        uint32_t rodataSizeAfterText = moduleInfo->rodataSizeAfterText;
288        if (rodataSizeBeforeText != 0) {
289            secOffset += rodataSizeBeforeText;
290            secOffset = AlignUp(secOffset, AOTFileInfo::TEXT_SEC_ALIGN);
291        }
292        uint32_t textSize = moduleInfo->textSize;
293        des[i].SetSecAddrAndSize(ElfSecName::TEXT, secAddr + secOffset, textSize);
294        secOffset += textSize;
295        if (rodataSizeAfterText != 0) {
296            secOffset = AlignUp(secOffset, AOTFileInfo::DATA_SEC_ALIGN);
297            secOffset += rodataSizeAfterText;
298        }
299    }
300}
301
302void ElfReader::SeparateArkStackMapSections(std::vector<ModuleSectionDes> &des,
303                                            const uintptr_t &secAddr,
304                                            llvm::ELF::Elf64_Off &secOffset,
305                                            const llvm::ELF::Elf64_Off &moduleInfoOffset)
306{
307    for (size_t i = 0; i < des.size(); ++i) {
308        auto moduleInfo = GetCurModuleInfo(i, moduleInfoOffset);
309        uint32_t stackMapSize = moduleInfo->stackMapSize;
310        des[i].SetArkStackMapPtr(reinterpret_cast<uint8_t *>(secAddr + secOffset));
311        des[i].SetArkStackMapSize(stackMapSize);
312        uint32_t index = moduleInfo->startIndex;
313        uint32_t cnt = moduleInfo->funcCount;
314        des[i].SetStartIndex(index);
315        des[i].SetFuncCount(cnt);
316        secOffset += stackMapSize;
317    }
318}
319
320void ElfReader::SeparateStrtabSections(std::vector<ModuleSectionDes> &des,
321                                       const uintptr_t &secAddr,
322                                       llvm::ELF::Elf64_Off &secOffset,
323                                       const llvm::ELF::Elf64_Off &moduleInfoOffset)
324{
325    for (size_t i = 0; i < des.size(); ++i) {
326        auto moduleInfo = GetCurModuleInfo(i, moduleInfoOffset);
327        uint32_t strtabSize = moduleInfo->strtabSize;
328        des[i].SetSecAddrAndSize(ElfSecName::STRTAB, secAddr + secOffset, strtabSize);
329        secOffset += strtabSize;
330    }
331}
332
333void ElfReader::SeparateSymtabSections(std::vector<ModuleSectionDes> &des,
334                                       const uintptr_t &secAddr,
335                                       llvm::ELF::Elf64_Off &secOffset,
336                                       const llvm::ELF::Elf64_Off &moduleInfoOffset)
337{
338    for (size_t i = 0; i < des.size(); ++i) {
339        auto moduleInfo = GetCurModuleInfo(i, moduleInfoOffset);
340        uint32_t symtabSize = moduleInfo->symtabSize;
341        des[i].SetSecAddrAndSize(ElfSecName::SYMTAB, secAddr + secOffset, symtabSize);
342        secOffset += symtabSize;
343    }
344}
345
346void ElfReader::SeparateTextSections(BinaryBufferParser &parser,
347                                     std::vector<ModuleSectionDes> &des,
348                                     const uint64_t &secAddr,
349                                     llvm::ELF::Elf64_Off &secOffset,
350                                     const llvm::ELF::Elf64_Off &curShOffset)
351{
352    for (size_t i = 0; i < des.size(); ++i) {
353        auto moduleInfo = moduleInfo_[i];
354        secOffset = AlignUp(secOffset, AOTFileInfo::PAGE_ALIGN);
355        uint32_t rodataSizeBeforeText = moduleInfo.rodataSizeBeforeText;
356        uint32_t rodataSizeAfterText = moduleInfo.rodataSizeAfterText;
357        if (rodataSizeBeforeText != 0) {
358            parser.ParseBuffer(reinterpret_cast<void *>(secAddr + secOffset), rodataSizeBeforeText,
359                               curShOffset + secOffset);
360            secOffset += rodataSizeBeforeText;
361            secOffset = AlignUp(secOffset, AOTFileInfo::TEXT_SEC_ALIGN);
362        }
363        uint32_t textSize = moduleInfo.textSize;
364        parser.ParseBuffer(reinterpret_cast<void *>(secAddr + secOffset), textSize, curShOffset + secOffset);
365        des[i].SetSecAddrAndSize(ElfSecName::TEXT, secAddr + secOffset, textSize);
366        secOffset += textSize;
367        if (rodataSizeAfterText != 0) {
368            secOffset = AlignUp(secOffset, AOTFileInfo::DATA_SEC_ALIGN);
369            parser.ParseBuffer(reinterpret_cast<void *>(secAddr + secOffset), rodataSizeAfterText,
370                               curShOffset + secOffset);
371            secOffset += rodataSizeAfterText;
372        }
373    }
374}
375
376void ElfReader::SeparateArkStackMapSections(BinaryBufferParser &parser,
377                                            std::vector<ModuleSectionDes> &des,
378                                            const uint64_t &secAddr,
379                                            llvm::ELF::Elf64_Off &secOffset,
380                                            const llvm::ELF::Elf64_Off &curShOffset)
381{
382    for (size_t i = 0; i < des.size(); ++i) {
383        auto moduleInfo = moduleInfo_[i];
384        uint32_t stackMapSize = moduleInfo.stackMapSize;
385        parser.ParseBuffer(reinterpret_cast<void *>(secAddr + secOffset), stackMapSize, curShOffset + secOffset);
386        des[i].SetArkStackMapPtr(reinterpret_cast<uint8_t *>(secAddr + secOffset));
387        des[i].SetArkStackMapSize(stackMapSize);
388        uint32_t index = moduleInfo.startIndex;
389        uint32_t cnt = moduleInfo.funcCount;
390        des[i].SetStartIndex(index);
391        des[i].SetFuncCount(cnt);
392        secOffset += stackMapSize;
393    }
394}
395
396void ElfReader::SeparateStrtabSections(BinaryBufferParser &parser,
397                                       std::vector<ModuleSectionDes> &des,
398                                       const uintptr_t &secAddr,
399                                       llvm::ELF::Elf64_Off &secOffset,
400                                       const llvm::ELF::Elf64_Off &curShOffset)
401{
402    for (size_t i = 0; i < des.size(); ++i) {
403        auto moduleInfo = moduleInfo_[i];
404        uint32_t strtabSize = moduleInfo.strtabSize;
405        parser.ParseBuffer(reinterpret_cast<void *>(secAddr + secOffset), strtabSize, curShOffset + secOffset);
406        des[i].SetSecAddrAndSize(ElfSecName::STRTAB, secAddr + secOffset, strtabSize);
407        secOffset += strtabSize;
408    }
409}
410
411void ElfReader::SeparateSymtabSections(BinaryBufferParser &parser,
412                                       std::vector<ModuleSectionDes> &des,
413                                       const uintptr_t &secAddr,
414                                       llvm::ELF::Elf64_Off &secOffset,
415                                       const llvm::ELF::Elf64_Off &curShOffset)
416{
417    for (size_t i = 0; i < des.size(); ++i) {
418        auto moduleInfo = moduleInfo_[i];
419        uint32_t symtabSize = moduleInfo.symtabSize;
420        parser.ParseBuffer(reinterpret_cast<void *>(secAddr + secOffset), symtabSize, curShOffset + secOffset);
421        des[i].SetSecAddrAndSize(ElfSecName::SYMTAB, secAddr + secOffset, symtabSize);
422        secOffset += symtabSize;
423    }
424}
425}  // namespace panda::ecmascript
426