Add dex container support to dexter am: 68fef98d8c am: fbeb8a3fad
Original change: https://android-review.googlesource.com/c/platform/tools/dexter/+/2740254
Change-Id: Ic66b05ddb5df54077b935287b94a7590970c6b12
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/slicer/dex_format.cc b/slicer/dex_format.cc
index b1a1ab0..16b36a0 100644
--- a/slicer/dex_format.cc
+++ b/slicer/dex_format.cc
@@ -19,10 +19,18 @@
#include "slicer/common.h"
#include <sstream>
+#include <cstdlib>
#include <zlib.h>
namespace dex {
+// The expected format of the magic is dex\nXXX\0 where XXX are digits. We extract this value.
+// Returns 0 if the version can not be parsed.
+u4 Header::GetVersion(const void* magic) {
+ const char* version = reinterpret_cast<const char*>(magic) + 4;
+ return version[3] == '\0' ? strtol(version, nullptr, 10) : 0;
+}
+
// Compute the DEX file checksum for a memory-mapped DEX file
u4 ComputeChecksum(const Header* header) {
const u1* start = reinterpret_cast<const u1*>(header);
diff --git a/slicer/export/slicer/dex_format.h b/slicer/export/slicer/dex_format.h
index 4e70bd1..e73d1dc 100644
--- a/slicer/export/slicer/dex_format.h
+++ b/slicer/export/slicer/dex_format.h
@@ -145,6 +145,36 @@
// "header_item"
struct Header {
+ static constexpr size_t kV40Size = 0x70; // Same as all previous dex versions.
+ static constexpr size_t kV41Size = 0x78; // Added container_{size,off} fields.
+ // See http://go/dex-container-format
+ static constexpr size_t kMaxSize = kV41Size;
+
+ static constexpr u4 kV41 = 41;
+ static constexpr u4 kMinVersion = 35; // Minimum supported dex version.
+ static constexpr u4 kMaxVersion = 41; // Maximum supported dex version.
+
+ // Parse magic number and extract the version integer. E.g.: `dex\n123\0` returns `123`.
+ // Returns 0 upon failure.
+ static u4 GetVersion(const void* magic);
+
+ u4 GetVersion() const {
+ return GetVersion(magic);
+ }
+
+ u4 ContainerSize() const {
+ return header_size >= kV41Size ? container_size : file_size;
+ }
+
+ u4 ContainerOff() const {
+ return header_size >= kV41Size ? container_off : 0;
+ }
+
+ void SetContainer(u4 off, u4 size) {
+ container_off = off;
+ container_size = size;
+ }
+
u1 magic[8];
u4 checksum;
u1 signature[kSHA1DigestLen];
@@ -168,6 +198,10 @@
u4 class_defs_off;
u4 data_size;
u4 data_off;
+
+ private:
+ u4 container_size;
+ u4 container_off;
};
// "map_item"
diff --git a/slicer/reader.cc b/slicer/reader.cc
index 6358315..14c43d7 100644
--- a/slicer/reader.cc
+++ b/slicer/reader.cc
@@ -1001,15 +1001,24 @@
// Basic .dex header structural checks
void Reader::ValidateHeader() {
- SLICER_CHECK_GT(size_, sizeof(dex::Header));
+ SLICER_CHECK_GT(size_, dex::Header::kV40Size);
// Known issue: For performance reasons the initial size_ passed to jvmti events might be an
// estimate. b/72402467
SLICER_CHECK_LE(header_->file_size, size_);
- SLICER_CHECK_EQ(header_->header_size, sizeof(dex::Header));
+ // Check that we support this version of dex header
+ SLICER_CHECK(
+ header_->header_size == dex::Header::kV40Size ||
+ header_->header_size == dex::Header::kV41Size);
SLICER_CHECK_EQ(header_->endian_tag, dex::kEndianConstant);
SLICER_CHECK_EQ(header_->data_size % 4, 0);
+ // If the dex file is within container with other dex files,
+ // adjust the base address to the start of the container.
+ SLICER_CHECK_LE(header_->ContainerSize() - header_->ContainerOff(), size_);
+ image_ -= header_->ContainerOff();
+ size_ = header_->ContainerSize();
+
// Known issue: The fields might be slighly corrupted b/65452964
// SLICER_CHECK_LE(header_->data_off + header_->data_size, size_);
@@ -1021,7 +1030,8 @@
SLICER_CHECK_EQ(header_->field_ids_off % 4, 0);
SLICER_CHECK_EQ(header_->method_ids_off % 4, 0);
SLICER_CHECK_EQ(header_->class_defs_off % 4, 0);
- SLICER_CHECK(header_->map_off >= header_->data_off && header_->map_off < size_);
+ SLICER_CHECK_GE(header_->map_off, header_->data_off);
+ SLICER_CHECK_LT(header_->map_off, size_);
SLICER_CHECK_EQ(header_->link_size, 0);
SLICER_CHECK_EQ(header_->link_off, 0);
SLICER_CHECK_EQ(header_->data_off % 4, 0);
diff --git a/slicer/writer.cc b/slicer/writer.cc
index bed17fb..c1f68a9 100644
--- a/slicer/writer.cc
+++ b/slicer/writer.cc
@@ -226,7 +226,7 @@
SLICER_CHECK_GT(section.ItemsCount(), 0);
dex::u4 offset = section.SectionOffset();
dex::u4 size = section.size();
- SLICER_CHECK_GE(offset, sizeof(dex::Header));
+ SLICER_CHECK_GE(offset, dex::Header::kV40Size);
SLICER_CHECK_LE(offset + size, image_size);
::memcpy(image + offset, section.data(), size);
@@ -253,12 +253,18 @@
// (ideally we shouldn't change the IR while generating an image)
dex_ir_->Normalize();
+ int version = Header::GetVersion(dex_ir_->magic.ptr());
+ SLICER_CHECK_NE(version, 0);
+ SLICER_CHECK_GE(version, Header::kMinVersion);
+ SLICER_CHECK_LE(version, Header::kMaxVersion);
+ u4 header_size = version >= Header::kV41 ? Header::kV41Size : Header::kV40Size;
+
// track the current offset within the .dex image
dex::u4 offset = 0;
// allocate the image and index sections
// (they will be back-filled)
- offset += sizeof(dex::Header);
+ offset += header_size;
offset += dex_->string_ids.Init(offset, dex_ir_->strings.size());
offset += dex_->type_ids.Init(offset, dex_ir_->types.size());
offset += dex_->proto_ids.Init(offset, dex_ir_->protos.size());
@@ -304,7 +310,7 @@
memset(image, 0, image_size);
// finally, back-fill the header
- SLICER_CHECK_GT(image_size, sizeof(dex::Header));
+ SLICER_CHECK_GT(image_size, header_size);
dex::Header* header = reinterpret_cast<dex::Header*>(image + 0);
@@ -312,7 +318,7 @@
memcpy(header->magic, dex_ir_->magic.ptr(), dex_ir_->magic.size());
header->file_size = image_size;
- header->header_size = sizeof(dex::Header);
+ header->header_size = header_size;
header->endian_tag = dex::kEndianConstant;
header->link_size = 0;
@@ -333,6 +339,11 @@
header->class_defs_off = dex_->class_defs.SectionOffset();
header->data_size = image_size - data_offset;
header->data_off = data_offset;
+ if (version >= Header::kV41) {
+ header->data_size = 0;
+ header->data_off = 0;
+ header->SetContainer(0, header->file_size);
+ }
// copy the individual sections to the final image
CopySection(dex_->string_ids, image, image_size);
@@ -384,7 +395,7 @@
template <class T>
static void AddMapItem(const T& section, std::vector<dex::MapItem>& items) {
if (section.ItemsCount() > 0) {
- SLICER_CHECK_GE(section.SectionOffset(), sizeof(dex::Header));
+ SLICER_CHECK_GE(section.SectionOffset(), dex::Header::kV40Size);
dex::MapItem map_item = {};
map_item.type = section.MapEntryType();
map_item.size = section.ItemsCount();