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 
18 namespace panda::ecmascript {
19 
Initx86ElfHeader()20 void 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 
InitArmElfHeader()47 void 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 
UpdateSectionOffset(Section &section)74 void JsJitDumpElf::UpdateSectionOffset(Section &section)
75 {
76     if (section.GetType() != SHT_NOBITS) {
77         section.SetOffset(globalOffset);
78     } else {
79         section.SetOffset(0);
80     }
81 }
82 
UpdateGlobalOffset(Section &section)83 void JsJitDumpElf::UpdateGlobalOffset(Section &section)
84 {
85     if (section.GetType() != SHT_NOBITS) {
86         globalOffset += section.GetSectionSize();
87     }
88 }
89 
LayoutSections()90 void 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 
RegisterSection(Section &section)114 void JsJitDumpElf::RegisterSection(Section &section)
115 {
116     sections.push_back(&section);
117     section.SetIndex(static_cast<maplebe::SectionIndex>(sections.size() - 1));
118 }
119 
Init()120 void 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 
AppendData(std::vector<uint8> &codeBuff)132 void JsJitDumpElf::AppendData(std::vector<uint8> &codeBuff)
133 {
134     textSection->AppendData(codeBuff.data(), codeBuff.size());
135 }
136 
AddSymToSymTab(const maplebe::Symbol &symbol, int64 symIdx)137 void JsJitDumpElf::AddSymToSymTab(const maplebe::Symbol &symbol, int64 symIdx)
138 {
139     localSymTab.push_back(std::make_pair(symbol, symIdx));
140 }
141 
AppendGlobalSymsToSymTabSec()142 void 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 
AppendSymbolToSymTab(int64 symIdx, uint64 funcSymValue, uint64 funcSymSize, const std::string &symbolName)152 void 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 
SetFileOffset(int fd, uint64 offset)162 void JsJitDumpElf::SetFileOffset(int fd, uint64 offset)
163 {
164     lseek(fd, offset, SEEK_SET);
165 }
166 
WriteJitElfFile(int fd)167 void 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 
ClearData()190 void 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