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