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/os.h" 26 #include "dex/compact_offset_table.h" 27 #include "mem_map.h" 28 #include "quicken_info.h" 29 30 namespace art { 31 32 class DexFile; 33 34 // VDEX files contain extracted DEX files. The VdexFile class maps the file to 35 // memory and provides tools for accessing its individual sections. 36 // 37 // File format: 38 // VdexFile::VerifierDepsHeader fixed-length header 39 // Dex file checksums 40 // 41 // Optionally: 42 // VdexFile::DexSectionHeader fixed-length header 43 // 44 // quicken_table_off[0] offset into QuickeningInfo section for offset table for DEX[0]. 45 // DEX[0] array of the input DEX files, the bytecode may have been quickened. 46 // quicken_table_off[1] 47 // DEX[1] 48 // ... 49 // DEX[D] 50 // 51 // VerifierDeps 52 // uint8[D][] verification dependencies 53 // 54 // Optionally: 55 // QuickeningInfo 56 // uint8[D][] quickening data 57 // uint32[D][] quickening data offset tables 58 59 class VdexFile { 60 public: 61 struct VerifierDepsHeader { 62 public: 63 VerifierDepsHeader(uint32_t number_of_dex_files_, 64 uint32_t verifier_deps_size, 65 bool has_dex_section); 66 GetMagicVerifierDepsHeader67 const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); } GetVerifierDepsVersionVerifierDepsHeader68 const char* GetVerifierDepsVersion() const { 69 return reinterpret_cast<const char*>(verifier_deps_version_); 70 } GetDexSectionVersionVerifierDepsHeader71 const char* GetDexSectionVersion() const { 72 return reinterpret_cast<const char*>(dex_section_version_); 73 } 74 bool IsMagicValid() const; 75 bool IsVerifierDepsVersionValid() const; 76 bool IsDexSectionVersionValid() const; IsValidVerifierDepsHeader77 bool IsValid() const { 78 return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid(); 79 } 80 bool HasDexSection() const; 81 GetVerifierDepsSizeVerifierDepsHeader82 uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; } GetNumberOfDexFilesVerifierDepsHeader83 uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; } 84 GetSizeOfChecksumsSectionVerifierDepsHeader85 size_t GetSizeOfChecksumsSection() const { 86 return sizeof(VdexChecksum) * GetNumberOfDexFiles(); 87 } 88 89 static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' }; 90 91 private: 92 static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' }; 93 94 // The format version of the verifier deps header and the verifier deps. 95 // Last update: Add DexSectionHeader 96 static constexpr uint8_t kVerifierDepsVersion[] = { '0', '1', '9', '\0' }; 97 98 // The format version of the dex section header and the dex section, containing 99 // both the dex code and the quickening data. 100 // Last update: Add owned section for CompactDex. 101 static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '2', '\0' }; 102 103 // If the .vdex file has no dex section (hence no dex code nor quickening data), 104 // we encode this magic version. 105 static constexpr uint8_t kDexSectionVersionEmpty[] = { '0', '0', '0', '\0' }; 106 107 uint8_t magic_[4]; 108 uint8_t verifier_deps_version_[4]; 109 uint8_t dex_section_version_[4]; 110 uint32_t number_of_dex_files_; 111 uint32_t verifier_deps_size_; 112 }; 113 114 struct DexSectionHeader { 115 public: 116 DexSectionHeader(uint32_t dex_size, 117 uint32_t dex_shared_data_size, 118 uint32_t quickening_info_size); 119 GetDexSizeDexSectionHeader120 uint32_t GetDexSize() const { return dex_size_; } GetDexSharedDataSizeDexSectionHeader121 uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; } GetQuickeningInfoSizeDexSectionHeader122 uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; } 123 GetDexSectionSizeDexSectionHeader124 size_t GetDexSectionSize() const { 125 return sizeof(DexSectionHeader) + 126 GetDexSize() + 127 GetDexSharedDataSize(); 128 } 129 130 private: 131 uint32_t dex_size_; 132 uint32_t dex_shared_data_size_; 133 uint32_t quickening_info_size_; 134 135 friend class VdexFile; // For updatig quickening_info_size_. 136 }; 137 GetComputedFileSize()138 size_t GetComputedFileSize() const { 139 size_t size = sizeof(VerifierDepsHeader); 140 const VerifierDepsHeader& header = GetVerifierDepsHeader(); 141 size += header.GetVerifierDepsSize(); 142 size += header.GetSizeOfChecksumsSection(); 143 if (header.HasDexSection()) { 144 size += GetDexSectionHeader().GetDexSectionSize(); 145 size += GetDexSectionHeader().GetQuickeningInfoSize(); 146 } 147 return size; 148 } 149 150 // Note: The file is called "primary" to match the naming with profiles. 151 static const constexpr char* kVdexNameInDmFile = "primary.vdex"; 152 153 typedef uint32_t VdexChecksum; 154 using QuickeningTableOffsetType = uint32_t; 155 VdexFile(MemMap * mmap)156 explicit VdexFile(MemMap* mmap) : mmap_(mmap) {} 157 158 // Returns nullptr if the vdex file cannot be opened or is not valid. 159 // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address. 160 static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr, 161 size_t mmap_size, 162 bool mmap_reuse, 163 const std::string& vdex_filename, 164 bool writable, 165 bool low_4gb, 166 bool unquicken, 167 std::string* error_msg); 168 169 // Returns nullptr if the vdex file cannot be opened or is not valid. 170 // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address. 171 static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr, 172 size_t mmap_size, 173 bool mmap_reuse, 174 int file_fd, 175 size_t vdex_length, 176 const std::string& vdex_filename, 177 bool writable, 178 bool low_4gb, 179 bool unquicken, 180 std::string* error_msg); 181 182 // 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)183 static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename, 184 bool writable, 185 bool low_4gb, 186 bool unquicken, 187 std::string* error_msg) { 188 return OpenAtAddress(nullptr, 189 0, 190 false, 191 vdex_filename, 192 writable, 193 low_4gb, 194 unquicken, 195 error_msg); 196 } 197 198 // 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)199 static std::unique_ptr<VdexFile> Open(int file_fd, 200 size_t vdex_length, 201 const std::string& vdex_filename, 202 bool writable, 203 bool low_4gb, 204 bool unquicken, 205 std::string* error_msg) { 206 return OpenAtAddress(nullptr, 207 0, 208 false, 209 file_fd, 210 vdex_length, 211 vdex_filename, 212 writable, 213 low_4gb, 214 unquicken, 215 error_msg); 216 } 217 Begin()218 const uint8_t* Begin() const { return mmap_->Begin(); } End()219 const uint8_t* End() const { return mmap_->End(); } Size()220 size_t Size() const { return mmap_->Size(); } 221 GetVerifierDepsHeader()222 const VerifierDepsHeader& GetVerifierDepsHeader() const { 223 return *reinterpret_cast<const VerifierDepsHeader*>(Begin()); 224 } 225 GetDexSectionHeaderOffset()226 uint32_t GetDexSectionHeaderOffset() const { 227 return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection(); 228 } 229 GetDexSectionHeader()230 const DexSectionHeader& GetDexSectionHeader() const { 231 DCHECK(GetVerifierDepsHeader().HasDexSection()); 232 return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset()); 233 } 234 GetVerifierDepsStart()235 const uint8_t* GetVerifierDepsStart() const { 236 const uint8_t* result = Begin() + GetDexSectionHeaderOffset(); 237 if (GetVerifierDepsHeader().HasDexSection()) { 238 // When there is a dex section, the verifier deps are after it, but before the quickening. 239 return result + GetDexSectionHeader().GetDexSectionSize(); 240 } else { 241 // When there is no dex section, the verifier deps are just after the header. 242 return result; 243 } 244 } 245 GetVerifierDepsData()246 ArrayRef<const uint8_t> GetVerifierDepsData() const { 247 return ArrayRef<const uint8_t>( 248 GetVerifierDepsStart(), 249 GetVerifierDepsHeader().GetVerifierDepsSize()); 250 } 251 GetQuickeningInfo()252 ArrayRef<const uint8_t> GetQuickeningInfo() const { 253 if (GetVerifierDepsHeader().HasDexSection()) { 254 return ArrayRef<const uint8_t>( 255 GetVerifierDepsData().data() + GetVerifierDepsHeader().GetVerifierDepsSize(), 256 GetDexSectionHeader().GetQuickeningInfoSize()); 257 } else { 258 return ArrayRef<const uint8_t>(); 259 } 260 } 261 IsValid()262 bool IsValid() const { 263 return mmap_->Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid(); 264 } 265 266 // This method is for iterating over the dex files in the vdex. If `cursor` is null, 267 // the first dex file is returned. If `cursor` is not null, it must point to a dex 268 // file and this method returns the next dex file if there is one, or null if there 269 // is none. 270 const uint8_t* GetNextDexFileData(const uint8_t* cursor) const; 271 272 // Get the location checksum of the dex file number `dex_file_index`. GetLocationChecksum(uint32_t dex_file_index)273 uint32_t GetLocationChecksum(uint32_t dex_file_index) const { 274 DCHECK_LT(dex_file_index, GetVerifierDepsHeader().GetNumberOfDexFiles()); 275 return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index]; 276 } 277 278 // Open all the dex files contained in this vdex file. 279 bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files, 280 std::string* error_msg); 281 282 // In-place unquicken the given `dex_files` based on `quickening_info`. 283 // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are 284 // decompiled to RETURN_VOID instructions using the slower ClassDataItemIterator 285 // instead of the faster QuickeningInfoIterator. 286 // Always unquickens using the vdex dex files as the source for quicken tables. 287 void Unquicken(const std::vector<const DexFile*>& target_dex_files, 288 bool decompile_return_instruction) const; 289 290 // Fully unquicken `target_dex_file` based on `quickening_info`. 291 void UnquickenDexFile(const DexFile& target_dex_file, 292 const DexFile& source_dex_file, 293 bool decompile_return_instruction) const; 294 295 // Return the quickening info of a given method index (or null if it's empty). 296 ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file, 297 uint32_t dex_method_idx) const; 298 HasDexSection()299 bool HasDexSection() const { 300 return GetVerifierDepsHeader().HasDexSection(); 301 } 302 303 private: 304 uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const; 305 306 // Source dex must be the in the vdex file. 307 void UnquickenDexFile(const DexFile& target_dex_file, 308 const uint8_t* source_dex_begin, 309 bool decompile_return_instruction) const; 310 311 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable( 312 const DexFile& dex_file, 313 const ArrayRef<const uint8_t>& quickening_info) const; 314 315 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable( 316 const uint8_t* source_dex_begin, 317 const ArrayRef<const uint8_t>& quickening_info) const; 318 319 bool ContainsDexFile(const DexFile& dex_file) const; 320 DexBegin()321 const uint8_t* DexBegin() const { 322 DCHECK(HasDexSection()); 323 return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader); 324 } 325 DexEnd()326 const uint8_t* DexEnd() const { 327 DCHECK(HasDexSection()); 328 return DexBegin() + GetDexSectionHeader().GetDexSize(); 329 } 330 331 std::unique_ptr<MemMap> mmap_; 332 333 DISALLOW_COPY_AND_ASSIGN(VdexFile); 334 }; 335 336 } // namespace art 337 338 #endif // ART_RUNTIME_VDEX_FILE_H_ 339