• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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