Skip to content

Instantly share code, notes, and snippets.

@anestisb
Last active April 14, 2024 17:36
Show Gist options
  • Save anestisb/71d6b0496912f801533dec9d264aa409 to your computer and use it in GitHub Desktop.
Save anestisb/71d6b0496912f801533dec9d264aa409 to your computer and use it in GitHub Desktop.
oatdump vdex unquicken
project art/
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index a8ab7c6..2bb04a2 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -442,7 +442,7 @@ void CompilerDriver::CompileAll(jobject class_loader,
// We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
// optimization does not depend on the boot image (the optimization relies on not
// having final fields in a class, which does not change for an app).
- VdexFile::Unquicken(dex_files, vdex_file->GetQuickeningInfo());
+ VdexFile::Unquicken(dex_files, vdex_file->GetQuickeningInfo(), /* decompile_return_instruction */ false);
Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
new verifier::VerifierDeps(dex_files, vdex_file->GetVerifierDepsData()));
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index d8d3cda..6e186ae 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1294,6 +1294,7 @@ class Dex2Oat FINAL {
/* writable */ false,
/* low_4gb */ false,
eagerly_unquicken_vdex,
+ /* decompile_return_instruction */ false,
&error_msg);
}
@@ -1344,6 +1345,7 @@ class Dex2Oat FINAL {
/* writable */ false,
/* low_4gb */ false,
eagerly_unquicken_vdex,
+ /* decompile_return_instruction */ false,
&error_msg);
// If there's any problem with the passed vdex, just warn and proceed
// without it.
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index 7e0a1be..8aacb50 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -314,10 +314,11 @@ static bool DisplayMappingIfFromVdexFile(pm_map_t* map, Printer* printer) {
// Extract all the dex files from the vdex file.
std::string error_msg;
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
- false /*writeable*/,
- false /*low_4gb*/,
- false /*unquicken */,
- &error_msg /*out*/));
+ false /* writeable */,
+ false /* low_4gb */,
+ false /* unquicken */,
+ false /* decompile_return_instruction */,
+ &error_msg /* out */));
if (vdex == nullptr) {
std::cerr << "Could not open vdex file "
<< vdex_name
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 878d0f2..5cd50e1 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -515,14 +515,58 @@ class OatDumper {
for (size_t i = 0; i < oat_dex_files_.size(); i++) {
const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
CHECK(oat_dex_file != nullptr);
+ if (!DumpOatDexFile(os, *oat_dex_file)) {
+ success = false;
+ }
+ }
+ }
+
+ if (options_.export_dex_location_) {
+ if (kIsVdexEnabled) {
+ std::string error_msg;
+ std::string vdex_filename = GetVdexFilename(oat_file_.GetLocation());
+ if (!OS::FileExists(vdex_filename.c_str())) {
+ os << "File " << vdex_filename.c_str() << " does not exist\n";
+ return false;
+ }
+
+ std::unique_ptr<VdexFile> vdex = VdexFile::Open(vdex_filename,
+ /* writable */ false,
+ /* low_4gb */ false,
+ /* unquicken */ true,
+ /* decompile_return_instruction */ true,
+ &error_msg);
+ if (vdex.get() == nullptr) {
+ os << "Failed to load vdex file '" << vdex_filename.c_str() << "': "
+ << error_msg << "\n";
+ return false;
+ }
+
+ std::vector<std::unique_ptr<const DexFile>> unique_ptr_dex_files;
+ if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, &error_msg)) {
+ os << "Failed to open dex files from vdex: " << error_msg << "\n";
+ return false;
+ }
+ if (oat_dex_files_.size() != unique_ptr_dex_files.size()) {
+ os << "Unexpected number of dex files\n";
+ return false;
+ }
- // If file export selected skip file analysis
- if (options_.export_dex_location_) {
- if (!ExportDexFile(os, *oat_dex_file)) {
+ size_t i = 0;
+ for (const auto& dex_file : unique_ptr_dex_files) {
+ const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
+ CHECK(oat_dex_file != nullptr);
+ CHECK(dex_file != nullptr);
+ if (!ExportDexFile(os, *oat_dex_file, dex_file.get())) {
success = false;
}
- } else {
- if (!DumpOatDexFile(os, *oat_dex_file)) {
+ i++;
+ }
+ } else {
+ for (size_t i = 0; i < oat_dex_files_.size(); i++) {
+ const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
+ CHECK(oat_dex_file != nullptr);
+ if (!ExportDexFile(os, *oat_dex_file, nullptr)) {
success = false;
}
}
@@ -981,15 +1025,9 @@ class OatDumper {
return success;
}
- bool ExportDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
+ bool ExportDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file, const DexFile* dex_file) {
std::string error_msg;
std::string dex_file_location = oat_dex_file.GetDexFileLocation();
-
- const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
- if (dex_file == nullptr) {
- os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
- return false;
- }
size_t fsize = oat_dex_file.FileSize();
// Some quick checks just in case
@@ -998,6 +1036,26 @@ class OatDumper {
return false;
}
+ if (dex_file == nullptr) {
+ // Exported bytecode is quickened (dex-to-dex transformations present)
+ dex_file = OpenDexFile(&oat_dex_file, &error_msg);
+ if (dex_file == nullptr) {
+ os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
+ return false;
+ }
+
+ // Recompute checksum
+ reinterpret_cast<art::DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_ =
+ dex_file->CalculateChecksum();
+ } else {
+ // Vdex unquicken output should match original input bytecode
+ uint32_t orig_checksum = reinterpret_cast<art::DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_;
+ if (orig_checksum != dex_file->CalculateChecksum()) {
+ os << "Unexpected checksum from unquicken dex file '" << dex_file_location << "'\n";
+ return false;
+ }
+ }
+
// Verify output directory exists
if (!OS::DirectoryExists(options_.export_dex_location_)) {
// TODO: Extend OS::DirectoryExists if symlink support is required
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index a816522..73e0fef 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -193,7 +193,12 @@ bool OatFileBase::LoadVdex(const std::string& vdex_filename,
bool writable,
bool low_4gb,
std::string* error_msg) {
- vdex_ = VdexFile::Open(vdex_filename, writable, low_4gb, /* unquicken*/ false, error_msg);
+ vdex_ = VdexFile::Open(vdex_filename,
+ writable,
+ low_4gb,
+ /* unquicken*/ false,
+ /* decompile_return_instruction */ false,
+ error_msg);
if (vdex_.get() == nullptr) {
*error_msg = StringPrintf("Failed to load vdex file '%s' %s",
vdex_filename.c_str(),
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index f0912cf..36ee77c 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -968,6 +968,7 @@ OatFileAssistant::OatStatus OatFileAssistant::OatFileInfo::Status() {
/*writeable*/false,
/*low_4gb*/false,
/*unquicken*/false,
+ /*decompile_return_instruction*/false,
&error_msg);
if (vdex == nullptr) {
status_ = kOatCannotOpen;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 8667310..477f3d6 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -908,7 +908,8 @@ static bool OpenDexFilesFromImage(const std::string& image_location,
std::unique_ptr<VdexFile> vdex_file(VdexFile::Open(vdex_filename,
false /* writable */,
false /* low_4gb */,
- false, /* unquicken */
+ false /* unquicken */,
+ false /* decompile_return_instruction */,
&error_msg));
if (vdex_file.get() == nullptr) {
return false;
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 842aa04..de96951 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -58,6 +58,7 @@ std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename,
bool writable,
bool low_4gb,
bool unquicken,
+ bool decompile_return_instruction,
std::string* error_msg) {
if (!OS::FileExists(vdex_filename.c_str())) {
*error_msg = "File " + vdex_filename + " does not exist.";
@@ -82,7 +83,7 @@ std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename,
return nullptr;
}
- return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, unquicken, error_msg);
+ return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, unquicken, decompile_return_instruction, error_msg);
}
std::unique_ptr<VdexFile> VdexFile::Open(int file_fd,
@@ -91,6 +92,7 @@ std::unique_ptr<VdexFile> VdexFile::Open(int file_fd,
bool writable,
bool low_4gb,
bool unquicken,
+ bool decompile_return_instruction,
std::string* error_msg) {
std::unique_ptr<MemMap> mmap(MemMap::MapFile(
vdex_length,
@@ -117,7 +119,9 @@ std::unique_ptr<VdexFile> VdexFile::Open(int file_fd,
if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) {
return nullptr;
}
- Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files), vdex->GetQuickeningInfo());
+ Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files),
+ vdex->GetQuickeningInfo(),
+ decompile_return_instruction);
// Update the quickening info size to pretend there isn't any.
reinterpret_cast<Header*>(vdex->mmap_->Begin())->quickening_info_size_ = 0;
}
@@ -165,7 +169,8 @@ bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_
}
void VdexFile::Unquicken(const std::vector<const DexFile*>& dex_files,
- const ArrayRef<const uint8_t>& quickening_info) {
+ const ArrayRef<const uint8_t>& quickening_info,
+ bool decompile_return_instruction) {
if (quickening_info.size() == 0) {
// If there is no quickening info, we bail early, as the code below expects at
// least the size of quickening data for each method that has a code item.
@@ -196,7 +201,7 @@ void VdexFile::Unquicken(const std::vector<const DexFile*>& dex_files,
quickening_info_ptr += sizeof(uint32_t);
optimizer::ArtDecompileDEX(*code_item,
ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
- /* decompile_return_instruction */ false);
+ decompile_return_instruction);
quickening_info_ptr += quickening_size;
}
it.Next();
@@ -209,7 +214,7 @@ void VdexFile::Unquicken(const std::vector<const DexFile*>& dex_files,
quickening_info_ptr += sizeof(uint32_t);
optimizer::ArtDecompileDEX(*code_item,
ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
- /* decompile_return_instruction */ false);
+ decompile_return_instruction);
quickening_info_ptr += quickening_size;
}
it.Next();
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 93d282b..78bcb88 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -85,6 +85,7 @@ class VdexFile {
bool writable,
bool low_4gb,
bool unquicken,
+ bool decompile_return_instruction,
std::string* error_msg);
// Returns nullptr if the vdex file cannot be opened or is not valid.
@@ -94,6 +95,7 @@ class VdexFile {
bool writable,
bool low_4gb,
bool unquicken,
+ bool decompile_return_instruction,
std::string* error_msg);
const uint8_t* Begin() const { return mmap_->Begin(); }
@@ -137,7 +139,8 @@ class VdexFile {
// In-place unquicken the given `dex_files` based on `quickening_info`.
static void Unquicken(const std::vector<const DexFile*>& dex_files,
- const ArrayRef<const uint8_t>& quickening_info);
+ const ArrayRef<const uint8_t>& quickening_info,
+ bool decompile_return_instruction);
private:
explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
diff --git a/runtime/vdex_file_test.cc b/runtime/vdex_file_test.cc
index ced6e28..bf73430 100644
--- a/runtime/vdex_file_test.cc
+++ b/runtime/vdex_file_test.cc
@@ -37,11 +37,16 @@ TEST_F(VdexFileTest, OpenEmptyVdex) {
/*writable*/false,
/*low_4gb*/false,
/*quicken*/false,
+ /*decompile_return_instruction*/false,
&error_msg);
EXPECT_TRUE(vdex == nullptr);
- vdex = VdexFile::Open(
- tmp.GetFilename(), /*writable*/false, /*low_4gb*/false, /*quicken*/ false, &error_msg);
+ vdex = VdexFile::Open(tmp.GetFilename(),
+ /*writable*/false,
+ /*low_4gb*/false,
+ /*quicken*/false,
+ /*decompile_return_instruction*/false,
+ &error_msg);
EXPECT_TRUE(vdex == nullptr);
}
@jeffreysmooths
Copy link

True

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment