Home | History | Annotate | Download | only in patchoat
      1 /*
      2  * Copyright (C) 2014 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 #ifndef ART_PATCHOAT_PATCHOAT_H_
     18 #define ART_PATCHOAT_PATCHOAT_H_
     19 
     20 #include "arch/instruction_set.h"
     21 #include "base/enums.h"
     22 #include "base/macros.h"
     23 #include "base/mutex.h"
     24 #include "base/os.h"
     25 #include "elf_file.h"
     26 #include "elf_utils.h"
     27 #include "gc/accounting/space_bitmap.h"
     28 #include "gc/heap.h"
     29 #include "gc/space/image_space.h"
     30 #include "runtime.h"
     31 
     32 namespace art {
     33 
     34 class ArtMethod;
     35 class ImageHeader;
     36 class OatHeader;
     37 
     38 namespace mirror {
     39 class Object;
     40 class PointerArray;
     41 class Reference;
     42 class Class;
     43 }  // namespace mirror
     44 
     45 class PatchOat {
     46  public:
     47   // Relocates the provided image by the specified offset. If output_image_directory is non-empty,
     48   // outputs the relocated image into that directory. If output_image_relocation_directory is
     49   // non-empty, outputs image relocation files (see GeneratePatch) into that directory.
     50   static bool Patch(const std::string& image_location,
     51                     off_t delta,
     52                     const std::string& output_image_directory,
     53                     const std::string& output_image_relocation_directory,
     54                     InstructionSet isa,
     55                     TimingLogger* timings);
     56   static bool Verify(const std::string& image_location,
     57                      const std::string& output_image_filename,
     58                      InstructionSet isa,
     59                      TimingLogger* timings);
     60 
     61   // Generates a patch which can be used to efficiently relocate the original file or to check that
     62   // a relocated file matches the original. The patch is generated from the difference of the
     63   // |original| and the already |relocated| image, and written to |output| in the form of unsigned
     64   // LEB128 for each relocation position.
     65   static bool GeneratePatch(const MemMap& original,
     66                             const MemMap& relocated,
     67                             std::vector<uint8_t>* output,
     68                             std::string* error_msg);
     69 
     70   ~PatchOat() {}
     71   PatchOat(PatchOat&&) = default;
     72 
     73  private:
     74   // All pointers are only borrowed.
     75   PatchOat(InstructionSet isa, MemMap* image,
     76            gc::accounting::ContinuousSpaceBitmap* bitmap, MemMap* heap, off_t delta,
     77            std::map<gc::space::ImageSpace*, std::unique_ptr<MemMap>>* map, TimingLogger* timings)
     78       : image_(image), bitmap_(bitmap), heap_(heap),
     79         delta_(delta), isa_(isa), space_map_(map), timings_(timings) {}
     80 
     81   // Was the .art image at image_path made with --compile-pic ?
     82   static bool IsImagePic(const ImageHeader& image_header, const std::string& image_path);
     83 
     84   enum MaybePic {
     85       NOT_PIC,            // Code not pic. Patch as usual.
     86       PIC,                // Code was pic. Create symlink; skip OAT patching.
     87       ERROR_OAT_FILE,     // Failed to symlink oat file
     88       ERROR_FIRST = ERROR_OAT_FILE,
     89   };
     90 
     91   // Was the .oat image at oat_in made with --compile-pic ?
     92   static MaybePic IsOatPic(const ElfFile* oat_in);
     93 
     94   static bool CreateVdexAndOatSymlinks(const std::string& input_image_filename,
     95                                        const std::string& output_image_filename);
     96 
     97 
     98   void VisitObject(mirror::Object* obj)
     99       REQUIRES_SHARED(Locks::mutator_lock_);
    100   void FixupMethod(ArtMethod* object, ArtMethod* copy)
    101       REQUIRES_SHARED(Locks::mutator_lock_);
    102 
    103   bool PatchImage(bool primary_image) REQUIRES_SHARED(Locks::mutator_lock_);
    104   void PatchArtFields(const ImageHeader* image_header) REQUIRES_SHARED(Locks::mutator_lock_);
    105   void PatchArtMethods(const ImageHeader* image_header) REQUIRES_SHARED(Locks::mutator_lock_);
    106   void PatchImTables(const ImageHeader* image_header) REQUIRES_SHARED(Locks::mutator_lock_);
    107   void PatchImtConflictTables(const ImageHeader* image_header)
    108       REQUIRES_SHARED(Locks::mutator_lock_);
    109   void PatchInternedStrings(const ImageHeader* image_header)
    110       REQUIRES_SHARED(Locks::mutator_lock_);
    111   void PatchClassTable(const ImageHeader* image_header)
    112       REQUIRES_SHARED(Locks::mutator_lock_);
    113   void PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots)
    114       REQUIRES_SHARED(Locks::mutator_lock_);
    115 
    116   bool WriteImage(File* out);
    117 
    118   template <typename T>
    119   T* RelocatedCopyOf(T* obj) const {
    120     if (obj == nullptr) {
    121       return nullptr;
    122     }
    123     DCHECK_GT(reinterpret_cast<uintptr_t>(obj), reinterpret_cast<uintptr_t>(heap_->Begin()));
    124     DCHECK_LT(reinterpret_cast<uintptr_t>(obj), reinterpret_cast<uintptr_t>(heap_->End()));
    125     uintptr_t heap_off =
    126         reinterpret_cast<uintptr_t>(obj) - reinterpret_cast<uintptr_t>(heap_->Begin());
    127     DCHECK_LT(heap_off, image_->Size());
    128     return reinterpret_cast<T*>(image_->Begin() + heap_off);
    129   }
    130 
    131   template <typename T>
    132   T* RelocatedCopyOfFollowImages(T* obj) const {
    133     if (obj == nullptr) {
    134       return nullptr;
    135     }
    136     // Find ImageSpace this belongs to.
    137     auto image_spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces();
    138     for (gc::space::ImageSpace* image_space : image_spaces) {
    139       if (image_space->Contains(obj)) {
    140         uintptr_t heap_off = reinterpret_cast<uintptr_t>(obj) -
    141                              reinterpret_cast<uintptr_t>(image_space->GetMemMap()->Begin());
    142         return reinterpret_cast<T*>(space_map_->find(image_space)->second->Begin() + heap_off);
    143       }
    144     }
    145     LOG(FATAL) << "Did not find object in boot image space " << obj;
    146     UNREACHABLE();
    147   }
    148 
    149   template <typename T>
    150   T* RelocatedAddressOfPointer(T* obj) const {
    151     if (obj == nullptr) {
    152       return obj;
    153     }
    154     auto ret = reinterpret_cast<uintptr_t>(obj) + delta_;
    155     // Trim off high bits in case negative relocation with 64 bit patchoat.
    156     if (Is32BitISA()) {
    157       ret = static_cast<uintptr_t>(static_cast<uint32_t>(ret));
    158     }
    159     return reinterpret_cast<T*>(ret);
    160   }
    161 
    162   bool Is32BitISA() const {
    163     return InstructionSetPointerSize(isa_) == PointerSize::k32;
    164   }
    165 
    166   // Walks through the old image and patches the mmap'd copy of it to the new offset. It does not
    167   // change the heap.
    168   class PatchVisitor {
    169    public:
    170     PatchVisitor(PatchOat* patcher, mirror::Object* copy) : patcher_(patcher), copy_(copy) {}
    171     ~PatchVisitor() {}
    172     void operator() (ObjPtr<mirror::Object> obj, MemberOffset off, bool b) const
    173         REQUIRES(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
    174     // For reference classes.
    175     void operator() (ObjPtr<mirror::Class> cls, ObjPtr<mirror::Reference>  ref) const
    176         REQUIRES(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
    177     // TODO: Consider using these for updating native class roots?
    178     void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED)
    179         const {}
    180     void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {}
    181 
    182    private:
    183     PatchOat* const patcher_;
    184     mirror::Object* const copy_;
    185   };
    186 
    187   // A mmap of the image we are patching. This is modified.
    188   const MemMap* const image_;
    189   // The bitmap over the image within the heap we are patching. This is not modified.
    190   gc::accounting::ContinuousSpaceBitmap* const bitmap_;
    191   // The heap we are patching. This is not modified.
    192   const MemMap* const heap_;
    193   // The amount we are changing the offset by.
    194   const off_t delta_;
    195   // Active instruction set, used to know the entrypoint size.
    196   const InstructionSet isa_;
    197 
    198   const std::map<gc::space::ImageSpace*, std::unique_ptr<MemMap>>* space_map_;
    199 
    200   TimingLogger* timings_;
    201 
    202   class FixupRootVisitor;
    203   class RelocatedPointerVisitor;
    204   class PatchOatArtFieldVisitor;
    205   class PatchOatArtMethodVisitor;
    206 
    207   DISALLOW_IMPLICIT_CONSTRUCTORS(PatchOat);
    208 };
    209 
    210 }  // namespace art
    211 #endif  // ART_PATCHOAT_PATCHOAT_H_
    212