summaryrefslogtreecommitdiff
path: root/patchoat/patchoat.cc
diff options
context:
space:
mode:
Diffstat (limited to 'patchoat/patchoat.cc')
-rw-r--r--patchoat/patchoat.cc291
1 files changed, 207 insertions, 84 deletions
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 85b4e6df32..eed20da178 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"
@@ -63,6 +66,47 @@ static InstructionSet ElfISAToInstructionSet(Elf32_Word isa) {
}
}
+static bool LocationToFilename(const std::string& location, InstructionSet isa,
+ std::string* filename) {
+ bool has_system = false;
+ bool has_cache = false;
+ // image_location = /system/framework/boot.art
+ // system_image_location = /system/framework/<image_isa>/boot.art
+ std::string system_filename(GetSystemImageFilename(location.c_str(), isa));
+ if (OS::FileExists(system_filename.c_str())) {
+ has_system = true;
+ }
+
+ bool have_android_data = false;
+ bool dalvik_cache_exists = false;
+ std::string dalvik_cache;
+ GetDalvikCache(GetInstructionSetString(isa), false, &dalvik_cache,
+ &have_android_data, &dalvik_cache_exists);
+
+ std::string cache_filename;
+ if (have_android_data && dalvik_cache_exists) {
+ // Always set output location even if it does not exist,
+ // so that the caller knows where to create the image.
+ //
+ // image_location = /system/framework/boot.art
+ // *image_filename = /data/dalvik-cache/<image_isa>/boot.art
+ std::string error_msg;
+ if (GetDalvikCacheFilename(location.c_str(), dalvik_cache.c_str(),
+ &cache_filename, &error_msg)) {
+ has_cache = true;
+ }
+ }
+ if (has_system) {
+ *filename = system_filename;
+ return true;
+ } else if (has_cache) {
+ *filename = cache_filename;
+ return true;
+ } else {
+ return false;
+ }
+}
+
bool PatchOat::Patch(const std::string& image_location, off_t delta,
File* output_image, InstructionSet isa,
TimingLogger* timings) {
@@ -74,10 +118,15 @@ bool PatchOat::Patch(const std::string& image_location, off_t delta,
TimingLogger::ScopedTiming t("Runtime Setup", timings);
const char *isa_name = GetInstructionSetString(isa);
- std::string image_filename(GetSystemImageFilename(image_location.c_str(), isa));
+ std::string image_filename;
+ if (!LocationToFilename(image_location, isa, &image_filename)) {
+ LOG(ERROR) << "Unable to find image at location " << image_location;
+ return false;
+ }
std::unique_ptr<File> input_image(OS::OpenFileForReading(image_filename.c_str()));
if (input_image.get() == nullptr) {
- LOG(ERROR) << "unable to open input image file.";
+ LOG(ERROR) << "unable to open input image file at " << image_filename
+ << " for location " << image_location;
return false;
}
int64_t image_len = input_image->GetLength();
@@ -125,7 +174,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;
}
@@ -159,10 +208,15 @@ bool PatchOat::Patch(const File* input_oat, const std::string& image_location, o
isa = ElfISAToInstructionSet(elf_hdr.e_machine);
}
const char* isa_name = GetInstructionSetString(isa);
- std::string image_filename(GetSystemImageFilename(image_location.c_str(), isa));
+ std::string image_filename;
+ if (!LocationToFilename(image_location, isa, &image_filename)) {
+ LOG(ERROR) << "Unable to find image at location " << image_location;
+ return false;
+ }
std::unique_ptr<File> input_image(OS::OpenFileForReading(image_filename.c_str()));
if (input_image.get() == nullptr) {
- LOG(ERROR) << "unable to open input image file.";
+ LOG(ERROR) << "unable to open input image file at " << image_filename
+ << " for location " << image_location;
return false;
}
int64_t image_len = input_image->GetLength();
@@ -216,11 +270,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 +290,7 @@ 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_);
+
CHECK(oat_file_.get() != nullptr);
CHECK(out != nullptr);
size_t expect = oat_file_->Size();
@@ -250,6 +305,11 @@ bool PatchOat::WriteElf(File* out) {
bool PatchOat::WriteImage(File* out) {
TimingLogger::ScopedTiming t("Writing image File", timings_);
+ std::string error_msg;
+
+ ScopedFlock img_flock;
+ img_flock.Init(out, &error_msg);
+
CHECK(image_ != nullptr);
CHECK(out != nullptr);
size_t expect = image_->Size();
@@ -406,16 +466,13 @@ bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogge
return true;
}
-bool PatchOat::CheckOatFile() {
- Elf32_Shdr* patches_sec = oat_file_->FindSectionByName(".oat_patches");
- if (patches_sec == nullptr) {
- return false;
- }
- if (patches_sec->sh_type != SHT_OAT_PATCH) {
+template <typename ptr_t>
+bool PatchOat::CheckOatFile(const Elf32_Shdr& patches_sec) {
+ if (patches_sec.sh_type != SHT_OAT_PATCH) {
return false;
}
- uintptr_t* patches = reinterpret_cast<uintptr_t*>(oat_file_->Begin() + patches_sec->sh_offset);
- uintptr_t* patches_end = patches + (patches_sec->sh_size/sizeof(uintptr_t));
+ ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file_->Begin() + patches_sec.sh_offset);
+ ptr_t* patches_end = patches + (patches_sec.sh_size / sizeof(ptr_t));
Elf32_Shdr* oat_data_sec = oat_file_->FindSectionByName(".rodata");
Elf32_Shdr* oat_text_sec = oat_file_->FindSectionByName(".text");
if (oat_data_sec == nullptr) {
@@ -437,19 +494,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 +545,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 +569,6 @@ bool PatchOat::PatchElf() {
}
}
- t.NewTiming("Fixup Elf Text Section");
- // Fixup text
- if (!PatchTextSection()) {
- return false;
- }
-
return true;
}
@@ -511,13 +593,31 @@ 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";
- CHECK_EQ(patches_sec->sh_type, SHT_OAT_PATCH) << "Unexpected type of .oat_patches";
- uintptr_t* patches = reinterpret_cast<uintptr_t*>(oat_file_->Begin() + patches_sec->sh_offset);
- uintptr_t* patches_end = patches + (patches_sec->sh_size/sizeof(uintptr_t));
+ if (patches_sec->sh_type != SHT_OAT_PATCH) {
+ LOG(ERROR) << "Unexpected type of .oat_patches";
+ return false;
+ }
+
+ switch (patches_sec->sh_entsize) {
+ case sizeof(uint32_t):
+ return PatchTextSection<uint32_t>(*patches_sec);
+ case sizeof(uint64_t):
+ return PatchTextSection<uint64_t>(*patches_sec);
+ default:
+ LOG(ERROR) << ".oat_patches Entsize of " << patches_sec->sh_entsize << "bits "
+ << "is not valid";
+ return false;
+ }
+}
+
+template <typename ptr_t>
+bool PatchOat::PatchTextSection(const Elf32_Shdr& patches_sec) {
+ DCHECK(CheckOatFile<ptr_t>(patches_sec)) << "Oat file invalid";
+ ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file_->Begin() + patches_sec.sh_offset);
+ ptr_t* patches_end = patches + (patches_sec.sh_size / sizeof(ptr_t));
Elf32_Shdr* oat_text_sec = oat_file_->FindSectionByName(".text");
CHECK(oat_text_sec != nullptr);
byte* to_patch = oat_file_->Begin() + oat_text_sec->sh_offset;
@@ -529,7 +629,6 @@ bool PatchOat::PatchTextSection() {
CHECK_LT(reinterpret_cast<uintptr_t>(patch_loc), to_patch_end);
*patch_loc += delta_;
}
-
return true;
}
@@ -585,9 +684,6 @@ static void Usage(const char *fmt, ...) {
UsageError(" --output-oat-file=<file.oat>: Specifies the exact file to write the patched oat");
UsageError(" file to.");
UsageError("");
- UsageError(" --output-oat-location=<file.oat>: Specifies the 'location' to write the patched");
- UsageError(" oat file to. If used one must also specify the --instruction-set");
- UsageError("");
UsageError(" --output-oat-fd=<file-descriptor>: Specifies the file-descriptor to write the");
UsageError(" the patched oat file to.");
UsageError("");
@@ -597,9 +693,6 @@ static void Usage(const char *fmt, ...) {
UsageError(" --output-image-fd=<file-descriptor>: Specifies the file-descriptor to write the");
UsageError(" the patched image file to.");
UsageError("");
- UsageError(" --output-image-location=<file.art>: Specifies the 'location' to write the patched");
- UsageError(" image file to. If used one must also specify the --instruction-set");
- UsageError("");
UsageError(" --orig-base-offset=<original-base-offset>: Specify the base offset the input file");
UsageError(" was compiled with. This is needed if one is specifying a --base-offset");
UsageError("");
@@ -614,7 +707,12 @@ 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(" --lock-output: Obtain a flock on output oat file before starting.");
+ UsageError("");
+ UsageError(" --no-lock-output: Do not attempt to obtain a flock on output oat file.");
UsageError("");
UsageError(" --dump-timings: dump out patch timing information");
UsageError("");
@@ -658,7 +756,15 @@ static File* CreateOrOpen(const char* name, bool* created) {
return OS::OpenFileReadWrite(name);
} else {
*created = true;
- return OS::CreateEmptyFile(name);
+ std::unique_ptr<File> f(OS::CreateEmptyFile(name));
+ if (f.get() != nullptr) {
+ if (fchmod(f->Fd(), 0644) != 0) {
+ PLOG(ERROR) << "Unable to make " << name << " world readable";
+ unlink(name);
+ return nullptr;
+ }
+ }
+ return f.release();
}
}
@@ -690,11 +796,9 @@ static int patchoat(int argc, char **argv) {
bool have_input_oat = false;
std::string input_image_location;
std::string output_oat_filename;
- std::string output_oat_location;
int output_oat_fd = -1;
bool have_output_oat = false;
std::string output_image_filename;
- std::string output_image_location;
int output_image_fd = -1;
bool have_output_image = false;
uintptr_t base_offset = 0;
@@ -706,6 +810,7 @@ static int patchoat(int argc, char **argv) {
std::string patched_image_filename;
std::string patched_image_location;
bool dump_timings = kIsDebugBuild;
+ bool lock_output = true;
for (int i = 0; i < argc; i++) {
const StringPiece option(argv[i]);
@@ -756,24 +861,15 @@ static int patchoat(int argc, char **argv) {
}
} else if (option.starts_with("--input-image-location=")) {
input_image_location = option.substr(strlen("--input-image-location=")).data();
- } else if (option.starts_with("--output-oat-location=")) {
- if (have_output_oat) {
- Usage("Only one of --output-oat-file, --output-oat-location and --output-oat-fd may "
- "be used.");
- }
- have_output_oat = true;
- output_oat_location = option.substr(strlen("--output-oat-location=")).data();
} else if (option.starts_with("--output-oat-file=")) {
if (have_output_oat) {
- Usage("Only one of --output-oat-file, --output-oat-location and --output-oat-fd may "
- "be used.");
+ Usage("Only one of --output-oat-file, and --output-oat-fd may be used.");
}
have_output_oat = true;
output_oat_filename = option.substr(strlen("--output-oat-file=")).data();
} else if (option.starts_with("--output-oat-fd=")) {
if (have_output_oat) {
- Usage("Only one of --output-oat-file, --output-oat-location and --output-oat-fd may "
- "be used.");
+ Usage("Only one of --output-oat-file, --output-oat-fd may be used.");
}
have_output_oat = true;
const char* oat_fd_str = option.substr(strlen("--output-oat-fd=")).data();
@@ -783,24 +879,15 @@ static int patchoat(int argc, char **argv) {
if (output_oat_fd < 0) {
Usage("--output-oat-fd pass a negative value %d", output_oat_fd);
}
- } else if (option.starts_with("--output-image-location=")) {
- if (have_output_image) {
- Usage("Only one of --output-image-file, --output-image-location and --output-image-fd may "
- "be used.");
- }
- have_output_image = true;
- output_image_location= option.substr(strlen("--output-image-location=")).data();
} else if (option.starts_with("--output-image-file=")) {
if (have_output_image) {
- Usage("Only one of --output-image-file, --output-image-location and --output-image-fd may "
- "be used.");
+ Usage("Only one of --output-image-file, and --output-image-fd may be used.");
}
have_output_image = true;
output_image_filename = option.substr(strlen("--output-image-file=")).data();
} else if (option.starts_with("--output-image-fd=")) {
if (have_output_image) {
- Usage("Only one of --output-image-file, --output-image-location and --output-image-fd "
- "may be used.");
+ Usage("Only one of --output-image-file, and --output-image-fd may be used.");
}
have_output_image = true;
const char* image_fd_str = option.substr(strlen("--output-image-fd=")).data();
@@ -833,6 +920,10 @@ static int patchoat(int argc, char **argv) {
patched_image_location = option.substr(strlen("--patched-image-location=")).data();
} else if (option.starts_with("--patched-image-file=")) {
patched_image_filename = option.substr(strlen("--patched-image-file=")).data();
+ } else if (option == "--lock-output") {
+ lock_output = true;
+ } else if (option == "--no-lock-output") {
+ lock_output = false;
} else if (option == "--dump-timings") {
dump_timings = true;
} else if (option == "--no-dump-timings") {
@@ -882,34 +973,36 @@ static int patchoat(int argc, char **argv) {
if (!isa_set) {
Usage("specifying a location requires specifying an instruction set");
}
- input_oat_filename = GetSystemImageFilename(input_oat_location.c_str(), isa);
- if (debug) {
- LOG(INFO) << "Using input-oat-file " << input_oat_filename;
+ if (!LocationToFilename(input_oat_location, isa, &input_oat_filename)) {
+ Usage("Unable to find filename for input oat location %s", input_oat_location.c_str());
}
- }
- if (!output_oat_location.empty()) {
- if (!isa_set) {
- Usage("specifying a location requires specifying an instruction set");
- }
- output_oat_filename = GetSystemImageFilename(output_oat_location.c_str(), isa);
if (debug) {
- LOG(INFO) << "Using output-oat-file " << output_oat_filename;
+ LOG(INFO) << "Using input-oat-file " << input_oat_filename;
}
}
- if (!output_image_location.empty()) {
+ if (!patched_image_location.empty()) {
if (!isa_set) {
Usage("specifying a location requires specifying an instruction set");
}
- output_image_filename = GetSystemImageFilename(output_image_location.c_str(), isa);
- if (debug) {
- LOG(INFO) << "Using output-image-file " << output_image_filename;
+ 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 (!patched_image_location.empty()) {
- if (!isa_set) {
- Usage("specifying a location requires specifying an instruction set");
+ 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());
}
- patched_image_filename = GetSystemImageFilename(patched_image_location.c_str(), isa);
if (debug) {
LOG(INFO) << "Using patched-image-file " << patched_image_filename;
}
@@ -950,6 +1043,9 @@ static int patchoat(int argc, char **argv) {
CHECK(!input_image_location.empty());
if (output_image_fd != -1) {
+ if (output_image_filename.empty()) {
+ output_image_filename = "output-image-file";
+ }
output_image.reset(new File(output_image_fd, output_image_filename));
} else {
CHECK(!output_image_filename.empty());
@@ -961,13 +1057,22 @@ static int patchoat(int argc, char **argv) {
if (have_oat_files) {
if (input_oat_fd != -1) {
+ if (input_oat_filename.empty()) {
+ input_oat_filename = "input-oat-file";
+ }
input_oat.reset(new File(input_oat_fd, input_oat_filename));
} else {
CHECK(!input_oat_filename.empty());
input_oat.reset(OS::OpenFileForReading(input_oat_filename.c_str()));
+ if (input_oat.get() == nullptr) {
+ LOG(ERROR) << "Could not open input oat file: " << strerror(errno);
+ }
}
if (output_oat_fd != -1) {
+ if (output_oat_filename.empty()) {
+ output_oat_filename = "output-oat-file";
+ }
output_oat.reset(new File(output_oat_fd, output_oat_filename));
} else {
CHECK(!output_oat_filename.empty());
@@ -993,8 +1098,26 @@ static int patchoat(int argc, char **argv) {
}
};
+ if ((have_oat_files && (input_oat.get() == nullptr || output_oat.get() == nullptr)) ||
+ (have_image_files && output_image.get() == nullptr)) {
+ cleanup(false);
+ return EXIT_FAILURE;
+ }
+
+ ScopedFlock output_oat_lock;
+ if (lock_output) {
+ std::string error_msg;
+ if (have_oat_files && !output_oat_lock.Init(output_oat.get(), &error_msg)) {
+ LOG(ERROR) << "Unable to lock output oat " << output_image->GetPath() << ": " << error_msg;
+ cleanup(false);
+ return EXIT_FAILURE;
+ }
+ }
+
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;