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#ifndef ECMASCRIPT_JIT_DUMP_ELF_H
17#define ECMASCRIPT_JIT_DUMP_ELF_H
18
19#include <vector>
20#include <string>
21#include <unistd.h>
22#include <unordered_map>
23
24#include "ecmascript/compiler/codegen/maple/maple_be/include/cg/elf_types.h"
25#include "ecmascript/log_wrapper.h"
26
27namespace panda::ecmascript {
28
29using uint8 = uint8_t;
30using uint16 = uint16_t;
31using uint32 = uint32_t;
32using uint64 = uint64_t;
33using int8 = int8_t;
34using int16 = int16_t;
35using int32 = int32_t;
36using int64 = int64_t;
37using uintptr = uintptr_t;
38
39const uint8 kLeftShift4Bits = 4;
40static const uint8 k8Bits = 8;
41
42class Section {
43public:
44    Section(const std::string &name, maplebe::Word type, maplebe::Xword flags, maplebe::Xword align) : name(name)
45    {
46        sectionHeader.sh_type = type;
47        sectionHeader.sh_flags = flags;
48        sectionHeader.sh_addralign = align;
49    }
50
51    virtual ~Section() = default;
52    virtual void GenerateData() = 0;
53    virtual void WriteSection(int fd) = 0;
54
55    virtual void ClearData()
56    {
57        return;
58    }
59
60    void SetIndex(maplebe::SectionIndex idx)
61    {
62        sectionIndex = idx;
63    }
64
65    maplebe::SectionIndex GetIndex() const
66    {
67        return sectionIndex;
68    }
69
70    void SetInfo(maplebe::Word value)
71    {
72        sectionHeader.sh_info = value;
73    }
74
75    void SetLink(const Section &section)
76    {
77        sectionHeader.sh_link = static_cast<maplebe::Word>(section.GetIndex());
78    }
79
80    void SetEntSize(maplebe::Xword value)
81    {
82        sectionHeader.sh_entsize = value;
83    }
84
85    void SetSectionSize(maplebe::Xword size)
86    {
87        sectionHeader.sh_size = size;
88    }
89
90    virtual maplebe::Xword GetSectionSize()
91    {
92        return sectionHeader.sh_size;
93    }
94
95    void SetAddr(maplebe::Address addr)
96    {
97        sectionHeader.sh_addr = addr;
98    }
99
100    maplebe::Address GetAddr() const
101    {
102        return sectionHeader.sh_addr;
103    }
104
105    maplebe::Xword GetFlags() const
106    {
107        return sectionHeader.sh_flags;
108    }
109
110    void SetOffset(maplebe::Offset value)
111    {
112        sectionHeader.sh_offset = value;
113    }
114
115    maplebe::Offset GetOffset() const
116    {
117        return sectionHeader.sh_offset;
118    }
119
120    maplebe::Xword GetAlign() const
121    {
122        return sectionHeader.sh_addralign;
123    }
124
125    const std::string &GetName() const
126    {
127        return name;
128    }
129
130    void SetSectionHeaderNameIndex(maplebe::Word index)
131    {
132        sectionHeader.sh_name = index;
133    }
134
135    maplebe::Word GetType() const
136    {
137        return sectionHeader.sh_type;
138    }
139
140    const maplebe::SectionHeader &GetSectionHeader() const
141    {
142        return sectionHeader;
143    }
144
145private:
146    std::string name;
147    maplebe::SectionIndex sectionIndex {};
148    maplebe::SectionHeader sectionHeader {};
149}; /* class Section */
150
151class RelaSection : public Section {
152public:
153    RelaSection(const std::string &name, maplebe::Word type, maplebe::Xword flags, maplebe::Word info,
154        maplebe::Xword align, const Section &link) : Section(name, type, flags, align)
155    {
156        SetEntSize(sizeof(maplebe::Rela));
157        SetInfo(info);
158        SetLink(link);
159    }
160
161    ~RelaSection() = default;
162
163    void GenerateData() override
164    {
165        SetSectionSize(relas.size() * sizeof(maplebe::Rela));
166    }
167
168    void WriteSection(int fd) override
169    {
170        (void)write(fd, reinterpret_cast<const char *>(relas.data()), relas.size() * sizeof(maplebe::Rela));
171    }
172
173    void AppendRela(maplebe::Rela rela)
174    {
175        relas.push_back(rela);
176    }
177
178private:
179    std::vector<maplebe::Rela> relas;
180}; /* class RelaSection */
181
182class SymbolSection : public Section {
183public:
184    SymbolSection(const std::string &name, maplebe::Word type, maplebe::Xword flags, maplebe::Xword align,
185        const Section &link) : Section(name, type, flags, align)
186    {
187        SetEntSize(sizeof(maplebe::Symbol));
188        SetLink(link);
189        SetInfo(1);
190        AppendSymbol({0, 0, 0, 0, 0, 0});
191    }
192
193    ~SymbolSection() = default;
194
195    void GenerateData() override
196    {
197        SetSectionSize(symbols.size() * sizeof(maplebe::Symbol));
198    }
199
200    void WriteSection(int fd) override
201    {
202        (void)write(fd, reinterpret_cast<const char *>(symbols.data()), symbols.size() * sizeof(maplebe::Symbol));
203    }
204
205    void AppendSymbol(const maplebe::Symbol &symbol)
206    {
207        symbols.push_back(symbol);
208    }
209
210    uint32 GetSymbolsSize() const
211    {
212        return symbols.size();
213    }
214
215    uint64 GetIdxInSymbols(int64 symIdx) const
216    {
217        return symbolIdxMap.at(symIdx);
218    }
219
220    void AppendIdxInSymbols(int64 symIdx)
221    {
222        symbolIdxMap[symIdx] = static_cast<uint64>(GetSymbolsSize() - 1);
223    }
224
225    bool ExistSymInSymbols(int64 symIdx)
226    {
227        return symbolIdxMap.count(symIdx) != 0;
228    }
229
230    uint32 GetDataSize() const
231    {
232        return symbols.size() * sizeof(maplebe::Symbol);
233    }
234
235    const char *GetAddr()
236    {
237        return reinterpret_cast<const char*>(symbols.data());
238    }
239
240    void ClearData() override
241    {
242        symbols.clear();
243        symbolIdxMap.clear();
244    }
245
246private:
247    std::vector<maplebe::Symbol> symbols;
248    std::unordered_map<int64, uint64> symbolIdxMap;
249}; /* class SymbolSection */
250
251class DataSection : public Section {
252public:
253    DataSection(const std::string &name, maplebe::Word type, maplebe::Xword flags, maplebe::Xword align)
254        : Section(name, type, flags, align) {}
255
256    ~DataSection() = default;
257
258    virtual void GenerateData() override
259    {
260        SetSectionSize(data.size());
261    }
262
263    virtual void WriteSection(int fd) override
264    {
265        (void)write(fd, reinterpret_cast<const char *>(data.data()), data.size());
266    }
267
268    void AppendData(const void *value, size_t size)
269    {
270        auto pdata = reinterpret_cast<const uint8 *>(value);
271        data.insert(data.end(), pdata, pdata + size);
272    }
273
274    void AppendData(int64 value, size_t size)
275    {
276        for (size_t i = 0; i < size; i++) {
277            auto pdata = static_cast<uint8>(value >> (i * k8Bits));
278            data.push_back(pdata);
279        }
280    }
281
282    void ClearData() override
283    {
284        data.clear();
285    }
286
287    uint32 GetDataSize() const
288    {
289        return data.size();
290    }
291
292    const std::vector<uint8> &GetData() const
293    {
294        return data;
295    }
296
297protected:
298    std::vector<uint8> data;
299}; /* class DataSection */
300
301class StringSection : public DataSection {
302public:
303    StringSection(const std::string &name, maplebe::Word type, maplebe::Xword flags, maplebe::Xword align)
304        : DataSection(name, type, flags, align)
305    {
306        AddString("\0");
307    }
308
309    ~StringSection() = default;
310
311    size_t AddString(const std::string &str)
312    {
313        size_t pos = data.size();
314        AppendData(str.c_str(), str.size() + 1);
315        return pos;
316    }
317}; /* class StringSection */
318
319class Alignment {
320public:
321    template <typename T>
322    static T Align(T offset, T align)
323    {
324        if (align <= 1) {
325            return offset;
326        }
327        return (offset + align - 1) & (~(align - 1));
328    }
329}; /* class Alignment */
330
331class JsJitDumpElf {
332public:
333    void Init();
334    void SetFileOffset(int fd, uint64 offset);
335    void Initx86ElfHeader();
336    void InitArmElfHeader();
337    void WriteJitElfFile(int fd);
338    void LayoutSections();
339    void UpdateSectionOffset(Section &section);
340    void UpdateGlobalOffset(Section &section);
341    void RegisterSection(Section &section);
342    void AppendData(std::vector<uint8> &codeBuff);
343    void AddSymToSymTab(const maplebe::Symbol &symbol, int64 symIdx);
344    void AppendGlobalSymsToSymTabSec();
345    void AppendSymbolToSymTab(int64 symIdx, uint64 funcSymValue, uint64 funcSymSize, const std::string &symbolName);
346    void ClearData();
347private:
348    std::vector<std::pair<maplebe::Symbol, int64>> localSymTab;
349    DataSection *textSection = nullptr;
350    SymbolSection *symbolTabSection = nullptr;
351    maplebe::FileHeader header {};
352    StringSection *strTabSection = nullptr;
353    std::vector<Section *> sections;
354    maplebe::Offset globalOffset = 0; /* global offset of the elf file */
355};
356
357}  // namespace panda::ecmascript
358#endif  // ECMASCRIPT_JIT_DUMP_ELF_H
359