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 #include "jit_writer.h"
17
18 #ifdef PANDA_COMPILER_CFI
19
20 namespace panda::compiler {
21 class JitCodeDataProvider : public ElfSectionDataProvider {
22 public:
JitCodeDataProvider(JitDebugWriter * jit_debug_writer)23 explicit JitCodeDataProvider(JitDebugWriter *jit_debug_writer) : jit_debug_writer_(jit_debug_writer) {}
24
FillData(Span<uint8_t> stream,size_t stream_begin) const25 void FillData(Span<uint8_t> stream, size_t stream_begin) const override
26 {
27 const size_t code_offset = CodeInfo::GetCodeOffset(jit_debug_writer_->GetArch());
28 CodePrefix prefix;
29 size_t curr_pos = stream_begin;
30 for (size_t i = 0; i < jit_debug_writer_->methods_.size(); i++) {
31 auto &method = jit_debug_writer_->methods_[i];
32 auto &method_header = jit_debug_writer_->method_headers_[i];
33 prefix.code_size = method.GetCode().size();
34 prefix.code_info_offset = code_offset + RoundUp(method.GetCode().size(), CodeInfo::ALIGNMENT);
35 prefix.code_info_size = method.GetCodeInfo().size();
36 // Prefix
37 curr_pos = stream_begin + method_header.code_offset;
38 const char *data = reinterpret_cast<char *>(&prefix);
39 CopyToSpan(stream, data, sizeof(prefix), curr_pos);
40 curr_pos += sizeof(prefix);
41
42 // Code
43 curr_pos += code_offset - sizeof(prefix);
44 data = reinterpret_cast<const char *>(method.GetCode().data());
45 CopyToSpan(stream, data, method.GetCode().size(), curr_pos);
46 curr_pos += method.GetCode().size();
47
48 // CodeInfo
49 curr_pos += RoundUp(method.GetCode().size(), CodeInfo::ALIGNMENT) - method.GetCode().size();
50 data = reinterpret_cast<const char *>(method.GetCodeInfo().data());
51 CopyToSpan(stream, data, method.GetCodeInfo().size(), curr_pos);
52 }
53 }
54
GetDataSize() const55 size_t GetDataSize() const override
56 {
57 return jit_debug_writer_->current_code_size_;
58 }
59
60 private:
61 JitDebugWriter *jit_debug_writer_;
62 };
63
Start()64 void JitDebugWriter::Start()
65 {
66 auto &file_header = file_headers_.emplace_back();
67 file_header.classes_offset = class_headers_.size();
68 file_header.file_checksum = 0;
69 file_header.file_offset = 0;
70 file_header.file_name_str = AddString("jit_code");
71 file_header.methods_offset = method_headers_.size();
72 }
73
End()74 void JitDebugWriter::End()
75 {
76 ASSERT(!file_headers_.empty());
77 auto &file_header = file_headers_.back();
78 file_header.classes_count = class_headers_.size() - file_header.classes_offset;
79 if (file_header.classes_count == 0) {
80 file_headers_.pop_back();
81 return;
82 }
83 file_header.methods_count = method_headers_.size() - file_header.methods_offset;
84 // We should keep class headers sorted, since AOT manager uses binary search to find classes.
85 std::sort(class_headers_.begin() + file_header.classes_offset, class_headers_.end(),
86 [](const auto &a, const auto &b) { return a.class_id < b.class_id; });
87 }
88
Write()89 bool JitDebugWriter::Write()
90 {
91 switch (GetArch()) {
92 #ifdef PANDA_TARGET_64
93 case Arch::AARCH64:
94 return WriteImpl<Arch::AARCH64>();
95 case Arch::X86_64:
96 return WriteImpl<Arch::X86_64>();
97 #endif
98 case Arch::AARCH32:
99 return WriteImpl<Arch::AARCH32>();
100 default:
101 LOG(ERROR, COMPILER) << "JitDebug: Unsupported arch";
102 return false;
103 }
104 }
105
106 template <Arch arch>
WriteImpl()107 bool JitDebugWriter::WriteImpl()
108 {
109 ElfBuilder<arch, true> builder;
110
111 // In gdb you may use '(gdb) info functions jitted' for find all jit-entry
112 builder.SetCodeName("(jitted) " + method_name_);
113
114 JitCodeDataProvider code_provider(this);
115 builder.GetTextSection()->SetDataProvider(&code_provider);
116
117 builder.SetFrameData(GetFrameData());
118 builder.Build("jitted_code");
119
120 auto elf_size {builder.GetFileSize()};
121 auto mem_range {code_allocator_->AllocateCodeUnprotected(elf_size)};
122 auto elf_data {reinterpret_cast<uint8_t *>(mem_range.GetData())};
123 if (elf_data == nullptr) {
124 return false;
125 }
126
127 builder.HackAddressesForJit(elf_data);
128
129 elf_ = {elf_data, elf_size};
130 builder.Write(elf_);
131 code_allocator_->ProtectCode(mem_range);
132
133 code_ = builder.GetTextSectionData();
134 return true;
135 }
136 } // namespace panda::compiler
137
138 #endif