Add oatdump support for app images
Example usage on host:
oatdumpd --app-oat=art/plus32.odex --app-image=art/plus32.art
--image=art/oats/system@framework@boot.art --instruction-set=arm
TODO: Add to oatdump test.
Bug: 27408512
Bug: 22858531
Change-Id: I320db8b76c780c6eadabcb45ce88f45950741484
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index 4219d97..ca0869a 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -42,7 +42,11 @@
size_t* oat_loaded_size,
size_t* oat_data_offset) {
std::string error_msg;
- std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, false, false, &error_msg));
+ std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file,
+ false,
+ false,
+ /*low_4gb*/false,
+ &error_msg));
CHECK(elf_file.get() != nullptr) << error_msg;
bool success = elf_file->GetLoadedSize(oat_loaded_size, &error_msg);
@@ -54,7 +58,7 @@
bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) {
std::string error_msg;
- std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg));
+ std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, /*low_4gb*/false, &error_msg));
CHECK(elf_file.get() != nullptr) << error_msg;
// Lookup "oatdata" symbol address.
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
index 7cf774e..449f514 100644
--- a/compiler/elf_writer_test.cc
+++ b/compiler/elf_writer_test.cc
@@ -64,7 +64,11 @@
ASSERT_TRUE(file.get() != nullptr);
{
std::string error_msg;
- std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(), false, false, &error_msg));
+ std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(),
+ false,
+ false,
+ /*low_4gb*/false,
+ &error_msg));
CHECK(ef.get() != nullptr) << error_msg;
EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", false);
EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", false);
@@ -72,7 +76,11 @@
}
{
std::string error_msg;
- std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(), false, false, &error_msg));
+ std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(),
+ false,
+ false,
+ /*low_4gb*/false,
+ &error_msg));
CHECK(ef.get() != nullptr) << error_msg;
EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", true);
EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", true);
@@ -80,9 +88,13 @@
}
{
std::string error_msg;
- std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(), false, true, &error_msg));
+ std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(),
+ false,
+ true,
+ /*low_4gb*/false,
+ &error_msg));
CHECK(ef.get() != nullptr) << error_msg;
- CHECK(ef->Load(false, &error_msg)) << error_msg;
+ CHECK(ef->Load(false, /*low_4gb*/false, &error_msg)) << error_msg;
EXPECT_EQ(dl_oatdata, ef->FindDynamicSymbolAddress("oatdata"));
EXPECT_EQ(dl_oatexec, ef->FindDynamicSymbolAddress("oatexec"));
EXPECT_EQ(dl_oatlastword, ef->FindDynamicSymbolAddress("oatlastword"));
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index d22044a..4b48107 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -230,7 +230,7 @@
return elf_writer->End();
}
- void TestDexFileInput(bool verify);
+ void TestDexFileInput(bool verify, bool low_4gb);
void TestZipFileInput(bool verify);
std::unique_ptr<const InstructionSetFeatures> insn_features_;
@@ -374,8 +374,14 @@
if (kCompile) { // OatWriter strips the code, regenerate to compare
compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
}
- std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), nullptr,
- nullptr, false, nullptr, &error_msg));
+ std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(),
+ tmp.GetFilename(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/true,
+ nullptr,
+ &error_msg));
ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
const OatHeader& oat_header = oat_file->GetOatHeader();
ASSERT_TRUE(oat_header.IsValid());
@@ -504,6 +510,7 @@
nullptr,
nullptr,
false,
+ /*low_4gb*/false,
nullptr,
&error_msg));
ASSERT_TRUE(oat_file != nullptr);
@@ -518,7 +525,7 @@
}
}
-void OatTest::TestDexFileInput(bool verify) {
+void OatTest::TestDexFileInput(bool verify, bool low_4gb) {
TimingLogger timings("OatTest::DexFileInput", false, false);
std::vector<const char*> input_filenames;
@@ -572,8 +579,13 @@
nullptr,
nullptr,
false,
+ low_4gb,
nullptr,
&error_msg));
+ if (low_4gb) {
+ uintptr_t begin = reinterpret_cast<uintptr_t>(opened_oat_file->Begin());
+ EXPECT_EQ(begin, static_cast<uint32_t>(begin));
+ }
ASSERT_TRUE(opened_oat_file != nullptr);
ASSERT_EQ(2u, opened_oat_file->GetOatDexFiles().size());
std::unique_ptr<const DexFile> opened_dex_file1 =
@@ -595,11 +607,15 @@
}
TEST_F(OatTest, DexFileInputCheckOutput) {
- TestDexFileInput(false);
+ TestDexFileInput(false, /*low_4gb*/false);
+}
+
+TEST_F(OatTest, DexFileInputCheckOutputLow4GB) {
+ TestDexFileInput(false, /*low_4gb*/true);
}
TEST_F(OatTest, DexFileInputCheckVerifier) {
- TestDexFileInput(true);
+ TestDexFileInput(true, /*low_4gb*/false);
}
void OatTest::TestZipFileInput(bool verify) {
@@ -667,6 +683,7 @@
nullptr,
nullptr,
false,
+ /*low_4gb*/false,
nullptr,
&error_msg));
ASSERT_TRUE(opened_oat_file != nullptr);
@@ -714,6 +731,7 @@
nullptr,
nullptr,
false,
+ /*low_4gb*/false,
nullptr,
&error_msg));
ASSERT_TRUE(opened_oat_file != nullptr);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 3ed5766..2cdd4c7 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -280,6 +280,8 @@
bool list_methods,
bool dump_header_only,
const char* export_dex_location,
+ const char* app_image,
+ const char* app_oat,
uint32_t addr2instr)
: dump_raw_mapping_table_(dump_raw_mapping_table),
dump_raw_gc_map_(dump_raw_gc_map),
@@ -293,6 +295,8 @@
list_methods_(list_methods),
dump_header_only_(dump_header_only),
export_dex_location_(export_dex_location),
+ app_image_(app_image),
+ app_oat_(app_oat),
addr2instr_(addr2instr),
class_loader_(nullptr) {}
@@ -308,6 +312,8 @@
const bool list_methods_;
const bool dump_header_only_;
const char* const export_dex_location_;
+ const char* const app_image_;
+ const char* const app_oat_;
uint32_t addr2instr_;
Handle<mirror::ClassLoader>* class_loader_;
};
@@ -1433,8 +1439,10 @@
class ImageDumper {
public:
- ImageDumper(std::ostream* os, gc::space::ImageSpace& image_space,
- const ImageHeader& image_header, OatDumperOptions* oat_dumper_options)
+ ImageDumper(std::ostream* os,
+ gc::space::ImageSpace& image_space,
+ const ImageHeader& image_header,
+ OatDumperOptions* oat_dumper_options)
: os_(os),
vios_(os),
indent1_(&vios_),
@@ -1532,16 +1540,23 @@
os << "OAT LOCATION: " << oat_location;
os << "\n";
std::string error_msg;
- const OatFile* oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(
- oat_location);
+ const OatFile* oat_file = image_space_.GetOatFile();
if (oat_file == nullptr) {
- oat_file = OatFile::Open(oat_location, oat_location,
- nullptr, nullptr, false, nullptr,
+ oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(oat_location);
+ }
+ if (oat_file == nullptr) {
+ oat_file = OatFile::Open(oat_location,
+ oat_location,
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ nullptr,
&error_msg);
- if (oat_file == nullptr) {
- os << "NOT FOUND: " << error_msg << "\n";
- return false;
- }
+ }
+ if (oat_file == nullptr) {
+ os << "OAT FILE NOT FOUND: " << error_msg << "\n";
+ return EXIT_FAILURE;
}
os << "\n";
@@ -1592,21 +1607,27 @@
// TODO: Dump fields.
// Dump methods after.
const auto& methods_section = image_header_.GetMethodsSection();
- const size_t pointer_size =
- InstructionSetPointerSize(oat_dumper_->GetOatInstructionSet());
DumpArtMethodVisitor visitor(this);
- methods_section.VisitPackedArtMethods(&visitor, image_space_.Begin(), pointer_size);
+ methods_section.VisitPackedArtMethods(&visitor,
+ image_space_.Begin(),
+ image_header_.GetPointerSize());
// Dump the large objects separately.
heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
indent_os << "\n";
}
os << "STATS:\n" << std::flush;
std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
- if (file.get() == nullptr) {
+ size_t data_size = image_header_.GetDataSize(); // stored size in file.
+ if (file == nullptr) {
LOG(WARNING) << "Failed to find image in " << image_filename;
- }
- if (file.get() != nullptr) {
+ } else {
stats_.file_bytes = file->GetLength();
+ // If the image is compressed, adjust to decompressed size.
+ size_t uncompressed_size = image_header_.GetImageSize() - sizeof(ImageHeader);
+ if (image_header_.GetStorageMode() == ImageHeader::kStorageModeUncompressed) {
+ DCHECK_EQ(uncompressed_size, data_size) << "Sizes should match for uncompressed image";
+ }
+ stats_.file_bytes += uncompressed_size - data_size;
}
size_t header_bytes = sizeof(ImageHeader);
const auto& object_section = image_header_.GetImageSection(ImageHeader::kSectionObjects);
@@ -1653,10 +1674,10 @@
uint32_t end_intern = intern_section.Offset() + intern_section.Size();
stats_.alignment_bytes += class_table_section.Offset() - end_intern;
- // Add space between class table and bitmap. Expect the bitmap to be page-aligned.
- uint32_t end_ctable = class_table_section.Offset() + class_table_section.Size();
+ // Add space between end of image data and bitmap. Expect the bitmap to be page-aligned.
+ const size_t bitmap_offset = sizeof(ImageHeader) + data_size;
CHECK_ALIGNED(bitmap_section.Offset(), kPageSize);
- stats_.alignment_bytes += bitmap_section.Offset() - end_ctable;
+ stats_.alignment_bytes += RoundUp(bitmap_offset, kPageSize) - bitmap_offset;
stats_.bitmap_bytes += bitmap_section.Size();
stats_.art_field_bytes += field_section.Size();
@@ -1680,7 +1701,7 @@
virtual void Visit(ArtMethod* method) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
std::ostream& indent_os = image_dumper_->vios_.Stream();
indent_os << method << " " << " ArtMethod: " << PrettyMethod(method) << "\n";
- image_dumper_->DumpMethod(method, image_dumper_, indent_os);
+ image_dumper_->DumpMethod(method, indent_os);
indent_os << "\n";
}
@@ -1773,10 +1794,9 @@
return image_space_.Contains(object);
}
- const void* GetQuickOatCodeBegin(ArtMethod* m)
- SHARED_REQUIRES(Locks::mutator_lock_) {
+ const void* GetQuickOatCodeBegin(ArtMethod* m) SHARED_REQUIRES(Locks::mutator_lock_) {
const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize(
- InstructionSetPointerSize(oat_dumper_->GetOatInstructionSet()));
+ image_header_.GetPointerSize());
if (Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(quick_code)) {
quick_code = oat_dumper_->GetQuickOatCode(m);
}
@@ -1835,8 +1855,7 @@
}
ScopedIndentation indent1(&state->vios_);
DumpFields(os, obj, obj_class);
- const auto image_pointer_size =
- InstructionSetPointerSize(state->oat_dumper_->GetOatInstructionSet());
+ const size_t image_pointer_size = state->image_header_.GetPointerSize();
if (obj->IsObjectArray()) {
auto* obj_array = obj->AsObjectArray<mirror::Object>();
for (int32_t i = 0, length = obj_array->GetLength(); i < length; i++) {
@@ -1881,7 +1900,9 @@
ScopedIndentation indent2(&state->vios_);
auto* resolved_methods = dex_cache->GetResolvedMethods();
for (size_t i = 0, length = dex_cache->NumResolvedMethods(); i < length; ++i) {
- auto* elem = mirror::DexCache::GetElementPtrSize(resolved_methods, i, image_pointer_size);
+ auto* elem = mirror::DexCache::GetElementPtrSize(resolved_methods,
+ i,
+ image_pointer_size);
size_t run = 0;
for (size_t j = i + 1;
j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_methods,
@@ -1943,13 +1964,11 @@
state->stats_.Update(obj_class->GetDescriptor(&temp), object_bytes);
}
- void DumpMethod(ArtMethod* method, ImageDumper* state, std::ostream& indent_os)
+ void DumpMethod(ArtMethod* method, std::ostream& indent_os)
SHARED_REQUIRES(Locks::mutator_lock_) {
DCHECK(method != nullptr);
- const auto image_pointer_size =
- InstructionSetPointerSize(state->oat_dumper_->GetOatInstructionSet());
- const void* quick_oat_code_begin = state->GetQuickOatCodeBegin(method);
- const void* quick_oat_code_end = state->GetQuickOatCodeEnd(method);
+ const void* quick_oat_code_begin = GetQuickOatCodeBegin(method);
+ const void* quick_oat_code_end = GetQuickOatCodeEnd(method);
OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(
reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader));
if (method->IsNative()) {
@@ -1958,13 +1977,13 @@
DCHECK(method_header->GetMappingTable() == nullptr) << PrettyMethod(method);
}
bool first_occurrence;
- uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method);
- state->ComputeOatSize(quick_oat_code_begin, &first_occurrence);
+ uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
+ ComputeOatSize(quick_oat_code_begin, &first_occurrence);
if (first_occurrence) {
- state->stats_.native_to_managed_code_bytes += quick_oat_code_size;
+ stats_.native_to_managed_code_bytes += quick_oat_code_size;
}
- if (quick_oat_code_begin !=
- method->GetEntryPointFromQuickCompiledCodePtrSize(image_pointer_size)) {
+ if (quick_oat_code_begin != method->GetEntryPointFromQuickCompiledCodePtrSize(
+ image_header_.GetPointerSize())) {
indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code_begin);
}
} else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
@@ -1973,46 +1992,44 @@
} else {
const DexFile::CodeItem* code_item = method->GetCodeItem();
size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
- state->stats_.dex_instruction_bytes += dex_instruction_bytes;
+ stats_.dex_instruction_bytes += dex_instruction_bytes;
bool first_occurrence;
- size_t gc_map_bytes = state->ComputeOatSize(
- method_header->GetNativeGcMap(), &first_occurrence);
+ size_t gc_map_bytes = ComputeOatSize(method_header->GetNativeGcMap(), &first_occurrence);
if (first_occurrence) {
- state->stats_.gc_map_bytes += gc_map_bytes;
+ stats_.gc_map_bytes += gc_map_bytes;
}
- size_t pc_mapping_table_bytes = state->ComputeOatSize(
+ size_t pc_mapping_table_bytes = ComputeOatSize(
method_header->GetMappingTable(), &first_occurrence);
if (first_occurrence) {
- state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
+ stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
}
size_t vmap_table_bytes = 0u;
if (!method_header->IsOptimized()) {
// Method compiled with the optimizing compiler have no vmap table.
- vmap_table_bytes = state->ComputeOatSize(
- method_header->GetVmapTable(), &first_occurrence);
+ vmap_table_bytes = ComputeOatSize(method_header->GetVmapTable(), &first_occurrence);
if (first_occurrence) {
- state->stats_.vmap_table_bytes += vmap_table_bytes;
+ stats_.vmap_table_bytes += vmap_table_bytes;
}
}
- uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method);
- state->ComputeOatSize(quick_oat_code_begin, &first_occurrence);
+ uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
+ ComputeOatSize(quick_oat_code_begin, &first_occurrence);
if (first_occurrence) {
- state->stats_.managed_code_bytes += quick_oat_code_size;
+ stats_.managed_code_bytes += quick_oat_code_size;
if (method->IsConstructor()) {
if (method->IsStatic()) {
- state->stats_.class_initializer_code_bytes += quick_oat_code_size;
+ stats_.class_initializer_code_bytes += quick_oat_code_size;
} else if (dex_instruction_bytes > kLargeConstructorDexBytes) {
- state->stats_.large_initializer_code_bytes += quick_oat_code_size;
+ stats_.large_initializer_code_bytes += quick_oat_code_size;
}
} else if (dex_instruction_bytes > kLargeMethodDexBytes) {
- state->stats_.large_method_code_bytes += quick_oat_code_size;
+ stats_.large_method_code_bytes += quick_oat_code_size;
}
}
- state->stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
+ stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
uint32_t method_access_flags = method->GetAccessFlags();
@@ -2022,11 +2039,11 @@
method_access_flags);
size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
- vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_pointer_size);
+ vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_header_.GetPointerSize());
double expansion =
static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes);
- state->stats_.ComputeOutliers(total_size, expansion, method);
+ stats_.ComputeOutliers(total_size, expansion, method);
}
}
@@ -2361,26 +2378,75 @@
DISALLOW_COPY_AND_ASSIGN(ImageDumper);
};
-static int DumpImage(Runtime* runtime, OatDumperOptions* options, std::ostream* os) {
+static int DumpImage(gc::space::ImageSpace* image_space,
+ OatDumperOptions* options,
+ std::ostream* os) SHARED_REQUIRES(Locks::mutator_lock_) {
+ const ImageHeader& image_header = image_space->GetImageHeader();
+ if (!image_header.IsValid()) {
+ fprintf(stderr, "Invalid image header %s\n", image_space->GetImageLocation().c_str());
+ return EXIT_FAILURE;
+ }
+ ImageDumper image_dumper(os, *image_space, image_header, options);
+ if (!image_dumper.Dump()) {
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
+
+static int DumpImages(Runtime* runtime, OatDumperOptions* options, std::ostream* os) {
// Dumping the image, no explicit class loader.
ScopedNullHandle<mirror::ClassLoader> null_class_loader;
options->class_loader_ = &null_class_loader;
ScopedObjectAccess soa(Thread::Current());
- gc::Heap* heap = runtime->GetHeap();
- std::vector<gc::space::ImageSpace*> image_spaces = heap->GetBootImageSpaces();
- CHECK(!image_spaces.empty());
- for (gc::space::ImageSpace* image_space : image_spaces) {
- const ImageHeader& image_header = image_space->GetImageHeader();
- if (!image_header.IsValid()) {
- fprintf(stderr, "Invalid image header %s\n", image_space->GetImageLocation().c_str());
+ if (options->app_image_ != nullptr) {
+ if (options->app_oat_ == nullptr) {
+ LOG(ERROR) << "Can not dump app image without app oat file";
return EXIT_FAILURE;
}
-
- ImageDumper image_dumper(os, *image_space, image_header, options);
- if (!image_dumper.Dump()) {
+ // We can't know if the app image is 32 bits yet, but it contains pointers into the oat file.
+ // We need to map the oat file in the low 4gb or else the fixup wont be able to fit oat file
+ // pointers into 32 bit pointer sized ArtMethods.
+ std::string error_msg;
+ std::unique_ptr<OatFile> oat_file(OatFile::Open(options->app_oat_,
+ options->app_oat_,
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/true,
+ nullptr,
+ &error_msg));
+ if (oat_file == nullptr) {
+ LOG(ERROR) << "Failed to open oat file " << options->app_oat_ << " with error " << error_msg;
return EXIT_FAILURE;
}
+ std::unique_ptr<gc::space::ImageSpace> space(
+ gc::space::ImageSpace::CreateFromAppImage(options->app_image_, oat_file.get(), &error_msg));
+ if (space == nullptr) {
+ LOG(ERROR) << "Failed to open app image " << options->app_image_ << " with error "
+ << error_msg;
+ }
+ // Open dex files for the image.
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ if (!runtime->GetClassLinker()->OpenImageDexFiles(space.get(), &dex_files, &error_msg)) {
+ LOG(ERROR) << "Failed to open app image dex files " << options->app_image_ << " with error "
+ << error_msg;
+ }
+ // Dump the actual image.
+ int result = DumpImage(space.get(), options, os);
+ if (result != EXIT_SUCCESS) {
+ return result;
+ }
+ // Fall through to dump the boot images.
+ }
+
+ gc::Heap* heap = runtime->GetHeap();
+ CHECK(heap->HasBootImageSpace()) << "No image spaces";
+ for (gc::space::ImageSpace* image_space : heap->GetBootImageSpaces()) {
+ int result = DumpImage(image_space, options, os);
+ if (result != EXIT_SUCCESS) {
+ return result;
+ }
}
return EXIT_SUCCESS;
}
@@ -2436,8 +2502,14 @@
static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options,
std::ostream* os) {
std::string error_msg;
- OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
- nullptr, &error_msg);
+ OatFile* oat_file = OatFile::Open(oat_filename,
+ oat_filename,
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ nullptr,
+ &error_msg);
if (oat_file == nullptr) {
fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
return EXIT_FAILURE;
@@ -2452,8 +2524,14 @@
static int SymbolizeOat(const char* oat_filename, std::string& output_name) {
std::string error_msg;
- OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
- nullptr, &error_msg);
+ OatFile* oat_file = OatFile::Open(oat_filename,
+ oat_filename,
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ nullptr,
+ &error_msg);
if (oat_file == nullptr) {
fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
return EXIT_FAILURE;
@@ -2524,6 +2602,10 @@
*error_msg = "Address conversion failed";
return kParseError;
}
+ } else if (option.starts_with("--app-image=")) {
+ app_image_ = option.substr(strlen("--app-image=")).data();
+ } else if (option.starts_with("--app-oat=")) {
+ app_oat_ = option.substr(strlen("--app-oat=")).data();
} else {
return kParseUnknownArgument;
}
@@ -2569,6 +2651,13 @@
"\n"
" --image=<file.art>: specifies an input image location.\n"
" Example: --image=/system/framework/boot.art\n"
+ "\n"
+ " --app-image=<file.art>: specifies an input app image. Must also have a specified\n"
+ " boot image and app oat file.\n"
+ " Example: --app-image=app.art\n"
+ "\n"
+ " --app-oat=<file.odex>: specifies an input app oat.\n"
+ " Example: --app-oat=app.odex\n"
"\n";
usage += Base::GetUsage();
@@ -2637,6 +2726,8 @@
bool dump_header_only_ = false;
uint32_t addr2instr_ = 0;
const char* export_dex_location_ = nullptr;
+ const char* app_image_ = nullptr;
+ const char* app_oat_ = nullptr;
};
struct OatdumpMain : public CmdlineMain<OatdumpArgs> {
@@ -2646,7 +2737,7 @@
// If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping.
bool absolute_addresses = (args_->oat_filename_ == nullptr);
- oat_dumper_options_ = std::unique_ptr<OatDumperOptions>(new OatDumperOptions(
+ oat_dumper_options_.reset(new OatDumperOptions(
args_->dump_raw_mapping_table_,
args_->dump_raw_gc_map_,
args_->dump_vmap_,
@@ -2659,6 +2750,8 @@
args_->list_methods_,
args_->dump_header_only_,
args_->export_dex_location_,
+ args_->app_image_,
+ args_->app_oat_,
args_->addr2instr_));
return (args_->boot_image_location_ != nullptr || args_->image_location_ != nullptr) &&
@@ -2691,7 +2784,7 @@
args_->os_) == EXIT_SUCCESS;
}
- return DumpImage(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS;
+ return DumpImages(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS;
}
std::unique_ptr<OatDumperOptions> oat_dumper_options_;
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index ebe89bb..8541210 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -473,39 +473,40 @@
}
template <typename Visitor>
-inline void ArtMethod::UpdateObjectsForImageRelocation(const Visitor& visitor) {
+inline void ArtMethod::UpdateObjectsForImageRelocation(const Visitor& visitor,
+ size_t pointer_size) {
mirror::Class* old_class = GetDeclaringClassUnchecked<kWithoutReadBarrier>();
mirror::Class* new_class = visitor(old_class);
if (old_class != new_class) {
SetDeclaringClass(new_class);
}
- ArtMethod** old_methods = GetDexCacheResolvedMethods(sizeof(void*));
+ ArtMethod** old_methods = GetDexCacheResolvedMethods(pointer_size);
ArtMethod** new_methods = visitor(old_methods);
if (old_methods != new_methods) {
- SetDexCacheResolvedMethods(new_methods, sizeof(void*));
+ SetDexCacheResolvedMethods(new_methods, pointer_size);
}
- GcRoot<mirror::Class>* old_types = GetDexCacheResolvedTypes(sizeof(void*));
+ GcRoot<mirror::Class>* old_types = GetDexCacheResolvedTypes(pointer_size);
GcRoot<mirror::Class>* new_types = visitor(old_types);
if (old_types != new_types) {
- SetDexCacheResolvedTypes(new_types, sizeof(void*));
+ SetDexCacheResolvedTypes(new_types, pointer_size);
}
}
template <ReadBarrierOption kReadBarrierOption, typename Visitor>
-inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor) {
+inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, size_t pointer_size) {
if (IsNative<kReadBarrierOption>()) {
- const void* old_native_code = GetEntryPointFromJni();
+ const void* old_native_code = GetEntryPointFromJniPtrSize(pointer_size);
const void* new_native_code = visitor(old_native_code);
if (old_native_code != new_native_code) {
- SetEntryPointFromJni(new_native_code);
+ SetEntryPointFromJniPtrSize(new_native_code, pointer_size);
}
} else {
- DCHECK(GetEntryPointFromJni() == nullptr);
+ DCHECK(GetEntryPointFromJniPtrSize(pointer_size) == nullptr);
}
- const void* old_code = GetEntryPointFromQuickCompiledCode();
+ const void* old_code = GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
const void* new_code = visitor(old_code);
if (old_code != new_code) {
- SetEntryPointFromQuickCompiledCode(new_code);
+ SetEntryPointFromQuickCompiledCodePtrSize(new_code, pointer_size);
}
}
diff --git a/runtime/art_method.h b/runtime/art_method.h
index ec00a7b..5ca362c 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -490,12 +490,12 @@
// Update heap objects and non-entrypoint pointers by the passed in visitor for image relocation.
// Does not use read barrier.
template <typename Visitor>
- ALWAYS_INLINE void UpdateObjectsForImageRelocation(const Visitor& visitor)
+ ALWAYS_INLINE void UpdateObjectsForImageRelocation(const Visitor& visitor, size_t pointer_size)
SHARED_REQUIRES(Locks::mutator_lock_);
// Update entry points by passing them through the visitor.
template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor>
- ALWAYS_INLINE void UpdateEntrypoints(const Visitor& visitor);
+ ALWAYS_INLINE void UpdateEntrypoints(const Visitor& visitor, size_t pointer_size);
protected:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 0689589..6a2b702 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1489,6 +1489,64 @@
const bool forward_strings_;
};
+static std::unique_ptr<const DexFile> OpenOatDexFile(const OatFile* oat_file,
+ const char* location,
+ std::string* error_msg)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ DCHECK(error_msg != nullptr);
+ std::unique_ptr<const DexFile> dex_file;
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(location, nullptr);
+ if (oat_dex_file == nullptr) {
+ *error_msg = StringPrintf("Failed finding oat dex file for %s %s",
+ oat_file->GetLocation().c_str(),
+ location);
+ return std::unique_ptr<const DexFile>();
+ }
+ std::string inner_error_msg;
+ dex_file = oat_dex_file->OpenDexFile(&inner_error_msg);
+ if (dex_file == nullptr) {
+ *error_msg = StringPrintf("Failed to open dex file %s from within oat file %s error '%s'",
+ location,
+ oat_file->GetLocation().c_str(),
+ inner_error_msg.c_str());
+ return std::unique_ptr<const DexFile>();
+ }
+
+ if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) {
+ *error_msg = StringPrintf("Checksums do not match for %s: %x vs %x",
+ location,
+ dex_file->GetLocationChecksum(),
+ oat_dex_file->GetDexFileLocationChecksum());
+ return std::unique_ptr<const DexFile>();
+ }
+ return dex_file;
+}
+
+bool ClassLinker::OpenImageDexFiles(gc::space::ImageSpace* space,
+ std::vector<std::unique_ptr<const DexFile>>* out_dex_files,
+ std::string* error_msg) {
+ ScopedAssertNoThreadSuspension nts(Thread::Current(), __FUNCTION__);
+ const ImageHeader& header = space->GetImageHeader();
+ mirror::Object* dex_caches_object = header.GetImageRoot(ImageHeader::kDexCaches);
+ DCHECK(dex_caches_object != nullptr);
+ mirror::ObjectArray<mirror::DexCache>* dex_caches =
+ dex_caches_object->AsObjectArray<mirror::DexCache>();
+ const OatFile* oat_file = space->GetOatFile();
+ for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
+ mirror::DexCache* dex_cache = dex_caches->Get(i);
+ std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
+ std::unique_ptr<const DexFile> dex_file = OpenOatDexFile(oat_file,
+ dex_file_location.c_str(),
+ error_msg);
+ if (dex_file == nullptr) {
+ return false;
+ }
+ dex_cache->SetDexFile(dex_file.get());
+ out_dex_files->push_back(std::move(dex_file));
+ }
+ return true;
+}
+
bool ClassLinker::AddImageSpace(
gc::space::ImageSpace* space,
Handle<mirror::ClassLoader> class_loader,
@@ -1555,29 +1613,10 @@
dex_location_path = dex_location_path.substr(0, pos + 1); // Keep trailing '/'
dex_file_location = dex_location_path + dex_file_location;
}
- const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location.c_str(),
- nullptr);
- if (oat_dex_file == nullptr) {
- *error_msg = StringPrintf("Failed finding oat dex file for %s %s",
- oat_file->GetLocation().c_str(),
- dex_file_location.c_str());
- return false;
- }
- std::string inner_error_msg;
- std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&inner_error_msg);
+ std::unique_ptr<const DexFile> dex_file = OpenOatDexFile(oat_file,
+ dex_file_location.c_str(),
+ error_msg);
if (dex_file == nullptr) {
- *error_msg = StringPrintf("Failed to open dex file %s from within oat file %s error '%s'",
- dex_file_location.c_str(),
- oat_file->GetLocation().c_str(),
- inner_error_msg.c_str());
- return false;
- }
-
- if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) {
- *error_msg = StringPrintf("Checksums do not match for %s: %x vs %x",
- dex_file_location.c_str(),
- dex_file->GetLocationChecksum(),
- oat_dex_file->GetDexFileLocationChecksum());
return false;
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 492a228..36ed820 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -149,6 +149,12 @@
REQUIRES(!dex_lock_)
SHARED_REQUIRES(Locks::mutator_lock_);
+ bool OpenImageDexFiles(gc::space::ImageSpace* space,
+ std::vector<std::unique_ptr<const DexFile>>* out_dex_files,
+ std::string* error_msg)
+ REQUIRES(!dex_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
// Finds a class by its descriptor, loading it if necessary.
// If class_loader is null, searches boot_class_path_.
mirror::Class* FindClass(Thread* self,
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 52da28b..3b4b88d 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -57,9 +57,12 @@
}
template <typename ElfTypes>
-ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open(
- File* file, bool writable, bool program_header_only,
- std::string* error_msg, uint8_t* requested_base) {
+ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open(File* file,
+ bool writable,
+ bool program_header_only,
+ bool low_4gb,
+ std::string* error_msg,
+ uint8_t* requested_base) {
std::unique_ptr<ElfFileImpl<ElfTypes>> elf_file(new ElfFileImpl<ElfTypes>
(file, writable, program_header_only, requested_base));
int prot;
@@ -71,26 +74,29 @@
prot = PROT_READ;
flags = MAP_PRIVATE;
}
- if (!elf_file->Setup(prot, flags, error_msg)) {
+ if (!elf_file->Setup(prot, flags, low_4gb, error_msg)) {
return nullptr;
}
return elf_file.release();
}
template <typename ElfTypes>
-ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open(
- File* file, int prot, int flags, std::string* error_msg) {
+ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open(File* file,
+ int prot,
+ int flags,
+ bool low_4gb,
+ std::string* error_msg) {
std::unique_ptr<ElfFileImpl<ElfTypes>> elf_file(new ElfFileImpl<ElfTypes>
(file, (prot & PROT_WRITE) == PROT_WRITE, /*program_header_only*/false,
/*requested_base*/nullptr));
- if (!elf_file->Setup(prot, flags, error_msg)) {
+ if (!elf_file->Setup(prot, flags, low_4gb, error_msg)) {
return nullptr;
}
return elf_file.release();
}
template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::Setup(int prot, int flags, std::string* error_msg) {
+bool ElfFileImpl<ElfTypes>::Setup(int prot, int flags, bool low_4gb, std::string* error_msg) {
int64_t temp_file_length = file_->GetLength();
if (temp_file_length < 0) {
errno = -temp_file_length;
@@ -114,7 +120,7 @@
flags,
file_->Fd(),
0,
- /*low4_gb*/false,
+ low_4gb,
file_->GetPath().c_str(),
error_msg),
error_msg)) {
@@ -133,7 +139,7 @@
flags,
file_->Fd(),
0,
- /*low4_gb*/false,
+ low_4gb,
file_->GetPath().c_str(),
error_msg),
error_msg)) {
@@ -147,7 +153,7 @@
flags,
file_->Fd(),
0,
- /*low4_gb*/false,
+ low_4gb,
file_->GetPath().c_str(),
error_msg),
error_msg)) {
@@ -1058,7 +1064,7 @@
}
template <typename ElfTypes>
-bool ElfFileImpl<ElfTypes>::Load(bool executable, std::string* error_msg) {
+bool ElfFileImpl<ElfTypes>::Load(bool executable, bool low_4gb, std::string* error_msg) {
CHECK(program_header_only_) << file_->GetPath();
if (executable) {
@@ -1124,7 +1130,10 @@
}
std::unique_ptr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(),
reserve_base_override,
- loaded_size, PROT_NONE, false, false,
+ loaded_size,
+ PROT_NONE,
+ low_4gb,
+ false,
error_msg));
if (reserve.get() == nullptr) {
*error_msg = StringPrintf("Failed to allocate %s: %s",
@@ -1656,7 +1665,11 @@
CHECK_NE(elf32_.get() == nullptr, elf64_.get() == nullptr);
}
-ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std::string* error_msg,
+ElfFile* ElfFile::Open(File* file,
+ bool writable,
+ bool program_header_only,
+ bool low_4gb,
+ std::string* error_msg,
uint8_t* requested_base) {
if (file->GetLength() < EI_NIDENT) {
*error_msg = StringPrintf("File %s is too short to be a valid ELF file",
@@ -1668,7 +1681,7 @@
MAP_PRIVATE,
file->Fd(),
0,
- /*low4_gb*/false,
+ low_4gb,
file->GetPath().c_str(),
error_msg));
if (map == nullptr && map->Size() != EI_NIDENT) {
@@ -1676,14 +1689,22 @@
}
uint8_t* header = map->Begin();
if (header[EI_CLASS] == ELFCLASS64) {
- ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, writable, program_header_only,
- error_msg, requested_base);
+ ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file,
+ writable,
+ program_header_only,
+ low_4gb,
+ error_msg,
+ requested_base);
if (elf_file_impl == nullptr)
return nullptr;
return new ElfFile(elf_file_impl);
} else if (header[EI_CLASS] == ELFCLASS32) {
- ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, writable, program_header_only,
- error_msg, requested_base);
+ ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file,
+ writable,
+ program_header_only,
+ low_4gb,
+ error_msg,
+ requested_base);
if (elf_file_impl == nullptr) {
return nullptr;
}
@@ -1698,6 +1719,8 @@
}
ElfFile* ElfFile::Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg) {
+ // low_4gb support not required for this path.
+ constexpr bool low_4gb = false;
if (file->GetLength() < EI_NIDENT) {
*error_msg = StringPrintf("File %s is too short to be a valid ELF file",
file->GetPath().c_str());
@@ -1708,7 +1731,7 @@
MAP_PRIVATE,
file->Fd(),
0,
- /*low4_gb*/false,
+ low_4gb,
file->GetPath().c_str(),
error_msg));
if (map == nullptr && map->Size() != EI_NIDENT) {
@@ -1716,13 +1739,21 @@
}
uint8_t* header = map->Begin();
if (header[EI_CLASS] == ELFCLASS64) {
- ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, mmap_prot, mmap_flags, error_msg);
+ ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file,
+ mmap_prot,
+ mmap_flags,
+ low_4gb,
+ error_msg);
if (elf_file_impl == nullptr) {
return nullptr;
}
return new ElfFile(elf_file_impl);
} else if (header[EI_CLASS] == ELFCLASS32) {
- ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, mmap_prot, mmap_flags, error_msg);
+ ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file,
+ mmap_prot,
+ mmap_flags,
+ low_4gb,
+ error_msg);
if (elf_file_impl == nullptr) {
return nullptr;
}
@@ -1744,8 +1775,8 @@
return elf32_->func(__VA_ARGS__); \
}
-bool ElfFile::Load(bool executable, std::string* error_msg) {
- DELEGATE_TO_IMPL(Load, executable, error_msg);
+bool ElfFile::Load(bool executable, bool low_4gb, std::string* error_msg) {
+ DELEGATE_TO_IMPL(Load, executable, low_4gb, error_msg);
}
const uint8_t* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const {
@@ -1810,7 +1841,7 @@
}
bool ElfFile::Strip(File* file, std::string* error_msg) {
- std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg));
+ std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, /*low_4gb*/false, error_msg));
if (elf_file.get() == nullptr) {
return false;
}
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 1188c97..b5229b5 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -38,15 +38,22 @@
// ELFObjectFile.
class ElfFile {
public:
- static ElfFile* Open(File* file, bool writable, bool program_header_only, std::string* error_msg,
+ static ElfFile* Open(File* file,
+ bool writable,
+ bool program_header_only,
+ bool low_4gb,
+ std::string* error_msg,
uint8_t* requested_base = nullptr); // TODO: move arg to before error_msg.
// Open with specific mmap flags, Always maps in the whole file, not just the
// program header sections.
- static ElfFile* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg);
+ static ElfFile* Open(File* file,
+ int mmap_prot,
+ int mmap_flags,
+ std::string* error_msg);
~ElfFile();
// Load segments into memory based on PT_LOAD program headers
- bool Load(bool executable, std::string* error_msg);
+ bool Load(bool executable, bool low_4gb, std::string* error_msg);
const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name) const;
diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h
index 2af31dc..1cdbedc 100644
--- a/runtime/elf_file_impl.h
+++ b/runtime/elf_file_impl.h
@@ -48,9 +48,17 @@
using Elf_Phdr = typename ElfTypes::Phdr;
using Elf_Dyn = typename ElfTypes::Dyn;
- static ElfFileImpl* Open(File* file, bool writable, bool program_header_only,
- std::string* error_msg, uint8_t* requested_base = nullptr);
- static ElfFileImpl* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg);
+ static ElfFileImpl* Open(File* file,
+ bool writable,
+ bool program_header_only,
+ bool low_4gb,
+ std::string* error_msg,
+ uint8_t* requested_base = nullptr);
+ static ElfFileImpl* Open(File* file,
+ int mmap_prot,
+ int mmap_flags,
+ bool low_4gb,
+ std::string* error_msg);
~ElfFileImpl();
const File& GetFile() const {
@@ -111,7 +119,7 @@
// Load segments into memory based on PT_LOAD program headers.
// executable is true at run time, false at compile time.
- bool Load(bool executable, std::string* error_msg);
+ bool Load(bool executable, bool low_4gb, std::string* error_msg);
bool Fixup(Elf_Addr base_address);
bool FixupDynamic(Elf_Addr base_address);
@@ -129,7 +137,7 @@
private:
ElfFileImpl(File* file, bool writable, bool program_header_only, uint8_t* requested_base);
- bool Setup(int prot, int flags, std::string* error_msg);
+ bool Setup(int prot, int flags, bool low_4gb, std::string* error_msg);
bool SetMap(MemMap* map, std::string* error_msg);
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index bea1dcc..895d3d3 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -617,7 +617,7 @@
}
// Returns the delta between the dest from the source.
- off_t Delta() const {
+ uintptr_t Delta() const {
return dest_ - source_;
}
@@ -639,6 +639,13 @@
const uintptr_t length_;
};
+std::ostream& operator<<(std::ostream& os, const RelocationRange& reloc) {
+ return os << "(" << reinterpret_cast<const void*>(reloc.Source()) << "-"
+ << reinterpret_cast<const void*>(reloc.Source() + reloc.Length()) << ")->("
+ << reinterpret_cast<const void*>(reloc.Dest()) << "-"
+ << reinterpret_cast<const void*>(reloc.Dest() + reloc.Length()) << ")";
+}
+
class FixupVisitor : public ValueObject {
public:
FixupVisitor(const RelocationRange& boot_image,
@@ -670,7 +677,7 @@
ALWAYS_INLINE const void* ForwardCode(const void* src) const {
const uintptr_t uint_src = reinterpret_cast<uintptr_t>(src);
if (boot_oat_.InSource(uint_src)) {
- return reinterpret_cast<const void*>(boot_oat_.ToDest(uint_src));
+ return reinterpret_cast<const void*>(boot_oat_.ToDest(uint_src));
}
if (app_oat_.InSource(uint_src)) {
return reinterpret_cast<const void*>(app_oat_.ToDest(uint_src));
@@ -687,13 +694,6 @@
const RelocationRange app_oat_;
};
-std::ostream& operator<<(std::ostream& os, const RelocationRange& reloc) {
- return os << "(" << reinterpret_cast<const void*>(reloc.Source()) << "-"
- << reinterpret_cast<const void*>(reloc.Source() + reloc.Length()) << ")->("
- << reinterpret_cast<const void*>(reloc.Dest()) << "-"
- << reinterpret_cast<const void*>(reloc.Dest() + reloc.Length()) << ")";
-}
-
// Adapt for mirror::Class::FixupNativePointers.
class FixupObjectAdapter : public FixupVisitor {
public:
@@ -756,8 +756,10 @@
public:
template<typename... Args>
explicit FixupObjectVisitor(gc::accounting::ContinuousSpaceBitmap* pointer_array_visited,
+ const size_t pointer_size,
Args... args)
: FixupVisitor(args...),
+ pointer_size_(pointer_size),
pointer_array_visited_(pointer_array_visited) {}
// Fix up separately since we also need to fix up method entrypoints.
@@ -791,7 +793,7 @@
if (array != nullptr &&
visitor.IsInAppImage(array) &&
!pointer_array_visited_->Test(array)) {
- array->Fixup<kVerifyNone, kWithoutReadBarrier>(array, sizeof(void*), visitor);
+ array->Fixup<kVerifyNone, kWithoutReadBarrier>(array, pointer_size_, visitor);
pointer_array_visited_->Set(array);
}
}
@@ -813,7 +815,7 @@
if (obj->IsClass<kVerifyNone, kWithoutReadBarrier>()) {
mirror::Class* klass = obj->AsClass<kVerifyNone, kWithoutReadBarrier>();
FixupObjectAdapter visitor(boot_image_, boot_oat_, app_image_, app_oat_);
- klass->FixupNativePointers<kVerifyNone, kWithoutReadBarrier>(klass, sizeof(void*), visitor);
+ klass->FixupNativePointers<kVerifyNone, kWithoutReadBarrier>(klass, pointer_size_, visitor);
// Deal with the pointer arrays. Use the helper function since multiple classes can reference
// the same arrays.
VisitPointerArray(klass->GetVTable<kVerifyNone, kWithoutReadBarrier>(), visitor);
@@ -832,6 +834,7 @@
}
private:
+ const size_t pointer_size_;
gc::accounting::ContinuousSpaceBitmap* const pointer_array_visited_;
};
@@ -850,7 +853,8 @@
class ForwardCodeAdapter {
public:
- ALWAYS_INLINE ForwardCodeAdapter(const FixupVisitor* visitor) : visitor_(visitor) {}
+ ALWAYS_INLINE ForwardCodeAdapter(const FixupVisitor* visitor)
+ : visitor_(visitor) {}
template <typename T>
ALWAYS_INLINE T* operator()(T* src) const {
@@ -864,19 +868,21 @@
class FixupArtMethodVisitor : public FixupVisitor, public ArtMethodVisitor {
public:
template<typename... Args>
- explicit FixupArtMethodVisitor(bool fixup_heap_objects, Args... args)
+ explicit FixupArtMethodVisitor(bool fixup_heap_objects, size_t pointer_size, Args... args)
: FixupVisitor(args...),
- fixup_heap_objects_(fixup_heap_objects) {}
+ fixup_heap_objects_(fixup_heap_objects),
+ pointer_size_(pointer_size) {}
virtual void Visit(ArtMethod* method) NO_THREAD_SAFETY_ANALYSIS {
if (fixup_heap_objects_) {
- method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this));
+ method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this), pointer_size_);
}
- method->UpdateEntrypoints<kWithoutReadBarrier>(ForwardCodeAdapter(this));
+ method->UpdateEntrypoints<kWithoutReadBarrier>(ForwardCodeAdapter(this), pointer_size_);
}
private:
const bool fixup_heap_objects_;
+ const size_t pointer_size_;
};
class FixupArtFieldVisitor : public FixupVisitor, public ArtFieldVisitor {
@@ -912,6 +918,7 @@
uint32_t boot_image_end = 0;
uint32_t boot_oat_begin = 0;
uint32_t boot_oat_end = 0;
+ const size_t pointer_size = image_header.GetPointerSize();
gc::Heap* const heap = Runtime::Current()->GetHeap();
heap->GetBootImagesSize(&boot_image_begin, &boot_image_end, &boot_oat_begin, &boot_oat_end);
CHECK_NE(boot_image_begin, boot_image_end)
@@ -974,6 +981,7 @@
target_base,
image_header.GetImageSize()));
FixupObjectVisitor fixup_object_visitor(visited_bitmap.get(),
+ pointer_size,
boot_image,
boot_oat,
app_image,
@@ -1023,10 +1031,10 @@
dex_cache->SetResolvedMethods(new_methods);
}
for (size_t j = 0, num = dex_cache->NumResolvedMethods(); j != num; ++j) {
- ArtMethod* orig = mirror::DexCache::GetElementPtrSize(new_methods, j, sizeof(void*));
+ ArtMethod* orig = mirror::DexCache::GetElementPtrSize(new_methods, j, pointer_size);
ArtMethod* copy = fixup_adapter.ForwardObject(orig);
if (orig != copy) {
- mirror::DexCache::SetElementPtrSize(new_methods, j, copy, sizeof(void*));
+ mirror::DexCache::SetElementPtrSize(new_methods, j, copy, pointer_size);
}
}
}
@@ -1037,10 +1045,10 @@
dex_cache->SetResolvedFields(new_fields);
}
for (size_t j = 0, num = dex_cache->NumResolvedFields(); j != num; ++j) {
- ArtField* orig = mirror::DexCache::GetElementPtrSize(new_fields, j, sizeof(void*));
+ ArtField* orig = mirror::DexCache::GetElementPtrSize(new_fields, j, pointer_size);
ArtField* copy = fixup_adapter.ForwardObject(orig);
if (orig != copy) {
- mirror::DexCache::SetElementPtrSize(new_fields, j, copy, sizeof(void*));
+ mirror::DexCache::SetElementPtrSize(new_fields, j, copy, pointer_size);
}
}
}
@@ -1049,11 +1057,16 @@
{
// Only touches objects in the app image, no need for mutator lock.
TimingLogger::ScopedTiming timing("Fixup methods", &logger);
- FixupArtMethodVisitor method_visitor(fixup_image, boot_image, boot_oat, app_image, app_oat);
+ FixupArtMethodVisitor method_visitor(fixup_image,
+ pointer_size,
+ boot_image,
+ boot_oat,
+ app_image,
+ app_oat);
image_header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods(
&method_visitor,
target_base,
- sizeof(void*));
+ pointer_size);
}
if (fixup_image) {
{
@@ -1381,6 +1394,7 @@
image_header.GetOatDataBegin(),
image_header.GetOatFileBegin(),
!Runtime::Current()->IsAotCompiler(),
+ /*low_4gb*/false,
nullptr,
error_msg);
if (oat_file == nullptr) {
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 7155c79..033ea56 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -89,6 +89,7 @@
uint8_t* oat_file_begin,
bool writable,
bool executable,
+ bool low_4gb,
const char* abs_dex_location,
std::string* error_msg);
@@ -102,6 +103,7 @@
uint8_t* oat_file_begin,
bool writable,
bool executable,
+ bool low_4gb,
std::string* error_msg) = 0;
bool ComputeFields(uint8_t* requested_base,
@@ -133,6 +135,7 @@
uint8_t* oat_file_begin,
bool writable,
bool executable,
+ bool low_4gb,
const char* abs_dex_location,
std::string* error_msg) {
std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(location, executable));
@@ -140,6 +143,7 @@
oat_file_begin,
writable,
executable,
+ low_4gb,
error_msg)) {
return nullptr;
}
@@ -147,7 +151,6 @@
if (!ret->ComputeFields(requested_base, elf_filename, error_msg)) {
return nullptr;
}
-
ret->PreSetup(elf_filename);
if (!ret->Setup(abs_dex_location, error_msg)) {
@@ -532,6 +535,7 @@
uint8_t* oat_file_begin,
bool writable,
bool executable,
+ bool low_4gb,
std::string* error_msg) OVERRIDE;
// Ask the linker where it mmaped the file and notify our mmap wrapper of the regions.
@@ -558,6 +562,7 @@
uint8_t* oat_file_begin,
bool writable,
bool executable,
+ bool low_4gb,
std::string* error_msg) {
// Use dlopen only when flagged to do so, and when it's OK to load things executable.
// TODO: Also try when not executable? The issue here could be re-mapping as writable (as
@@ -567,6 +572,10 @@
*error_msg = "DlOpen is disabled.";
return false;
}
+ if (low_4gb) {
+ *error_msg = "DlOpen does not support low 4gb loading.";
+ return false;
+ }
if (writable) {
*error_msg = "DlOpen does not support writable loading.";
return false;
@@ -702,6 +711,7 @@
uint8_t* oat_file_begin, // Override base if not null
bool writable,
bool executable,
+ bool low_4gb,
const char* abs_dex_location,
std::string* error_msg);
@@ -723,6 +733,7 @@
uint8_t* oat_file_begin, // Override where the file is loaded to if not null
bool writable,
bool executable,
+ bool low_4gb,
std::string* error_msg) OVERRIDE;
void PreSetup(const std::string& elf_filename ATTRIBUTE_UNUSED) OVERRIDE {
@@ -733,6 +744,7 @@
uint8_t* oat_file_begin, // Override where the file is loaded to if not null
bool writable,
bool executable,
+ bool low_4gb,
std::string* error_msg);
private:
@@ -748,11 +760,17 @@
uint8_t* oat_file_begin, // Override base if not null
bool writable,
bool executable,
+ bool low_4gb,
const char* abs_dex_location,
std::string* error_msg) {
ScopedTrace trace("Open elf file " + location);
std::unique_ptr<ElfOatFile> oat_file(new ElfOatFile(location, executable));
- bool success = oat_file->ElfFileOpen(file, oat_file_begin, writable, executable, error_msg);
+ bool success = oat_file->ElfFileOpen(file,
+ oat_file_begin,
+ writable,
+ low_4gb,
+ executable,
+ error_msg);
if (!success) {
CHECK(!error_msg->empty());
return nullptr;
@@ -792,6 +810,7 @@
uint8_t* oat_file_begin, // Override where the file is loaded to if not null
bool writable,
bool executable,
+ bool low_4gb,
std::string* error_msg) {
ScopedTrace trace(__PRETTY_FUNCTION__);
std::unique_ptr<File> file(OS::OpenFileForReading(elf_filename.c_str()));
@@ -803,6 +822,7 @@
oat_file_begin,
writable,
executable,
+ low_4gb,
error_msg);
}
@@ -810,19 +830,21 @@
uint8_t* oat_file_begin,
bool writable,
bool executable,
+ bool low_4gb,
std::string* error_msg) {
ScopedTrace trace(__PRETTY_FUNCTION__);
// TODO: rename requested_base to oat_data_begin
elf_file_.reset(ElfFile::Open(file,
writable,
/*program_header_only*/true,
+ low_4gb,
error_msg,
oat_file_begin));
if (elf_file_ == nullptr) {
DCHECK(!error_msg->empty());
return false;
}
- bool loaded = elf_file_->Load(executable, error_msg);
+ bool loaded = elf_file_->Load(executable, low_4gb, error_msg);
DCHECK(loaded || !error_msg->empty());
return loaded;
}
@@ -870,6 +892,7 @@
uint8_t* requested_base,
uint8_t* oat_file_begin,
bool executable,
+ bool low_4gb,
const char* abs_dex_location,
std::string* error_msg) {
ScopedTrace trace("Open oat file " + location);
@@ -885,15 +908,15 @@
oat_file_begin,
false,
executable,
+ low_4gb,
abs_dex_location,
error_msg);
if (with_dlopen != nullptr) {
return with_dlopen;
}
if (kPrintDlOpenErrorMessage) {
- LOG(ERROR) << "Failed to dlopen: " << *error_msg;
+ LOG(ERROR) << "Failed to dlopen: " << filename << " with error " << *error_msg;
}
-
// If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons:
//
// On target, dlopen may fail when compiling due to selinux restrictions on installd.
@@ -913,6 +936,7 @@
oat_file_begin,
false,
executable,
+ low_4gb,
abs_dex_location,
error_msg);
return with_internal;
@@ -929,6 +953,7 @@
nullptr,
true,
false,
+ /*low_4gb*/false,
abs_dex_location,
error_msg);
}
@@ -944,6 +969,7 @@
nullptr,
false,
false,
+ /*low_4gb*/false,
abs_dex_location,
error_msg);
}
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 1084253..7af77ae 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -64,6 +64,7 @@
uint8_t* requested_base,
uint8_t* oat_file_begin,
bool executable,
+ bool low_4gb,
const char* abs_dex_location,
std::string* error_msg);
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 90712c6..cbc0ec6 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -815,8 +815,13 @@
const std::string& odex_file_name = *OdexFileName();
std::string error_msg;
cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
- odex_file_name.c_str(), nullptr, nullptr, load_executable_,
- dex_location_.c_str(), &error_msg));
+ odex_file_name.c_str(),
+ nullptr,
+ nullptr,
+ load_executable_,
+ /*low_4gb*/false,
+ dex_location_.c_str(),
+ &error_msg));
if (cached_odex_file_.get() == nullptr) {
VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
<< odex_file_name << ": " << error_msg;
@@ -846,8 +851,13 @@
const std::string& oat_file_name = *OatFileName();
std::string error_msg;
cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
- oat_file_name.c_str(), nullptr, nullptr, load_executable_,
- dex_location_.c_str(), &error_msg));
+ oat_file_name.c_str(),
+ nullptr,
+ nullptr,
+ load_executable_,
+ /*low_4gb*/false,
+ dex_location_.c_str(),
+ &error_msg));
if (cached_oat_file_.get() == nullptr) {
VLOG(oat) << "OatFileAssistant test for existing oat file "
<< oat_file_name << ": " << error_msg;
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 4541468..046d8ae 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -218,9 +218,14 @@
// Verify the odex file was generated as expected and really is
// unrelocated.
- std::unique_ptr<OatFile> odex_file(OatFile::Open(
- odex_location.c_str(), odex_location.c_str(), nullptr, nullptr,
- false, dex_location.c_str(), &error_msg));
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+ odex_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
const std::vector<gc::space::ImageSpace*> image_spaces =
@@ -252,9 +257,14 @@
setenv("ANDROID_DATA", android_data_.c_str(), 1);
// Verify the odex file was generated as expected.
- std::unique_ptr<OatFile> odex_file(OatFile::Open(
- odex_location.c_str(), odex_location.c_str(), nullptr, nullptr,
- false, dex_location.c_str(), &error_msg));
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+ odex_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
EXPECT_TRUE(odex_file->IsPic());
}
@@ -269,9 +279,14 @@
ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
// Verify the odex file was generated as expected.
- std::unique_ptr<OatFile> odex_file(OatFile::Open(
- odex_location.c_str(), odex_location.c_str(), nullptr, nullptr,
- false, dex_location.c_str(), &error_msg));
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+ odex_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
EXPECT_TRUE(odex_file->IsExtractOnly());
EXPECT_EQ(odex_file->GetOatHeader().GetImageFileLocationOatChecksum(), 0u);
@@ -290,9 +305,14 @@
ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
// Verify the odex file was generated as expected.
- std::unique_ptr<OatFile> odex_file(OatFile::Open(
- odex_location.c_str(), odex_location.c_str(), nullptr, nullptr,
- false, dex_location.c_str(), &error_msg));
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+ odex_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
printf("error %s", error_msg.c_str());
ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
EXPECT_TRUE(odex_file->IsProfileGuideCompiled());
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index e95f2c5..0dfb0cf 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -810,7 +810,11 @@
return false;
}
std::string error_msg;
- std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.release(), false, false, &error_msg));
+ std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.release(),
+ false,
+ false,
+ /*low_4gb*/false,
+ &error_msg));
if (elf_file.get() == nullptr) {
return false;
}