blob: 72f03f266a8945820bd7139b60c435155d19cadb [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:
38// VdexFile::Header fixed-length header
39//
Mathieu Chartier210531f2018-01-12 10:15:51 -080040// quicken_table_off[0] offset into QuickeningInfo section for offset table for DEX[0].
41// DEX[0] array of the input DEX files, the bytecode may have been quickened.
42// quicken_table_off[1]
43// DEX[1]
David Brazdil7b49e6c2016-09-01 11:06:18 +010044// ...
45// DEX[D]
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +000046// VerifierDeps
47// uint8[D][] verification dependencies
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +010048// QuickeningInfo
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +000049// uint8[D][] quickening data
Mathieu Chartier210531f2018-01-12 10:15:51 -080050// uint32[D][] quickening data offset tables
David Brazdil7b49e6c2016-09-01 11:06:18 +010051
52class VdexFile {
53 public:
54 struct Header {
55 public:
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +000056 Header(uint32_t number_of_dex_files_,
57 uint32_t dex_size,
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -080058 uint32_t dex_shared_data_size,
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +000059 uint32_t verifier_deps_size,
60 uint32_t quickening_info_size);
David Brazdil7b49e6c2016-09-01 11:06:18 +010061
Nicolas Geoffraye70dd562016-10-30 21:03:35 +000062 const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
63 const char* GetVersion() const { return reinterpret_cast<const char*>(version_); }
David Brazdil7b49e6c2016-09-01 11:06:18 +010064 bool IsMagicValid() const;
65 bool IsVersionValid() const;
Nicolas Geoffraye70dd562016-10-30 21:03:35 +000066 bool IsValid() const { return IsMagicValid() && IsVersionValid(); }
David Brazdil7b49e6c2016-09-01 11:06:18 +010067
David Brazdil5d5a36b2016-09-14 15:34:10 +010068 uint32_t GetDexSize() const { return dex_size_; }
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -080069 uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
David Brazdil5d5a36b2016-09-14 15:34:10 +010070 uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
Nicolas Geoffray4acefd32016-10-24 13:14:58 +010071 uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +000072 uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
David Brazdil5d5a36b2016-09-14 15:34:10 +010073
David Brazdil93592f52017-12-08 10:53:27 +000074 size_t GetComputedFileSize() const {
75 return sizeof(Header) +
76 GetSizeOfChecksumsSection() +
77 GetDexSize() +
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -080078 GetDexSharedDataSize() +
David Brazdil93592f52017-12-08 10:53:27 +000079 GetVerifierDepsSize() +
80 GetQuickeningInfoSize();
81 }
82
83 size_t GetSizeOfChecksumsSection() const {
84 return sizeof(VdexChecksum) * GetNumberOfDexFiles();
85 }
86
Nicolas Geoffray36930ec2017-05-09 13:23:34 +010087 static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' };
88
David Brazdil7b49e6c2016-09-01 11:06:18 +010089 private:
90 static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
Mathieu Chartier20b2ce42018-02-22 12:52:03 -080091 // Last update: Change quickening info table format.
92 static constexpr uint8_t kVdexVersion[] = { '0', '1', '8', '\0' };
David Brazdil7b49e6c2016-09-01 11:06:18 +010093
94 uint8_t magic_[4];
95 uint8_t version_[4];
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +000096 uint32_t number_of_dex_files_;
David Brazdil5d5a36b2016-09-14 15:34:10 +010097 uint32_t dex_size_;
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -080098 uint32_t dex_shared_data_size_;
David Brazdil5d5a36b2016-09-14 15:34:10 +010099 uint32_t verifier_deps_size_;
Nicolas Geoffray4acefd32016-10-24 13:14:58 +0100100 uint32_t quickening_info_size_;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100101
102 friend class VdexFile;
David Brazdil7b49e6c2016-09-01 11:06:18 +0100103 };
104
Nicolas Geoffraybaeaa9b2018-01-26 14:31:17 +0000105 // Note: The file is called "primary" to match the naming with profiles.
106 static const constexpr char* kVdexNameInDmFile = "primary.vdex";
107
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000108 typedef uint32_t VdexChecksum;
Mathieu Chartier210531f2018-01-12 10:15:51 -0800109 using QuickeningTableOffsetType = uint32_t;
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000110
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300111 explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
112
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000113 // Returns nullptr if the vdex file cannot be opened or is not valid.
David Srbeckyec2cdf42017-12-08 16:21:25 +0000114 // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
115 static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
116 size_t mmap_size,
117 bool mmap_reuse,
118 const std::string& vdex_filename,
119 bool writable,
120 bool low_4gb,
121 bool unquicken,
122 std::string* error_msg);
123
124 // Returns nullptr if the vdex file cannot be opened or is not valid.
125 // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
126 static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
127 size_t mmap_size,
128 bool mmap_reuse,
129 int file_fd,
130 size_t vdex_length,
131 const std::string& vdex_filename,
132 bool writable,
133 bool low_4gb,
134 bool unquicken,
135 std::string* error_msg);
136
137 // Returns nullptr if the vdex file cannot be opened or is not valid.
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000138 static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
139 bool writable,
140 bool low_4gb,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100141 bool unquicken,
David Srbeckyec2cdf42017-12-08 16:21:25 +0000142 std::string* error_msg) {
143 return OpenAtAddress(nullptr,
144 0,
145 false,
146 vdex_filename,
147 writable,
148 low_4gb,
149 unquicken,
150 error_msg);
151 }
David Brazdil7b49e6c2016-09-01 11:06:18 +0100152
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000153 // Returns nullptr if the vdex file cannot be opened or is not valid.
154 static std::unique_ptr<VdexFile> Open(int file_fd,
155 size_t vdex_length,
156 const std::string& vdex_filename,
157 bool writable,
158 bool low_4gb,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100159 bool unquicken,
David Srbeckyec2cdf42017-12-08 16:21:25 +0000160 std::string* error_msg) {
161 return OpenAtAddress(nullptr,
162 0,
163 false,
164 file_fd,
165 vdex_length,
166 vdex_filename,
167 writable,
168 low_4gb,
169 unquicken,
170 error_msg);
171 }
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000172
David Brazdil7b49e6c2016-09-01 11:06:18 +0100173 const uint8_t* Begin() const { return mmap_->Begin(); }
174 const uint8_t* End() const { return mmap_->End(); }
175 size_t Size() const { return mmap_->Size(); }
176
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000177 const Header& GetHeader() const {
178 return *reinterpret_cast<const Header*>(Begin());
179 }
180
181 ArrayRef<const uint8_t> GetVerifierDepsData() const {
182 return ArrayRef<const uint8_t>(
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -0800183 DexBegin() + GetHeader().GetDexSize() + GetHeader().GetDexSharedDataSize(),
184 GetHeader().GetVerifierDepsSize());
Nicolas Geoffraye70dd562016-10-30 21:03:35 +0000185 }
186
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000187 ArrayRef<const uint8_t> GetQuickeningInfo() const {
188 return ArrayRef<const uint8_t>(
189 GetVerifierDepsData().data() + GetHeader().GetVerifierDepsSize(),
190 GetHeader().GetQuickeningInfoSize());
191 }
192
193 bool IsValid() const {
194 return mmap_->Size() >= sizeof(Header) && GetHeader().IsValid();
195 }
196
197 // This method is for iterating over the dex files in the vdex. If `cursor` is null,
198 // the first dex file is returned. If `cursor` is not null, it must point to a dex
199 // file and this method returns the next dex file if there is one, or null if there
200 // is none.
201 const uint8_t* GetNextDexFileData(const uint8_t* cursor) const;
202
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000203 // Get the location checksum of the dex file number `dex_file_index`.
204 uint32_t GetLocationChecksum(uint32_t dex_file_index) const {
205 DCHECK_LT(dex_file_index, GetHeader().GetNumberOfDexFiles());
206 return reinterpret_cast<const uint32_t*>(Begin() + sizeof(Header))[dex_file_index];
207 }
208
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100209 // Open all the dex files contained in this vdex file.
David Sehrbeca4fe2017-03-30 17:50:24 -0700210 bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
211 std::string* error_msg);
212
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100213 // In-place unquicken the given `dex_files` based on `quickening_info`.
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300214 // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
215 // decompiled to RETURN_VOID instructions using the slower ClassDataItemIterator
216 // instead of the faster QuickeningInfoIterator.
Mathieu Chartier210531f2018-01-12 10:15:51 -0800217 // Always unquickens using the vdex dex files as the source for quicken tables.
218 void Unquicken(const std::vector<const DexFile*>& target_dex_files,
219 bool decompile_return_instruction) const;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100220
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +0000221 // Fully unquicken `target_dex_file` based on `quickening_info`.
Mathieu Chartier210531f2018-01-12 10:15:51 -0800222 void UnquickenDexFile(const DexFile& target_dex_file,
223 const DexFile& source_dex_file,
224 bool decompile_return_instruction) const;
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100225
Mathieu Chartier210531f2018-01-12 10:15:51 -0800226 // Return the quickening info of a given method index (or null if it's empty).
227 ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file,
228 uint32_t dex_method_idx) const;
Nicolas Geoffrayb4c6acb2017-11-10 12:48:14 +0000229
Nicolas Geoffraybc177272018-01-24 14:55:32 +0000230 bool HasDexSection() const {
231 return GetHeader().GetDexSize() != 0;
232 }
233
David Brazdil7b49e6c2016-09-01 11:06:18 +0100234 private:
Mathieu Chartier210531f2018-01-12 10:15:51 -0800235 uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const;
236
237 // Source dex must be the in the vdex file.
238 void UnquickenDexFile(const DexFile& target_dex_file,
239 const uint8_t* source_dex_begin,
240 bool decompile_return_instruction) const;
241
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800242 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
Mathieu Chartier210531f2018-01-12 10:15:51 -0800243 const DexFile& dex_file,
244 const ArrayRef<const uint8_t>& quickening_info) const;
245
Mathieu Chartier2daa1342018-02-20 16:19:28 -0800246 CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
Mathieu Chartier210531f2018-01-12 10:15:51 -0800247 const uint8_t* source_dex_begin,
Mathieu Chartier210531f2018-01-12 10:15:51 -0800248 const ArrayRef<const uint8_t>& quickening_info) const;
249
Mathieu Chartier210531f2018-01-12 10:15:51 -0800250 bool ContainsDexFile(const DexFile& dex_file) const;
251
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000252 const uint8_t* DexBegin() const {
David Brazdil93592f52017-12-08 10:53:27 +0000253 return Begin() + sizeof(Header) + GetHeader().GetSizeOfChecksumsSection();
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000254 }
255
256 const uint8_t* DexEnd() const {
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +0000257 return DexBegin() + GetHeader().GetDexSize();
258 }
259
David Brazdil7b49e6c2016-09-01 11:06:18 +0100260 std::unique_ptr<MemMap> mmap_;
261
262 DISALLOW_COPY_AND_ASSIGN(VdexFile);
263};
264
265} // namespace art
266
267#endif // ART_RUNTIME_VDEX_FILE_H_