blob: 77e1f2ccfed204ed8ea63ae850c250ff20a7bd9a [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 Sehrc431b9d2018-03-02 12:01:51 -080025#include "base/os.h"
Mathieu Chartier2daa1342018-02-20 16:19:28 -080026#include "dex/compact_offset_table.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010027#include "mem_map.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.
100 static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '1', '\0' };
101
102 // If the .vdex file has no dex section (hence no dex code nor quickening data),
103 // we encode this magic version.
104 static constexpr uint8_t kDexSectionVersionEmpty[] = { '0', '0', '0', '\0' };
David Brazdil7b49e6c2016-09-01 11:06:18 +0100105
106 uint8_t magic_[4];
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000107 uint8_t verifier_deps_version_[4];
108 uint8_t dex_section_version_[4];
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000109 uint32_t number_of_dex_files_;
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000110 uint32_t verifier_deps_size_;
111 };
112
113 struct DexSectionHeader {
114 public:
115 DexSectionHeader(uint32_t dex_size,
116 uint32_t dex_shared_data_size,
117 uint32_t quickening_info_size);
118
119 uint32_t GetDexSize() const { return dex_size_; }
120 uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
121 uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
122
123 size_t GetDexSectionSize() const {
124 return sizeof(DexSectionHeader) +
125 GetDexSize() +
126 GetDexSharedDataSize();
127 }
128
129 private:
David Brazdil5d5a36b2016-09-14 15:34:10 +0100130 uint32_t dex_size_;
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -0800131 uint32_t dex_shared_data_size_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100132 uint32_t quickening_info_size_;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100133
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000134 friend class VdexFile; // For updatig quickening_info_size_.
David Brazdil7b49e6c2016-09-01 11:06:18 +0100135 };
136
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000137 size_t GetComputedFileSize() const {
138 size_t size = sizeof(VerifierDepsHeader);
139 const VerifierDepsHeader& header = GetVerifierDepsHeader();
140 size += header.GetVerifierDepsSize();
141 size += header.GetSizeOfChecksumsSection();
142 if (header.HasDexSection()) {
143 size += GetDexSectionHeader().GetDexSectionSize();
144 size += GetDexSectionHeader().GetQuickeningInfoSize();
145 }
146 return size;
147 }
148
Nicolas Geoffraybaeaa9b2018-01-26 14:31:17 +0000149 // Note: The file is called "primary" to match the naming with profiles.
150 static const constexpr char* kVdexNameInDmFile = "primary.vdex";
151
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000152 typedef uint32_t VdexChecksum;
Mathieu Chartier210531f2018-01-12 10:15:51 -0800153 using QuickeningTableOffsetType = uint32_t;
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000154
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300155 explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
156
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000157 // Returns nullptr if the vdex file cannot be opened or is not valid.
David Srbeckyec2cdf42017-12-08 16:21:25 +0000158 // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
159 static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
160 size_t mmap_size,
161 bool mmap_reuse,
162 const std::string& vdex_filename,
163 bool writable,
164 bool low_4gb,
165 bool unquicken,
166 std::string* error_msg);
167
168 // Returns nullptr if the vdex file cannot be opened or is not valid.
169 // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
170 static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
171 size_t mmap_size,
172 bool mmap_reuse,
173 int file_fd,
174 size_t vdex_length,
175 const std::string& vdex_filename,
176 bool writable,
177 bool low_4gb,
178 bool unquicken,
179 std::string* error_msg);
180
181 // Returns nullptr if the vdex file cannot be opened or is not valid.
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000182 static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
183 bool writable,
184 bool low_4gb,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100185 bool unquicken,
David Srbeckyec2cdf42017-12-08 16:21:25 +0000186 std::string* error_msg) {
187 return OpenAtAddress(nullptr,
188 0,
189 false,
190 vdex_filename,
191 writable,
192 low_4gb,
193 unquicken,
194 error_msg);
195 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100196
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000197 // Returns nullptr if the vdex file cannot be opened or is not valid.
198 static std::unique_ptr<VdexFile> Open(int file_fd,
199 size_t vdex_length,
200 const std::string& vdex_filename,
201 bool writable,
202 bool low_4gb,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100203 bool unquicken,
David Srbeckyec2cdf42017-12-08 16:21:25 +0000204 std::string* error_msg) {
205 return OpenAtAddress(nullptr,
206 0,
207 false,
208 file_fd,
209 vdex_length,
210 vdex_filename,
211 writable,
212 low_4gb,
213 unquicken,
214 error_msg);
215 }
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000216
David Brazdil7b49e6c2016-09-01 11:06:18 +0100217 const uint8_t* Begin() const { return mmap_->Begin(); }
218 const uint8_t* End() const { return mmap_->End(); }
219 size_t Size() const { return mmap_->Size(); }
220
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000221 const VerifierDepsHeader& GetVerifierDepsHeader() const {
222 return *reinterpret_cast<const VerifierDepsHeader*>(Begin());
223 }
224
225 uint32_t GetDexSectionHeaderOffset() const {
226 return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection();
227 }
228
229 const DexSectionHeader& GetDexSectionHeader() const {
230 DCHECK(GetVerifierDepsHeader().HasDexSection());
231 return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset());
232 }
233
234 const uint8_t* GetVerifierDepsStart() const {
235 const uint8_t* result = Begin() + GetDexSectionHeaderOffset();
236 if (GetVerifierDepsHeader().HasDexSection()) {
237 // When there is a dex section, the verifier deps are after it, but before the quickening.
238 return result + GetDexSectionHeader().GetDexSectionSize();
239 } else {
240 // When there is no dex section, the verifier deps are just after the header.
241 return result;
242 }
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000243 }
244
245 ArrayRef<const uint8_t> GetVerifierDepsData() const {
246 return ArrayRef<const uint8_t>(
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000247 GetVerifierDepsStart(),
248 GetVerifierDepsHeader().GetVerifierDepsSize());
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000249 }
250
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000251 ArrayRef<const uint8_t> GetQuickeningInfo() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000252 if (GetVerifierDepsHeader().HasDexSection()) {
253 return ArrayRef<const uint8_t>(
254 GetVerifierDepsData().data() + GetVerifierDepsHeader().GetVerifierDepsSize(),
255 GetDexSectionHeader().GetQuickeningInfoSize());
256 } else {
257 return ArrayRef<const uint8_t>();
258 }
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000259 }
260
261 bool IsValid() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000262 return mmap_->Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid();
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000263 }
264
265 // This method is for iterating over the dex files in the vdex. If `cursor` is null,
266 // the first dex file is returned. If `cursor` is not null, it must point to a dex
267 // file and this method returns the next dex file if there is one, or null if there
268 // is none.
269 const uint8_t* GetNextDexFileData(const uint8_t* cursor) const;
270
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000271 // Get the location checksum of the dex file number `dex_file_index`.
272 uint32_t GetLocationChecksum(uint32_t dex_file_index) const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000273 DCHECK_LT(dex_file_index, GetVerifierDepsHeader().GetNumberOfDexFiles());
274 return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index];
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000275 }
276
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100277 // Open all the dex files contained in this vdex file.
David Sehrbeca4fe2017-03-30 17:50:24 -0700278 bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
279 std::string* error_msg);
280
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100281 // In-place unquicken the given `dex_files` based on `quickening_info`.
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300282 // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
283 // decompiled to RETURN_VOID instructions using the slower ClassDataItemIterator
284 // instead of the faster QuickeningInfoIterator.
Mathieu Chartier210531f2018-01-12 10:15:51 -0800285 // Always unquickens using the vdex dex files as the source for quicken tables.
286 void Unquicken(const std::vector<const DexFile*>& target_dex_files,
287 bool decompile_return_instruction) const;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100288
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +0000289 // Fully unquicken `target_dex_file` based on `quickening_info`.
Mathieu Chartier210531f2018-01-12 10:15:51 -0800290 void UnquickenDexFile(const DexFile& target_dex_file,
291 const DexFile& source_dex_file,
292 bool decompile_return_instruction) const;
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100293
Mathieu Chartier210531f2018-01-12 10:15:51 -0800294 // Return the quickening info of a given method index (or null if it's empty).
295 ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file,
296 uint32_t dex_method_idx) const;
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +0000297
Nicolas Geoffraybc177272018-01-24 14:55:32 +0000298 bool HasDexSection() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000299 return GetVerifierDepsHeader().HasDexSection();
Nicolas Geoffraybc177272018-01-24 14:55:32 +0000300 }
301
David Brazdil7b49e6c2016-09-01 11:06:18 +0100302 private:
Mathieu Chartier210531f2018-01-12 10:15:51 -0800303 uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const;
304
305 // Source dex must be the in the vdex file.
306 void UnquickenDexFile(const DexFile& target_dex_file,
307 const uint8_t* source_dex_begin,
308 bool decompile_return_instruction) const;
309
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800310 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
Mathieu Chartier210531f2018-01-12 10:15:51 -0800311 const DexFile& dex_file,
312 const ArrayRef<const uint8_t>& quickening_info) const;
313
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800314 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
Mathieu Chartier210531f2018-01-12 10:15:51 -0800315 const uint8_t* source_dex_begin,
Mathieu Chartier210531f2018-01-12 10:15:51 -0800316 const ArrayRef<const uint8_t>& quickening_info) const;
317
Mathieu Chartier210531f2018-01-12 10:15:51 -0800318 bool ContainsDexFile(const DexFile& dex_file) const;
319
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000320 const uint8_t* DexBegin() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000321 DCHECK(HasDexSection());
322 return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader);
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000323 }
324
325 const uint8_t* DexEnd() const {
Nicolas Geoffray3a293552018-03-02 10:52:16 +0000326 DCHECK(HasDexSection());
327 return DexBegin() + GetDexSectionHeader().GetDexSize();
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000328 }
329
David Brazdil7b49e6c2016-09-01 11:06:18 +0100330 std::unique_ptr<MemMap> mmap_;
331
332 DISALLOW_COPY_AND_ASSIGN(VdexFile);
333};
334
335} // namespace art
336
337#endif // ART_RUNTIME_VDEX_FILE_H_