diff options
Diffstat (limited to 'patchoat/patchoat.cc')
| -rw-r--r-- | patchoat/patchoat.cc | 145 |
1 files changed, 100 insertions, 45 deletions
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 3a155be807..a71197a6ce 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -92,6 +92,32 @@ static bool LocationToFilename(const std::string& location, InstructionSet isa, } } +static const OatHeader* GetOatHeader(const ElfFile* elf_file) { + uint64_t off = 0; + if (!elf_file->GetSectionOffsetAndSize(".rodata", &off, nullptr)) { + return nullptr; + } + + OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf_file->Begin() + off); + return oat_header; +} + +// This function takes an elf file and reads the current patch delta value +// encoded in its oat header value +static bool ReadOatPatchDelta(const ElfFile* elf_file, off_t* delta, std::string* error_msg) { + const OatHeader* oat_header = GetOatHeader(elf_file); + if (oat_header == nullptr) { + *error_msg = "Unable to get oat header from elf file."; + return false; + } + if (!oat_header->IsValid()) { + *error_msg = "Elf file has an invalid oat header"; + return false; + } + *delta = oat_header->GetImagePatchDelta(); + return true; +} + bool PatchOat::Patch(const std::string& image_location, off_t delta, File* output_image, InstructionSet isa, TimingLogger* timings) { @@ -419,24 +445,43 @@ bool PatchOat::ReplaceOatFileWithSymlink(const std::string& input_oat_filename, return true; } +class PatchOatArtFieldVisitor : public ArtFieldVisitor { + public: + explicit PatchOatArtFieldVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {} + + void Visit(ArtField* field) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { + ArtField* const dest = patch_oat_->RelocatedCopyOf(field); + dest->SetDeclaringClass(patch_oat_->RelocatedAddressOfPointer(field->GetDeclaringClass())); + } + + private: + PatchOat* const patch_oat_; +}; + void PatchOat::PatchArtFields(const ImageHeader* image_header) { + PatchOatArtFieldVisitor visitor(this); const auto& section = image_header->GetImageSection(ImageHeader::kSectionArtFields); - for (size_t pos = 0; pos < section.Size(); pos += sizeof(ArtField)) { - auto* src = reinterpret_cast<ArtField*>(heap_->Begin() + section.Offset() + pos); - auto* dest = RelocatedCopyOf(src); - dest->SetDeclaringClass(RelocatedAddressOfPointer(src->GetDeclaringClass())); - } + section.VisitPackedArtFields(&visitor, heap_->Begin()); } +class PatchOatArtMethodVisitor : public ArtMethodVisitor { + public: + explicit PatchOatArtMethodVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {} + + void Visit(ArtMethod* method) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { + ArtMethod* const dest = patch_oat_->RelocatedCopyOf(method); + patch_oat_->FixupMethod(method, dest); + } + + private: + PatchOat* const patch_oat_; +}; + void PatchOat::PatchArtMethods(const ImageHeader* image_header) { const auto& section = image_header->GetMethodsSection(); const size_t pointer_size = InstructionSetPointerSize(isa_); - size_t method_size = ArtMethod::ObjectSize(pointer_size); - for (size_t pos = 0; pos < section.Size(); pos += method_size) { - auto* src = reinterpret_cast<ArtMethod*>(heap_->Begin() + section.Offset() + pos); - auto* dest = RelocatedCopyOf(src); - FixupMethod(src, dest); - } + PatchOatArtMethodVisitor visitor(this); + section.VisitPackedArtMethods(&visitor, heap_->Begin(), pointer_size); } class FixupRootVisitor : public RootVisitor { @@ -445,7 +490,7 @@ class FixupRootVisitor : public RootVisitor { } void VisitRoots(mirror::Object*** roots, size_t count, const RootInfo& info ATTRIBUTE_UNUSED) - OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { for (size_t i = 0; i < count; ++i) { *roots[i] = patch_oat_->RelocatedAddressOfPointer(*roots[i]); } @@ -453,7 +498,7 @@ class FixupRootVisitor : public RootVisitor { void VisitRoots(mirror::CompressedReference<mirror::Object>** roots, size_t count, const RootInfo& info ATTRIBUTE_UNUSED) - OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { for (size_t i = 0; i < count; ++i) { roots[i]->Assign(patch_oat_->RelocatedAddressOfPointer(roots[i]->AsMirrorPtr())); } @@ -565,25 +610,6 @@ void PatchOat::PatchVisitor::operator() (mirror::Class* cls ATTRIBUTE_UNUSED, copy_->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(off, moved_object); } -const OatHeader* PatchOat::GetOatHeader(const ElfFile* elf_file) { - if (elf_file->Is64Bit()) { - return GetOatHeader<ElfFileImpl64>(elf_file->GetImpl64()); - } else { - return GetOatHeader<ElfFileImpl32>(elf_file->GetImpl32()); - } -} - -template <typename ElfFileImpl> -const OatHeader* PatchOat::GetOatHeader(const ElfFileImpl* elf_file) { - auto rodata_sec = elf_file->FindSectionByName(".rodata"); - if (rodata_sec == nullptr) { - return nullptr; - } - - OatHeader* oat_header = reinterpret_cast<OatHeader*>(elf_file->Begin() + rodata_sec->sh_offset); - return oat_header; -} - // Called by BitmapCallback void PatchOat::VisitObject(mirror::Object* object) { mirror::Object* copy = RelocatedCopyOf(object); @@ -597,12 +623,12 @@ void PatchOat::VisitObject(mirror::Object* object) { } } PatchOat::PatchVisitor visitor(this, copy); - object->VisitReferences<true, kVerifyNone>(visitor, visitor); + object->VisitReferences<kVerifyNone>(visitor, visitor); if (object->IsClass<kVerifyNone>()) { auto* klass = object->AsClass(); auto* copy_klass = down_cast<mirror::Class*>(copy); - copy_klass->SetSFieldsUnchecked(RelocatedAddressOfPointer(klass->GetSFields())); - copy_klass->SetIFieldsUnchecked(RelocatedAddressOfPointer(klass->GetIFields())); + copy_klass->SetSFieldsPtrUnchecked(RelocatedAddressOfPointer(klass->GetSFieldsPtr())); + copy_klass->SetIFieldsPtrUnchecked(RelocatedAddressOfPointer(klass->GetIFieldsPtr())); copy_klass->SetDirectMethodsPtrUnchecked( RelocatedAddressOfPointer(klass->GetDirectMethodsPtr())); copy_klass->SetVirtualMethodsPtr(RelocatedAddressOfPointer(klass->GetVirtualMethodsPtr())); @@ -651,8 +677,6 @@ void PatchOat::FixupMethod(ArtMethod* object, ArtMethod* copy) { copy->SetDexCacheResolvedTypes(RelocatedAddressOfPointer(object->GetDexCacheResolvedTypes())); copy->SetEntryPointFromQuickCompiledCodePtrSize(RelocatedAddressOfPointer( object->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)), pointer_size); - copy->SetEntryPointFromInterpreterPtrSize(RelocatedAddressOfPointer( - object->GetEntryPointFromInterpreterPtrSize(pointer_size)), pointer_size); copy->SetEntryPointFromJniPtrSize(RelocatedAddressOfPointer( object->GetEntryPointFromJniPtrSize(pointer_size)), pointer_size); } @@ -853,11 +877,11 @@ NO_RETURN static void Usage(const char *fmt, ...) { UsageError(" --base-offset-delta=<delta>: Specify the amount to change the old base-offset by."); UsageError(" This value may be negative."); UsageError(""); - UsageError(" --patched-image-file=<file.art>: Use the same patch delta as was used to patch"); - UsageError(" the given image file."); + UsageError(" --patched-image-file=<file.art>: Relocate the oat file to be the same as the"); + UsageError(" given image file."); UsageError(""); - UsageError(" --patched-image-location=<file.art>: Use the same patch delta as was used to"); - UsageError(" patch the given image location. If used one must also specify the"); + UsageError(" --patched-image-location=<file.art>: Relocate the oat file to be the same as the"); + UsageError(" image at the given location. If used one must also specify the"); UsageError(" --instruction-set flag. It will search for this image in the same way that"); UsageError(" is done when loading one."); UsageError(""); @@ -973,6 +997,7 @@ static int patchoat(int argc, char **argv) { bool orig_base_offset_set = false; off_t base_delta = 0; bool base_delta_set = false; + bool match_delta = false; std::string patched_image_filename; std::string patched_image_location; bool dump_timings = kIsDebugBuild; @@ -1171,7 +1196,11 @@ static int patchoat(int argc, char **argv) { base_delta_set = true; base_delta = base_offset - orig_base_offset; } else if (!patched_image_filename.empty()) { + if (have_image_files) { + Usage("--patched-image-location should not be used when patching other images"); + } base_delta_set = true; + match_delta = true; std::string error_msg; if (!ReadBaseDelta(patched_image_filename.c_str(), &base_delta, &error_msg)) { Usage(error_msg.c_str(), patched_image_filename.c_str()); @@ -1289,6 +1318,32 @@ static int patchoat(int argc, char **argv) { return EXIT_FAILURE; } + if (match_delta) { + CHECK(!have_image_files); // We will not do this with images. + std::string error_msg; + // Figure out what the current delta is so we can match it to the desired delta. + std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat.get(), PROT_READ, MAP_PRIVATE, + &error_msg)); + off_t current_delta = 0; + if (elf.get() == nullptr) { + LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg; + cleanup(false); + return EXIT_FAILURE; + } else if (!ReadOatPatchDelta(elf.get(), ¤t_delta, &error_msg)) { + LOG(ERROR) << "Unable to get current delta: " << error_msg; + cleanup(false); + return EXIT_FAILURE; + } + // Before this line base_delta is the desired final delta. We need it to be the actual amount to + // change everything by. We subtract the current delta from it to make it this. + base_delta -= current_delta; + if (!IsAligned<kPageSize>(base_delta)) { + LOG(ERROR) << "Given image file was relocated by an illegal delta"; + cleanup(false); + return false; + } + } + if (debug) { LOG(INFO) << "moving offset by " << base_delta << " (0x" << std::hex << base_delta << ") bytes or " @@ -1315,18 +1370,18 @@ static int patchoat(int argc, char **argv) { new_oat_out); // The order here doesn't matter. If the first one is successfully saved and the second one // erased, ImageSpace will still detect a problem and not use the files. - ret = ret && FinishFile(output_image.get(), ret); - ret = ret && FinishFile(output_oat.get(), ret); + ret = FinishFile(output_image.get(), ret); + ret = FinishFile(output_oat.get(), ret); } else if (have_oat_files) { TimingLogger::ScopedTiming pt("patch oat", &timings); ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings, output_oat_fd >= 0, // was it opened from FD? new_oat_out); - ret = ret && FinishFile(output_oat.get(), ret); + ret = FinishFile(output_oat.get(), ret); } else if (have_image_files) { TimingLogger::ScopedTiming pt("patch image", &timings); ret = PatchOat::Patch(input_image_location, base_delta, output_image.get(), isa, &timings); - ret = ret && FinishFile(output_image.get(), ret); + ret = FinishFile(output_image.get(), ret); } else { CHECK(false); ret = true; |