blob: 102b73fdaec74eec1379618a8450bc271d25686a [file] [log] [blame]
David Brazdil7b49e6c2016-09-01 11:06:18 +01001/*
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
Nicolas Geoffraye70dd562016-10-30 21:03:35 +000023#include "base/array_ref.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010024#include "base/macros.h"
David Sehr79e26072018-04-06 17:58:50 -070025#include "base/mem_map.h"
David Sehrc431b9d2018-03-02 12:01:51 -080026#include "base/os.h"
Mathieu Chartier2daa1342018-02-20 16:19:28 -080027#include "dex/compact_offset_table.h"
David Brazdil35a3f6a2019-03-04 15:59:06 +000028#include "dex/dex_file.h"
Mathieu Chartier210531f2018-01-12 10:15:51 -080029#include "quicken_info.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010030
31namespace art {
32
David Brazdil35a3f6a2019-03-04 15:59:06 +000033class ClassLoaderContext;
34
35namespace verifier {
36class VerifierDeps;
37} // namespace verifier
David Sehrbeca4fe2017-03-30 17:50:24 -070038
David Brazdil7b49e6c2016-09-01 11:06:18 +010039// 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:
Nicolas Geoffray3a293552018-03-02 10:52:16 +000043// VdexFile::VerifierDepsHeader fixed-length header
44// Dex file checksums
David Brazdil7b49e6c2016-09-01 11:06:18 +010045//
Nicolas Geoffray3a293552018-03-02 10:52:16 +000046// 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//
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +000056// VerifierDeps
57// uint8[D][] verification dependencies
Nicolas Geoffray3a293552018-03-02 10:52:16 +000058//
59// Optionally:
60// QuickeningInfo
61// uint8[D][] quickening data
62// uint32[D][] quickening data offset tables
David Brazdil7b49e6c2016-09-01 11:06:18 +010063
64class VdexFile {
65 public:
David Brazdil35a3f6a2019-03-04 15:59:06 +000066 using VdexChecksum = uint32_t;
67 using QuickeningTableOffsetType = uint32_t;
68
Nicolas Geoffray3a293552018-03-02 10:52:16 +000069 struct VerifierDepsHeader {
David Brazdil7b49e6c2016-09-01 11:06:18 +010070 public:
Nicolas Geoffray3a293552018-03-02 10:52:16 +000071 VerifierDepsHeader(uint32_t number_of_dex_files_,
72 uint32_t verifier_deps_size,
David Brazdil35a3f6a2019-03-04 15:59:06 +000073 bool has_dex_section,
74 uint32_t bootclasspath_checksums_size = 0,
75 uint32_t class_loader_context_size = 0);
David Brazdil7b49e6c2016-09-01 11:06:18 +010076
Nicolas Geoffraye70dd562016-10-30 21:03:35 +000077 const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
Nicolas Geoffray3a293552018-03-02 10:52:16 +000078 const char* GetVerifierDepsVersion() const {
79 return reinterpret_cast<const char*>(verifier_deps_version_);
David Brazdil93592f52017-12-08 10:53:27 +000080 }
Nicolas Geoffray3a293552018-03-02 10:52:16 +000081 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;
87 bool IsValid() const {
88 return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid();
89 }
90 bool HasDexSection() const;
91
92 uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
93 uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
David Brazdil35a3f6a2019-03-04 15:59:06 +000094 uint32_t GetBootClassPathChecksumStringSize() const { return bootclasspath_checksums_size_; }
95 uint32_t GetClassLoaderContextStringSize() const { return class_loader_context_size_; }
David Brazdil93592f52017-12-08 10:53:27 +000096
97 size_t GetSizeOfChecksumsSection() const {
98 return sizeof(VdexChecksum) * GetNumberOfDexFiles();
99 }
100
David Brazdil35a3f6a2019-03-04 15:59:06 +0000101 const VdexChecksum* GetDexChecksumsArray() const {
102 return reinterpret_cast<const VdexChecksum*>(
103 reinterpret_cast<const uint8_t*>(this) + sizeof(VerifierDepsHeader));
104 }
105
106 VdexChecksum GetDexChecksumAtOffset(size_t idx) const {
107 DCHECK_LT(idx, GetNumberOfDexFiles());
108 return GetDexChecksumsArray()[idx];
109 }
110
Nicolas Geoffray36930ec2017-05-09 13:23:34 +0100111 static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' };
112
David Brazdil7b49e6c2016-09-01 11:06:18 +0100113 private:
114 static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000115
116 // The format version of the verifier deps header and the verifier deps.
David Brazdil35a3f6a2019-03-04 15:59:06 +0000117 // Last update: Add boot checksum, class loader context.
118 static constexpr uint8_t kVerifierDepsVersion[] = { '0', '2', '1', '\0' };
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000119
120 // The format version of the dex section header and the dex section, containing
121 // both the dex code and the quickening data.
Mathieu Chartierc17b7d82018-03-14 14:00:04 -0700122 // Last update: Add owned section for CompactDex.
123 static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '2', '\0' };
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000124
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' };
David Brazdil7b49e6c2016-09-01 11:06:18 +0100128
129 uint8_t magic_[4];
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000130 uint8_t verifier_deps_version_[4];
131 uint8_t dex_section_version_[4];
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000132 uint32_t number_of_dex_files_;
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000133 uint32_t verifier_deps_size_;
David Brazdil35a3f6a2019-03-04 15:59:06 +0000134 uint32_t bootclasspath_checksums_size_;
135 uint32_t class_loader_context_size_;
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000136 };
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
144 uint32_t GetDexSize() const { return dex_size_; }
145 uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
146 uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
147
148 size_t GetDexSectionSize() const {
149 return sizeof(DexSectionHeader) +
150 GetDexSize() +
151 GetDexSharedDataSize();
152 }
153
154 private:
David Brazdil5d5a36b2016-09-14 15:34:10 +0100155 uint32_t dex_size_;
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -0800156 uint32_t dex_shared_data_size_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100157 uint32_t quickening_info_size_;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100158
David Brazdil35a3f6a2019-03-04 15:59:06 +0000159 friend class VdexFile; // For updating quickening_info_size_.
David Brazdil7b49e6c2016-09-01 11:06:18 +0100160 };
161
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000162 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 }
David Brazdil35a3f6a2019-03-04 15:59:06 +0000171 size += header.GetBootClassPathChecksumStringSize();
172 size += header.GetClassLoaderContextStringSize();
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000173 return size;
174 }
175
Nicolas Geoffraybaeaa9b2018-01-26 14:31:17 +0000176 // Note: The file is called "primary" to match the naming with profiles.
177 static const constexpr char* kVdexNameInDmFile = "primary.vdex";
178
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100179 explicit VdexFile(MemMap&& mmap) : mmap_(std::move(mmap)) {}
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300180
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000181 // Returns nullptr if the vdex file cannot be opened or is not valid.
David Srbeckyec2cdf42017-12-08 16:21:25 +0000182 // 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.
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000206 static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
207 bool writable,
208 bool low_4gb,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100209 bool unquicken,
David Srbeckyec2cdf42017-12-08 16:21:25 +0000210 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 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100220
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000221 // Returns nullptr if the vdex file cannot be opened or is not valid.
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,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100227 bool unquicken,
David Srbeckyec2cdf42017-12-08 16:21:25 +0000228 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 }
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000240
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100241 const uint8_t* Begin() const { return mmap_.Begin(); }
242 const uint8_t* End() const { return mmap_.End(); }
243 size_t Size() const { return mmap_.Size(); }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100244
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000245 const VerifierDepsHeader& GetVerifierDepsHeader() const {
246 return *reinterpret_cast<const VerifierDepsHeader*>(Begin());
247 }
248
249 uint32_t GetDexSectionHeaderOffset() const {
250 return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection();
251 }
252
253 const DexSectionHeader& GetDexSectionHeader() const {
254 DCHECK(GetVerifierDepsHeader().HasDexSection());
255 return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset());
256 }
257
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 }
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000267 }
268
269 ArrayRef<const uint8_t> GetVerifierDepsData() const {
270 return ArrayRef<const uint8_t>(
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000271 GetVerifierDepsStart(),
272 GetVerifierDepsHeader().GetVerifierDepsSize());
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000273 }
274
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000275 ArrayRef<const uint8_t> GetQuickeningInfo() const {
David Brazdil35a3f6a2019-03-04 15:59:06 +0000276 return ArrayRef<const uint8_t>(
277 GetVerifierDepsData().end(),
278 GetVerifierDepsHeader().HasDexSection()
279 ? GetDexSectionHeader().GetQuickeningInfoSize() : 0);
280 }
281
282 ArrayRef<const uint8_t> GetBootClassPathChecksumData() const {
283 return ArrayRef<const uint8_t>(
284 GetQuickeningInfo().end(),
285 GetVerifierDepsHeader().GetBootClassPathChecksumStringSize());
286 }
287
288 ArrayRef<const uint8_t> GetClassLoaderContextData() const {
289 return ArrayRef<const uint8_t>(
290 GetBootClassPathChecksumData().end(),
291 GetVerifierDepsHeader().GetClassLoaderContextStringSize());
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000292 }
293
294 bool IsValid() const {
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100295 return mmap_.Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid();
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000296 }
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
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000304 // Get the location checksum of the dex file number `dex_file_index`.
305 uint32_t GetLocationChecksum(uint32_t dex_file_index) const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000306 DCHECK_LT(dex_file_index, GetVerifierDepsHeader().GetNumberOfDexFiles());
307 return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index];
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000308 }
309
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100310 // Open all the dex files contained in this vdex file.
David Sehrbeca4fe2017-03-30 17:50:24 -0700311 bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
312 std::string* error_msg);
313
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100314 // In-place unquicken the given `dex_files` based on `quickening_info`.
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300315 // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -0700316 // decompiled to RETURN_VOID instructions using the slower ClassAccessor instead of the faster
317 // QuickeningInfoIterator.
Mathieu Chartier210531f2018-01-12 10:15:51 -0800318 // 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;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100321
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +0000322 // Fully unquicken `target_dex_file` based on `quickening_info`.
Mathieu Chartier210531f2018-01-12 10:15:51 -0800323 void UnquickenDexFile(const DexFile& target_dex_file,
324 const DexFile& source_dex_file,
325 bool decompile_return_instruction) const;
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100326
Mathieu Chartier210531f2018-01-12 10:15:51 -0800327 // 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;
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +0000330
Nicolas Geoffraybc177272018-01-24 14:55:32 +0000331 bool HasDexSection() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000332 return GetVerifierDepsHeader().HasDexSection();
Nicolas Geoffraybc177272018-01-24 14:55:32 +0000333 }
334
David Brazdil35a3f6a2019-03-04 15:59:06 +0000335 // 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
David Brazdil7126c5b2019-03-05 00:02:51 +0000345 // 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
David Brazdil7b49e6c2016-09-01 11:06:18 +0100357 private:
Mathieu Chartier210531f2018-01-12 10:15:51 -0800358 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
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800365 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
Mathieu Chartier210531f2018-01-12 10:15:51 -0800366 const DexFile& dex_file,
367 const ArrayRef<const uint8_t>& quickening_info) const;
368
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800369 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
Mathieu Chartier210531f2018-01-12 10:15:51 -0800370 const uint8_t* source_dex_begin,
Mathieu Chartier210531f2018-01-12 10:15:51 -0800371 const ArrayRef<const uint8_t>& quickening_info) const;
372
Mathieu Chartier210531f2018-01-12 10:15:51 -0800373 bool ContainsDexFile(const DexFile& dex_file) const;
374
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000375 const uint8_t* DexBegin() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000376 DCHECK(HasDexSection());
377 return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader);
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000378 }
379
380 const uint8_t* DexEnd() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000381 DCHECK(HasDexSection());
382 return DexBegin() + GetDexSectionHeader().GetDexSize();
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000383 }
384
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100385 MemMap mmap_;
David Brazdil7b49e6c2016-09-01 11:06:18 +0100386
387 DISALLOW_COPY_AND_ASSIGN(VdexFile);
388};
389
390} // namespace art
391
392#endif // ART_RUNTIME_VDEX_FILE_H_