blob: 955098d8c2cbf934a0e07a171cffa098f4c42789 [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#include "vdex_file.h"
18
Andreas Gampe0dfc3152017-04-24 07:58:06 -070019#include <sys/mman.h> // For the PROT_* and MAP_* constants.
20
David Brazdil7b49e6c2016-09-01 11:06:18 +010021#include <memory>
22
Nicolas Geoffray28453cf2017-08-10 15:30:26 +010023#include "base/bit_utils.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010024#include "base/logging.h"
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +010025#include "base/stl_util.h"
Andreas Gampef7e82232016-09-12 15:55:56 -070026#include "base/unix_file/fd_file.h"
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +000027#include "dex_file.h"
Mathieu Chartier79c87da2017-10-10 11:54:29 -070028#include "dex_file_loader.h"
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +010029#include "dex_to_dex_decompiler.h"
David Brazdil7b49e6c2016-09-01 11:06:18 +010030
31namespace art {
32
Nicolas Geoffray36930ec2017-05-09 13:23:34 +010033constexpr uint8_t VdexFile::Header::kVdexInvalidMagic[4];
David Brazdil7b49e6c2016-09-01 11:06:18 +010034constexpr uint8_t VdexFile::Header::kVdexMagic[4];
35constexpr uint8_t VdexFile::Header::kVdexVersion[4];
36
37bool VdexFile::Header::IsMagicValid() const {
38 return (memcmp(magic_, kVdexMagic, sizeof(kVdexMagic)) == 0);
39}
40
41bool VdexFile::Header::IsVersionValid() const {
42 return (memcmp(version_, kVdexVersion, sizeof(kVdexVersion)) == 0);
43}
44
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +000045VdexFile::Header::Header(uint32_t number_of_dex_files,
46 uint32_t dex_size,
Nicolas Geoffray4acefd32016-10-24 13:14:58 +010047 uint32_t verifier_deps_size,
48 uint32_t quickening_info_size)
Nicolas Geoffrayf54e5df2016-12-01 10:45:08 +000049 : number_of_dex_files_(number_of_dex_files),
50 dex_size_(dex_size),
Nicolas Geoffray4acefd32016-10-24 13:14:58 +010051 verifier_deps_size_(verifier_deps_size),
52 quickening_info_size_(quickening_info_size) {
David Brazdil7b49e6c2016-09-01 11:06:18 +010053 memcpy(magic_, kVdexMagic, sizeof(kVdexMagic));
54 memcpy(version_, kVdexVersion, sizeof(kVdexVersion));
55 DCHECK(IsMagicValid());
56 DCHECK(IsVersionValid());
57}
58
Richard Uhlerb8ab63a2017-01-31 11:27:37 +000059std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename,
60 bool writable,
61 bool low_4gb,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +010062 bool unquicken,
Richard Uhlerb8ab63a2017-01-31 11:27:37 +000063 std::string* error_msg) {
David Brazdil7b49e6c2016-09-01 11:06:18 +010064 if (!OS::FileExists(vdex_filename.c_str())) {
65 *error_msg = "File " + vdex_filename + " does not exist.";
66 return nullptr;
67 }
68
69 std::unique_ptr<File> vdex_file;
70 if (writable) {
71 vdex_file.reset(OS::OpenFileReadWrite(vdex_filename.c_str()));
72 } else {
73 vdex_file.reset(OS::OpenFileForReading(vdex_filename.c_str()));
74 }
75 if (vdex_file == nullptr) {
76 *error_msg = "Could not open file " + vdex_filename +
77 (writable ? " for read/write" : "for reading");
78 return nullptr;
79 }
80
81 int64_t vdex_length = vdex_file->GetLength();
82 if (vdex_length == -1) {
83 *error_msg = "Could not read the length of file " + vdex_filename;
84 return nullptr;
85 }
86
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +010087 return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, unquicken, error_msg);
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +000088}
89
Richard Uhlerb8ab63a2017-01-31 11:27:37 +000090std::unique_ptr<VdexFile> VdexFile::Open(int file_fd,
91 size_t vdex_length,
92 const std::string& vdex_filename,
93 bool writable,
94 bool low_4gb,
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +010095 bool unquicken,
Richard Uhlerb8ab63a2017-01-31 11:27:37 +000096 std::string* error_msg) {
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +010097 std::unique_ptr<MemMap> mmap(MemMap::MapFile(
98 vdex_length,
99 (writable || unquicken) ? PROT_READ | PROT_WRITE : PROT_READ,
100 unquicken ? MAP_PRIVATE : MAP_SHARED,
101 file_fd,
102 0 /* start offset */,
103 low_4gb,
104 vdex_filename.c_str(),
105 error_msg));
David Brazdil7b49e6c2016-09-01 11:06:18 +0100106 if (mmap == nullptr) {
107 *error_msg = "Failed to mmap file " + vdex_filename + " : " + *error_msg;
108 return nullptr;
109 }
110
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000111 std::unique_ptr<VdexFile> vdex(new VdexFile(mmap.release()));
112 if (!vdex->IsValid()) {
113 *error_msg = "Vdex file is not valid";
114 return nullptr;
115 }
116
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100117 if (unquicken) {
118 std::vector<std::unique_ptr<const DexFile>> unique_ptr_dex_files;
119 if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) {
120 return nullptr;
121 }
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300122 Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files),
123 vdex->GetQuickeningInfo(),
124 /* decompile_return_instruction */ false);
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100125 // Update the quickening info size to pretend there isn't any.
126 reinterpret_cast<Header*>(vdex->mmap_->Begin())->quickening_info_size_ = 0;
127 }
128
David Brazdil7b49e6c2016-09-01 11:06:18 +0100129 *error_msg = "Success";
Richard Uhlerb8ab63a2017-01-31 11:27:37 +0000130 return vdex;
David Brazdil7b49e6c2016-09-01 11:06:18 +0100131}
132
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000133const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor) const {
134 DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End()));
135 if (cursor == nullptr) {
136 // Beginning of the iteration, return the first dex file if there is one.
137 return HasDexSection() ? DexBegin() : nullptr;
138 } else {
139 // Fetch the next dex file. Return null if there is none.
140 const uint8_t* data = cursor + reinterpret_cast<const DexFile::Header*>(cursor)->file_size_;
Nicolas Geoffray28453cf2017-08-10 15:30:26 +0100141 // Dex files are required to be 4 byte aligned. the OatWriter makes sure they are, see
142 // OatWriter::SeekToDexFiles.
143 data = AlignUp(data, 4);
Nicolas Geoffrayb0bbe8e2016-11-19 10:42:37 +0000144 return (data == DexEnd()) ? nullptr : data;
145 }
146}
147
David Sehrbeca4fe2017-03-30 17:50:24 -0700148bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
149 std::string* error_msg) {
150 size_t i = 0;
151 for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr);
152 dex_file_start != nullptr;
153 dex_file_start = GetNextDexFileData(dex_file_start), ++i) {
154 size_t size = reinterpret_cast<const DexFile::Header*>(dex_file_start)->file_size_;
155 // TODO: Supply the location information for a vdex file.
156 static constexpr char kVdexLocation[] = "";
Mathieu Chartier79c87da2017-10-10 11:54:29 -0700157 std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation);
158 std::unique_ptr<const DexFile> dex(DexFileLoader::Open(dex_file_start,
159 size,
160 location,
161 GetLocationChecksum(i),
162 nullptr /*oat_dex_file*/,
163 false /*verify*/,
164 false /*verify_checksum*/,
165 error_msg));
David Sehrbeca4fe2017-03-30 17:50:24 -0700166 if (dex == nullptr) {
167 return false;
168 }
169 dex_files->push_back(std::move(dex));
170 }
171 return true;
172}
173
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100174// Utility class to easily iterate over the quickening data.
175class QuickeningInfoIterator {
176 public:
177 QuickeningInfoIterator(uint32_t dex_file_index,
178 uint32_t number_of_dex_files,
179 const ArrayRef<const uint8_t>& quickening_info)
180 : quickening_info_(quickening_info) {
181 const unaligned_uint32_t* dex_file_indices = reinterpret_cast<const unaligned_uint32_t*>(
182 quickening_info.data() +
183 quickening_info.size() -
184 number_of_dex_files * sizeof(uint32_t));
185 current_code_item_end_ = (dex_file_index == number_of_dex_files - 1)
186 ? dex_file_indices
187 : reinterpret_cast<const unaligned_uint32_t*>(
188 quickening_info_.data() + dex_file_indices[dex_file_index + 1]);
189 current_code_item_ptr_ = reinterpret_cast<const uint32_t*>(
190 quickening_info_.data() + dex_file_indices[dex_file_index]);
191 }
192
193 bool Done() const {
194 return current_code_item_ptr_ == current_code_item_end_;
195 }
196
197 void Advance() {
198 current_code_item_ptr_ += 2;
199 }
200
201 uint32_t GetCurrentCodeItemOffset() const {
202 return current_code_item_ptr_[0];
203 }
204
205 const ArrayRef<const uint8_t> GetCurrentQuickeningInfo() const {
206 return ArrayRef<const uint8_t>(
207 // Add sizeof(uint32_t) to remove the length from the data pointer.
208 quickening_info_.data() + current_code_item_ptr_[1] + sizeof(uint32_t),
209 *reinterpret_cast<const unaligned_uint32_t*>(
210 quickening_info_.data() + current_code_item_ptr_[1]));
211 }
212
213 private:
214 typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
215 const ArrayRef<const uint8_t>& quickening_info_;
216 const unaligned_uint32_t* current_code_item_ptr_;
217 const unaligned_uint32_t* current_code_item_end_;
218
219 DISALLOW_COPY_AND_ASSIGN(QuickeningInfoIterator);
220};
221
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100222void VdexFile::Unquicken(const std::vector<const DexFile*>& dex_files,
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300223 const ArrayRef<const uint8_t>& quickening_info,
224 bool decompile_return_instruction) {
225 if (quickening_info.size() == 0 && !decompile_return_instruction) {
226 // Bail early if there is no quickening info and no need to decompile
227 // RETURN_VOID_NO_BARRIER instructions to RETURN_VOID instructions.
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100228 return;
229 }
Anestis Bechtsoudisa1f56a82017-10-08 23:37:10 +0300230
231 // When we do not decompile RETURN_VOID_NO_BARRIER use the faster
232 // QuickeningInfoIterator, otherwise use the slower ClassDataItemIterator
233 if (!decompile_return_instruction) {
234 for (uint32_t i = 0; i < dex_files.size(); ++i) {
235 for (QuickeningInfoIterator it(i, dex_files.size(), quickening_info);
236 !it.Done();
237 it.Advance()) {
238 optimizer::ArtDecompileDEX(
239 *dex_files[i]->GetCodeItem(it.GetCurrentCodeItemOffset()),
240 it.GetCurrentQuickeningInfo(),
241 decompile_return_instruction);
242 }
243 }
244 } else {
245 for (uint32_t i = 0; i < dex_files.size(); ++i) {
246 QuickeningInfoIterator quick_it(i, dex_files.size(), quickening_info);
247 for (uint32_t j = 0; j < dex_files[i]->NumClassDefs(); ++j) {
248 const DexFile::ClassDef& class_def = dex_files[i]->GetClassDef(j);
249 const uint8_t* class_data = dex_files[i]->GetClassData(class_def);
250 if (class_data != nullptr) {
251 for (ClassDataItemIterator class_it(*dex_files[i], class_data);
252 class_it.HasNext();
253 class_it.Next()) {
254 if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
255 uint32_t offset = class_it.GetMethodCodeItemOffset();
256 if (!quick_it.Done() && offset == quick_it.GetCurrentCodeItemOffset()) {
257 optimizer::ArtDecompileDEX(
258 *class_it.GetMethodCodeItem(),
259 quick_it.GetCurrentQuickeningInfo(),
260 decompile_return_instruction);
261 quick_it.Advance();
262 } else {
263 optimizer::ArtDecompileDEX(*class_it.GetMethodCodeItem(),
264 /* quickened_info */ {},
265 decompile_return_instruction);
266 }
267 }
268 }
269 }
270 }
271 DCHECK(quick_it.Done()) << "Failed to use all quickening info";
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100272 }
273 }
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100274}
275
276static constexpr uint32_t kNoDexFile = -1;
277
278uint32_t VdexFile::GetDexFileIndex(const DexFile& dex_file) const {
279 uint32_t dex_index = 0;
280 for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr);
281 dex_file_start != dex_file.Begin();
282 dex_file_start = GetNextDexFileData(dex_file_start)) {
283 if (dex_file_start == nullptr) {
284 return kNoDexFile;
285 }
286 dex_index++;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100287 }
Nicolas Geoffrayb02ba932017-07-13 15:53:54 +0100288 return dex_index;
289}
290
291void VdexFile::FullyUnquickenDexFile(const DexFile& target_dex_file,
292 const DexFile& original_dex_file) const {
293 uint32_t dex_index = GetDexFileIndex(original_dex_file);
294 if (dex_index == kNoDexFile) {
295 return;
296 }
297
298 constexpr bool kDecompileReturnInstruction = true;
299 QuickeningInfoIterator it(dex_index, GetHeader().GetNumberOfDexFiles(), GetQuickeningInfo());
300 // Iterate over the class definitions. Even if there is no quickening info,
301 // we want to unquicken RETURN_VOID_NO_BARRIER instruction.
302 for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) {
303 const DexFile::ClassDef& class_def = target_dex_file.GetClassDef(i);
304 const uint8_t* class_data = target_dex_file.GetClassData(class_def);
305 if (class_data != nullptr) {
306 for (ClassDataItemIterator class_it(target_dex_file, class_data);
307 class_it.HasNext();
308 class_it.Next()) {
309 if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
310 uint32_t offset = class_it.GetMethodCodeItemOffset();
311 if (!it.Done() && offset == it.GetCurrentCodeItemOffset()) {
312 optimizer::ArtDecompileDEX(
313 *class_it.GetMethodCodeItem(),
314 it.GetCurrentQuickeningInfo(),
315 kDecompileReturnInstruction);
316 it.Advance();
317 } else {
318 optimizer::ArtDecompileDEX(*class_it.GetMethodCodeItem(),
319 ArrayRef<const uint8_t>(nullptr, 0),
320 kDecompileReturnInstruction);
321 }
322 }
323 }
324 }
325 }
326}
327
328const uint8_t* VdexFile::GetQuickenedInfoOf(const DexFile& dex_file,
329 uint32_t code_item_offset) const {
330 if (GetQuickeningInfo().size() == 0) {
331 // Bail early if there is no quickening info.
332 return nullptr;
333 }
334
335 uint32_t dex_index = GetDexFileIndex(dex_file);
336 if (dex_index == kNoDexFile) {
337 return nullptr;
338 }
339
340 for (QuickeningInfoIterator it(dex_index, GetHeader().GetNumberOfDexFiles(), GetQuickeningInfo());
341 !it.Done();
342 it.Advance()) {
343 if (code_item_offset == it.GetCurrentCodeItemOffset()) {
344 return it.GetCurrentQuickeningInfo().data();
345 }
346 }
347 return nullptr;
Nicolas Geoffray4e868fa2017-04-21 17:16:44 +0100348}
349
David Brazdil7b49e6c2016-09-01 11:06:18 +0100350} // namespace art