1/*
2 * Copyright (c) 2024 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/dfx/dump_code/jit_dump_elf.h"
17
18namespace panda::ecmascript {
19
20void JsJitDumpElf::Initx86ElfHeader()
21{
22    header.e_ident[EI_MAG0] = ELFMAG0;
23    header.e_ident[EI_MAG1] = ELFMAG1;
24    header.e_ident[EI_MAG2] = ELFMAG2;
25    header.e_ident[EI_MAG3] = ELFMAG3;
26    header.e_ident[EI_CLASS] = ELFCLASS64;
27    header.e_ident[EI_DATA] = ELFDATA2LSB;
28    header.e_ident[EI_VERSION] = EV_CURRENT;
29    header.e_ident[EI_OSABI] = ELFOSABI_NONE; /* ELFOSABI_NONE represents UNIX System V */
30    header.e_ident[EI_ABIVERSION] = 0;
31    (void)std::fill_n(&header.e_ident[EI_PAD], EI_NIDENT - EI_PAD, 0);
32    header.e_type = ET_REL;
33    header.e_machine = EM_X86_64;
34    header.e_version = EV_CURRENT;
35    header.e_entry = 0;
36    header.e_phoff = 0;
37    header.e_shoff = 0; /* later get */
38    header.e_flags = 0; /* The Intel architecture defines no flags; so this member contains zero. */
39    header.e_ehsize = sizeof(maplebe::FileHeader);
40    header.e_phentsize = 0;
41    header.e_phnum = 0;
42    header.e_shentsize = sizeof(maplebe::SectionHeader);
43    header.e_shnum = static_cast<uint16>(sections.size());
44    header.e_shstrndx = strTabSection->GetIndex();
45}
46
47void JsJitDumpElf::InitArmElfHeader()
48{
49    header.e_ident[EI_MAG0] = ELFMAG0;
50    header.e_ident[EI_MAG1] = ELFMAG1;
51    header.e_ident[EI_MAG2] = ELFMAG2;
52    header.e_ident[EI_MAG3] = ELFMAG3;
53    header.e_ident[EI_CLASS] = ELFCLASS64;
54    header.e_ident[EI_DATA] = ELFDATA2LSB;
55    header.e_ident[EI_VERSION] = EV_CURRENT;
56    header.e_ident[EI_OSABI] = ELFOSABI_LINUX;
57    header.e_ident[EI_ABIVERSION] = 0;
58    std::fill_n(&header.e_ident[EI_PAD], EI_NIDENT - EI_PAD, 0);
59    header.e_type = ET_REL;
60    header.e_version = 1;
61    header.e_machine = EM_AARCH64;
62    header.e_flags = 0;
63    header.e_entry = 0;
64    header.e_ehsize = sizeof(maplebe::FileHeader);
65    header.e_phentsize = sizeof(maplebe::SegmentHeader);
66    header.e_shentsize = sizeof(maplebe::SectionHeader);
67    header.e_shstrndx = strTabSection->GetIndex();
68    header.e_shoff = 0;
69    header.e_phoff = 0;
70    header.e_shnum = sections.size();
71    header.e_phnum = 0;
72}
73
74void JsJitDumpElf::UpdateSectionOffset(Section &section)
75{
76    if (section.GetType() != SHT_NOBITS) {
77        section.SetOffset(globalOffset);
78    } else {
79        section.SetOffset(0);
80    }
81}
82
83void JsJitDumpElf::UpdateGlobalOffset(Section &section)
84{
85    if (section.GetType() != SHT_NOBITS) {
86        globalOffset += section.GetSectionSize();
87    }
88}
89
90void JsJitDumpElf::LayoutSections()
91{
92    globalOffset = sizeof(maplebe::FileHeader);
93    globalOffset = Alignment::Align<maplebe::Offset>(globalOffset, k8Bits);
94
95    for (auto *section : sections) {
96        section->SetSectionHeaderNameIndex(static_cast<maplebe::Word>(strTabSection->AddString(section->GetName())));
97    }
98
99    for (auto *section : sections) {
100        globalOffset = Alignment::Align<maplebe::Offset>(globalOffset, section->GetAlign());
101        /* lay out section */
102        UpdateSectionOffset(*section);
103        if (section->GetType() != SHT_NOBITS) {
104            section->GenerateData();
105        }
106        UpdateGlobalOffset(*section);
107    }
108
109    globalOffset = Alignment::Align<maplebe::Offset>(globalOffset, 16U);
110    header.e_shoff = globalOffset;
111    header.e_shnum = static_cast<uint16>(sections.size());
112}
113
114void JsJitDumpElf::RegisterSection(Section &section)
115{
116    sections.push_back(&section);
117    section.SetIndex(static_cast<maplebe::SectionIndex>(sections.size() - 1));
118}
119
120void JsJitDumpElf::Init()
121{
122    DataSection *nullDataSection = new DataSection(" ", SHT_NULL, 0, 0);
123    RegisterSection(*nullDataSection);
124    strTabSection = new StringSection(".strtab", SHT_STRTAB, 0, 1);
125    RegisterSection(*strTabSection);
126    textSection = new DataSection(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, k8Bits);
127    RegisterSection(*textSection);
128    symbolTabSection = new SymbolSection(".symtab", SHT_SYMTAB, 0, k8Bits, *strTabSection);
129    RegisterSection(*symbolTabSection);
130}
131
132void JsJitDumpElf::AppendData(std::vector<uint8> &codeBuff)
133{
134    textSection->AppendData(codeBuff.data(), codeBuff.size());
135}
136
137void JsJitDumpElf::AddSymToSymTab(const maplebe::Symbol &symbol, int64 symIdx)
138{
139    localSymTab.push_back(std::make_pair(symbol, symIdx));
140}
141
142void JsJitDumpElf::AppendGlobalSymsToSymTabSec()
143{
144    for (auto elem : localSymTab) {
145        const maplebe::Symbol &symbol = elem.first;
146        int64 symIdx = elem.second;
147        symbolTabSection->AppendSymbol(symbol);
148        symbolTabSection->AppendIdxInSymbols(symIdx);
149    }
150}
151
152void JsJitDumpElf::AppendSymbolToSymTab(int64 symIdx, uint64 funcSymValue, uint64 funcSymSize,
153                                        const std::string &symbolName)
154{
155    uint8 funcSymType = STB_GLOBAL;
156    auto nameIndex = strTabSection->AddString(symbolName);
157    AddSymToSymTab({static_cast<maplebe::Word>(nameIndex),
158        static_cast<uint8>((funcSymType << kLeftShift4Bits) + (STT_FUNC & 0xf)), 0, textSection->GetIndex(),
159        funcSymValue, funcSymSize}, symIdx);
160}
161
162void JsJitDumpElf::SetFileOffset(int fd, uint64 offset)
163{
164    lseek(fd, offset, SEEK_SET);
165}
166
167void JsJitDumpElf::WriteJitElfFile(int fd)
168{
169    AppendGlobalSymsToSymTabSec();
170    /* Init elf file header */
171    InitArmElfHeader();
172    LayoutSections();
173    /* write header */
174    (void)write(fd, reinterpret_cast<const char *>(&header), sizeof(header));
175    /* write sections */
176    for (auto *section : sections) {
177        if (section->GetType() == SHT_NOBITS) {
178            continue;
179        }
180        SetFileOffset(fd, section->GetOffset());
181        section->WriteSection(fd);
182    }
183    SetFileOffset(fd, header.e_shoff);
184    /* write section table */
185    for (auto *section : sections) {
186        (void)write(fd, &section->GetSectionHeader(), sizeof(section->GetSectionHeader()));
187    }
188}
189
190void JsJitDumpElf::ClearData()
191{
192    localSymTab.clear();
193    globalOffset = 0;
194    textSection->ClearData();
195    symbolTabSection->ClearData();
196    strTabSection->ClearData();
197    sections.clear();
198}
199
200}  // namespace panda::ecmascript
201