Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "vdex_file.h"
     18 
     19 #include <sys/mman.h>  // For the PROT_* and MAP_* constants.
     20 
     21 #include <memory>
     22 
     23 #include "base/bit_utils.h"
     24 #include "base/logging.h"
     25 #include "base/stl_util.h"
     26 #include "base/unix_file/fd_file.h"
     27 #include "dex_file.h"
     28 #include "dex_to_dex_decompiler.h"
     29 
     30 namespace art {
     31 
     32 constexpr uint8_t VdexFile::Header::kVdexInvalidMagic[4];
     33 constexpr uint8_t VdexFile::Header::kVdexMagic[4];
     34 constexpr uint8_t VdexFile::Header::kVdexVersion[4];
     35 
     36 bool VdexFile::Header::IsMagicValid() const {
     37   return (memcmp(magic_, kVdexMagic, sizeof(kVdexMagic)) == 0);
     38 }
     39 
     40 bool VdexFile::Header::IsVersionValid() const {
     41   return (memcmp(version_, kVdexVersion, sizeof(kVdexVersion)) == 0);
     42 }
     43 
     44 VdexFile::Header::Header(uint32_t number_of_dex_files,
     45                          uint32_t dex_size,
     46                          uint32_t verifier_deps_size,
     47                          uint32_t quickening_info_size)
     48     : number_of_dex_files_(number_of_dex_files),
     49       dex_size_(dex_size),
     50       verifier_deps_size_(verifier_deps_size),
     51       quickening_info_size_(quickening_info_size) {
     52   memcpy(magic_, kVdexMagic, sizeof(kVdexMagic));
     53   memcpy(version_, kVdexVersion, sizeof(kVdexVersion));
     54   DCHECK(IsMagicValid());
     55   DCHECK(IsVersionValid());
     56 }
     57 
     58 std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename,
     59                                          bool writable,
     60                                          bool low_4gb,
     61                                          bool unquicken,
     62                                          std::string* error_msg) {
     63   if (!OS::FileExists(vdex_filename.c_str())) {
     64     *error_msg = "File " + vdex_filename + " does not exist.";
     65     return nullptr;
     66   }
     67 
     68   std::unique_ptr<File> vdex_file;
     69   if (writable) {
     70     vdex_file.reset(OS::OpenFileReadWrite(vdex_filename.c_str()));
     71   } else {
     72     vdex_file.reset(OS::OpenFileForReading(vdex_filename.c_str()));
     73   }
     74   if (vdex_file == nullptr) {
     75     *error_msg = "Could not open file " + vdex_filename +
     76                  (writable ? " for read/write" : "for reading");
     77     return nullptr;
     78   }
     79 
     80   int64_t vdex_length = vdex_file->GetLength();
     81   if (vdex_length == -1) {
     82     *error_msg = "Could not read the length of file " + vdex_filename;
     83     return nullptr;
     84   }
     85 
     86   return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, unquicken, error_msg);
     87 }
     88 
     89 std::unique_ptr<VdexFile> VdexFile::Open(int file_fd,
     90                                          size_t vdex_length,
     91                                          const std::string& vdex_filename,
     92                                          bool writable,
     93                                          bool low_4gb,
     94                                          bool unquicken,
     95                                          std::string* error_msg) {
     96   std::unique_ptr<MemMap> mmap(MemMap::MapFile(
     97       vdex_length,
     98       (writable || unquicken) ? PROT_READ | PROT_WRITE : PROT_READ,
     99       unquicken ? MAP_PRIVATE : MAP_SHARED,
    100       file_fd,
    101       0 /* start offset */,
    102       low_4gb,
    103       vdex_filename.c_str(),
    104       error_msg));
    105   if (mmap == nullptr) {
    106     *error_msg = "Failed to mmap file " + vdex_filename + " : " + *error_msg;
    107     return nullptr;
    108   }
    109 
    110   std::unique_ptr<VdexFile> vdex(new VdexFile(mmap.release()));
    111   if (!vdex->IsValid()) {
    112     *error_msg = "Vdex file is not valid";
    113     return nullptr;
    114   }
    115 
    116   if (unquicken) {
    117     std::vector<std::unique_ptr<const DexFile>> unique_ptr_dex_files;
    118     if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) {
    119       return nullptr;
    120     }
    121     Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files), vdex->GetQuickeningInfo());
    122     // Update the quickening info size to pretend there isn't any.
    123     reinterpret_cast<Header*>(vdex->mmap_->Begin())->quickening_info_size_ = 0;
    124   }
    125 
    126   *error_msg = "Success";
    127   return vdex;
    128 }
    129 
    130 const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor) const {
    131   DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End()));
    132   if (cursor == nullptr) {
    133     // Beginning of the iteration, return the first dex file if there is one.
    134     return HasDexSection() ? DexBegin() : nullptr;
    135   } else {
    136     // Fetch the next dex file. Return null if there is none.
    137     const uint8_t* data = cursor + reinterpret_cast<const DexFile::Header*>(cursor)->file_size_;
    138     // Dex files are required to be 4 byte aligned. the OatWriter makes sure they are, see
    139     // OatWriter::SeekToDexFiles.
    140     data = AlignUp(data, 4);
    141     return (data == DexEnd()) ? nullptr : data;
    142   }
    143 }
    144 
    145 bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
    146                                std::string* error_msg) {
    147   size_t i = 0;
    148   for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr);
    149        dex_file_start != nullptr;
    150        dex_file_start = GetNextDexFileData(dex_file_start), ++i) {
    151     size_t size = reinterpret_cast<const DexFile::Header*>(dex_file_start)->file_size_;
    152     // TODO: Supply the location information for a vdex file.
    153     static constexpr char kVdexLocation[] = "";
    154     std::string location = DexFile::GetMultiDexLocation(i, kVdexLocation);
    155     std::unique_ptr<const DexFile> dex(DexFile::Open(dex_file_start,
    156                                                      size,
    157                                                      location,
    158                                                      GetLocationChecksum(i),
    159                                                      nullptr /*oat_dex_file*/,
    160                                                      false /*verify*/,
    161                                                      false /*verify_checksum*/,
    162                                                      error_msg));
    163     if (dex == nullptr) {
    164       return false;
    165     }
    166     dex_files->push_back(std::move(dex));
    167   }
    168   return true;
    169 }
    170 
    171 // Utility class to easily iterate over the quickening data.
    172 class QuickeningInfoIterator {
    173  public:
    174   QuickeningInfoIterator(uint32_t dex_file_index,
    175                          uint32_t number_of_dex_files,
    176                          const ArrayRef<const uint8_t>& quickening_info)
    177       : quickening_info_(quickening_info) {
    178     const unaligned_uint32_t* dex_file_indices = reinterpret_cast<const unaligned_uint32_t*>(
    179             quickening_info.data() +
    180             quickening_info.size() -
    181             number_of_dex_files * sizeof(uint32_t));
    182     current_code_item_end_ = (dex_file_index == number_of_dex_files - 1)
    183         ? dex_file_indices
    184         : reinterpret_cast<const unaligned_uint32_t*>(
    185               quickening_info_.data() + dex_file_indices[dex_file_index + 1]);
    186     current_code_item_ptr_ = reinterpret_cast<const uint32_t*>(
    187         quickening_info_.data() + dex_file_indices[dex_file_index]);
    188   }
    189 
    190   bool Done() const {
    191     return current_code_item_ptr_ == current_code_item_end_;
    192   }
    193 
    194   void Advance() {
    195     current_code_item_ptr_ += 2;
    196   }
    197 
    198   uint32_t GetCurrentCodeItemOffset() const {
    199     return current_code_item_ptr_[0];
    200   }
    201 
    202   const ArrayRef<const uint8_t> GetCurrentQuickeningInfo() const {
    203     return ArrayRef<const uint8_t>(
    204         // Add sizeof(uint32_t) to remove the length from the data pointer.
    205         quickening_info_.data() + current_code_item_ptr_[1] + sizeof(uint32_t),
    206         *reinterpret_cast<const unaligned_uint32_t*>(
    207             quickening_info_.data() + current_code_item_ptr_[1]));
    208   }
    209 
    210  private:
    211   typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
    212   const ArrayRef<const uint8_t>& quickening_info_;
    213   const unaligned_uint32_t* current_code_item_ptr_;
    214   const unaligned_uint32_t* current_code_item_end_;
    215 
    216   DISALLOW_COPY_AND_ASSIGN(QuickeningInfoIterator);
    217 };
    218 
    219 void VdexFile::Unquicken(const std::vector<const DexFile*>& dex_files,
    220                          const ArrayRef<const uint8_t>& quickening_info) {
    221   if (quickening_info.size() == 0) {
    222     // Bail early if there is no quickening info.
    223     return;
    224   }
    225   // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
    226   // optimization does not depend on the boot image (the optimization relies on not
    227   // having final fields in a class, which does not change for an app).
    228   constexpr bool kDecompileReturnInstruction = false;
    229   for (uint32_t i = 0; i < dex_files.size(); ++i) {
    230     for (QuickeningInfoIterator it(i, dex_files.size(), quickening_info);
    231          !it.Done();
    232          it.Advance()) {
    233       optimizer::ArtDecompileDEX(
    234           *dex_files[i]->GetCodeItem(it.GetCurrentCodeItemOffset()),
    235           it.GetCurrentQuickeningInfo(),
    236           kDecompileReturnInstruction);
    237     }
    238   }
    239 }
    240 
    241 static constexpr uint32_t kNoDexFile = -1;
    242 
    243 uint32_t VdexFile::GetDexFileIndex(const DexFile& dex_file) const {
    244   uint32_t dex_index = 0;
    245   for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr);
    246        dex_file_start != dex_file.Begin();
    247        dex_file_start = GetNextDexFileData(dex_file_start)) {
    248     if (dex_file_start == nullptr) {
    249       return kNoDexFile;
    250     }
    251     dex_index++;
    252   }
    253   return dex_index;
    254 }
    255 
    256 void VdexFile::FullyUnquickenDexFile(const DexFile& target_dex_file,
    257                                      const DexFile& original_dex_file) const {
    258   uint32_t dex_index = GetDexFileIndex(original_dex_file);
    259   if (dex_index == kNoDexFile) {
    260     return;
    261   }
    262 
    263   constexpr bool kDecompileReturnInstruction = true;
    264   QuickeningInfoIterator it(dex_index, GetHeader().GetNumberOfDexFiles(), GetQuickeningInfo());
    265   // Iterate over the class definitions. Even if there is no quickening info,
    266   // we want to unquicken RETURN_VOID_NO_BARRIER instruction.
    267   for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) {
    268     const DexFile::ClassDef& class_def = target_dex_file.GetClassDef(i);
    269     const uint8_t* class_data = target_dex_file.GetClassData(class_def);
    270     if (class_data != nullptr) {
    271       for (ClassDataItemIterator class_it(target_dex_file, class_data);
    272            class_it.HasNext();
    273            class_it.Next()) {
    274         if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
    275           uint32_t offset = class_it.GetMethodCodeItemOffset();
    276           if (!it.Done() && offset == it.GetCurrentCodeItemOffset()) {
    277             optimizer::ArtDecompileDEX(
    278                 *class_it.GetMethodCodeItem(),
    279                 it.GetCurrentQuickeningInfo(),
    280                 kDecompileReturnInstruction);
    281             it.Advance();
    282           } else {
    283             optimizer::ArtDecompileDEX(*class_it.GetMethodCodeItem(),
    284                                        ArrayRef<const uint8_t>(nullptr, 0),
    285                                        kDecompileReturnInstruction);
    286           }
    287         }
    288       }
    289     }
    290   }
    291 }
    292 
    293 const uint8_t* VdexFile::GetQuickenedInfoOf(const DexFile& dex_file,
    294                                             uint32_t code_item_offset) const {
    295   if (GetQuickeningInfo().size() == 0) {
    296     // Bail early if there is no quickening info.
    297     return nullptr;
    298   }
    299 
    300   uint32_t dex_index = GetDexFileIndex(dex_file);
    301   if (dex_index == kNoDexFile) {
    302     return nullptr;
    303   }
    304 
    305   for (QuickeningInfoIterator it(dex_index, GetHeader().GetNumberOfDexFiles(), GetQuickeningInfo());
    306        !it.Done();
    307        it.Advance()) {
    308     if (code_item_offset == it.GetCurrentCodeItemOffset()) {
    309       return it.GetCurrentQuickeningInfo().data();
    310     }
    311   }
    312   return nullptr;
    313 }
    314 
    315 }  // namespace art
    316