summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/Android.executable.mk2
-rw-r--r--patchoat/Android.mk8
-rw-r--r--patchoat/patchoat.cc148
3 files changed, 151 insertions, 7 deletions
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index 412f2ddfee..6fd6b2bfff 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -50,6 +50,7 @@ define build-art-executable
art_target_or_host := $(5)
art_ndebug_or_debug := $(6)
art_multilib := $(7)
+ art_static_libraries := $(8)
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
@@ -57,6 +58,7 @@ define build-art-executable
LOCAL_SRC_FILES := $$(art_source)
LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime $$(art_c_includes)
LOCAL_SHARED_LIBRARIES += $$(art_shared_libraries)
+ LOCAL_STATIC_LIBRARIES += $$(art_static_libraries)
LOCAL_WHOLE_STATIC_LIBRARIES += libsigchain
ifeq ($$(art_ndebug_or_debug),ndebug)
diff --git a/patchoat/Android.mk b/patchoat/Android.mk
index 8b6b9ad773..b1fc9a9bd8 100644
--- a/patchoat/Android.mk
+++ b/patchoat/Android.mk
@@ -30,16 +30,16 @@ else
endif
ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
- $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils,art/compiler,target,ndebug,$(patchoat_arch)))
+ $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils,art/compiler,target,ndebug,$(patchoat_arch),libz))
endif
ifeq ($(ART_BUILD_TARGET_DEBUG),true)
- $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils,art/compiler,target,debug,$(patchoat_arch)))
+ $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils,art/compiler,target,debug,$(patchoat_arch),libz))
endif
# We always build patchoat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
ifeq ($(ART_BUILD_NDEBUG),true)
- $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),,art/compiler,host,ndebug))
+ $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),,art/compiler,host,ndebug,,libz))
endif
ifeq ($(ART_BUILD_DEBUG),true)
- $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),,art/compiler,host,debug))
+ $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),,art/compiler,host,debug,,libz))
endif
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index b046ea1ef4..0b35697505 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -45,6 +45,7 @@
#include "runtime.h"
#include "scoped_thread_state_change.h"
#include "thread.h"
+#include "zlib.h"
#include "utils.h"
namespace art {
@@ -800,6 +801,16 @@ static void Usage(const char *fmt, ...) {
UsageError(" --input-oat-fd=<file-descriptor>: Specifies the file-descriptor of the oat file");
UsageError(" to be patched.");
UsageError("");
+ UsageError(" --input-oat-gz-file=<file.oat.gz>: Specifies the exact filename of");
+ UsageError(" the gzip-compressed oat file to be patched.");
+ UsageError("");
+ UsageError(" --input-oat-gz-fd=<file-descriptor>: Specifies the file-descriptor of");
+ UsageError(" the gzip-compressed oat file to be patched.");
+ UsageError("");
+ UsageError(" --swap-file=<file-name>: Specifies a temporary gzip file.");
+ UsageError("");
+ UsageError(" --swap-fd=<file-descriptor>: Specifies a temporary gzip file descriptor.");
+ UsageError("");
UsageError(" --input-oat-location=<file.oat>: Specifies the 'location' to read the patched");
UsageError(" oat file from. If used one must also supply the --instruction-set");
UsageError("");
@@ -908,6 +919,67 @@ static bool FinishFile(File* file, bool close) {
}
}
+static int Inflate(int input_oat_gz_fd, const std::string& input_oat_gz_filename, int tmp_fd, std::string* err) {
+ gzFile in_gzfile = input_oat_gz_fd != -1 ? gzdopen(input_oat_gz_fd, "rb") :
+ gzopen(input_oat_gz_filename.c_str(), "rb");
+ if (in_gzfile == nullptr) {
+ *err = input_oat_gz_fd != -1 ?
+ StringPrintf("Could not open gzip file fd=%d: %s",
+ input_oat_gz_fd, strerror(errno)) :
+ StringPrintf("Could not open gzip file %s: %s",
+ input_oat_gz_filename.c_str(), strerror(errno));
+ return -1;
+ }
+
+ int out_fd = dup(tmp_fd);
+ if (out_fd == -1) {
+ *err = strerror(errno);
+ return -1;
+ }
+
+ constexpr size_t INFLATE_BUFLEN = 16384;
+ std::unique_ptr<File> out_file(new File(out_fd, false));
+ std::unique_ptr<Byte[]> buf(new Byte[INFLATE_BUFLEN]);
+ int len;
+
+ while (0 < (len = gzread(in_gzfile, buf.get(), INFLATE_BUFLEN))) {
+ if (!out_file->WriteFully(buf.get(), len)) {
+ *err = StringPrintf("Could not write to fd=%d: %s", tmp_fd, out_file->GetPath().c_str());
+ gzclose(in_gzfile);
+ return -1;
+ }
+ }
+
+ int errnum;
+ const char* gzerrstr = gzerror(in_gzfile, &errnum);
+
+ if (len < 0 || errnum != Z_OK) {
+ *err = input_oat_gz_fd != -1 ?
+ StringPrintf("Could not inflate gzip file fd=%d: %s",
+ input_oat_gz_fd, gzerrstr) :
+ StringPrintf("Could not inflate gzip file %s: %s",
+ input_oat_gz_filename.c_str(), gzerrstr);
+ gzclose(in_gzfile);
+ return -1;
+ }
+
+ if ((errnum = gzclose(in_gzfile)) != Z_OK) {
+ *err = input_oat_gz_fd != -1 ?
+ StringPrintf("Could not close gzip file fd=%d: gzclose() returned %d",
+ input_oat_gz_fd, errnum) :
+ StringPrintf("Could not close gzip file %s: gzclose() returned %d",
+ input_oat_gz_filename.c_str(), errnum);
+ }
+
+ if (out_file->Flush() != 0) {
+ *err = StringPrintf("Could not flush tmp file fd=%d", tmp_fd);
+ return -1;
+ }
+
+ out_file->DisableAutoClose();
+ return out_fd;
+}
+
static int patchoat(int argc, char **argv) {
InitLogging(argv);
MemMap::Init();
@@ -932,8 +1004,12 @@ static int patchoat(int argc, char **argv) {
bool isa_set = false;
InstructionSet isa = kNone;
std::string input_oat_filename;
+ std::string input_oat_gz_filename;
std::string input_oat_location;
int input_oat_fd = -1;
+ int input_oat_gz_fd = -1;
+ std::string swap_file_name;
+ int swap_fd = -1;
bool have_input_oat = false;
std::string input_image_location;
std::string output_oat_filename;
@@ -968,19 +1044,29 @@ static int patchoat(int argc, char **argv) {
}
} else if (option.starts_with("--input-oat-location=")) {
if (have_input_oat) {
- Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used.");
+ Usage("Only one of --input-oat-file, --input-oat-gz-file, --input-oat-location, "
+ "--input-oat-fd and --input-oat-gz-fd may be used.");
}
have_input_oat = true;
input_oat_location = option.substr(strlen("--input-oat-location=")).data();
} else if (option.starts_with("--input-oat-file=")) {
if (have_input_oat) {
- Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used.");
+ Usage("Only one of --input-oat-file, --input-oat-gz-file, --input-oat-location, "
+ "--input-oat-fd and --input-oat-gz-fd may be used.");
}
have_input_oat = true;
input_oat_filename = option.substr(strlen("--input-oat-file=")).data();
+ } else if (option.starts_with("--input-oat-gz-file=")) {
+ if (have_input_oat) {
+ Usage("Only one of --input-oat-file, --input-oat-gz-file, --input-oat-location, "
+ "--input-oat-fd and --input-oat-gz-fd may be used.");
+ }
+ have_input_oat = true;
+ input_oat_gz_filename = option.substr(strlen("--input-oat-gz-file=")).data();
} else if (option.starts_with("--input-oat-fd=")) {
if (have_input_oat) {
- Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used.");
+ Usage("Only one of --input-oat-file, --input-oat-gz-file, --input-oat-location, "
+ "--input-oat-fd and --input-oat-gz-fd may be used.");
}
have_input_oat = true;
const char* oat_fd_str = option.substr(strlen("--input-oat-fd=")).data();
@@ -990,6 +1076,29 @@ static int patchoat(int argc, char **argv) {
if (input_oat_fd < 0) {
Usage("--input-oat-fd pass a negative value %d", input_oat_fd);
}
+ } else if (option.starts_with("--input-oat-gz-fd=")) {
+ if (have_input_oat) {
+ Usage("Only one of --input-oat-file, --input-oat-gz-file, --input-oat-location, "
+ "--input-oat-fd and --input-oat-gz-fd may be used.");
+ }
+ have_input_oat = true;
+ const char* oat_gz_fd_str = option.substr(strlen("--input-oat-gz-fd=")).data();
+ if (!ParseInt(oat_gz_fd_str, &input_oat_gz_fd)) {
+ Usage("Failed to parse --input-oat-fd argument '%s' as an integer", oat_gz_fd_str);
+ }
+ if (input_oat_gz_fd < 0) {
+ Usage("--input-oat-gz-fd pass a negative value %d", input_oat_gz_fd);
+ }
+ } else if (option.starts_with("--swap-file=")) {
+ swap_file_name = option.substr(strlen("--swap-file=")).data();
+ } else if (option.starts_with("--swap-fd=")) {
+ const char* swap_fd_str = option.substr(strlen("--swap-fd=")).data();
+ if (!ParseInt(swap_fd_str, &swap_fd)) {
+ Usage("Failed to parse --swap-fd argument '%s' as an integer", swap_fd_str);
+ }
+ if (swap_fd < 0) {
+ Usage("--swap-fd passed a negative value %d", swap_fd);
+ }
} 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-file=")) {
@@ -1088,6 +1197,11 @@ static int patchoat(int argc, char **argv) {
Usage("Either both input and output image must be supplied or niether must be.");
}
+ if ((input_oat_gz_fd != -1 || !input_oat_gz_filename.empty()) !=
+ (swap_fd != -1 || !swap_file_name.empty())) {
+ Usage("Either both input gzip and swap must be supplied or niether must be.");
+ }
+
// We know we have both the input and output so rename for clarity.
bool have_image_files = have_output_image;
bool have_oat_files = have_output_oat;
@@ -1111,6 +1225,26 @@ static int patchoat(int argc, char **argv) {
LOG(INFO) << "Using input-oat-file " << input_oat_filename;
}
}
+
+ // Swap file handling.
+ //
+ // If the swap fd is not -1, we assume this is the file descriptor of an open but unlinked file
+ // that we can use for swap.
+ //
+ // If the swap fd is -1 and we have a swap-file string, open the given file as a swap file. We
+ // will immediately unlink to satisfy the swap fd assumption.
+ std::unique_ptr<File> swap_file;
+ if (swap_fd == -1 && !swap_file_name.empty()) {
+ swap_file.reset(OS::CreateEmptyFile(swap_file_name.c_str()));
+ if (swap_file.get() == nullptr) {
+ PLOG(ERROR) << "Failed to create swap file: " << swap_file_name;
+ return EXIT_FAILURE;
+ }
+ swap_fd = swap_file->Fd();
+ swap_file->MarkUnchecked(); // We don't want to track this, it will be unlinked immediately.
+ unlink(swap_file_name.c_str());
+ }
+
if (!patched_image_location.empty()) {
if (!isa_set) {
Usage("specifying a location requires specifying an instruction set");
@@ -1189,8 +1323,16 @@ static int patchoat(int argc, char **argv) {
}
if (have_oat_files) {
+ if (input_oat_gz_fd != -1 || !input_oat_gz_filename.empty()) {
+ std::string err;
+ input_oat_fd = Inflate(input_oat_gz_fd, input_oat_gz_filename, swap_fd, &err);
+ if (input_oat_fd == -1) {
+ LOG(ERROR) << "Failed to inflate input file: " << err;
+ }
+ }
if (input_oat_fd != -1) {
if (input_oat_filename.empty()) {
+ // TODO: make sure this will not be used to create symlink if input_oat_fd is PIC
input_oat_filename = "input-oat-file";
}
input_oat.reset(new File(input_oat_fd, input_oat_filename, false));