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 §ion,
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 §ion,
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 *>(§ion->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(§_data, cfi_offsets);
1307 FillCalleesInfo(§_data, cfi_info);
1308 FillEpilogInfo(§_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