diff options
Diffstat (limited to 'patchoat/patchoat.cc')
-rw-r--r-- | patchoat/patchoat.cc | 106 |
1 files changed, 88 insertions, 18 deletions
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 85b4e6d..55d582f 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -17,11 +17,14 @@ #include <stdio.h> #include <stdlib.h> +#include <sys/file.h> #include <sys/stat.h> +#include <unistd.h> #include <string> #include <vector> +#include "base/scoped_flock.h" #include "base/stringpiece.h" #include "base/stringprintf.h" #include "elf_utils.h" @@ -125,7 +128,7 @@ bool PatchOat::Patch(const std::string& image_location, off_t delta, delta, timings); t.NewTiming("Patching files"); if (!p.PatchImage()) { - LOG(INFO) << "Failed to patch image file " << input_image->GetPath(); + LOG(ERROR) << "Failed to patch image file " << input_image->GetPath(); return false; } @@ -216,11 +219,11 @@ bool PatchOat::Patch(const File* input_oat, const std::string& image_location, o delta, timings); t.NewTiming("Patching files"); if (!p.PatchElf()) { - LOG(INFO) << "Failed to patch oat file " << input_oat->GetPath(); + LOG(ERROR) << "Failed to patch oat file " << input_oat->GetPath(); return false; } if (!p.PatchImage()) { - LOG(INFO) << "Failed to patch image file " << input_image->GetPath(); + LOG(ERROR) << "Failed to patch image file " << input_image->GetPath(); return false; } @@ -236,6 +239,12 @@ bool PatchOat::Patch(const File* input_oat, const std::string& image_location, o bool PatchOat::WriteElf(File* out) { TimingLogger::ScopedTiming t("Writing Elf File", timings_); + std::string error_msg; + + // Lock the output file. + ScopedFlock flock; + flock.Init(out, &error_msg); + CHECK(oat_file_.get() != nullptr); CHECK(out != nullptr); size_t expect = oat_file_->Size(); @@ -250,6 +259,12 @@ bool PatchOat::WriteElf(File* out) { bool PatchOat::WriteImage(File* out) { TimingLogger::ScopedTiming t("Writing image File", timings_); + std::string error_msg; + + // Lock the output file. + ScopedFlock flock; + flock.Init(out, &error_msg); + CHECK(image_ != nullptr); CHECK(out != nullptr); size_t expect = image_->Size(); @@ -437,19 +452,50 @@ bool PatchOat::CheckOatFile() { return true; } +bool PatchOat::PatchOatHeader() { + Elf32_Shdr *rodata_sec = oat_file_->FindSectionByName(".rodata"); + if (rodata_sec == nullptr) { + return false; + } + OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file_->Begin() + rodata_sec->sh_offset); + if (!oat_header->IsValid()) { + LOG(ERROR) << "Elf file " << oat_file_->GetFile().GetPath() << " has an invalid oat header"; + return false; + } + oat_header->RelocateOat(delta_); + return true; +} + bool PatchOat::PatchElf() { - TimingLogger::ScopedTiming t("Fixup Elf Headers", timings_); + TimingLogger::ScopedTiming t("Fixup Elf Text Section", timings_); + if (!PatchTextSection()) { + return false; + } + + if (!PatchOatHeader()) { + return false; + } + + bool need_fixup = false; + t.NewTiming("Fixup Elf Headers"); // Fixup Phdr's for (unsigned int i = 0; i < oat_file_->GetProgramHeaderNum(); i++) { Elf32_Phdr& hdr = oat_file_->GetProgramHeader(i); - if (hdr.p_vaddr != 0) { + if (hdr.p_vaddr != 0 && hdr.p_vaddr != hdr.p_offset) { + need_fixup = true; hdr.p_vaddr += delta_; } - if (hdr.p_paddr != 0) { + if (hdr.p_paddr != 0 && hdr.p_paddr != hdr.p_offset) { + need_fixup = true; hdr.p_paddr += delta_; } } - // Fixup Shdr's + if (!need_fixup) { + // This was never passed through ElfFixup so all headers/symbols just have their offset as + // their addr. Therefore we do not need to update these parts. + return true; + } + t.NewTiming("Fixup Section Headers"); for (unsigned int i = 0; i < oat_file_->GetSectionHeaderNum(); i++) { Elf32_Shdr& hdr = oat_file_->GetSectionHeader(i); if (hdr.sh_addr != 0) { @@ -457,7 +503,7 @@ bool PatchOat::PatchElf() { } } - // Fixup Dynamics. + t.NewTiming("Fixup Dynamics"); for (Elf32_Word i = 0; i < oat_file_->GetDynamicNum(); i++) { Elf32_Dyn& dyn = oat_file_->GetDynamic(i); if (IsDynamicSectionPointer(dyn.d_tag, oat_file_->GetHeader().e_machine)) { @@ -481,12 +527,6 @@ bool PatchOat::PatchElf() { } } - t.NewTiming("Fixup Elf Text Section"); - // Fixup text - if (!PatchTextSection()) { - return false; - } - return true; } @@ -511,7 +551,7 @@ bool PatchOat::PatchSymbols(Elf32_Shdr* section) { bool PatchOat::PatchTextSection() { Elf32_Shdr* patches_sec = oat_file_->FindSectionByName(".oat_patches"); if (patches_sec == nullptr) { - LOG(INFO) << ".oat_patches section not found. Aborting patch"; + LOG(ERROR) << ".oat_patches section not found. Aborting patch"; return false; } DCHECK(CheckOatFile()) << "Oat file invalid"; @@ -614,7 +654,8 @@ static void Usage(const char *fmt, ...) { 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(" --instruction-set flag."); + UsageError(" --instruction-set flag. It will search for this image in the same way that"); + UsageError(" is done when loading one."); UsageError(""); UsageError(" --dump-timings: dump out patch timing information"); UsageError(""); @@ -909,7 +950,25 @@ static int patchoat(int argc, char **argv) { if (!isa_set) { Usage("specifying a location requires specifying an instruction set"); } - patched_image_filename = GetSystemImageFilename(patched_image_location.c_str(), isa); + std::string system_filename; + bool has_system = false; + std::string cache_filename; + bool has_cache = false; + bool has_android_data_unused = false; + if (!gc::space::ImageSpace::FindImageFilename(patched_image_location.c_str(), isa, + &system_filename, &has_system, &cache_filename, + &has_android_data_unused, &has_cache)) { + Usage("Unable to determine image file for location %s", patched_image_location.c_str()); + } + if (has_cache) { + patched_image_filename = cache_filename; + } else if (has_system) { + LOG(WARNING) << "Only image file found was in /system for image location " + << patched_image_location; + patched_image_filename = system_filename; + } else { + Usage("Unable to determine image file for location %s", patched_image_location.c_str()); + } if (debug) { LOG(INFO) << "Using patched-image-file " << patched_image_filename; } @@ -969,6 +1028,14 @@ static int patchoat(int argc, char **argv) { if (output_oat_fd != -1) { output_oat.reset(new File(output_oat_fd, output_oat_filename)); + } else if (output_oat_filename == input_oat_filename) { + // This could be a wierd situation, since we'd be writting from an mmap'd copy of this file. + // Lets just unlink it. + if (0 != unlink(input_oat_filename.c_str())) { + PLOG(ERROR) << "Could not unlink " << input_oat_filename << " to make room for output"; + return false; + } + output_oat.reset(OS::CreateEmptyFile(output_oat_filename.c_str())); } else { CHECK(!output_oat_filename.empty()); output_oat.reset(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out)); @@ -994,7 +1061,9 @@ static int patchoat(int argc, char **argv) { }; if (debug) { - LOG(INFO) << "moving offset by " << base_delta << " (0x" << std::hex << base_delta << ") bytes"; + LOG(INFO) << "moving offset by " << base_delta + << " (0x" << std::hex << base_delta << ") bytes or " + << std::dec << (base_delta/kPageSize) << " pages."; } bool ret; @@ -1011,6 +1080,7 @@ static int patchoat(int argc, char **argv) { ret = PatchOat::Patch(input_image_location, base_delta, output_image.get(), isa, &timings); } cleanup(ret); + sync(); return (ret) ? EXIT_SUCCESS : EXIT_FAILURE; } |