• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 COMPILER_AOT_AOT_BULDER_ELF_BUILDER_H
17 #define COMPILER_AOT_AOT_BULDER_ELF_BUILDER_H
18 
19 #include <elf.h>
20 #include <vector>
21 #include <string>
22 #include <tuple>
23 #include <fstream>
24 #include <functional>
25 #ifdef PANDA_COMPILER_CFI
26 #include <libdwarf/libdwarf.h>
27 #include <libdwarf/dwarf.h>
28 #endif
29 
30 #include "include/class.h"
31 
32 namespace panda::compiler {
33 
34 class ElfSectionDataProvider {
35 public:
36     using DataCallback = void (*)(Span<const uint8_t>);
37 
38     virtual void FillData(Span<uint8_t> os, size_t pos) const = 0;
39     virtual size_t GetDataSize() const = 0;
40 
41     ElfSectionDataProvider() = default;
42     NO_COPY_SEMANTIC(ElfSectionDataProvider);
43     NO_MOVE_SEMANTIC(ElfSectionDataProvider);
44     virtual ~ElfSectionDataProvider() = default;
45 };
46 
47 #ifdef PANDA_COMPILER_CFI
48 class DwarfSectionData {
49 public:
50     using FdeInst = std::tuple<Dwarf_Small, Dwarf_Unsigned, Dwarf_Unsigned>;
51     DwarfSectionData() = default;
52 
AddFdeInst(Dwarf_Small op,Dwarf_Unsigned val1,Dwarf_Unsigned val2)53     void AddFdeInst(Dwarf_Small op, Dwarf_Unsigned val1, Dwarf_Unsigned val2)
54     {
55         fde_.emplace_back(op, val1, val2);
56     }
57 
AddFdeInst(const FdeInst & fde)58     void AddFdeInst(const FdeInst &fde)
59     {
60         fde_.push_back(fde);
61     }
62 
SetOffset(Dwarf_Unsigned offset)63     void SetOffset(Dwarf_Unsigned offset)
64     {
65         offset_ = offset;
66     }
67 
SetSize(Dwarf_Unsigned size)68     void SetSize(Dwarf_Unsigned size)
69     {
70         size_ = size;
71     }
72 
GetFde()73     const auto &GetFde() const
74     {
75         return fde_;
76     }
77 
GetOffset()78     auto GetOffset() const
79     {
80         return offset_;
81     }
82 
GetSize()83     auto GetSize() const
84     {
85         return size_;
86     }
87 
88 private:
89     std::vector<FdeInst> fde_;
90     Dwarf_Unsigned offset_ {0};
91     Dwarf_Unsigned size_ {0};
92 };
93 #endif  // PANDA_COMPILER_CFI
94 
95 template <Arch arch, bool is_jit_mode = false>
96 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
97 class ElfBuilder {
98     static constexpr size_t PAGE_SIZE_VALUE = 0x1000;
99     using ElfAddr = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Addr, Elf32_Addr>;
100     using ElfOff = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Off, Elf32_Off>;
101     using ElfHalf = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Half, Elf32_Half>;
102     using ElfWord = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Word, Elf32_Word>;
103     using ElfSword = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Sword, Elf32_Sword>;
104     using ElfXword = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Xword, Elf32_Xword>;
105     using ElfSxword = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Sxword, Elf32_Sxword>;
106     using ElfEhdr = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Ehdr, Elf32_Ehdr>;
107     using ElfShdr = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Shdr, Elf32_Shdr>;
108     using ElfSym = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Sym, Elf32_Sym>;
109     using ElfRel = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Rel, Elf32_Rel>;
110     using ElfRela = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Rela, Elf32_Rela>;
111     using ElfPhdr = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Phdr, Elf32_Phdr>;
112     using ElfDyn = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Dyn, Elf32_Dyn>;
113     using ElfSection = std::conditional_t<ArchTraits<arch>::IS_64_BITS, Elf64_Section, Elf32_Section>;
114 
115 public:
116     class Section {
117     public:
118         // NOLINTNEXTLINE(modernize-pass-by-value)
Section(ElfBuilder & builder,const std::string & name,ElfWord type,ElfWord flags,Section * link,ElfWord info,ElfWord align,ElfWord entsize)119         Section(ElfBuilder &builder, const std::string &name, ElfWord type, ElfWord flags, Section *link, ElfWord info,
120                 ElfWord align, ElfWord entsize)
121             : builder_(builder), name_(name), header_ {}, link_(link)
122         {
123             header_.sh_type = type;
124             header_.sh_flags = flags;
125             header_.sh_info = info;
126             header_.sh_addralign = align;
127             header_.sh_entsize = entsize;
128         }
129         virtual ~Section() = default;
130         NO_MOVE_SEMANTIC(Section);
131         NO_COPY_SEMANTIC(Section);
132 
GetData()133         virtual void *GetData()
134         {
135             UNREACHABLE();
136         }
GetDataSize()137         virtual size_t GetDataSize() const
138         {
139             return header_.sh_size;
140         }
141 
GetName()142         const std::string &GetName() const
143         {
144             return name_;
145         }
146 
GetIndex()147         size_t GetIndex() const
148         {
149             return index_;
150         }
151 
GetAddress()152         auto GetAddress() const
153         {
154             return header_.sh_addr;
155         }
156 
SetSize(size_t size)157         void SetSize(size_t size)
158         {
159             header_.sh_size = size;
160         }
161 
SetDataProvider(ElfSectionDataProvider * data_provider)162         void SetDataProvider(ElfSectionDataProvider *data_provider)
163         {
164             data_provider_ = data_provider;
165         }
166 
GetDataProvider()167         ElfSectionDataProvider *GetDataProvider() const
168         {
169             return data_provider_;
170         }
171 
172     private:
173         ElfBuilder &builder_;
174         std::string name_;
175         size_t index_ {std::numeric_limits<size_t>::max()};
176         ElfShdr header_ {};
177         Section *link_ {};
178         ElfSectionDataProvider *data_provider_ {nullptr};
179 
180         friend class ElfBuilder;
181     };
182 
183     class DataSection : public Section {
184     public:
185         using Section::Section;
186 
187         DataSection() = default;
188         NO_COPY_SEMANTIC(DataSection);
189         NO_MOVE_SEMANTIC(DataSection);
190         ~DataSection() override = default;  // NOLINT(hicpp-use-override, modernize-use-override)
191 
AppendData(const void * data,size_t size)192         void AppendData(const void *data, size_t size)
193         {
194             auto pdata = reinterpret_cast<const uint8_t *>(data);
195             data_.insert(data_.end(), pdata, pdata + size);  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
196         }
197 
GetData()198         void *GetData() override
199         {
200             return data_.data();
201         }
202 
GetVector()203         auto &GetVector()
204         {
205             return data_;
206         }
207 
GetDataSize()208         size_t GetDataSize() const override
209         {
210             return this->data_provider_ != nullptr ? this->data_provider_->GetDataSize() : data_.size();
211         }
212 
213     private:
214         std::vector<uint8_t> data_;
215     };
216 
217     class SymbolSection : public Section {
218     public:
219         using ThunkFunc = std::function<ElfAddr(void)>;
220 
221         using Section::Section;
SymbolSection(ElfBuilder & builder,const std::string & name,ElfWord type,ElfWord flags,Section * link,ElfWord info,ElfWord align,ElfWord entsize)222         SymbolSection(ElfBuilder &builder, const std::string &name, ElfWord type, ElfWord flags, Section *link,
223                       ElfWord info, ElfWord align, ElfWord entsize)
224             : Section(builder, name, type, flags, link, info, align, entsize)
225         {
226             symbols_.emplace_back(ElfSym {});
227             thunks_.emplace_back();
228         }
229 
GetData()230         void *GetData() override
231         {
232             return symbols_.data();
233         }
234 
GetDataSize()235         size_t GetDataSize() const override
236         {
237             return symbols_.size() * sizeof(ElfSym);
238         }
239 
240         void Resolve();
241 
242     private:
243         std::vector<ElfSym> symbols_;
244         std::vector<ThunkFunc> thunks_;
245 
246         friend class ElfBuilder;
247     };
248 
249     class StringSection : public DataSection {
250     public:
StringSection(ElfBuilder & builder,const std::string & name,ElfWord flags,ElfWord align)251         StringSection(ElfBuilder &builder, const std::string &name, ElfWord flags, ElfWord align)
252             : DataSection(builder, name, SHT_STRTAB, flags, nullptr, 0, align, 0)
253         {
254             AddString("\0");  // NOLINT(bugprone-string-literal-with-embedded-nul)
255         }
256 
AddString(const std::string & str)257         ElfWord AddString(const std::string &str)
258         {
259             auto pos = DataSection::GetDataSize();
260             DataSection::AppendData(str.data(), str.size() + 1);
261             return pos;
262         }
263     };
264 
265 public:
~ElfBuilder()266     ~ElfBuilder()
267     {
268         for (auto segment : segments_) {
269             delete segment;
270         }
271     }
272 
ElfBuilder()273     ElfBuilder()
274     {
275         AddSection(&hash_section_);
276         AddSection(&text_section_);
277         AddSection(&shstrtab_section_);
278         AddSection(&dynstr_section_);
279         AddSection(&dynsym_section_);
280         if constexpr (!is_jit_mode) {  // NOLINT
281             AddSection(&aot_section_);
282             AddSection(&got_section_);
283             AddSection(&dynamic_section_);
284         }
285 #ifdef PANDA_COMPILER_CFI
286         AddSection(&frame_section_);
287 #endif
288     }
289 
290     NO_MOVE_SEMANTIC(ElfBuilder);
291     NO_COPY_SEMANTIC(ElfBuilder);
292 
AddSectionName(const std::string & name)293     ElfWord AddSectionName(const std::string &name)
294     {
295         return name.empty() ? 0 : shstrtab_section_.AddString(name);
296     }
297 
AddSection(Section * section)298     void AddSection(Section *section)
299     {
300         sections_.push_back(section);
301         section->index_ = sections_.size() - 1;
302     }
303 
304     template <bool is_function = false>
305     void AddSymbol(const std::string &name, ElfWord size, const Section &section,
306                    typename SymbolSection::ThunkFunc thunk);
307 
GetTextSection()308     auto GetTextSection()
309     {
310         return &text_section_;
311     }
312 
GetAotSection()313     auto GetAotSection()
314     {
315         return &aot_section_;
316     }
317 
318 #ifdef PANDA_COMPILER_CFI
GetFrameSection()319     auto GetFrameSection()
320     {
321         return &frame_section_;
322     }
323 
SetFrameData(std::vector<DwarfSectionData> * frame_data)324     void SetFrameData(std::vector<DwarfSectionData> *frame_data)
325     {
326         frame_data_ = frame_data;
327     }
328     void FillFrameSection();
329 
SetCodeName(const std::string & method_name)330     void SetCodeName(const std::string &method_name)
331     {
332         method_name_ = method_name;
333     }
334 #endif
335 
GetGotSection()336     auto GetGotSection()
337     {
338         return &got_section_;
339     }
340 
341     void Build(const std::string &file_name);
342 
343     void SettleSection(Section *section);
344 
345     void Write(const std::string &file_name);
346     void Write(Span<uint8_t> stream);
347 
UpdateOffset(ElfWord align)348     ElfOff UpdateOffset(ElfWord align)
349     {
350         current_offset_ = RoundUp(current_offset_, align);
351         return current_offset_;
352     }
353 
UpdateAddress(ElfWord align)354     ElfOff UpdateAddress(ElfWord align)
355     {
356         current_address_ = RoundUp(current_address_, align);
357         return current_address_;
358     }
359 
GetFileSize()360     size_t GetFileSize() const
361     {
362         return current_offset_;
363     }
364 
365 #ifdef PANDA_COMPILER_CFI
GetFrameData()366     std::vector<DwarfSectionData> *GetFrameData()
367     {
368         return frame_data_;
369     }
370 
GetTextSectionData()371     Span<uint8_t> GetTextSectionData() const
372     {
373         static_assert(is_jit_mode);
374         return {reinterpret_cast<uint8_t *>(text_section_.header_.sh_addr), text_section_.header_.sh_size};
375     }
376 
HackAddressesForJit(const uint8_t * elf_data)377     void HackAddressesForJit(const uint8_t *elf_data)
378     {
379         static_assert(is_jit_mode);
380         ASSERT(frame_data_->size() == 1U);
381         ASSERT(segments_.empty());
382         ASSERT(dynsym_section_.symbols_.size() == 2U);
383 
384         for (auto section : sections_) {
385             if ((section->header_.sh_flags & SHF_ALLOC) != 0) {  // NOLINT(hicpp-signed-bitwise)
386                 section->header_.sh_addr += down_cast<typename ElfBuilder<arch, is_jit_mode>::ElfAddr>(elf_data);
387             }
388         }
389 
390         ASSERT(dynsym_section_.symbols_[0].st_value == 0);
391         dynsym_section_.symbols_[1U].st_value +=
392             down_cast<typename ElfBuilder<arch, is_jit_mode>::ElfAddr>(elf_data) + CodeInfo::GetCodeOffset(arch);
393 
394         // Some dark magic there. Here we patch the address of JIT code in frame debug info entry.
395         // TODO (asidorov): rework to more readable code
396         uint8_t *cie_addr_8 {static_cast<uint8_t *>(frame_section_.GetData())};
397         uint32_t *cie_addr_32 {reinterpret_cast<uint32_t *>(cie_addr_8)};
398         uint32_t cie_length {*cie_addr_32 + static_cast<uint32_t>(sizeof(uint32_t))};
399         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
400         uint8_t *fde_initial_pc_addr_8 {cie_addr_8 + cie_length + 2U * sizeof(uint32_t)};
401         uintptr_t *fde_initial_pc_addr_ptr {reinterpret_cast<uintptr_t *>(fde_initial_pc_addr_8)};
402         *fde_initial_pc_addr_ptr += down_cast<typename ElfBuilder<arch, is_jit_mode>::ElfAddr>(elf_data);
403     }
404 #endif
405 
406 private:
407     void MakeHeader();
408     void AddSymbols();
409     void SettleSectionsForAot();
410     void SettleSectionsForJit();
411     void ConstructHashSection();
412     void ConstructDynamicSection(const std::string &file_name);
413 
414     struct Segment {
SegmentSegment415         Segment(ElfAddr addr, ElfOff offset, ElfWord type, ElfWord flags, ElfWord align)
416         {
417             header.p_type = type;
418             header.p_flags = flags;
419             header.p_vaddr = header.p_paddr = addr;
420             header.p_align = align;
421             header.p_offset = offset;
422         }
423 
424         ElfPhdr header {};  // NOLINT(misc-non-private-member-variables-in-classes)
425     };
426 
427     class SegmentScope {
428     public:
429         template <typename... Args>
430         SegmentScope(ElfBuilder &builder, ElfWord type, ElfWord flags, bool first = false)
builder_(builder)431             : builder_(builder),
432               start_address_(first ? 0 : RoundUp(builder.current_address_, PAGE_SIZE_VALUE)),
433               start_offset_(first ? 0 : RoundUp(builder.current_offset_, PAGE_SIZE_VALUE))
434         {
435             auto *segment = new Segment(start_address_, start_offset_, type, flags, PAGE_SIZE_VALUE);
436             builder_.segments_.push_back(segment);
437             builder_.current_segment_ = segment;
438         }
~SegmentScope()439         ~SegmentScope()
440         {
441             builder_.current_segment_->header.p_filesz = builder_.current_offset_ - start_offset_;
442             builder_.current_segment_->header.p_memsz = builder_.current_address_ - start_address_;
443             builder_.current_segment_ = nullptr;
444         }
445 
446         NO_MOVE_SEMANTIC(SegmentScope);
447         NO_COPY_SEMANTIC(SegmentScope);
448 
449     private:
450         ElfBuilder &builder_;
451         ElfAddr start_address_;
452         ElfAddr start_offset_;
453     };
454 
455     class AddrPatch {
456         using PatchFunc = std::function<ElfAddr(void)>;
457 
458     public:
AddrPatch(ElfAddr * addr,PatchFunc func)459         AddrPatch(ElfAddr *addr, PatchFunc func) : address_(addr), patch_func_(std::move(func)) {}
Patch()460         void Patch()
461         {
462             *address_ = patch_func_();
463         }
464 
465     private:
466         ElfAddr *address_;
467         PatchFunc patch_func_;
468     };
469 
470 private:
471     static constexpr size_t MAX_SEGMENTS_COUNT = 10;
472     static constexpr size_t DYNSTR_SECTION_ALIGN = 8;
473     static constexpr size_t JIT_TEXT_ALIGNMENT = ArchTraits<arch>::CODE_ALIGNMENT;
474     static constexpr size_t JIT_DATA_ALIGNMENT = ArchTraits<arch>::POINTER_SIZE;
475     static constexpr size_t JIT_DYNSTR_ALIGNMENT = 1U;
476     ElfEhdr header_ {};
477     std::vector<Section *> sections_;
478     std::vector<Segment *> segments_;
479     std::vector<AddrPatch> patches_;
480     ElfAddr current_address_ {0};
481     ElfOff current_offset_ {0};
482     Segment *current_segment_ {nullptr};
483 
484     DataSection hash_section_ =
485         // NOLINTNEXTLINE(hicpp-signed-bitwise)
486         DataSection(*this, ".hash", SHT_HASH, SHF_ALLOC, &dynsym_section_, 0, sizeof(ElfWord), sizeof(ElfWord));
487     DataSection text_section_ =
488         // NOLINTNEXTLINE(hicpp-signed-bitwise)
489         DataSection(*this, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0,
490                     is_jit_mode ? JIT_TEXT_ALIGNMENT : PAGE_SIZE_VALUE, 0);
491     StringSection shstrtab_section_ = StringSection(*this, ".shstrtab", 0, 1);
492     StringSection dynstr_section_ =  // NOLINTNEXTLINE(hicpp-signed-bitwise)
493         StringSection(*this, ".dynstr", SHF_ALLOC, is_jit_mode ? JIT_DYNSTR_ALIGNMENT : DYNSTR_SECTION_ALIGN);
494     SymbolSection dynsym_section_ =
495         // NOLINTNEXTLINE(hicpp-signed-bitwise)
496         SymbolSection(*this, ".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_section_, 1, sizeof(ElfOff), sizeof(ElfSym));
497     // NOLINTNEXTLINE(hicpp-signed-bitwise)
498     DataSection aot_section_ = DataSection(*this, ".aot", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, sizeof(ElfWord), 0);
499     // NOLINTNEXTLINE(hicpp-signed-bitwise)
500     DataSection got_section_ = DataSection(*this, ".aot_got", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, PAGE_SIZE_VALUE, 0);
501     DataSection dynamic_section_ =
502         // NOLINTNEXTLINE(hicpp-signed-bitwise)
503         DataSection(*this, ".dynamic", SHT_DYNAMIC, SHF_ALLOC, &dynstr_section_, 0, PAGE_SIZE_VALUE, sizeof(ElfDyn));
504 #ifdef PANDA_COMPILER_CFI
505     DataSection frame_section_ =
506         // NOLINTNEXTLINE(hicpp-signed-bitwise)
507         DataSection(*this, ".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0,
508                     is_jit_mode ? JIT_DATA_ALIGNMENT : PAGE_SIZE_VALUE, 0);
509 
510     std::vector<DwarfSectionData> *frame_data_ {nullptr};
511 #endif
512     std::string method_name_ = std::string("code");
513 
514     friend SegmentScope;
515 };
516 
517 template <Arch arch, bool is_jit_mode>
518 template <bool is_function>
AddSymbol(const std::string & name,ElfWord size,const Section & section,typename SymbolSection::ThunkFunc thunk)519 void ElfBuilder<arch, is_jit_mode>::AddSymbol(const std::string &name, ElfWord size, const Section &section,
520                                               typename SymbolSection::ThunkFunc thunk)
521 {
522     uint8_t symbol_type = is_function ? STT_FUNC : STT_OBJECT;
523     auto name_idx = dynstr_section_.AddString(name);
524     auto st_info =
525         // NOLINTNEXTLINE(readability-magic-numbers, hicpp-signed-bitwise)
526         static_cast<uint8_t>((STB_GLOBAL << 4) + (symbol_type & 0xf));
527 
528     if constexpr (ArchTraits<arch>::IS_64_BITS) {      // NOLINT(readability-braces-around-statements)
529         dynsym_section_.symbols_.push_back({name_idx,  // st_nam
530                                             st_info,   // st_info
531                                             0,         /* st_other */
532                                             static_cast<ElfSection>(section.GetIndex()),  // st_shndx
533                                             0,                                            // st_value
534                                             size});                                       // st_size
535     } else {                                           // NOLINT(readability-misleading-indentation)
536         dynsym_section_.symbols_.push_back({name_idx,  // st_name
537                                             0,         // st_value
538                                             size,      // st_size
539                                             st_info,   // st_info
540                                             0,         // st_other
541                                             static_cast<ElfSection>(section.GetIndex())});  // st_shndx
542     }
543     dynsym_section_.thunks_.push_back(thunk);
544 }
545 
546 template <Arch arch, bool is_jit_mode>
Resolve()547 void ElfBuilder<arch, is_jit_mode>::SymbolSection::Resolve()
548 {
549     for (auto i = 0U; i < thunks_.size(); i++) {
550         if (thunks_[i]) {
551             symbols_[i].st_value = thunks_[i]();
552         }
553     }
554 }
555 
556 template <Arch arch, bool is_jit_mode>
ConstructDynamicSection(const std::string & file_name)557 void ElfBuilder<arch, is_jit_mode>::ConstructDynamicSection(const std::string &file_name)
558 {
559     using ElfDynDValType = decltype(ElfDyn::d_un.d_val);  // NOLINT(cppcoreguidelines-pro-type-union-access)
560     auto soname = dynstr_section_.AddString(file_name);
561     auto dynstr_section_size = dynstr_section_.GetDataSize();
562     // Make sure widening is zero-extension, if any
563     static_assert(std::is_unsigned<decltype(soname)>::value && std::is_unsigned<decltype(dynstr_section_size)>::value);
564 
565     // NOLINTNEXTLINE(modernize-avoid-c-arrays)
566     ElfDyn dyns[] = {
567         {DT_HASH, {0}},    // will be patched
568         {DT_STRTAB, {0}},  // will be patched
569         {DT_SYMTAB, {0}},  // will be patched
570         {DT_SYMENT, {sizeof(ElfSym)}},
571         {DT_STRSZ, {static_cast<ElfDynDValType>(dynstr_section_size)}},
572         {DT_SONAME, {static_cast<ElfDynDValType>(soname)}},
573         {DT_NULL, {0}},
574     };
575     dynamic_section_.AppendData(&dyns, sizeof(dyns));
576 
577     auto first_patch_argument =
578         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
579         reinterpret_cast<ElfAddr *>(reinterpret_cast<uint8_t *>(dynamic_section_.GetData()) +
580                                     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
581                                     2U * sizeof(ElfDyn) + offsetof(ElfDyn, d_un.d_ptr));
582     patches_.emplace_back(first_patch_argument, [this]() { return dynsym_section_.GetAddress(); });
583 
584     auto second_patch_argument =
585         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
586         reinterpret_cast<ElfAddr *>(reinterpret_cast<uint8_t *>(dynamic_section_.GetData()) +
587                                     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
588                                     1U * sizeof(ElfDyn) + offsetof(ElfDyn, d_un.d_ptr));
589     patches_.emplace_back(second_patch_argument, [this]() { return dynstr_section_.GetAddress(); });
590 
591     auto third_patch_argument =
592         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
593         reinterpret_cast<ElfAddr *>(reinterpret_cast<uint8_t *>(dynamic_section_.GetData()) +
594                                     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
595                                     0U * sizeof(ElfDyn) + offsetof(ElfDyn, d_un.d_ptr));
596     patches_.emplace_back(third_patch_argument, [this]() { return hash_section_.GetAddress(); });
597 }
598 
599 template <Arch arch, bool is_jit_mode>
Build(const std::string & file_name)600 void ElfBuilder<arch, is_jit_mode>::Build(const std::string &file_name)
601 {
602     shstrtab_section_.header_.sh_name = AddSectionName(shstrtab_section_.GetName());
603     for (auto section : sections_) {
604         section->header_.sh_name = AddSectionName(section->GetName());
605         if (section->link_) {
606             section->header_.sh_link = section->link_->GetIndex();
607         }
608     }
609 
610     AddSymbols();
611 
612     ConstructHashSection();
613 
614     if constexpr (!is_jit_mode) {  // NOLINT
615         ConstructDynamicSection(file_name);
616     }
617 
618     if constexpr (is_jit_mode) {  // NOLINT
619         SettleSectionsForJit();
620     } else {  // NOLINT
621         SettleSectionsForAot();
622     }
623 
624     MakeHeader();
625 
626     dynsym_section_.Resolve();
627     std::for_each(patches_.begin(), patches_.end(), [](auto &patch) { patch.Patch(); });
628 }
629 
630 template <Arch arch, bool is_jit_mode>
ConstructHashSection()631 void ElfBuilder<arch, is_jit_mode>::ConstructHashSection()
632 {
633     ElfWord value = 1;
634     auto sym_count = dynsym_section_.GetDataSize() / sizeof(ElfSym);
635     hash_section_.AppendData(&value, sizeof(value));
636     hash_section_.AppendData(&sym_count, sizeof(value));
637     hash_section_.AppendData(&value, sizeof(value));
638     value = 0;
639     hash_section_.AppendData(&value, sizeof(value));
640     for (auto i = 2U; i < sym_count; i++) {
641         hash_section_.AppendData(&i, sizeof(value));
642     }
643     value = 0;
644     hash_section_.AppendData(&value, sizeof(value));
645 }
646 
647 template <Arch arch, bool is_jit_mode>
MakeHeader()648 void ElfBuilder<arch, is_jit_mode>::MakeHeader()
649 {
650     header_.e_ident[EI_MAG0] = ELFMAG0;
651     header_.e_ident[EI_MAG1] = ELFMAG1;
652     header_.e_ident[EI_MAG2] = ELFMAG2;
653     header_.e_ident[EI_MAG3] = ELFMAG3;
654     header_.e_ident[EI_CLASS] = ArchTraits<arch>::IS_64_BITS ? ELFCLASS64 : ELFCLASS32;
655     header_.e_ident[EI_DATA] = ELFDATA2LSB;
656     header_.e_ident[EI_VERSION] = EV_CURRENT;
657     header_.e_ident[EI_OSABI] = ELFOSABI_LINUX;
658     header_.e_ident[EI_ABIVERSION] = 0;
659     std::fill_n(&header_.e_ident[EI_PAD], EI_NIDENT - EI_PAD, 0);
660     header_.e_type = ET_DYN;
661     header_.e_version = 1;
662     switch (arch) {
663         case Arch::AARCH32:
664             header_.e_machine = EM_ARM;
665             header_.e_flags = EF_ARM_EABI_VER5;
666             break;
667         case Arch::AARCH64:
668             header_.e_machine = EM_AARCH64;
669             header_.e_flags = 0;
670             break;
671         case Arch::X86:
672             header_.e_machine = EM_386;
673             header_.e_flags = 0;
674             break;
675         case Arch::X86_64:
676             header_.e_machine = EM_X86_64;
677             header_.e_flags = 0;
678             break;
679         default:
680             UNREACHABLE();
681     }
682     header_.e_entry = 0;
683     header_.e_ehsize = sizeof(ElfEhdr);
684     header_.e_phentsize = sizeof(ElfPhdr);
685     header_.e_shentsize = sizeof(ElfShdr);
686     header_.e_shstrndx = shstrtab_section_.GetIndex();
687     current_offset_ = RoundUp(current_offset_, alignof(ElfShdr));
688     header_.e_shoff = UpdateOffset(alignof(ElfShdr));
689     current_offset_ += sections_.size() * sizeof(ElfShdr);
690     header_.e_phoff = is_jit_mode ? 0U : sizeof(ElfEhdr);
691     header_.e_shnum = sections_.size();
692     header_.e_phnum = is_jit_mode ? 0U : segments_.size();
693 }
694 
695 template <Arch arch, bool is_jit_mode>
AddSymbols()696 void ElfBuilder<arch, is_jit_mode>::AddSymbols()
697 {
698     AddSymbol(method_name_, text_section_.GetDataSize(), text_section_,
699               [this]() { return text_section_.GetAddress(); });
700     if constexpr (!is_jit_mode) {  // NOLINT
701         AddSymbol("code_end", text_section_.GetDataSize(), text_section_,
702                   [this]() { return text_section_.GetAddress() + text_section_.GetDataSize(); });
703         AddSymbol("aot", aot_section_.GetDataSize(), aot_section_, [this]() { return aot_section_.GetAddress(); });
704         AddSymbol("aot_end", aot_section_.GetDataSize(), aot_section_,
705                   [this]() { return aot_section_.GetAddress() + aot_section_.GetDataSize(); });
706     }
707 }
708 
709 template <Arch arch, bool is_jit_mode>
SettleSectionsForAot()710 void ElfBuilder<arch, is_jit_mode>::SettleSectionsForAot()
711 {
712     static_assert(!is_jit_mode);
713 
714     // NOLINTNEXTLINE(hicpp-signed-bitwise)
715     auto phdr_segment = new Segment(sizeof(ElfEhdr), sizeof(ElfEhdr), PT_PHDR, PF_R, sizeof(ElfOff));
716     segments_.push_back(phdr_segment);
717 
718     {
719         SegmentScope segment_scope(*this, PT_LOAD, PF_R, true);  // NOLINT(hicpp-signed-bitwise)
720         current_address_ = sizeof(ElfEhdr) + sizeof(ElfPhdr) * MAX_SEGMENTS_COUNT;
721         current_offset_ = sizeof(ElfEhdr) + sizeof(ElfPhdr) * MAX_SEGMENTS_COUNT;
722         SettleSection(&dynstr_section_);
723         SettleSection(&dynsym_section_);
724         SettleSection(&hash_section_);
725         SettleSection(&aot_section_);
726     }
727 
728     {
729         SegmentScope segment_scope(*this, PT_LOAD, PF_R | PF_W);  // NOLINT(hicpp-signed-bitwise)
730         SettleSection(&got_section_);
731     }
732 
733     {
734         SegmentScope segment_scope(*this, PT_LOAD, PF_R | PF_X);  // NOLINT(hicpp-signed-bitwise)
735         SettleSection(&text_section_);
736     }
737 
738 #ifdef PANDA_COMPILER_CFI
739     if (!frame_data_->empty()) {
740         SegmentScope segment_scope(*this, PT_LOAD, PF_R);  // NOLINT(hicpp-signed-bitwise)
741         FillFrameSection();
742         SettleSection(&frame_section_);
743     }
744 #endif
745 
746     {
747         SegmentScope segment_scope(*this, PT_DYNAMIC, PF_R | PF_W);  // NOLINT(hicpp-signed-bitwise)
748         SettleSection(&dynamic_section_);
749     }
750 
751     SettleSection(&shstrtab_section_);
752 
753     auto lod_dynamic_segment = new Segment(*segments_.back());
754     ASSERT(lod_dynamic_segment->header.p_type == PT_DYNAMIC);
755     lod_dynamic_segment->header.p_type = PT_LOAD;
756     segments_.insert(segments_.end() - 1, lod_dynamic_segment);
757 
758     ASSERT(segments_.size() <= MAX_SEGMENTS_COUNT);
759     phdr_segment->header.p_filesz = phdr_segment->header.p_memsz = segments_.size() * sizeof(ElfPhdr);
760 }
761 
762 template <Arch arch, bool is_jit_mode>
SettleSectionsForJit()763 void ElfBuilder<arch, is_jit_mode>::SettleSectionsForJit()
764 {
765     static_assert(is_jit_mode);
766 
767     current_address_ = sizeof(ElfEhdr);
768     current_offset_ = sizeof(ElfEhdr);
769 
770     SettleSection(&text_section_);
771 #ifdef PANDA_COMPILER_CFI
772     if (!frame_data_->empty()) {
773         FillFrameSection();
774         SettleSection(&frame_section_);
775     }
776 #endif
777     SettleSection(&dynsym_section_);
778     SettleSection(&hash_section_);
779     SettleSection(&dynstr_section_);
780     SettleSection(&shstrtab_section_);
781 }
782 
783 template <Arch arch, bool is_jit_mode>
SettleSection(Section * section)784 void ElfBuilder<arch, is_jit_mode>::SettleSection(Section *section)
785 {
786     bool is_section_alloc {(section->header_.sh_flags & SHF_ALLOC) != 0};  // NOLINT(hicpp-signed-bitwise)
787     if (is_jit_mode || !is_section_alloc) {
788         ASSERT(current_segment_ == nullptr);
789     } else {
790         ASSERT(current_segment_ != nullptr && current_segment_->header.p_type != PT_NULL);
791     }
792 
793     section->header_.sh_size = section->GetDataSize();
794     if (is_section_alloc) {
795         section->header_.sh_addr = UpdateAddress(section->header_.sh_addralign);
796         if (section->header_.sh_type != SHT_NOBITS) {
797             ASSERT(section->GetDataSize() != 0 || section->header_.sh_type == SHT_PROGBITS);
798             section->header_.sh_offset = UpdateOffset(section->header_.sh_addralign);
799             current_offset_ += section->header_.sh_size;
800         } else {
801             section->header_.sh_offset = 0;
802         }
803         current_address_ += section->header_.sh_size;
804     } else {
805         section->header_.sh_offset = RoundUp(current_offset_, section->header_.sh_addralign);
806         current_offset_ += section->header_.sh_size;
807     }
808 }
809 
810 template <Arch arch, bool is_jit_mode>
Write(const std::string & file_name)811 void ElfBuilder<arch, is_jit_mode>::Write(const std::string &file_name)
812 {
813     std::vector<uint8_t> data(GetFileSize());
814     auto data_span {Span(data)};
815     Write(data_span);
816 
817     std::ofstream elf_file(file_name, std::ios::binary);
818     elf_file.write(reinterpret_cast<char *>(data_span.Data()), data_span.Size());
819 }
820 
CopyToSpan(Span<uint8_t> to,const char * from,size_t size,size_t begin_index)821 static inline void CopyToSpan(Span<uint8_t> to, const char *from, size_t size, size_t begin_index)
822 {
823     ASSERT(begin_index < to.Size());
824     auto max_size {to.Size() - begin_index};
825     errno_t res = memcpy_s(&to[begin_index], max_size, from, size);
826     if (res != 0) {
827         UNREACHABLE();
828     }
829 }
830 
831 template <Arch arch, bool is_jit_mode>
Write(Span<uint8_t> stream)832 void ElfBuilder<arch, is_jit_mode>::Write(Span<uint8_t> stream)
833 {
834     ASSERT(!stream.Empty());
835     char *header = reinterpret_cast<char *>(&header_);
836     CopyToSpan(stream, header, sizeof(header_), 0);
837     for (auto section : sections_) {
838         if (auto data_provider = section->GetDataProvider(); data_provider != nullptr) {
839             auto i = section->header_.sh_offset;
840             data_provider->FillData(stream, i);
841         } else if (section->GetDataSize() && section->header_.sh_type != SHT_NOBITS) {
842             auto i = section->header_.sh_offset;
843             const char *data = reinterpret_cast<const char *>(section->GetData());
844             CopyToSpan(stream, data, section->GetDataSize(), i);
845         }
846     }
847 
848     auto i = header_.e_shoff;
849     for (auto section : sections_) {
850         const char *data = reinterpret_cast<const char *>(&section->header_);
851         CopyToSpan(stream, data, sizeof(section->header_), i);
852         i += sizeof(section->header_);
853     }
854 
855     i = header_.e_phoff;
856     for (auto segment : segments_) {
857         const char *data = reinterpret_cast<const char *>(&segment->header);
858         CopyToSpan(stream, data, sizeof(segment->header), i);
859         i += sizeof(segment->header);
860     }
861 }
862 
863 #ifdef PANDA_COMPILER_CFI
864 template <Arch arch>
865 class CfiGenerator {
866 public:
CfiGenerator(Span<DwarfSectionData> frame_data)867     explicit CfiGenerator(Span<DwarfSectionData> frame_data) : frame_data_(frame_data) {}
868 
GenerateDebugInfo()869     void GenerateDebugInfo()
870     {
871         if (!debug_info_.empty() || frame_data_.empty()) {
872             return;
873         }
874 
875         auto dw {Initialize()};
876         auto cie {CreateCie(dw)};
877 
878         for (const auto &data : frame_data_) {
879             AddFde(dw, cie, data);
880         }
881 
882         Finalize(dw);
883     }
884 
GetDebugInfo()885     Span<const uint8_t> GetDebugInfo() const
886     {
887         return Span(debug_info_);
888     }
889 
890 private:
891     enum DwarfSection {
892         REL_DEBUG_FRAME = 0,
893         DEBUG_FRAME = 1,
894     };
895 
CreateSectionCallback(char * name,int size,Dwarf_Unsigned type,Dwarf_Unsigned flags,Dwarf_Unsigned link,Dwarf_Unsigned info,Dwarf_Unsigned * sect_name_index,void * user_data,int * error)896     static inline int CreateSectionCallback(char *name, [[maybe_unused]] int size, [[maybe_unused]] Dwarf_Unsigned type,
897                                             [[maybe_unused]] Dwarf_Unsigned flags, [[maybe_unused]] Dwarf_Unsigned link,
898                                             [[maybe_unused]] Dwarf_Unsigned info,
899                                             [[maybe_unused]] Dwarf_Unsigned *sect_name_index,
900                                             [[maybe_unused]] void *user_data, [[maybe_unused]] int *error)
901     {
902         if (strcmp(name, ".rel.debug_frame") == 0) {
903             return DwarfSection::REL_DEBUG_FRAME;
904         }
905         if (strcmp(name, ".debug_frame") == 0) {
906             return DwarfSection::DEBUG_FRAME;
907         }
908         UNREACHABLE();
909     }
910 
Initialize()911     Dwarf_P_Debug Initialize() const
912     {
913         Dwarf_P_Debug dw {nullptr};
914         Dwarf_Error error {nullptr};
915         [[maybe_unused]] auto ret =
916             // NOLINTNEXTLINE(hicpp-signed-bitwise)
917             dwarf_producer_init(DW_DLC_WRITE | DW_DLC_SIZE_64 | DW_DLC_SYMBOLIC_RELOCATIONS,
918                                 reinterpret_cast<Dwarf_Callback_Func>(CreateSectionCallback), nullptr, nullptr, nullptr,
919                                 GetIsaName(arch), "V2", nullptr, &dw, &error);
920 
921         ASSERT(error == DW_DLV_OK);
922         return dw;
923     }
924 
GetCieInitInstructions()925     Span<Dwarf_Small> GetCieInitInstructions() const
926     {
927         // NOLINTNEXTLINE(modernize-avoid-c-arrays)
928         static Dwarf_Small cie_init_instructions_arm[] = {
929             DW_CFA_def_cfa,
930             GetDwarfSP(arch),
931             0U,
932         };
933 
934         // NOLINTNEXTLINE(modernize-avoid-c-arrays)
935         static Dwarf_Small cie_init_instructions_amd64[] = {
936             // NOLINTNEXTLINE(hicpp-signed-bitwise)
937             DW_CFA_def_cfa, GetDwarfSP(arch), PointerSize(arch), DW_CFA_offset | GetDwarfRIP(arch), 1U,
938         };
939 
940         if (arch == Arch::AARCH32 || arch == Arch::AARCH64) {
941             return Span(cie_init_instructions_arm, std::size(cie_init_instructions_arm));
942         }
943         if (arch == Arch::X86_64) {
944             return Span(cie_init_instructions_amd64, std::size(cie_init_instructions_amd64));
945         }
946         UNREACHABLE();
947     }
948 
CreateCie(Dwarf_P_Debug dw)949     Dwarf_Unsigned CreateCie(Dwarf_P_Debug dw) const
950     {
951         Dwarf_Error error {nullptr};
952         auto cie_init_instructions {GetCieInitInstructions()};
953         Dwarf_Unsigned cie =
954             dwarf_add_frame_cie(dw, const_cast<char *>(""), static_cast<Dwarf_Small>(GetInstructionAlignment(arch)),
955                                 static_cast<Dwarf_Small>(-PointerSize(arch)), GetDwarfRIP(arch),
956                                 cie_init_instructions.data(), cie_init_instructions.SizeBytes(), &error);
957         ASSERT(error == DW_DLV_OK);
958         return cie;
959     }
960 
AddFde(Dwarf_P_Debug dw,Dwarf_Unsigned cie,const DwarfSectionData & data)961     void AddFde(Dwarf_P_Debug dw, Dwarf_Unsigned cie, const DwarfSectionData &data) const
962     {
963         Dwarf_Error error {nullptr};
964         Dwarf_P_Fde fde = dwarf_new_fde(dw, &error);
965         ASSERT(error == DW_DLV_OK);
966         for (const auto &inst : data.GetFde()) {
967             auto [op, par1, par2] = inst;
968             dwarf_add_fde_inst(fde, op, par1, par2, &error);
969             ASSERT(error == DW_DLV_OK);
970         }
971 
972         dwarf_add_frame_fde(dw, fde, nullptr, cie, data.GetOffset(), data.GetSize(), DwarfSection::DEBUG_FRAME, &error);
973         ASSERT(error == DW_DLV_OK);
974     }
975 
Finalize(Dwarf_P_Debug dw)976     void Finalize(Dwarf_P_Debug dw)
977     {
978         Dwarf_Error error {nullptr};
979         auto sections = dwarf_transform_to_disk_form(dw, &error);
980         ASSERT(error == DW_DLV_OK);
981 
982         ASSERT(debug_info_.empty());
983         for (decltype(sections) i {0}; i < sections; ++i) {
984             Dwarf_Unsigned len = 0;
985             Dwarf_Signed elfIdx = 0;
986             auto bytes = reinterpret_cast<const uint8_t *>(
987                 dwarf_get_section_bytes(dw, DwarfSection::DEBUG_FRAME, &elfIdx, &len, &error));
988             ASSERT(error == DW_DLV_OK);
989 
990             std::copy_n(bytes, len, std::back_inserter(debug_info_));
991         }
992 
993         constexpr size_t TERMINATOR_SIZE {4U};
994         constexpr uint8_t TERMINATOR_VALUE {0U};
995         std::fill_n(std::back_inserter(debug_info_), TERMINATOR_SIZE, TERMINATOR_VALUE);
996 
997         dwarf_producer_finish(dw, &error);
998         ASSERT(error == DW_DLV_OK);
999 
1000         constexpr size_t CIE_ID_OFFSET {4U};
1001         // zero out CIE ID field
1002         *reinterpret_cast<uint32_t *>(&debug_info_[CIE_ID_OFFSET]) = 0;
1003 
1004         constexpr size_t FDE_CIE_DISTANCE_OFFSET {4U};
1005         constexpr size_t FDE_LENGTH_SIZE {4U};
1006         size_t base {0};
1007         for (size_t i {0}; i < frame_data_.size(); ++i) {
1008             // read FDE length field + 4 bytes (size of length field), get next FDE
1009             size_t fde_offset {base + *reinterpret_cast<uint32_t *>(&debug_info_[base]) + FDE_LENGTH_SIZE};
1010             // set distance to the parent CIE in FDE
1011             ASSERT(debug_info_.size() > fde_offset + FDE_CIE_DISTANCE_OFFSET + 3U);
1012             *reinterpret_cast<uint32_t *>(&debug_info_[fde_offset + FDE_CIE_DISTANCE_OFFSET]) =
1013                 fde_offset + FDE_CIE_DISTANCE_OFFSET;
1014             base = fde_offset;
1015             ASSERT(debug_info_.size() > base);
1016         }
1017     }
1018 
1019     Span<DwarfSectionData> frame_data_;
1020     std::vector<uint8_t> debug_info_;
1021 };
1022 
1023 template <Arch arch, bool is_jit_mode>
FillFrameSection()1024 void ElfBuilder<arch, is_jit_mode>::FillFrameSection()
1025 {
1026     // compute code offset for method
1027     for (auto &data : *frame_data_) {
1028         data.SetOffset(text_section_.header_.sh_offset + data.GetOffset() + CodeInfo::GetCodeOffset(arch));
1029     }
1030 
1031     CfiGenerator<arch> cfi_gen {Span(*frame_data_)};
1032     cfi_gen.GenerateDebugInfo();
1033     auto debug_info {cfi_gen.GetDebugInfo()};
1034 
1035     // Generate frame data
1036     GetFrameSection()->AppendData(debug_info.data(), debug_info.size());
1037 }
1038 #endif  // #ifdef PANDA_COMPILER_CFI
1039 
1040 class ElfWriter {
1041 public:
SetArch(Arch arch)1042     void SetArch(Arch arch)
1043     {
1044         arch_ = arch;
1045     }
GetArch()1046     Arch GetArch() const
1047     {
1048         return arch_;
1049     }
1050 
SetRuntime(RuntimeInterface * runtime)1051     void SetRuntime(RuntimeInterface *runtime)
1052     {
1053         runtime_ = runtime;
1054     }
1055 
GetRuntime()1056     RuntimeInterface *GetRuntime()
1057     {
1058         return runtime_;
1059     }
1060 
GetCurrentCodeAddress()1061     uintptr_t GetCurrentCodeAddress() const
1062     {
1063         return current_code_size_;
1064     }
1065 
StartClass(const Class & klass)1066     void StartClass(const Class &klass)
1067     {
1068         ClassHeader *class_header = &class_headers_.emplace_back();
1069         current_bitmap_ = &class_methods_bitmaps_.emplace_back();
1070         class_header->class_id = klass.GetFileId().GetOffset();
1071         class_header->methods_offset = method_headers_.size();
1072         current_bitmap_->resize(klass.GetMethods().size());
1073     }
1074 
EndClass()1075     void EndClass()
1076     {
1077         ASSERT(!class_headers_.empty());
1078         auto &class_header = class_headers_.back();
1079         class_header.methods_count = method_headers_.size() - class_header.methods_offset;
1080         if (class_header.methods_count != 0) {
1081             ASSERT(IsAligned<sizeof(uint32_t)>(current_bitmap_->GetContainerSizeInBytes()));
1082             class_header.methods_bitmap_offset = bitmap_size_;
1083             class_header.methods_bitmap_size = current_bitmap_->size();
1084             bitmap_size_ += current_bitmap_->GetContainerSize();
1085         } else {
1086             CHECK_EQ(class_methods_bitmaps_.size(), class_headers_.size());
1087             class_headers_.pop_back();
1088             class_methods_bitmaps_.pop_back();
1089         }
1090     }
1091 
AddMethod(const CompiledMethod & method,size_t method_index)1092     void AddMethod(const CompiledMethod &method, size_t method_index)
1093     {
1094         if (method.GetMethod() == nullptr || method.GetCode().Empty()) {
1095             return;
1096         }
1097         methods_.push_back(method);
1098         auto &method_header = method_headers_.emplace_back();
1099         method_header.method_id = method.GetMethod()->GetFileId().GetOffset();
1100         method_header.code_offset = current_code_size_;
1101         method_header.code_size = method.GetOverallSize();
1102         current_code_size_ += method_header.code_size;
1103         current_code_size_ = RoundUp(current_code_size_, GetCodeAlignment(arch_));
1104         current_bitmap_->SetBit(method_index);
1105 
1106 #ifdef PANDA_COMPILER_CFI
1107         if (GetEmitDebugInfo()) {
1108             FillDebugInfo(method.GetCfiInfo(), method_header);
1109         }
1110 #endif
1111     }
1112 
SetClassContext(const std::string & ctx)1113     void SetClassContext(const std::string &ctx)
1114     {
1115         class_ctx_ = ctx;
1116     }
1117 
1118 #ifdef PANDA_COMPILER_CFI
SetEmitDebugInfo(bool emit_debug_info)1119     void SetEmitDebugInfo([[maybe_unused]] bool emit_debug_info)
1120     {
1121         emit_debug_info_ = emit_debug_info;
1122     }
1123 
GetEmitDebugInfo()1124     bool GetEmitDebugInfo() const
1125     {
1126         return emit_debug_info_;
1127     }
1128 #endif
1129 
AddString(const std::string & str)1130     size_t AddString(const std::string &str)
1131     {
1132         auto pos = string_table_.size();
1133         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1134         string_table_.insert(string_table_.end(), str.data(), str.data() + str.size() + 1);
1135         return pos;
1136     }
1137 
1138     template <Arch arch, bool is_jit_mode>
1139     void GenerateSymbols(ElfBuilder<arch, is_jit_mode> &builder);
1140 
1141 #ifdef PANDA_COMPILER_CFI
1142     inline void PrepareOffsetsForDwarf(CfiOffsets *offsets) const;
1143 
1144     inline void FillPrologueInfo(DwarfSectionData *sect_data, const CfiOffsets &cfi_offsets) const;
1145 
1146     inline void FillCalleesInfo(DwarfSectionData *sect_data, const CfiInfo &cfi_info) const;
1147 
1148     inline void FillEpilogInfo(DwarfSectionData *sect_data, const CfiOffsets &cfi_offsets) const;
1149 
1150     inline void FillDebugInfo(CfiInfo cfi_info, const compiler::MethodHeader &method_header);
1151 
AddFrameData(const DwarfSectionData & data)1152     void AddFrameData(const DwarfSectionData &data)
1153     {
1154         frame_data_.push_back(data);
1155     }
1156 
GetFrameData()1157     std::vector<DwarfSectionData> *GetFrameData()
1158     {
1159         return &frame_data_;
1160     }
1161 
1162 #endif
1163 private:
1164     std::string class_ctx_;
1165     Arch arch_ {Arch::NONE};
1166     size_t current_code_size_ {0};
1167 
1168     std::vector<compiler::PandaFileHeader> file_headers_;
1169     std::vector<compiler::ClassHeader> class_headers_;
1170     std::vector<compiler::MethodHeader> method_headers_;
1171     std::vector<CompiledMethod> methods_;
1172 
1173     std::vector<char> string_table_;
1174     uint32_t gc_type_ {static_cast<uint32_t>(mem::GCType::INVALID_GC)};
1175 
1176     std::vector<BitVector<>> class_methods_bitmaps_;
1177     static_assert(sizeof(BitVector<>::container_value_type) == sizeof(uint32_t));
1178     BitVector<> *current_bitmap_ {nullptr};
1179     uint32_t bitmap_size_ {0};
1180 
1181     RuntimeInterface *runtime_ {nullptr};
1182 #ifdef PANDA_COMPILER_CFI
1183     std::vector<DwarfSectionData> frame_data_;
1184     bool emit_debug_info_ {false};
1185 #endif
1186 
1187     friend class CodeDataProvider;
1188     friend class JitCodeDataProvider;
1189     friend class AotBuilder;
1190     friend class JitDebugWriter;
1191 };
1192 
1193 #ifdef PANDA_COMPILER_CFI
1194 static constexpr size_t LR_CFA_OFFSET {1U};
1195 static constexpr size_t FP_CFA_OFFSET {2U};
1196 static constexpr size_t DWARF_ARM_FP_REGS_START {64U};
1197 
PrepareOffsetsForDwarf(CfiOffsets * offsets)1198 void ElfWriter::PrepareOffsetsForDwarf(CfiOffsets *offsets) const
1199 {
1200     // Make relative offsets
1201     offsets->pop_fplr -= offsets->pop_callees;
1202     offsets->pop_callees -= offsets->push_callees;
1203     offsets->push_callees -= offsets->set_fp;
1204     offsets->set_fp -= offsets->push_fplr;
1205 
1206     // Make offsets in alignment units
1207     auto inst_alignment {GetInstructionAlignment(arch_)};
1208 
1209     offsets->push_fplr /= inst_alignment;
1210     offsets->set_fp /= inst_alignment;
1211     offsets->push_callees /= inst_alignment;
1212     offsets->pop_callees /= inst_alignment;
1213     offsets->pop_fplr /= inst_alignment;
1214 }
1215 
FillPrologueInfo(DwarfSectionData * sect_data,const CfiOffsets & cfi_offsets)1216 void ElfWriter::FillPrologueInfo(DwarfSectionData *sect_data, const CfiOffsets &cfi_offsets) const
1217 {
1218     sect_data->AddFdeInst(DW_CFA_advance_loc, cfi_offsets.push_fplr, 0);
1219     sect_data->AddFdeInst(DW_CFA_def_cfa_offset, FP_CFA_OFFSET * PointerSize(arch_), 0);
1220     if (arch_ == Arch::AARCH32 || arch_ == Arch::AARCH64) {
1221         sect_data->AddFdeInst(DW_CFA_offset, GetDwarfLR(arch_), LR_CFA_OFFSET);
1222     }
1223     sect_data->AddFdeInst(DW_CFA_offset, GetDwarfFP(arch_), FP_CFA_OFFSET);
1224 
1225     sect_data->AddFdeInst(DW_CFA_advance_loc, cfi_offsets.set_fp, 0);
1226     sect_data->AddFdeInst(DW_CFA_def_cfa_register, GetDwarfFP(arch_), 0);
1227 }
1228 
FillCalleesInfo(DwarfSectionData * sect_data,const CfiInfo & cfi_info)1229 void ElfWriter::FillCalleesInfo(DwarfSectionData *sect_data, const CfiInfo &cfi_info) const
1230 {
1231     const auto &cfi_offsets {cfi_info.offsets};
1232 
1233     sect_data->AddFdeInst(DW_CFA_advance_loc, cfi_offsets.push_callees, 0);
1234 
1235     const auto &callees {cfi_info.callee_regs};
1236     size_t callee_slot {0};
1237     for (size_t i {0}; i < callees.size(); ++i) {
1238         auto reg {(callees.size() - 1U) - i};
1239         if (callees.test(reg)) {
1240 #ifdef PANDA_COMPILER_TARGET_X86_64
1241             if (arch_ == Arch::X86_64) {
1242                 reg = amd64::ConvertRegNumber(reg);
1243             }
1244 #endif
1245             sect_data->AddFdeInst(DW_CFA_offset, reg,
1246                                   FP_CFA_OFFSET + CFrameLayout::CALLEE_REGS_START_SLOT + callee_slot++);
1247         }
1248     }
1249 
1250     const auto &vcallees {cfi_info.callee_vregs};
1251     for (size_t i {0}; i < vcallees.size(); ++i) {
1252         auto vreg {(vcallees.size() - 1) - i};
1253         if (vcallees.test(vreg)) {
1254             ASSERT(arch_ == Arch::AARCH32 || arch_ == Arch::AARCH64);
1255             sect_data->AddFdeInst(DW_CFA_offset, DWARF_ARM_FP_REGS_START + vreg,
1256                                   FP_CFA_OFFSET + CFrameLayout::CALLEE_REGS_START_SLOT + callee_slot++);
1257         }
1258     }
1259 
1260     sect_data->AddFdeInst(DW_CFA_advance_loc, cfi_offsets.pop_callees, 0);
1261     for (size_t i {0}; i < callees.size(); ++i) {
1262         auto reg {(callees.size() - 1U) - i};
1263         if (callees.test(reg)) {
1264 #ifdef PANDA_COMPILER_TARGET_X86_64
1265             if (arch_ == Arch::X86_64) {
1266                 reg = amd64::ConvertRegNumber(reg);
1267             }
1268 #endif
1269             sect_data->AddFdeInst(DW_CFA_same_value, reg, 0);
1270         }
1271     }
1272 
1273     for (size_t i {0}; i < vcallees.size(); ++i) {
1274         auto vreg {(vcallees.size() - 1) - i};
1275         if (vcallees.test(vreg)) {
1276             ASSERT(arch_ == Arch::AARCH32 || arch_ == Arch::AARCH64);
1277             sect_data->AddFdeInst(DW_CFA_same_value, DWARF_ARM_FP_REGS_START + vreg, 0);
1278         }
1279     }
1280 }
1281 
FillEpilogInfo(DwarfSectionData * sect_data,const CfiOffsets & cfi_offsets)1282 void ElfWriter::FillEpilogInfo(DwarfSectionData *sect_data, const CfiOffsets &cfi_offsets) const
1283 {
1284     sect_data->AddFdeInst(DW_CFA_advance_loc, cfi_offsets.pop_fplr, 0);
1285     sect_data->AddFdeInst(DW_CFA_same_value, GetDwarfFP(arch_), 0);
1286     if (arch_ == Arch::AARCH32 || arch_ == Arch::AARCH64) {
1287         sect_data->AddFdeInst(DW_CFA_same_value, GetDwarfLR(arch_), 0);
1288         sect_data->AddFdeInst(DW_CFA_def_cfa, GetDwarfSP(arch_), 0);
1289     } else if (arch_ == Arch::X86_64) {
1290         sect_data->AddFdeInst(DW_CFA_def_cfa, GetDwarfSP(arch_), 1U * PointerSize(arch_));
1291     } else {
1292         UNREACHABLE();
1293     }
1294 }
1295 
FillDebugInfo(CfiInfo cfi_info,const compiler::MethodHeader & method_header)1296 void ElfWriter::FillDebugInfo(CfiInfo cfi_info, const compiler::MethodHeader &method_header)
1297 {
1298     DwarfSectionData sect_data;
1299     // Will be patched later
1300     sect_data.SetOffset(method_header.code_offset);
1301     sect_data.SetSize(method_header.code_size);
1302 
1303     auto &cfi_offsets {cfi_info.offsets};
1304     PrepareOffsetsForDwarf(&cfi_offsets);
1305 
1306     FillPrologueInfo(&sect_data, cfi_offsets);
1307     FillCalleesInfo(&sect_data, cfi_info);
1308     FillEpilogInfo(&sect_data, cfi_offsets);
1309 
1310     AddFrameData(sect_data);
1311 }
1312 #endif
1313 
1314 }  // namespace panda::compiler
1315 
1316 #endif  // COMPILER_AOT_AOT_BULDER_ELF_BUILDER_H
1317