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