Home | History | Annotate | Download | only in linker
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "multi_oat_relative_patcher.h"
     18 
     19 #include "compiled_method.h"
     20 #include "debug/method_debug_info.h"
     21 #include "gtest/gtest.h"
     22 #include "linker/linker_patch.h"
     23 #include "linker/vector_output_stream.h"
     24 
     25 namespace art {
     26 namespace linker {
     27 
     28 static const MethodReference kNullMethodRef = MethodReference(nullptr, 0u);
     29 
     30 class MultiOatRelativePatcherTest : public testing::Test {
     31  protected:
     32   class MockPatcher : public RelativePatcher {
     33    public:
     34     MockPatcher() { }
     35 
     36     uint32_t ReserveSpace(uint32_t offset,
     37                           const CompiledMethod* compiled_method ATTRIBUTE_UNUSED,
     38                           MethodReference method_ref) OVERRIDE {
     39       last_reserve_offset_ = offset;
     40       last_reserve_method_ = method_ref;
     41       offset += next_reserve_adjustment_;
     42       next_reserve_adjustment_ = 0u;
     43       return offset;
     44     }
     45 
     46     uint32_t ReserveSpaceEnd(uint32_t offset) OVERRIDE {
     47       last_reserve_offset_ = offset;
     48       last_reserve_method_ = kNullMethodRef;
     49       offset += next_reserve_adjustment_;
     50       next_reserve_adjustment_ = 0u;
     51       return offset;
     52     }
     53 
     54     uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE {
     55       last_write_offset_ = offset;
     56       if (next_write_alignment_ != 0u) {
     57         offset += next_write_alignment_;
     58         bool success = WriteCodeAlignment(out, next_write_alignment_);
     59         CHECK(success);
     60         next_write_alignment_ = 0u;
     61       }
     62       if (next_write_call_thunk_ != 0u) {
     63         offset += next_write_call_thunk_;
     64         std::vector<uint8_t> thunk(next_write_call_thunk_, 'c');
     65         bool success = WriteThunk(out, ArrayRef<const uint8_t>(thunk));
     66         CHECK(success);
     67         next_write_call_thunk_ = 0u;
     68       }
     69       if (next_write_misc_thunk_ != 0u) {
     70         offset += next_write_misc_thunk_;
     71         std::vector<uint8_t> thunk(next_write_misc_thunk_, 'm');
     72         bool success = WriteMiscThunk(out, ArrayRef<const uint8_t>(thunk));
     73         CHECK(success);
     74         next_write_misc_thunk_ = 0u;
     75       }
     76       return offset;
     77     }
     78 
     79     void PatchCall(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
     80                    uint32_t literal_offset,
     81                    uint32_t patch_offset,
     82                    uint32_t target_offset) OVERRIDE {
     83       last_literal_offset_ = literal_offset;
     84       last_patch_offset_ = patch_offset;
     85       last_target_offset_ = target_offset;
     86     }
     87 
     88     void PatchPcRelativeReference(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
     89                                   const LinkerPatch& patch,
     90                                   uint32_t patch_offset,
     91                                   uint32_t target_offset) OVERRIDE {
     92       last_literal_offset_ = patch.LiteralOffset();
     93       last_patch_offset_ = patch_offset;
     94       last_target_offset_ = target_offset;
     95     }
     96 
     97     void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
     98                                      const LinkerPatch& patch ATTRIBUTE_UNUSED,
     99                                      uint32_t patch_offset ATTRIBUTE_UNUSED) {
    100       LOG(FATAL) << "UNIMPLEMENTED";
    101     }
    102 
    103     std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(
    104         uint32_t executable_offset ATTRIBUTE_UNUSED) {
    105       LOG(FATAL) << "UNIMPLEMENTED";
    106       UNREACHABLE();
    107     }
    108 
    109     uint32_t last_reserve_offset_ = 0u;
    110     MethodReference last_reserve_method_ = kNullMethodRef;
    111     uint32_t next_reserve_adjustment_ = 0u;
    112 
    113     uint32_t last_write_offset_ = 0u;
    114     uint32_t next_write_alignment_ = 0u;
    115     uint32_t next_write_call_thunk_ = 0u;
    116     uint32_t next_write_misc_thunk_ = 0u;
    117 
    118     uint32_t last_literal_offset_ = 0u;
    119     uint32_t last_patch_offset_ = 0u;
    120     uint32_t last_target_offset_ = 0u;
    121   };
    122 
    123   MultiOatRelativePatcherTest()
    124       : instruction_set_features_(InstructionSetFeatures::FromCppDefines()),
    125         patcher_(kRuntimeISA, instruction_set_features_.get()) {
    126     std::unique_ptr<MockPatcher> mock(new MockPatcher());
    127     mock_ = mock.get();
    128     patcher_.relative_patcher_ = std::move(mock);
    129   }
    130 
    131   std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
    132   MultiOatRelativePatcher patcher_;
    133   MockPatcher* mock_;
    134 };
    135 
    136 TEST_F(MultiOatRelativePatcherTest, Offsets) {
    137   const DexFile* dex_file = reinterpret_cast<const DexFile*>(1);
    138   MethodReference ref1(dex_file, 1u);
    139   MethodReference ref2(dex_file, 2u);
    140   EXPECT_EQ(0u, patcher_.GetOffset(ref1));
    141   EXPECT_EQ(0u, patcher_.GetOffset(ref2));
    142 
    143   uint32_t adjustment1 = 0x1000;
    144   patcher_.StartOatFile(adjustment1);
    145   EXPECT_EQ(0u, patcher_.GetOffset(ref1));
    146   EXPECT_EQ(0u, patcher_.GetOffset(ref2));
    147 
    148   uint32_t off1 = 0x1234;
    149   patcher_.SetOffset(ref1, off1);
    150   EXPECT_EQ(off1, patcher_.GetOffset(ref1));
    151   EXPECT_EQ(0u, patcher_.GetOffset(ref2));
    152 
    153   uint32_t adjustment2 = 0x30000;
    154   patcher_.StartOatFile(adjustment2);
    155   EXPECT_EQ(off1 + adjustment1 - adjustment2, patcher_.GetOffset(ref1));
    156   EXPECT_EQ(0u, patcher_.GetOffset(ref2));
    157 
    158   uint32_t off2 = 0x4321;
    159   patcher_.SetOffset(ref2, off2);
    160   EXPECT_EQ(off1 + adjustment1 - adjustment2, patcher_.GetOffset(ref1));
    161   EXPECT_EQ(off2, patcher_.GetOffset(ref2));
    162 
    163   uint32_t adjustment3 = 0x78000;
    164   patcher_.StartOatFile(adjustment3);
    165   EXPECT_EQ(off1 + adjustment1 - adjustment3, patcher_.GetOffset(ref1));
    166   EXPECT_EQ(off2 + adjustment2 - adjustment3, patcher_.GetOffset(ref2));
    167 }
    168 
    169 TEST_F(MultiOatRelativePatcherTest, OffsetsInReserve) {
    170   const DexFile* dex_file = reinterpret_cast<const DexFile*>(1);
    171   MethodReference ref1(dex_file, 1u);
    172   MethodReference ref2(dex_file, 2u);
    173   MethodReference ref3(dex_file, 3u);
    174   const CompiledMethod* method = reinterpret_cast<const CompiledMethod*>(-1);
    175 
    176   uint32_t adjustment1 = 0x1000;
    177   patcher_.StartOatFile(adjustment1);
    178 
    179   uint32_t method1_offset = 0x100;
    180   uint32_t method1_offset_check = patcher_.ReserveSpace(method1_offset, method, ref1);
    181   ASSERT_EQ(adjustment1 + method1_offset, mock_->last_reserve_offset_);
    182   ASSERT_TRUE(ref1 == mock_->last_reserve_method_);
    183   ASSERT_EQ(method1_offset, method1_offset_check);
    184 
    185   uint32_t method2_offset = 0x1230;
    186   uint32_t method2_reserve_adjustment = 0x10;
    187   mock_->next_reserve_adjustment_ = method2_reserve_adjustment;
    188   uint32_t method2_offset_adjusted = patcher_.ReserveSpace(method2_offset, method, ref2);
    189   ASSERT_EQ(adjustment1 + method2_offset, mock_->last_reserve_offset_);
    190   ASSERT_TRUE(ref2 == mock_->last_reserve_method_);
    191   ASSERT_EQ(method2_offset + method2_reserve_adjustment, method2_offset_adjusted);
    192 
    193   uint32_t end1_offset = 0x4320;
    194   uint32_t end1_offset_check = patcher_.ReserveSpaceEnd(end1_offset);
    195   ASSERT_EQ(adjustment1 + end1_offset, mock_->last_reserve_offset_);
    196   ASSERT_TRUE(kNullMethodRef == mock_->last_reserve_method_);
    197   ASSERT_EQ(end1_offset, end1_offset_check);
    198 
    199   uint32_t adjustment2 = 0xd000;
    200   patcher_.StartOatFile(adjustment2);
    201 
    202   uint32_t method3_offset = 0xf00;
    203   uint32_t method3_offset_check = patcher_.ReserveSpace(method3_offset, method, ref3);
    204   ASSERT_EQ(adjustment2 + method3_offset, mock_->last_reserve_offset_);
    205   ASSERT_TRUE(ref3 == mock_->last_reserve_method_);
    206   ASSERT_EQ(method3_offset, method3_offset_check);
    207 
    208   uint32_t end2_offset = 0x2400;
    209   uint32_t end2_reserve_adjustment = 0x20;
    210   mock_->next_reserve_adjustment_ = end2_reserve_adjustment;
    211   uint32_t end2_offset_adjusted = patcher_.ReserveSpaceEnd(end2_offset);
    212   ASSERT_EQ(adjustment2 + end2_offset, mock_->last_reserve_offset_);
    213   ASSERT_TRUE(kNullMethodRef == mock_->last_reserve_method_);
    214   ASSERT_EQ(end2_offset + end2_reserve_adjustment, end2_offset_adjusted);
    215 }
    216 
    217 TEST_F(MultiOatRelativePatcherTest, Write) {
    218   std::vector<uint8_t> output;
    219   VectorOutputStream vos("output", &output);
    220 
    221   uint32_t adjustment1 = 0x1000;
    222   patcher_.StartOatFile(adjustment1);
    223 
    224   uint32_t method1_offset = 0x100;
    225   uint32_t method1_offset_check = patcher_.WriteThunks(&vos, method1_offset);
    226   ASSERT_EQ(adjustment1 + method1_offset, mock_->last_write_offset_);
    227   ASSERT_EQ(method1_offset, method1_offset_check);
    228   vos.WriteFully("1", 1);  // Mark method1.
    229 
    230   uint32_t method2_offset = 0x1230;
    231   uint32_t method2_alignment_size = 1;
    232   uint32_t method2_call_thunk_size = 2;
    233   mock_->next_write_alignment_ = method2_alignment_size;
    234   mock_->next_write_call_thunk_ = method2_call_thunk_size;
    235   uint32_t method2_offset_adjusted = patcher_.WriteThunks(&vos, method2_offset);
    236   ASSERT_EQ(adjustment1 + method2_offset, mock_->last_write_offset_);
    237   ASSERT_EQ(method2_offset + method2_alignment_size + method2_call_thunk_size,
    238             method2_offset_adjusted);
    239   vos.WriteFully("2", 1);  // Mark method2.
    240 
    241   EXPECT_EQ(method2_alignment_size, patcher_.CodeAlignmentSize());
    242   EXPECT_EQ(method2_call_thunk_size, patcher_.RelativeCallThunksSize());
    243 
    244   uint32_t adjustment2 = 0xd000;
    245   patcher_.StartOatFile(adjustment2);
    246 
    247   uint32_t method3_offset = 0xf00;
    248   uint32_t method3_alignment_size = 2;
    249   uint32_t method3_misc_thunk_size = 1;
    250   mock_->next_write_alignment_ = method3_alignment_size;
    251   mock_->next_write_misc_thunk_ = method3_misc_thunk_size;
    252   uint32_t method3_offset_adjusted = patcher_.WriteThunks(&vos, method3_offset);
    253   ASSERT_EQ(adjustment2 + method3_offset, mock_->last_write_offset_);
    254   ASSERT_EQ(method3_offset + method3_alignment_size + method3_misc_thunk_size,
    255             method3_offset_adjusted);
    256   vos.WriteFully("3", 1);  // Mark method3.
    257 
    258   EXPECT_EQ(method3_alignment_size, patcher_.CodeAlignmentSize());
    259   EXPECT_EQ(method3_misc_thunk_size, patcher_.MiscThunksSize());
    260 
    261   uint8_t expected_output[] = {
    262       '1',
    263       0, 'c', 'c', '2',
    264       0, 0, 'm', '3',
    265   };
    266   ASSERT_EQ(arraysize(expected_output), output.size());
    267   for (size_t i = 0; i != arraysize(expected_output); ++i) {
    268     ASSERT_EQ(expected_output[i], output[i]) << i;
    269   }
    270 }
    271 
    272 TEST_F(MultiOatRelativePatcherTest, Patch) {
    273   std::vector<uint8_t> code(16);
    274 
    275   uint32_t adjustment1 = 0x1000;
    276   patcher_.StartOatFile(adjustment1);
    277 
    278   uint32_t method1_literal_offset = 4u;
    279   uint32_t method1_patch_offset = 0x1234u;
    280   uint32_t method1_target_offset = 0x8888u;
    281   patcher_.PatchCall(&code, method1_literal_offset, method1_patch_offset, method1_target_offset);
    282   DCHECK_EQ(method1_literal_offset, mock_->last_literal_offset_);
    283   DCHECK_EQ(method1_patch_offset + adjustment1, mock_->last_patch_offset_);
    284   DCHECK_EQ(method1_target_offset + adjustment1, mock_->last_target_offset_);
    285 
    286   uint32_t method2_literal_offset = 12u;
    287   uint32_t method2_patch_offset = 0x7654u;
    288   uint32_t method2_target_offset = 0xccccu;
    289   LinkerPatch method2_patch =
    290       LinkerPatch::StringBssEntryPatch(method2_literal_offset, nullptr, 0u, 1u);
    291   patcher_.PatchPcRelativeReference(
    292       &code, method2_patch, method2_patch_offset, method2_target_offset);
    293   DCHECK_EQ(method2_literal_offset, mock_->last_literal_offset_);
    294   DCHECK_EQ(method2_patch_offset + adjustment1, mock_->last_patch_offset_);
    295   DCHECK_EQ(method2_target_offset + adjustment1, mock_->last_target_offset_);
    296 
    297   uint32_t adjustment2 = 0xd000;
    298   patcher_.StartOatFile(adjustment2);
    299 
    300   uint32_t method3_literal_offset = 8u;
    301   uint32_t method3_patch_offset = 0x108u;
    302   uint32_t method3_target_offset = 0x200u;
    303   patcher_.PatchCall(&code, method3_literal_offset, method3_patch_offset, method3_target_offset);
    304   DCHECK_EQ(method3_literal_offset, mock_->last_literal_offset_);
    305   DCHECK_EQ(method3_patch_offset + adjustment2, mock_->last_patch_offset_);
    306   DCHECK_EQ(method3_target_offset + adjustment2, mock_->last_target_offset_);
    307 }
    308 
    309 }  // namespace linker
    310 }  // namespace art
    311