xref: /aosp_15_r20/art/dex2oat/linker/relative_patcher_test.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_DEX2OAT_LINKER_RELATIVE_PATCHER_TEST_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_DEX2OAT_LINKER_RELATIVE_PATCHER_TEST_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <gtest/gtest.h>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
23*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set_features.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/array_ref.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
27*795d594fSAndroid Build Coastguard Worker #include "dex/method_reference.h"
28*795d594fSAndroid Build Coastguard Worker #include "dex/string_reference.h"
29*795d594fSAndroid Build Coastguard Worker #include "driver/compiled_method-inl.h"
30*795d594fSAndroid Build Coastguard Worker #include "driver/compiled_method_storage.h"
31*795d594fSAndroid Build Coastguard Worker #include "linker/relative_patcher.h"
32*795d594fSAndroid Build Coastguard Worker #include "oat/oat_quick_method_header.h"
33*795d594fSAndroid Build Coastguard Worker #include "stream/vector_output_stream.h"
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker namespace art {
36*795d594fSAndroid Build Coastguard Worker namespace linker {
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker // Base class providing infrastructure for architecture-specific tests.
39*795d594fSAndroid Build Coastguard Worker class RelativePatcherTest : public testing::Test {
40*795d594fSAndroid Build Coastguard Worker  protected:
RelativePatcherTest(InstructionSet instruction_set,const std::string & variant)41*795d594fSAndroid Build Coastguard Worker   RelativePatcherTest(InstructionSet instruction_set, const std::string& variant)
42*795d594fSAndroid Build Coastguard Worker       : storage_(/*swap_fd=*/ -1),
43*795d594fSAndroid Build Coastguard Worker         instruction_set_(instruction_set),
44*795d594fSAndroid Build Coastguard Worker         instruction_set_features_(nullptr),
45*795d594fSAndroid Build Coastguard Worker         method_offset_map_(),
46*795d594fSAndroid Build Coastguard Worker         patcher_(nullptr),
47*795d594fSAndroid Build Coastguard Worker         bss_begin_(0u),
48*795d594fSAndroid Build Coastguard Worker         compiled_method_refs_(),
49*795d594fSAndroid Build Coastguard Worker         compiled_methods_(),
50*795d594fSAndroid Build Coastguard Worker         patched_code_(),
51*795d594fSAndroid Build Coastguard Worker         output_(),
52*795d594fSAndroid Build Coastguard Worker         out_(nullptr) {
53*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
54*795d594fSAndroid Build Coastguard Worker     instruction_set_features_ =
55*795d594fSAndroid Build Coastguard Worker         InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg);
56*795d594fSAndroid Build Coastguard Worker     CHECK(instruction_set_features_ != nullptr) << error_msg;
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker     patched_code_.reserve(16 * KB);
59*795d594fSAndroid Build Coastguard Worker   }
60*795d594fSAndroid Build Coastguard Worker 
SetUp()61*795d594fSAndroid Build Coastguard Worker   void SetUp() override {
62*795d594fSAndroid Build Coastguard Worker     Reset();
63*795d594fSAndroid Build Coastguard Worker   }
64*795d594fSAndroid Build Coastguard Worker 
TearDown()65*795d594fSAndroid Build Coastguard Worker   void TearDown() override {
66*795d594fSAndroid Build Coastguard Worker     thunk_provider_.Reset();
67*795d594fSAndroid Build Coastguard Worker     compiled_methods_.clear();
68*795d594fSAndroid Build Coastguard Worker     patcher_.reset();
69*795d594fSAndroid Build Coastguard Worker     bss_begin_ = 0u;
70*795d594fSAndroid Build Coastguard Worker     string_index_to_offset_map_.clear();
71*795d594fSAndroid Build Coastguard Worker     method_index_to_offset_map_.clear();
72*795d594fSAndroid Build Coastguard Worker     compiled_method_refs_.clear();
73*795d594fSAndroid Build Coastguard Worker     compiled_methods_.clear();
74*795d594fSAndroid Build Coastguard Worker     patched_code_.clear();
75*795d594fSAndroid Build Coastguard Worker     output_.clear();
76*795d594fSAndroid Build Coastguard Worker     out_.reset();
77*795d594fSAndroid Build Coastguard Worker   }
78*795d594fSAndroid Build Coastguard Worker 
79*795d594fSAndroid Build Coastguard Worker   // Reset the helper to start another test. Creating and tearing down the Runtime is expensive,
80*795d594fSAndroid Build Coastguard Worker   // so we merge related tests together.
Reset()81*795d594fSAndroid Build Coastguard Worker   virtual void Reset() {
82*795d594fSAndroid Build Coastguard Worker     thunk_provider_.Reset();
83*795d594fSAndroid Build Coastguard Worker     method_offset_map_.map.clear();
84*795d594fSAndroid Build Coastguard Worker     patcher_ = RelativePatcher::Create(instruction_set_,
85*795d594fSAndroid Build Coastguard Worker                                        instruction_set_features_.get(),
86*795d594fSAndroid Build Coastguard Worker                                        &thunk_provider_,
87*795d594fSAndroid Build Coastguard Worker                                        &method_offset_map_);
88*795d594fSAndroid Build Coastguard Worker     bss_begin_ = 0u;
89*795d594fSAndroid Build Coastguard Worker     string_index_to_offset_map_.clear();
90*795d594fSAndroid Build Coastguard Worker     method_index_to_offset_map_.clear();
91*795d594fSAndroid Build Coastguard Worker     compiled_method_refs_.clear();
92*795d594fSAndroid Build Coastguard Worker     compiled_methods_.clear();
93*795d594fSAndroid Build Coastguard Worker     patched_code_.clear();
94*795d594fSAndroid Build Coastguard Worker     output_.clear();
95*795d594fSAndroid Build Coastguard Worker     out_.reset(new VectorOutputStream("test output stream", &output_));
96*795d594fSAndroid Build Coastguard Worker   }
97*795d594fSAndroid Build Coastguard Worker 
MethodRef(uint32_t method_idx)98*795d594fSAndroid Build Coastguard Worker   MethodReference MethodRef(uint32_t method_idx) {
99*795d594fSAndroid Build Coastguard Worker     CHECK_NE(method_idx, 0u);
100*795d594fSAndroid Build Coastguard Worker     return MethodReference(nullptr, method_idx);
101*795d594fSAndroid Build Coastguard Worker   }
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker   void AddCompiledMethod(
104*795d594fSAndroid Build Coastguard Worker       MethodReference method_ref,
105*795d594fSAndroid Build Coastguard Worker       const ArrayRef<const uint8_t>& code,
106*795d594fSAndroid Build Coastguard Worker       const ArrayRef<const LinkerPatch>& patches = ArrayRef<const LinkerPatch>()) {
107*795d594fSAndroid Build Coastguard Worker     compiled_method_refs_.push_back(method_ref);
108*795d594fSAndroid Build Coastguard Worker     compiled_methods_.emplace_back(new CompiledMethod(
109*795d594fSAndroid Build Coastguard Worker         &storage_,
110*795d594fSAndroid Build Coastguard Worker         instruction_set_,
111*795d594fSAndroid Build Coastguard Worker         code,
112*795d594fSAndroid Build Coastguard Worker         /* vmap_table */ ArrayRef<const uint8_t>(),
113*795d594fSAndroid Build Coastguard Worker         /* cfi_info */ ArrayRef<const uint8_t>(),
114*795d594fSAndroid Build Coastguard Worker         patches));
115*795d594fSAndroid Build Coastguard Worker   }
116*795d594fSAndroid Build Coastguard Worker 
CodeAlignmentSize(uint32_t header_offset_to_align)117*795d594fSAndroid Build Coastguard Worker   uint32_t CodeAlignmentSize(uint32_t header_offset_to_align) {
118*795d594fSAndroid Build Coastguard Worker     // We want to align the code rather than the preheader.
119*795d594fSAndroid Build Coastguard Worker     uint32_t unaligned_code_offset = header_offset_to_align + sizeof(OatQuickMethodHeader);
120*795d594fSAndroid Build Coastguard Worker     uint32_t aligned_code_offset =
121*795d594fSAndroid Build Coastguard Worker         CompiledMethod::AlignCode(unaligned_code_offset, instruction_set_);
122*795d594fSAndroid Build Coastguard Worker     return aligned_code_offset - unaligned_code_offset;
123*795d594fSAndroid Build Coastguard Worker   }
124*795d594fSAndroid Build Coastguard Worker 
Link()125*795d594fSAndroid Build Coastguard Worker   void Link() {
126*795d594fSAndroid Build Coastguard Worker     // Reserve space.
127*795d594fSAndroid Build Coastguard Worker     static_assert(kTrampolineOffset == 0u, "Unexpected trampoline offset.");
128*795d594fSAndroid Build Coastguard Worker     uint32_t offset = kTrampolineSize;
129*795d594fSAndroid Build Coastguard Worker     size_t idx = 0u;
130*795d594fSAndroid Build Coastguard Worker     for (auto& compiled_method : compiled_methods_) {
131*795d594fSAndroid Build Coastguard Worker       offset = patcher_->ReserveSpace(offset, compiled_method.get(), compiled_method_refs_[idx]);
132*795d594fSAndroid Build Coastguard Worker 
133*795d594fSAndroid Build Coastguard Worker       uint32_t alignment_size = CodeAlignmentSize(offset);
134*795d594fSAndroid Build Coastguard Worker       offset += alignment_size;
135*795d594fSAndroid Build Coastguard Worker 
136*795d594fSAndroid Build Coastguard Worker       offset += sizeof(OatQuickMethodHeader);
137*795d594fSAndroid Build Coastguard Worker       uint32_t quick_code_offset = offset + compiled_method->GetEntryPointAdjustment();
138*795d594fSAndroid Build Coastguard Worker       const auto code = compiled_method->GetQuickCode();
139*795d594fSAndroid Build Coastguard Worker       offset += code.size();
140*795d594fSAndroid Build Coastguard Worker 
141*795d594fSAndroid Build Coastguard Worker       method_offset_map_.map.Put(compiled_method_refs_[idx], quick_code_offset);
142*795d594fSAndroid Build Coastguard Worker       ++idx;
143*795d594fSAndroid Build Coastguard Worker     }
144*795d594fSAndroid Build Coastguard Worker     offset = patcher_->ReserveSpaceEnd(offset);
145*795d594fSAndroid Build Coastguard Worker     uint32_t output_size = offset;
146*795d594fSAndroid Build Coastguard Worker     output_.reserve(output_size);
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker     // Write data.
149*795d594fSAndroid Build Coastguard Worker     DCHECK(output_.empty());
150*795d594fSAndroid Build Coastguard Worker     uint8_t fake_trampoline[kTrampolineSize];
151*795d594fSAndroid Build Coastguard Worker     memset(fake_trampoline, 0, sizeof(fake_trampoline));
152*795d594fSAndroid Build Coastguard Worker     out_->WriteFully(fake_trampoline, kTrampolineSize);
153*795d594fSAndroid Build Coastguard Worker     offset = kTrampolineSize;
154*795d594fSAndroid Build Coastguard Worker     static const uint8_t kPadding[] = {
155*795d594fSAndroid Build Coastguard Worker         0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
156*795d594fSAndroid Build Coastguard Worker     };
157*795d594fSAndroid Build Coastguard Worker     uint8_t fake_header[sizeof(OatQuickMethodHeader)];
158*795d594fSAndroid Build Coastguard Worker     memset(fake_header, 0, sizeof(fake_header));
159*795d594fSAndroid Build Coastguard Worker     for (auto& compiled_method : compiled_methods_) {
160*795d594fSAndroid Build Coastguard Worker       offset = patcher_->WriteThunks(out_.get(), offset);
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker       uint32_t alignment_size = CodeAlignmentSize(offset);
163*795d594fSAndroid Build Coastguard Worker       CHECK_LE(alignment_size, sizeof(kPadding));
164*795d594fSAndroid Build Coastguard Worker       out_->WriteFully(kPadding, alignment_size);
165*795d594fSAndroid Build Coastguard Worker       offset += alignment_size;
166*795d594fSAndroid Build Coastguard Worker 
167*795d594fSAndroid Build Coastguard Worker       out_->WriteFully(fake_header, sizeof(OatQuickMethodHeader));
168*795d594fSAndroid Build Coastguard Worker       offset += sizeof(OatQuickMethodHeader);
169*795d594fSAndroid Build Coastguard Worker       ArrayRef<const uint8_t> code = compiled_method->GetQuickCode();
170*795d594fSAndroid Build Coastguard Worker       if (!compiled_method->GetPatches().empty()) {
171*795d594fSAndroid Build Coastguard Worker         patched_code_.assign(code.begin(), code.end());
172*795d594fSAndroid Build Coastguard Worker         code = ArrayRef<const uint8_t>(patched_code_);
173*795d594fSAndroid Build Coastguard Worker         for (const LinkerPatch& patch : compiled_method->GetPatches()) {
174*795d594fSAndroid Build Coastguard Worker           if (patch.GetType() == LinkerPatch::Type::kCallRelative) {
175*795d594fSAndroid Build Coastguard Worker             auto result = method_offset_map_.FindMethodOffset(patch.TargetMethod());
176*795d594fSAndroid Build Coastguard Worker             uint32_t target_offset =
177*795d594fSAndroid Build Coastguard Worker                 result.first ? result.second
178*795d594fSAndroid Build Coastguard Worker                              : kTrampolineOffset + compiled_method->GetEntryPointAdjustment();
179*795d594fSAndroid Build Coastguard Worker             patcher_->PatchCall(&patched_code_,
180*795d594fSAndroid Build Coastguard Worker                                 patch.LiteralOffset(),
181*795d594fSAndroid Build Coastguard Worker                                 offset + patch.LiteralOffset(),
182*795d594fSAndroid Build Coastguard Worker                                 target_offset);
183*795d594fSAndroid Build Coastguard Worker           } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
184*795d594fSAndroid Build Coastguard Worker             uint32_t target_offset =
185*795d594fSAndroid Build Coastguard Worker                 bss_begin_ +
186*795d594fSAndroid Build Coastguard Worker                 string_index_to_offset_map_.Get(patch.TargetString().StringIndex().index_);
187*795d594fSAndroid Build Coastguard Worker             patcher_->PatchPcRelativeReference(&patched_code_,
188*795d594fSAndroid Build Coastguard Worker                                                patch,
189*795d594fSAndroid Build Coastguard Worker                                                offset + patch.LiteralOffset(),
190*795d594fSAndroid Build Coastguard Worker                                                target_offset);
191*795d594fSAndroid Build Coastguard Worker           } else if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
192*795d594fSAndroid Build Coastguard Worker             uint32_t target_offset =
193*795d594fSAndroid Build Coastguard Worker                 bss_begin_ + method_index_to_offset_map_.Get(patch.TargetMethod().index);
194*795d594fSAndroid Build Coastguard Worker             patcher_->PatchPcRelativeReference(&patched_code_,
195*795d594fSAndroid Build Coastguard Worker                                                patch,
196*795d594fSAndroid Build Coastguard Worker                                                offset + patch.LiteralOffset(),
197*795d594fSAndroid Build Coastguard Worker                                                target_offset);
198*795d594fSAndroid Build Coastguard Worker           } else if (patch.GetType() == LinkerPatch::Type::kStringRelative) {
199*795d594fSAndroid Build Coastguard Worker             uint32_t target_offset =
200*795d594fSAndroid Build Coastguard Worker                 string_index_to_offset_map_.Get(patch.TargetString().StringIndex().index_);
201*795d594fSAndroid Build Coastguard Worker             patcher_->PatchPcRelativeReference(&patched_code_,
202*795d594fSAndroid Build Coastguard Worker                                                patch,
203*795d594fSAndroid Build Coastguard Worker                                                offset + patch.LiteralOffset(),
204*795d594fSAndroid Build Coastguard Worker                                                target_offset);
205*795d594fSAndroid Build Coastguard Worker           } else if (patch.GetType() == LinkerPatch::Type::kCallEntrypoint) {
206*795d594fSAndroid Build Coastguard Worker             patcher_->PatchEntrypointCall(&patched_code_,
207*795d594fSAndroid Build Coastguard Worker                                           patch,
208*795d594fSAndroid Build Coastguard Worker                                           offset + patch.LiteralOffset());
209*795d594fSAndroid Build Coastguard Worker           } else if (patch.GetType() == LinkerPatch::Type::kBakerReadBarrierBranch) {
210*795d594fSAndroid Build Coastguard Worker             patcher_->PatchBakerReadBarrierBranch(&patched_code_,
211*795d594fSAndroid Build Coastguard Worker                                                   patch,
212*795d594fSAndroid Build Coastguard Worker                                                   offset + patch.LiteralOffset());
213*795d594fSAndroid Build Coastguard Worker           } else {
214*795d594fSAndroid Build Coastguard Worker             LOG(FATAL) << "Bad patch type. " << patch.GetType();
215*795d594fSAndroid Build Coastguard Worker             UNREACHABLE();
216*795d594fSAndroid Build Coastguard Worker           }
217*795d594fSAndroid Build Coastguard Worker         }
218*795d594fSAndroid Build Coastguard Worker       }
219*795d594fSAndroid Build Coastguard Worker       out_->WriteFully(&code[0], code.size());
220*795d594fSAndroid Build Coastguard Worker       offset += code.size();
221*795d594fSAndroid Build Coastguard Worker     }
222*795d594fSAndroid Build Coastguard Worker     offset = patcher_->WriteThunks(out_.get(), offset);
223*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(offset, output_size);
224*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(output_.size(), output_size);
225*795d594fSAndroid Build Coastguard Worker   }
226*795d594fSAndroid Build Coastguard Worker 
CheckLinkedMethod(MethodReference method_ref,const ArrayRef<const uint8_t> & expected_code)227*795d594fSAndroid Build Coastguard Worker   bool CheckLinkedMethod(MethodReference method_ref, const ArrayRef<const uint8_t>& expected_code) {
228*795d594fSAndroid Build Coastguard Worker     // Check that the original code size must match linked_code.size().
229*795d594fSAndroid Build Coastguard Worker     size_t idx = 0u;
230*795d594fSAndroid Build Coastguard Worker     for (auto ref : compiled_method_refs_) {
231*795d594fSAndroid Build Coastguard Worker       if (ref == method_ref) {
232*795d594fSAndroid Build Coastguard Worker         break;
233*795d594fSAndroid Build Coastguard Worker       }
234*795d594fSAndroid Build Coastguard Worker       ++idx;
235*795d594fSAndroid Build Coastguard Worker     }
236*795d594fSAndroid Build Coastguard Worker     CHECK_NE(idx, compiled_method_refs_.size());
237*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(compiled_methods_[idx]->GetQuickCode().size(), expected_code.size());
238*795d594fSAndroid Build Coastguard Worker 
239*795d594fSAndroid Build Coastguard Worker     auto result = method_offset_map_.FindMethodOffset(method_ref);
240*795d594fSAndroid Build Coastguard Worker     CHECK(result.first);  // Must have been linked.
241*795d594fSAndroid Build Coastguard Worker     size_t offset = result.second - compiled_methods_[idx]->GetEntryPointAdjustment();
242*795d594fSAndroid Build Coastguard Worker     CHECK_LT(offset, output_.size());
243*795d594fSAndroid Build Coastguard Worker     CHECK_LE(offset + expected_code.size(), output_.size());
244*795d594fSAndroid Build Coastguard Worker     ArrayRef<const uint8_t> linked_code(&output_[offset], expected_code.size());
245*795d594fSAndroid Build Coastguard Worker     if (linked_code == expected_code) {
246*795d594fSAndroid Build Coastguard Worker       return true;
247*795d594fSAndroid Build Coastguard Worker     }
248*795d594fSAndroid Build Coastguard Worker     // Log failure info.
249*795d594fSAndroid Build Coastguard Worker     DumpDiff(expected_code, linked_code);
250*795d594fSAndroid Build Coastguard Worker     return false;
251*795d594fSAndroid Build Coastguard Worker   }
252*795d594fSAndroid Build Coastguard Worker 
DumpDiff(const ArrayRef<const uint8_t> & expected_code,const ArrayRef<const uint8_t> & linked_code)253*795d594fSAndroid Build Coastguard Worker   void DumpDiff(const ArrayRef<const uint8_t>& expected_code,
254*795d594fSAndroid Build Coastguard Worker                 const ArrayRef<const uint8_t>& linked_code) {
255*795d594fSAndroid Build Coastguard Worker     std::ostringstream expected_hex;
256*795d594fSAndroid Build Coastguard Worker     std::ostringstream linked_hex;
257*795d594fSAndroid Build Coastguard Worker     std::ostringstream diff_indicator;
258*795d594fSAndroid Build Coastguard Worker     static const char digits[] = "0123456789abcdef";
259*795d594fSAndroid Build Coastguard Worker     bool found_diff = false;
260*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i != expected_code.size(); ++i) {
261*795d594fSAndroid Build Coastguard Worker       expected_hex << " " << digits[expected_code[i] >> 4] << digits[expected_code[i] & 0xf];
262*795d594fSAndroid Build Coastguard Worker       linked_hex << " " << digits[linked_code[i] >> 4] << digits[linked_code[i] & 0xf];
263*795d594fSAndroid Build Coastguard Worker       if (!found_diff) {
264*795d594fSAndroid Build Coastguard Worker         found_diff = (expected_code[i] != linked_code[i]);
265*795d594fSAndroid Build Coastguard Worker         diff_indicator << (found_diff ? " ^^" : "   ");
266*795d594fSAndroid Build Coastguard Worker       }
267*795d594fSAndroid Build Coastguard Worker     }
268*795d594fSAndroid Build Coastguard Worker     CHECK(found_diff);
269*795d594fSAndroid Build Coastguard Worker     std::string expected_hex_str = expected_hex.str();
270*795d594fSAndroid Build Coastguard Worker     std::string linked_hex_str = linked_hex.str();
271*795d594fSAndroid Build Coastguard Worker     std::string diff_indicator_str = diff_indicator.str();
272*795d594fSAndroid Build Coastguard Worker     if (diff_indicator_str.length() > 60) {
273*795d594fSAndroid Build Coastguard Worker       CHECK_EQ(diff_indicator_str.length() % 3u, 0u);
274*795d594fSAndroid Build Coastguard Worker       size_t remove = diff_indicator_str.length() / 3 - 5;
275*795d594fSAndroid Build Coastguard Worker       std::ostringstream oss;
276*795d594fSAndroid Build Coastguard Worker       oss << "[stripped " << remove << "]";
277*795d594fSAndroid Build Coastguard Worker       std::string replacement = oss.str();
278*795d594fSAndroid Build Coastguard Worker       expected_hex_str.replace(0u, remove * 3u, replacement);
279*795d594fSAndroid Build Coastguard Worker       linked_hex_str.replace(0u, remove * 3u, replacement);
280*795d594fSAndroid Build Coastguard Worker       diff_indicator_str.replace(0u, remove * 3u, replacement);
281*795d594fSAndroid Build Coastguard Worker     }
282*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "diff expected_code linked_code";
283*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "<" << expected_hex_str;
284*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << ">" << linked_hex_str;
285*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << " " << diff_indicator_str;
286*795d594fSAndroid Build Coastguard Worker   }
287*795d594fSAndroid Build Coastguard Worker 
288*795d594fSAndroid Build Coastguard Worker   class ThunkProvider : public RelativePatcherThunkProvider {
289*795d594fSAndroid Build Coastguard Worker    public:
ThunkProvider()290*795d594fSAndroid Build Coastguard Worker     ThunkProvider() {}
291*795d594fSAndroid Build Coastguard Worker 
SetThunkCode(const LinkerPatch & patch,ArrayRef<const uint8_t> code,const std::string & debug_name)292*795d594fSAndroid Build Coastguard Worker     void SetThunkCode(const LinkerPatch& patch,
293*795d594fSAndroid Build Coastguard Worker                       ArrayRef<const uint8_t> code,
294*795d594fSAndroid Build Coastguard Worker                       const std::string& debug_name) {
295*795d594fSAndroid Build Coastguard Worker       thunk_map_.emplace(ThunkKey(patch), ThunkValue(code, debug_name));
296*795d594fSAndroid Build Coastguard Worker     }
297*795d594fSAndroid Build Coastguard Worker 
GetThunkCode(const LinkerPatch & patch,ArrayRef<const uint8_t> * code,std::string * debug_name)298*795d594fSAndroid Build Coastguard Worker     void GetThunkCode(const LinkerPatch& patch,
299*795d594fSAndroid Build Coastguard Worker                       /*out*/ ArrayRef<const uint8_t>* code,
300*795d594fSAndroid Build Coastguard Worker                       /*out*/ std::string* debug_name) override {
301*795d594fSAndroid Build Coastguard Worker       auto it = thunk_map_.find(ThunkKey(patch));
302*795d594fSAndroid Build Coastguard Worker       CHECK(it != thunk_map_.end());
303*795d594fSAndroid Build Coastguard Worker       const ThunkValue& value = it->second;
304*795d594fSAndroid Build Coastguard Worker       CHECK(code != nullptr);
305*795d594fSAndroid Build Coastguard Worker       *code = value.GetCode();
306*795d594fSAndroid Build Coastguard Worker       CHECK(debug_name != nullptr);
307*795d594fSAndroid Build Coastguard Worker       *debug_name = value.GetDebugName();
308*795d594fSAndroid Build Coastguard Worker     }
309*795d594fSAndroid Build Coastguard Worker 
Reset()310*795d594fSAndroid Build Coastguard Worker     void Reset() {
311*795d594fSAndroid Build Coastguard Worker       thunk_map_.clear();
312*795d594fSAndroid Build Coastguard Worker     }
313*795d594fSAndroid Build Coastguard Worker 
314*795d594fSAndroid Build Coastguard Worker    private:
315*795d594fSAndroid Build Coastguard Worker     class ThunkKey {
316*795d594fSAndroid Build Coastguard Worker      public:
ThunkKey(const LinkerPatch & patch)317*795d594fSAndroid Build Coastguard Worker       explicit ThunkKey(const LinkerPatch& patch)
318*795d594fSAndroid Build Coastguard Worker           : type_(patch.GetType()),
319*795d594fSAndroid Build Coastguard Worker             custom_value1_(CustomValue1(patch)),
320*795d594fSAndroid Build Coastguard Worker             custom_value2_(CustomValue2(patch)) {
321*795d594fSAndroid Build Coastguard Worker         CHECK(patch.GetType() == LinkerPatch::Type::kCallEntrypoint ||
322*795d594fSAndroid Build Coastguard Worker               patch.GetType() == LinkerPatch::Type::kBakerReadBarrierBranch ||
323*795d594fSAndroid Build Coastguard Worker               patch.GetType() == LinkerPatch::Type::kCallRelative);
324*795d594fSAndroid Build Coastguard Worker       }
325*795d594fSAndroid Build Coastguard Worker 
326*795d594fSAndroid Build Coastguard Worker       bool operator<(const ThunkKey& other) const {
327*795d594fSAndroid Build Coastguard Worker         if (custom_value1_ != other.custom_value1_) {
328*795d594fSAndroid Build Coastguard Worker           return custom_value1_ < other.custom_value1_;
329*795d594fSAndroid Build Coastguard Worker         }
330*795d594fSAndroid Build Coastguard Worker         if (custom_value2_ != other.custom_value2_) {
331*795d594fSAndroid Build Coastguard Worker           return custom_value2_ < other.custom_value2_;
332*795d594fSAndroid Build Coastguard Worker         }
333*795d594fSAndroid Build Coastguard Worker         return type_ < other.type_;
334*795d594fSAndroid Build Coastguard Worker       }
335*795d594fSAndroid Build Coastguard Worker 
336*795d594fSAndroid Build Coastguard Worker      private:
CustomValue1(const LinkerPatch & patch)337*795d594fSAndroid Build Coastguard Worker       static uint32_t CustomValue1(const LinkerPatch& patch) {
338*795d594fSAndroid Build Coastguard Worker         switch (patch.GetType()) {
339*795d594fSAndroid Build Coastguard Worker           case LinkerPatch::Type::kCallEntrypoint:
340*795d594fSAndroid Build Coastguard Worker             return patch.EntrypointOffset();
341*795d594fSAndroid Build Coastguard Worker           case LinkerPatch::Type::kBakerReadBarrierBranch:
342*795d594fSAndroid Build Coastguard Worker             return patch.GetBakerCustomValue1();
343*795d594fSAndroid Build Coastguard Worker           default:
344*795d594fSAndroid Build Coastguard Worker             return 0;
345*795d594fSAndroid Build Coastguard Worker         }
346*795d594fSAndroid Build Coastguard Worker       }
347*795d594fSAndroid Build Coastguard Worker 
CustomValue2(const LinkerPatch & patch)348*795d594fSAndroid Build Coastguard Worker       static uint32_t CustomValue2(const LinkerPatch& patch) {
349*795d594fSAndroid Build Coastguard Worker         switch (patch.GetType()) {
350*795d594fSAndroid Build Coastguard Worker           case LinkerPatch::Type::kBakerReadBarrierBranch:
351*795d594fSAndroid Build Coastguard Worker             return patch.GetBakerCustomValue2();
352*795d594fSAndroid Build Coastguard Worker           default:
353*795d594fSAndroid Build Coastguard Worker             return 0;
354*795d594fSAndroid Build Coastguard Worker         }
355*795d594fSAndroid Build Coastguard Worker       }
356*795d594fSAndroid Build Coastguard Worker 
357*795d594fSAndroid Build Coastguard Worker       const LinkerPatch::Type type_;
358*795d594fSAndroid Build Coastguard Worker       const uint32_t custom_value1_;
359*795d594fSAndroid Build Coastguard Worker       const uint32_t custom_value2_;
360*795d594fSAndroid Build Coastguard Worker     };
361*795d594fSAndroid Build Coastguard Worker 
362*795d594fSAndroid Build Coastguard Worker     class ThunkValue {
363*795d594fSAndroid Build Coastguard Worker      public:
ThunkValue(ArrayRef<const uint8_t> code,const std::string & debug_name)364*795d594fSAndroid Build Coastguard Worker       ThunkValue(ArrayRef<const uint8_t> code, const std::string& debug_name)
365*795d594fSAndroid Build Coastguard Worker           : code_(code.begin(), code.end()), debug_name_(debug_name) {}
GetCode()366*795d594fSAndroid Build Coastguard Worker       ArrayRef<const uint8_t> GetCode() const { return ArrayRef<const uint8_t>(code_); }
GetDebugName()367*795d594fSAndroid Build Coastguard Worker       const std::string& GetDebugName() const { return debug_name_; }
368*795d594fSAndroid Build Coastguard Worker 
369*795d594fSAndroid Build Coastguard Worker      private:
370*795d594fSAndroid Build Coastguard Worker       const std::vector<uint8_t> code_;
371*795d594fSAndroid Build Coastguard Worker       const std::string debug_name_;
372*795d594fSAndroid Build Coastguard Worker     };
373*795d594fSAndroid Build Coastguard Worker 
374*795d594fSAndroid Build Coastguard Worker     std::map<ThunkKey, ThunkValue> thunk_map_;
375*795d594fSAndroid Build Coastguard Worker   };
376*795d594fSAndroid Build Coastguard Worker 
377*795d594fSAndroid Build Coastguard Worker   // Map method reference to assinged offset.
378*795d594fSAndroid Build Coastguard Worker   // Wrap the map in a class implementing RelativePatcherTargetProvider.
379*795d594fSAndroid Build Coastguard Worker   class MethodOffsetMap final : public RelativePatcherTargetProvider {
380*795d594fSAndroid Build Coastguard Worker    public:
FindMethodOffset(MethodReference ref)381*795d594fSAndroid Build Coastguard Worker     std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) override {
382*795d594fSAndroid Build Coastguard Worker       auto it = map.find(ref);
383*795d594fSAndroid Build Coastguard Worker       if (it == map.end()) {
384*795d594fSAndroid Build Coastguard Worker         return std::pair<bool, uint32_t>(false, 0u);
385*795d594fSAndroid Build Coastguard Worker       } else {
386*795d594fSAndroid Build Coastguard Worker         return std::pair<bool, uint32_t>(true, it->second);
387*795d594fSAndroid Build Coastguard Worker       }
388*795d594fSAndroid Build Coastguard Worker     }
389*795d594fSAndroid Build Coastguard Worker     SafeMap<MethodReference, uint32_t> map;
390*795d594fSAndroid Build Coastguard Worker   };
391*795d594fSAndroid Build Coastguard Worker 
392*795d594fSAndroid Build Coastguard Worker   static const uint32_t kTrampolineSize = 4u;
393*795d594fSAndroid Build Coastguard Worker   static const uint32_t kTrampolineOffset = 0u;
394*795d594fSAndroid Build Coastguard Worker 
395*795d594fSAndroid Build Coastguard Worker   CompiledMethodStorage storage_;
396*795d594fSAndroid Build Coastguard Worker   InstructionSet instruction_set_;
397*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
398*795d594fSAndroid Build Coastguard Worker 
399*795d594fSAndroid Build Coastguard Worker   ThunkProvider thunk_provider_;
400*795d594fSAndroid Build Coastguard Worker   MethodOffsetMap method_offset_map_;
401*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<RelativePatcher> patcher_;
402*795d594fSAndroid Build Coastguard Worker   uint32_t bss_begin_;
403*795d594fSAndroid Build Coastguard Worker   SafeMap<uint32_t, uint32_t> string_index_to_offset_map_;
404*795d594fSAndroid Build Coastguard Worker   SafeMap<uint32_t, uint32_t> method_index_to_offset_map_;
405*795d594fSAndroid Build Coastguard Worker   std::vector<MethodReference> compiled_method_refs_;
406*795d594fSAndroid Build Coastguard Worker   std::vector<std::unique_ptr<CompiledMethod>> compiled_methods_;
407*795d594fSAndroid Build Coastguard Worker   std::vector<uint8_t> patched_code_;
408*795d594fSAndroid Build Coastguard Worker   std::vector<uint8_t> output_;
409*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<VectorOutputStream> out_;
410*795d594fSAndroid Build Coastguard Worker };
411*795d594fSAndroid Build Coastguard Worker 
412*795d594fSAndroid Build Coastguard Worker }  // namespace linker
413*795d594fSAndroid Build Coastguard Worker }  // namespace art
414*795d594fSAndroid Build Coastguard Worker 
415*795d594fSAndroid Build Coastguard Worker #endif  // ART_DEX2OAT_LINKER_RELATIVE_PATCHER_TEST_H_
416