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
30namespace art {
31
32class 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
59class 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
67    const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
68    const char* GetVerifierDepsVersion() const {
69      return reinterpret_cast<const char*>(verifier_deps_version_);
70    }
71    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;
77    bool IsValid() const {
78      return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid();
79    }
80    bool HasDexSection() const;
81
82    uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
83    uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
84
85    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
120    uint32_t GetDexSize() const { return dex_size_; }
121    uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
122    uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
123
124    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
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
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.
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.
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
218  const uint8_t* Begin() const { return mmap_->Begin(); }
219  const uint8_t* End() const { return mmap_->End(); }
220  size_t Size() const { return mmap_->Size(); }
221
222  const VerifierDepsHeader& GetVerifierDepsHeader() const {
223    return *reinterpret_cast<const VerifierDepsHeader*>(Begin());
224  }
225
226  uint32_t GetDexSectionHeaderOffset() const {
227    return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection();
228  }
229
230  const DexSectionHeader& GetDexSectionHeader() const {
231    DCHECK(GetVerifierDepsHeader().HasDexSection());
232    return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset());
233  }
234
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
246  ArrayRef<const uint8_t> GetVerifierDepsData() const {
247    return ArrayRef<const uint8_t>(
248        GetVerifierDepsStart(),
249        GetVerifierDepsHeader().GetVerifierDepsSize());
250  }
251
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
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`.
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
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
321  const uint8_t* DexBegin() const {
322    DCHECK(HasDexSection());
323    return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader);
324  }
325
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