• 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 #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