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 #ifndef ART_RUNTIME_VDEX_FILE_H_ 18 #define ART_RUNTIME_VDEX_FILE_H_ 19 20 #include <stdint.h> 21 #include <string> 22 23 #include "base/array_ref.h" 24 #include "base/macros.h" 25 #include "base/mem_map.h" 26 #include "base/os.h" 27 #include "dex/compact_offset_table.h" 28 #include "dex/dex_file.h" 29 #include "quicken_info.h" 30 31 namespace art { 32 33 class ClassLoaderContext; 34 35 namespace verifier { 36 class VerifierDeps; 37 } // namespace verifier 38 39 // VDEX files contain extracted DEX files. The VdexFile class maps the file to 40 // memory and provides tools for accessing its individual sections. 41 // 42 // File format: 43 // VdexFile::VerifierDepsHeader fixed-length header 44 // Dex file checksums 45 // 46 // Optionally: 47 // VdexFile::DexSectionHeader fixed-length header 48 // 49 // quicken_table_off[0] offset into QuickeningInfo section for offset table for DEX[0]. 50 // DEX[0] array of the input DEX files, the bytecode may have been quickened. 51 // quicken_table_off[1] 52 // DEX[1] 53 // ... 54 // DEX[D] 55 // 56 // VerifierDeps 57 // uint8[D][] verification dependencies 58 // 59 // Optionally: 60 // QuickeningInfo 61 // uint8[D][] quickening data 62 // uint32[D][] quickening data offset tables 63 64 class VdexFile { 65 public: 66 using VdexChecksum = uint32_t; 67 using QuickeningTableOffsetType = uint32_t; 68 69 struct VerifierDepsHeader { 70 public: 71 VerifierDepsHeader(uint32_t number_of_dex_files_, 72 uint32_t verifier_deps_size, 73 bool has_dex_section, 74 uint32_t bootclasspath_checksums_size = 0, 75 uint32_t class_loader_context_size = 0); 76 GetMagicVerifierDepsHeader77 const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); } GetVerifierDepsVersionVerifierDepsHeader78 const char* GetVerifierDepsVersion() const { 79 return reinterpret_cast<const char*>(verifier_deps_version_); 80 } GetDexSectionVersionVerifierDepsHeader81 const char* GetDexSectionVersion() const { 82 return reinterpret_cast<const char*>(dex_section_version_); 83 } 84 bool IsMagicValid() const; 85 bool IsVerifierDepsVersionValid() const; 86 bool IsDexSectionVersionValid() const; IsValidVerifierDepsHeader87 bool IsValid() const { 88 return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid(); 89 } 90 bool HasDexSection() const; 91 GetVerifierDepsSizeVerifierDepsHeader92 uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; } GetNumberOfDexFilesVerifierDepsHeader93 uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; } GetBootClassPathChecksumStringSizeVerifierDepsHeader94 uint32_t GetBootClassPathChecksumStringSize() const { return bootclasspath_checksums_size_; } GetClassLoaderContextStringSizeVerifierDepsHeader95 uint32_t GetClassLoaderContextStringSize() const { return class_loader_context_size_; } 96 GetSizeOfChecksumsSectionVerifierDepsHeader97 size_t GetSizeOfChecksumsSection() const { 98 return sizeof(VdexChecksum) * GetNumberOfDexFiles(); 99 } 100 GetDexChecksumsArrayVerifierDepsHeader101 const VdexChecksum* GetDexChecksumsArray() const { 102 return reinterpret_cast<const VdexChecksum*>( 103 reinterpret_cast<const uint8_t*>(this) + sizeof(VerifierDepsHeader)); 104 } 105 GetDexChecksumAtOffsetVerifierDepsHeader106 VdexChecksum GetDexChecksumAtOffset(size_t idx) const { 107 DCHECK_LT(idx, GetNumberOfDexFiles()); 108 return GetDexChecksumsArray()[idx]; 109 } 110 111 static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' }; 112 113 private: 114 static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' }; 115 116 // The format version of the verifier deps header and the verifier deps. 117 // Last update: Add boot checksum, class loader context. 118 static constexpr uint8_t kVerifierDepsVersion[] = { '0', '2', '1', '\0' }; 119 120 // The format version of the dex section header and the dex section, containing 121 // both the dex code and the quickening data. 122 // Last update: Add owned section for CompactDex. 123 static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '2', '\0' }; 124 125 // If the .vdex file has no dex section (hence no dex code nor quickening data), 126 // we encode this magic version. 127 static constexpr uint8_t kDexSectionVersionEmpty[] = { '0', '0', '0', '\0' }; 128 129 uint8_t magic_[4]; 130 uint8_t verifier_deps_version_[4]; 131 uint8_t dex_section_version_[4]; 132 uint32_t number_of_dex_files_; 133 uint32_t verifier_deps_size_; 134 uint32_t bootclasspath_checksums_size_; 135 uint32_t class_loader_context_size_; 136 }; 137 138 struct DexSectionHeader { 139 public: 140 DexSectionHeader(uint32_t dex_size, 141 uint32_t dex_shared_data_size, 142 uint32_t quickening_info_size); 143 GetDexSizeDexSectionHeader144 uint32_t GetDexSize() const { return dex_size_; } GetDexSharedDataSizeDexSectionHeader145 uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; } GetQuickeningInfoSizeDexSectionHeader146 uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; } 147 GetDexSectionSizeDexSectionHeader148 size_t GetDexSectionSize() const { 149 return sizeof(DexSectionHeader) + 150 GetDexSize() + 151 GetDexSharedDataSize(); 152 } 153 154 private: 155 uint32_t dex_size_; 156 uint32_t dex_shared_data_size_; 157 uint32_t quickening_info_size_; 158 159 friend class VdexFile; // For updating quickening_info_size_. 160 }; 161 GetComputedFileSize()162 size_t GetComputedFileSize() const { 163 size_t size = sizeof(VerifierDepsHeader); 164 const VerifierDepsHeader& header = GetVerifierDepsHeader(); 165 size += header.GetVerifierDepsSize(); 166 size += header.GetSizeOfChecksumsSection(); 167 if (header.HasDexSection()) { 168 size += GetDexSectionHeader().GetDexSectionSize(); 169 size += GetDexSectionHeader().GetQuickeningInfoSize(); 170 } 171 size += header.GetBootClassPathChecksumStringSize(); 172 size += header.GetClassLoaderContextStringSize(); 173 return size; 174 } 175 176 // Note: The file is called "primary" to match the naming with profiles. 177 static const constexpr char* kVdexNameInDmFile = "primary.vdex"; 178 VdexFile(MemMap && mmap)179 explicit VdexFile(MemMap&& mmap) : mmap_(std::move(mmap)) {} 180 181 // Returns nullptr if the vdex file cannot be opened or is not valid. 182 // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address. 183 static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr, 184 size_t mmap_size, 185 bool mmap_reuse, 186 const std::string& vdex_filename, 187 bool writable, 188 bool low_4gb, 189 bool unquicken, 190 std::string* error_msg); 191 192 // Returns nullptr if the vdex file cannot be opened or is not valid. 193 // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address. 194 static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr, 195 size_t mmap_size, 196 bool mmap_reuse, 197 int file_fd, 198 size_t vdex_length, 199 const std::string& vdex_filename, 200 bool writable, 201 bool low_4gb, 202 bool unquicken, 203 std::string* error_msg); 204 205 // Returns nullptr if the vdex file cannot be opened or is not valid. Open(const std::string & vdex_filename,bool writable,bool low_4gb,bool unquicken,std::string * error_msg)206 static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename, 207 bool writable, 208 bool low_4gb, 209 bool unquicken, 210 std::string* error_msg) { 211 return OpenAtAddress(nullptr, 212 0, 213 false, 214 vdex_filename, 215 writable, 216 low_4gb, 217 unquicken, 218 error_msg); 219 } 220 221 // Returns nullptr if the vdex file cannot be opened or is not valid. Open(int file_fd,size_t vdex_length,const std::string & vdex_filename,bool writable,bool low_4gb,bool unquicken,std::string * error_msg)222 static std::unique_ptr<VdexFile> Open(int file_fd, 223 size_t vdex_length, 224 const std::string& vdex_filename, 225 bool writable, 226 bool low_4gb, 227 bool unquicken, 228 std::string* error_msg) { 229 return OpenAtAddress(nullptr, 230 0, 231 false, 232 file_fd, 233 vdex_length, 234 vdex_filename, 235 writable, 236 low_4gb, 237 unquicken, 238 error_msg); 239 } 240 Begin()241 const uint8_t* Begin() const { return mmap_.Begin(); } End()242 const uint8_t* End() const { return mmap_.End(); } Size()243 size_t Size() const { return mmap_.Size(); } 244 GetVerifierDepsHeader()245 const VerifierDepsHeader& GetVerifierDepsHeader() const { 246 return *reinterpret_cast<const VerifierDepsHeader*>(Begin()); 247 } 248 GetDexSectionHeaderOffset()249 uint32_t GetDexSectionHeaderOffset() const { 250 return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection(); 251 } 252 GetDexSectionHeader()253 const DexSectionHeader& GetDexSectionHeader() const { 254 DCHECK(GetVerifierDepsHeader().HasDexSection()); 255 return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset()); 256 } 257 GetVerifierDepsStart()258 const uint8_t* GetVerifierDepsStart() const { 259 const uint8_t* result = Begin() + GetDexSectionHeaderOffset(); 260 if (GetVerifierDepsHeader().HasDexSection()) { 261 // When there is a dex section, the verifier deps are after it, but before the quickening. 262 return result + GetDexSectionHeader().GetDexSectionSize(); 263 } else { 264 // When there is no dex section, the verifier deps are just after the header. 265 return result; 266 } 267 } 268 GetVerifierDepsData()269 ArrayRef<const uint8_t> GetVerifierDepsData() const { 270 return ArrayRef<const uint8_t>( 271 GetVerifierDepsStart(), 272 GetVerifierDepsHeader().GetVerifierDepsSize()); 273 } 274 GetQuickeningInfo()275 ArrayRef<const uint8_t> GetQuickeningInfo() const { 276 return ArrayRef<const uint8_t>( 277 GetVerifierDepsData().end(), 278 GetVerifierDepsHeader().HasDexSection() 279 ? GetDexSectionHeader().GetQuickeningInfoSize() : 0); 280 } 281 GetBootClassPathChecksumData()282 ArrayRef<const uint8_t> GetBootClassPathChecksumData() const { 283 return ArrayRef<const uint8_t>( 284 GetQuickeningInfo().end(), 285 GetVerifierDepsHeader().GetBootClassPathChecksumStringSize()); 286 } 287 GetClassLoaderContextData()288 ArrayRef<const uint8_t> GetClassLoaderContextData() const { 289 return ArrayRef<const uint8_t>( 290 GetBootClassPathChecksumData().end(), 291 GetVerifierDepsHeader().GetClassLoaderContextStringSize()); 292 } 293 IsValid()294 bool IsValid() const { 295 return mmap_.Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid(); 296 } 297 298 // This method is for iterating over the dex files in the vdex. If `cursor` is null, 299 // the first dex file is returned. If `cursor` is not null, it must point to a dex 300 // file and this method returns the next dex file if there is one, or null if there 301 // is none. 302 const uint8_t* GetNextDexFileData(const uint8_t* cursor) const; 303 304 // Get the location checksum of the dex file number `dex_file_index`. GetLocationChecksum(uint32_t dex_file_index)305 uint32_t GetLocationChecksum(uint32_t dex_file_index) const { 306 DCHECK_LT(dex_file_index, GetVerifierDepsHeader().GetNumberOfDexFiles()); 307 return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index]; 308 } 309 310 // Open all the dex files contained in this vdex file. 311 bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files, 312 std::string* error_msg); 313 314 // In-place unquicken the given `dex_files` based on `quickening_info`. 315 // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are 316 // decompiled to RETURN_VOID instructions using the slower ClassAccessor instead of the faster 317 // QuickeningInfoIterator. 318 // Always unquickens using the vdex dex files as the source for quicken tables. 319 void Unquicken(const std::vector<const DexFile*>& target_dex_files, 320 bool decompile_return_instruction) const; 321 322 // Fully unquicken `target_dex_file` based on `quickening_info`. 323 void UnquickenDexFile(const DexFile& target_dex_file, 324 const DexFile& source_dex_file, 325 bool decompile_return_instruction) const; 326 327 // Return the quickening info of a given method index (or null if it's empty). 328 ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file, 329 uint32_t dex_method_idx) const; 330 HasDexSection()331 bool HasDexSection() const { 332 return GetVerifierDepsHeader().HasDexSection(); 333 } 334 335 // Writes a vdex into `path` and returns true on success. 336 // The vdex will not contain a dex section but will store checksums of `dex_files`, 337 // encoded `verifier_deps`, as well as the current boot class path cheksum and 338 // encoded `class_loader_context`. 339 static bool WriteToDisk(const std::string& path, 340 const std::vector<const DexFile*>& dex_files, 341 const verifier::VerifierDeps& verifier_deps, 342 const std::string& class_loader_context, 343 std::string* error_msg); 344 345 // Returns true if the dex file checksums stored in the vdex header match 346 // the checksums in `dex_headers`. Both the number of dex files and their 347 // order must match too. 348 bool MatchesDexFileChecksums(const std::vector<const DexFile::Header*>& dex_headers) const; 349 350 // Returns true if the boot class path checksum stored in the vdex matches 351 // the checksum of boot class path in the current runtime. 352 bool MatchesBootClassPathChecksums() const; 353 354 // Returns true if the class loader context stored in the vdex matches `context`. 355 bool MatchesClassLoaderContext(const ClassLoaderContext& context) const; 356 357 private: 358 uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const; 359 360 // Source dex must be the in the vdex file. 361 void UnquickenDexFile(const DexFile& target_dex_file, 362 const uint8_t* source_dex_begin, 363 bool decompile_return_instruction) const; 364 365 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable( 366 const DexFile& dex_file, 367 const ArrayRef<const uint8_t>& quickening_info) const; 368 369 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable( 370 const uint8_t* source_dex_begin, 371 const ArrayRef<const uint8_t>& quickening_info) const; 372 373 bool ContainsDexFile(const DexFile& dex_file) const; 374 DexBegin()375 const uint8_t* DexBegin() const { 376 DCHECK(HasDexSection()); 377 return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader); 378 } 379 DexEnd()380 const uint8_t* DexEnd() const { 381 DCHECK(HasDexSection()); 382 return DexBegin() + GetDexSectionHeader().GetDexSize(); 383 } 384 385 MemMap mmap_; 386 387 DISALLOW_COPY_AND_ASSIGN(VdexFile); 388 }; 389 390 } // namespace art 391 392 #endif // ART_RUNTIME_VDEX_FILE_H_ 393