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 #include <unordered_set> 23 24 #include <android-base/logging.h> 25 26 #include "base/bit_utils.h" 27 #include "base/leb128.h" 28 #include "base/stl_util.h" 29 #include "base/unix_file/fd_file.h" 30 #include "dex/art_dex_file_loader.h" 31 #include "dex/dex_file.h" 32 #include "dex/dex_file_loader.h" 33 #include "dex/hidden_api_access_flags.h" 34 #include "dex_to_dex_decompiler.h" 35 #include "quicken_info.h" 36 37 namespace art { 38 39 constexpr uint8_t VdexFile::VerifierDepsHeader::kVdexInvalidMagic[4]; 40 constexpr uint8_t VdexFile::VerifierDepsHeader::kVdexMagic[4]; 41 constexpr uint8_t VdexFile::VerifierDepsHeader::kVerifierDepsVersion[4]; 42 constexpr uint8_t VdexFile::VerifierDepsHeader::kDexSectionVersion[4]; 43 constexpr uint8_t VdexFile::VerifierDepsHeader::kDexSectionVersionEmpty[4]; 44 45 bool VdexFile::VerifierDepsHeader::IsMagicValid() const { 46 return (memcmp(magic_, kVdexMagic, sizeof(kVdexMagic)) == 0); 47 } 48 49 bool VdexFile::VerifierDepsHeader::IsVerifierDepsVersionValid() const { 50 return (memcmp(verifier_deps_version_, kVerifierDepsVersion, sizeof(kVerifierDepsVersion)) == 0); 51 } 52 53 bool VdexFile::VerifierDepsHeader::IsDexSectionVersionValid() const { 54 return (memcmp(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion)) == 0) || 55 (memcmp(dex_section_version_, kDexSectionVersionEmpty, sizeof(kDexSectionVersionEmpty)) == 0); 56 } 57 58 bool VdexFile::VerifierDepsHeader::HasDexSection() const { 59 return (memcmp(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion)) == 0); 60 } 61 62 VdexFile::VerifierDepsHeader::VerifierDepsHeader(uint32_t number_of_dex_files, 63 uint32_t verifier_deps_size, 64 bool has_dex_section) 65 : number_of_dex_files_(number_of_dex_files), 66 verifier_deps_size_(verifier_deps_size) { 67 memcpy(magic_, kVdexMagic, sizeof(kVdexMagic)); 68 memcpy(verifier_deps_version_, kVerifierDepsVersion, sizeof(kVerifierDepsVersion)); 69 if (has_dex_section) { 70 memcpy(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion)); 71 } else { 72 memcpy(dex_section_version_, kDexSectionVersionEmpty, sizeof(kDexSectionVersionEmpty)); 73 } 74 DCHECK(IsMagicValid()); 75 DCHECK(IsVerifierDepsVersionValid()); 76 DCHECK(IsDexSectionVersionValid()); 77 } 78 79 VdexFile::DexSectionHeader::DexSectionHeader(uint32_t dex_size, 80 uint32_t dex_shared_data_size, 81 uint32_t quickening_info_size) 82 : dex_size_(dex_size), 83 dex_shared_data_size_(dex_shared_data_size), 84 quickening_info_size_(quickening_info_size) { 85 } 86 87 std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, 88 size_t mmap_size, 89 bool mmap_reuse, 90 const std::string& vdex_filename, 91 bool writable, 92 bool low_4gb, 93 bool unquicken, 94 std::string* error_msg) { 95 if (!OS::FileExists(vdex_filename.c_str())) { 96 *error_msg = "File " + vdex_filename + " does not exist."; 97 return nullptr; 98 } 99 100 std::unique_ptr<File> vdex_file; 101 if (writable) { 102 vdex_file.reset(OS::OpenFileReadWrite(vdex_filename.c_str())); 103 } else { 104 vdex_file.reset(OS::OpenFileForReading(vdex_filename.c_str())); 105 } 106 if (vdex_file == nullptr) { 107 *error_msg = "Could not open file " + vdex_filename + 108 (writable ? " for read/write" : "for reading"); 109 return nullptr; 110 } 111 112 int64_t vdex_length = vdex_file->GetLength(); 113 if (vdex_length == -1) { 114 *error_msg = "Could not read the length of file " + vdex_filename; 115 return nullptr; 116 } 117 118 return OpenAtAddress(mmap_addr, 119 mmap_size, 120 mmap_reuse, 121 vdex_file->Fd(), 122 vdex_length, 123 vdex_filename, 124 writable, 125 low_4gb, 126 unquicken, 127 error_msg); 128 } 129 130 std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, 131 size_t mmap_size, 132 bool mmap_reuse, 133 int file_fd, 134 size_t vdex_length, 135 const std::string& vdex_filename, 136 bool writable, 137 bool low_4gb, 138 bool unquicken, 139 std::string* error_msg) { 140 if (mmap_addr != nullptr && mmap_size < vdex_length) { 141 LOG(WARNING) << "Insufficient pre-allocated space to mmap vdex."; 142 mmap_addr = nullptr; 143 mmap_reuse = false; 144 } 145 CHECK(!mmap_reuse || mmap_addr != nullptr); 146 std::unique_ptr<MemMap> mmap(MemMap::MapFileAtAddress( 147 mmap_addr, 148 vdex_length, 149 (writable || unquicken) ? PROT_READ | PROT_WRITE : PROT_READ, 150 unquicken ? MAP_PRIVATE : MAP_SHARED, 151 file_fd, 152 0 /* start offset */, 153 low_4gb, 154 mmap_reuse, 155 vdex_filename.c_str(), 156 error_msg)); 157 if (mmap == nullptr) { 158 *error_msg = "Failed to mmap file " + vdex_filename + " : " + *error_msg; 159 return nullptr; 160 } 161 162 std::unique_ptr<VdexFile> vdex(new VdexFile(mmap.release())); 163 if (!vdex->IsValid()) { 164 *error_msg = "Vdex file is not valid"; 165 return nullptr; 166 } 167 168 if (unquicken && vdex->HasDexSection()) { 169 std::vector<std::unique_ptr<const DexFile>> unique_ptr_dex_files; 170 if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) { 171 return nullptr; 172 } 173 vdex->Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files), 174 /* decompile_return_instruction */ false); 175 // Update the quickening info size to pretend there isn't any. 176 size_t offset = vdex->GetDexSectionHeaderOffset(); 177 reinterpret_cast<DexSectionHeader*>(vdex->mmap_->Begin() + offset)->quickening_info_size_ = 0; 178 } 179 180 *error_msg = "Success"; 181 return vdex; 182 } 183 184 const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor) const { 185 DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End())); 186 if (cursor == nullptr) { 187 // Beginning of the iteration, return the first dex file if there is one. 188 return HasDexSection() ? DexBegin() + sizeof(QuickeningTableOffsetType) : nullptr; 189 } else { 190 // Fetch the next dex file. Return null if there is none. 191 const uint8_t* data = cursor + reinterpret_cast<const DexFile::Header*>(cursor)->file_size_; 192 // Dex files are required to be 4 byte aligned. the OatWriter makes sure they are, see 193 // OatWriter::SeekToDexFiles. 194 data = AlignUp(data, 4); 195 196 return (data == DexEnd()) ? nullptr : data + sizeof(QuickeningTableOffsetType); 197 } 198 } 199 200 bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files, 201 std::string* error_msg) { 202 const ArtDexFileLoader dex_file_loader; 203 size_t i = 0; 204 for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr); 205 dex_file_start != nullptr; 206 dex_file_start = GetNextDexFileData(dex_file_start), ++i) { 207 size_t size = reinterpret_cast<const DexFile::Header*>(dex_file_start)->file_size_; 208 // TODO: Supply the location information for a vdex file. 209 static constexpr char kVdexLocation[] = ""; 210 std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation); 211 std::unique_ptr<const DexFile> dex(dex_file_loader.OpenWithDataSection( 212 dex_file_start, 213 size, 214 /*data_base*/ nullptr, 215 /*data_size*/ 0u, 216 location, 217 GetLocationChecksum(i), 218 nullptr /*oat_dex_file*/, 219 false /*verify*/, 220 false /*verify_checksum*/, 221 error_msg)); 222 if (dex == nullptr) { 223 return false; 224 } 225 dex_files->push_back(std::move(dex)); 226 } 227 return true; 228 } 229 230 void VdexFile::Unquicken(const std::vector<const DexFile*>& target_dex_files, 231 bool decompile_return_instruction) const { 232 const uint8_t* source_dex = GetNextDexFileData(nullptr); 233 for (const DexFile* target_dex : target_dex_files) { 234 UnquickenDexFile(*target_dex, source_dex, decompile_return_instruction); 235 source_dex = GetNextDexFileData(source_dex); 236 } 237 DCHECK(source_dex == nullptr); 238 } 239 240 uint32_t VdexFile::GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const { 241 DCHECK_GE(source_dex_begin, DexBegin()); 242 DCHECK_LT(source_dex_begin, DexEnd()); 243 return reinterpret_cast<const QuickeningTableOffsetType*>(source_dex_begin)[-1]; 244 } 245 246 CompactOffsetTable::Accessor VdexFile::GetQuickenInfoOffsetTable( 247 const uint8_t* source_dex_begin, 248 const ArrayRef<const uint8_t>& quickening_info) const { 249 // The offset a is in preheader right before the dex file. 250 const uint32_t offset = GetQuickeningInfoTableOffset(source_dex_begin); 251 return CompactOffsetTable::Accessor(quickening_info.SubArray(offset).data()); 252 } 253 254 CompactOffsetTable::Accessor VdexFile::GetQuickenInfoOffsetTable( 255 const DexFile& dex_file, 256 const ArrayRef<const uint8_t>& quickening_info) const { 257 return GetQuickenInfoOffsetTable(dex_file.Begin(), quickening_info); 258 } 259 260 static ArrayRef<const uint8_t> GetQuickeningInfoAt(const ArrayRef<const uint8_t>& quickening_info, 261 uint32_t quickening_offset) { 262 // Subtract offset of one since 0 represents unused and cannot be in the table. 263 ArrayRef<const uint8_t> remaining = quickening_info.SubArray(quickening_offset - 1); 264 return remaining.SubArray(0u, QuickenInfoTable::SizeInBytes(remaining)); 265 } 266 267 void VdexFile::UnquickenDexFile(const DexFile& target_dex_file, 268 const DexFile& source_dex_file, 269 bool decompile_return_instruction) const { 270 UnquickenDexFile(target_dex_file, source_dex_file.Begin(), decompile_return_instruction); 271 } 272 273 void VdexFile::UnquickenDexFile(const DexFile& target_dex_file, 274 const uint8_t* source_dex_begin, 275 bool decompile_return_instruction) const { 276 ArrayRef<const uint8_t> quickening_info = GetQuickeningInfo(); 277 if (quickening_info.empty()) { 278 // Bail early if there is no quickening info and no need to decompile. This means there is also 279 // no RETURN_VOID to decompile since the empty table takes a non zero amount of space. 280 return; 281 } 282 // Make sure to not unquicken the same code item multiple times. 283 std::unordered_set<const DexFile::CodeItem*> unquickened_code_item; 284 CompactOffsetTable::Accessor accessor(GetQuickenInfoOffsetTable(source_dex_begin, 285 quickening_info)); 286 for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) { 287 const DexFile::ClassDef& class_def = target_dex_file.GetClassDef(i); 288 const uint8_t* class_data = target_dex_file.GetClassData(class_def); 289 if (class_data != nullptr) { 290 for (ClassDataItemIterator class_it(target_dex_file, class_data); 291 class_it.HasNext(); 292 class_it.Next()) { 293 if (class_it.IsAtMethod()) { 294 const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem(); 295 if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) { 296 const uint32_t offset = accessor.GetOffset(class_it.GetMemberIndex()); 297 // Offset being 0 means not quickened. 298 if (offset != 0u) { 299 ArrayRef<const uint8_t> quicken_data = GetQuickeningInfoAt(quickening_info, offset); 300 optimizer::ArtDecompileDEX( 301 target_dex_file, 302 *code_item, 303 quicken_data, 304 decompile_return_instruction); 305 } 306 } 307 } 308 DexFile::UnHideAccessFlags(class_it); 309 } 310 } 311 } 312 } 313 314 ArrayRef<const uint8_t> VdexFile::GetQuickenedInfoOf(const DexFile& dex_file, 315 uint32_t dex_method_idx) const { 316 ArrayRef<const uint8_t> quickening_info = GetQuickeningInfo(); 317 if (quickening_info.empty()) { 318 return ArrayRef<const uint8_t>(); 319 } 320 CHECK_LT(dex_method_idx, dex_file.NumMethodIds()); 321 const uint32_t quickening_offset = 322 GetQuickenInfoOffsetTable(dex_file, quickening_info).GetOffset(dex_method_idx); 323 if (quickening_offset == 0u) { 324 return ArrayRef<const uint8_t>(); 325 } 326 return GetQuickeningInfoAt(quickening_info, quickening_offset); 327 } 328 329 } // namespace art 330