blob: a39ec3128f473f68ec059468599884bd4c3e0416 [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"
Mathieu Chartier210531f2018-01-12 10:15:51 -080028#include "quicken_info.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010029
30namespace art {
31
David Sehrbeca4fe2017-03-30 17:50:24 -070032class DexFile;
33
David Brazdil7b49e6c2016-09-01 11:06:18 +010034// 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:
Nicolas Geoffray3a293552018-03-02 10:52:16 +000038// VdexFile::VerifierDepsHeader fixed-length header
39// Dex file checksums
David Brazdil7b49e6c2016-09-01 11:06:18 +010040//
Nicolas Geoffray3a293552018-03-02 10:52:16 +000041// 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//
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +000051// VerifierDeps
52// uint8[D][] verification dependencies
Nicolas Geoffray3a293552018-03-02 10:52:16 +000053//
54// Optionally:
55// QuickeningInfo
56// uint8[D][] quickening data
57// uint32[D][] quickening data offset tables
David Brazdil7b49e6c2016-09-01 11:06:18 +010058
59class VdexFile {
60 public:
Nicolas Geoffray3a293552018-03-02 10:52:16 +000061 struct VerifierDepsHeader {
David Brazdil7b49e6c2016-09-01 11:06:18 +010062 public:
Nicolas Geoffray3a293552018-03-02 10:52:16 +000063 VerifierDepsHeader(uint32_t number_of_dex_files_,
64 uint32_t verifier_deps_size,
65 bool has_dex_section);
David Brazdil7b49e6c2016-09-01 11:06:18 +010066
Nicolas Geoffraye70dd562016-10-30 21:03:35 +000067 const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
Nicolas Geoffray3a293552018-03-02 10:52:16 +000068 const char* GetVerifierDepsVersion() const {
69 return reinterpret_cast<const char*>(verifier_deps_version_);
David Brazdil93592f52017-12-08 10:53:27 +000070 }
Nicolas Geoffray3a293552018-03-02 10:52:16 +000071 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_; }
David Brazdil93592f52017-12-08 10:53:27 +000084
85 size_t GetSizeOfChecksumsSection() const {
86 return sizeof(VdexChecksum) * GetNumberOfDexFiles();
87 }
88
Nicolas Geoffray36930ec2017-05-09 13:23:34 +010089 static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' };
90
David Brazdil7b49e6c2016-09-01 11:06:18 +010091 private:
92 static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
Nicolas Geoffray3a293552018-03-02 10:52:16 +000093
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.
Mathieu Chartierc17b7d82018-03-14 14:00:04 -0700100 // Last update: Add owned section for CompactDex.
101 static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '2', '\0' };
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000102
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' };
David Brazdil7b49e6c2016-09-01 11:06:18 +0100106
107 uint8_t magic_[4];
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000108 uint8_t verifier_deps_version_[4];
109 uint8_t dex_section_version_[4];
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000110 uint32_t number_of_dex_files_;
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000111 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:
David Brazdil5d5a36b2016-09-14 15:34:10 +0100131 uint32_t dex_size_;
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -0800132 uint32_t dex_shared_data_size_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100133 uint32_t quickening_info_size_;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100134
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000135 friend class VdexFile; // For updatig quickening_info_size_.
David Brazdil7b49e6c2016-09-01 11:06:18 +0100136 };
137
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000138 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
Nicolas Geoffraybaeaa9b2018-01-26 14:31:17 +0000150 // Note: The file is called "primary" to match the naming with profiles.
151 static const constexpr char* kVdexNameInDmFile = "primary.vdex";
152
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000153 typedef uint32_t VdexChecksum;
Mathieu Chartier210531f2018-01-12 10:15:51 -0800154 using QuickeningTableOffsetType = uint32_t;
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000155
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100156 explicit VdexFile(MemMap&& mmap) : mmap_(std::move(mmap)) {}
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300157
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000158 // Returns nullptr if the vdex file cannot be opened or is not valid.
David Srbeckyec2cdf42017-12-08 16:21:25 +0000159 // 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.
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000183 static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
184 bool writable,
185 bool low_4gb,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100186 bool unquicken,
David Srbeckyec2cdf42017-12-08 16:21:25 +0000187 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 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100197
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000198 // 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,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100204 bool unquicken,
David Srbeckyec2cdf42017-12-08 16:21:25 +0000205 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 }
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000217
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100218 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(); }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100221
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000222 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 }
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000244 }
245
246 ArrayRef<const uint8_t> GetVerifierDepsData() const {
247 return ArrayRef<const uint8_t>(
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000248 GetVerifierDepsStart(),
249 GetVerifierDepsHeader().GetVerifierDepsSize());
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000250 }
251
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000252 ArrayRef<const uint8_t> GetQuickeningInfo() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000253 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 }
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000260 }
261
262 bool IsValid() const {
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100263 return mmap_.Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid();
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000264 }
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
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000272 // Get the location checksum of the dex file number `dex_file_index`.
273 uint32_t GetLocationChecksum(uint32_t dex_file_index) const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000274 DCHECK_LT(dex_file_index, GetVerifierDepsHeader().GetNumberOfDexFiles());
275 return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index];
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000276 }
277
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100278 // Open all the dex files contained in this vdex file.
David Sehrbeca4fe2017-03-30 17:50:24 -0700279 bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
280 std::string* error_msg);
281
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100282 // In-place unquicken the given `dex_files` based on `quickening_info`.
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300283 // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -0700284 // decompiled to RETURN_VOID instructions using the slower ClassAccessor instead of the faster
285 // QuickeningInfoIterator.
Mathieu Chartier210531f2018-01-12 10:15:51 -0800286 // 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;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100289
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +0000290 // Fully unquicken `target_dex_file` based on `quickening_info`.
Mathieu Chartier210531f2018-01-12 10:15:51 -0800291 void UnquickenDexFile(const DexFile& target_dex_file,
292 const DexFile& source_dex_file,
293 bool decompile_return_instruction) const;
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100294
Mathieu Chartier210531f2018-01-12 10:15:51 -0800295 // 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;
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +0000298
Nicolas Geoffraybc177272018-01-24 14:55:32 +0000299 bool HasDexSection() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000300 return GetVerifierDepsHeader().HasDexSection();
Nicolas Geoffraybc177272018-01-24 14:55:32 +0000301 }
302
David Brazdil7b49e6c2016-09-01 11:06:18 +0100303 private:
Mathieu Chartier210531f2018-01-12 10:15:51 -0800304 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
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800311 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
Mathieu Chartier210531f2018-01-12 10:15:51 -0800312 const DexFile& dex_file,
313 const ArrayRef<const uint8_t>& quickening_info) const;
314
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800315 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
Mathieu Chartier210531f2018-01-12 10:15:51 -0800316 const uint8_t* source_dex_begin,
Mathieu Chartier210531f2018-01-12 10:15:51 -0800317 const ArrayRef<const uint8_t>& quickening_info) const;
318
Mathieu Chartier210531f2018-01-12 10:15:51 -0800319 bool ContainsDexFile(const DexFile& dex_file) const;
320
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000321 const uint8_t* DexBegin() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000322 DCHECK(HasDexSection());
323 return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader);
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000324 }
325
326 const uint8_t* DexEnd() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000327 DCHECK(HasDexSection());
328 return DexBegin() + GetDexSectionHeader().GetDexSize();
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000329 }
330
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100331 MemMap mmap_;
David Brazdil7b49e6c2016-09-01 11:06:18 +0100332
333 DISALLOW_COPY_AND_ASSIGN(VdexFile);
334};
335
336} // namespace art
337
338#endif // ART_RUNTIME_VDEX_FILE_H_