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