1 /*
2 * Copyright (C) 2011 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 "oat_file.h"
18
19 #include <dlfcn.h>
20 #ifndef __APPLE__
21 #include <link.h> // for dl_iterate_phdr.
22 #endif
23 #include <unistd.h>
24
25 #include <cstdlib>
26 #include <cstring>
27 #include <sstream>
28 #include <type_traits>
29 #include <sys/stat.h>
30
31 // dlopen_ext support from bionic.
32 #ifdef ART_TARGET_ANDROID
33 #include "android/dlext.h"
34 #include "nativeloader/dlext_namespaces.h"
35 #endif
36
37 #include <android-base/logging.h>
38 #include "android-base/stringprintf.h"
39
40 #include "arch/instruction_set_features.h"
41 #include "art_method.h"
42 #include "base/bit_vector.h"
43 #include "base/enums.h"
44 #include "base/file_utils.h"
45 #include "base/logging.h" // For VLOG_IS_ON.
46 #include "base/mem_map.h"
47 #include "base/os.h"
48 #include "base/stl_util.h"
49 #include "base/string_view_cpp20.h"
50 #include "base/systrace.h"
51 #include "base/unix_file/fd_file.h"
52 #include "base/utils.h"
53 #include "dex/art_dex_file_loader.h"
54 #include "dex/dex_file.h"
55 #include "dex/dex_file_loader.h"
56 #include "dex/dex_file_structs.h"
57 #include "dex/dex_file_types.h"
58 #include "dex/standard_dex_file.h"
59 #include "dex/type_lookup_table.h"
60 #include "dex/utf-inl.h"
61 #include "elf/elf_utils.h"
62 #include "elf_file.h"
63 #include "gc_root.h"
64 #include "gc/heap.h"
65 #include "gc/space/image_space.h"
66 #include "mirror/class.h"
67 #include "mirror/object-inl.h"
68 #include "oat.h"
69 #include "oat_file-inl.h"
70 #include "oat_file_manager.h"
71 #include "runtime-inl.h"
72 #include "vdex_file.h"
73 #include "verifier/verifier_deps.h"
74
75 namespace art {
76
77 using android::base::StringPrintf;
78
79 // Whether OatFile::Open will try dlopen. Fallback is our own ELF loader.
80 static constexpr bool kUseDlopen = true;
81
82 // Whether OatFile::Open will try dlopen on the host. On the host we're not linking against
83 // bionic, so cannot take advantage of the support for changed semantics (loading the same soname
84 // multiple times). However, if/when we switch the above, we likely want to switch this, too,
85 // to get test coverage of the code paths.
86 static constexpr bool kUseDlopenOnHost = true;
87
88 // For debugging, Open will print DlOpen error message if set to true.
89 static constexpr bool kPrintDlOpenErrorMessage = false;
90
91 // Note for OatFileBase and descendents:
92 //
93 // These are used in OatFile::Open to try all our loaders.
94 //
95 // The process is simple:
96 //
97 // 1) Allocate an instance through the standard constructor (location, executable)
98 // 2) Load() to try to open the file.
99 // 3) ComputeFields() to populate the OatFile fields like begin_, using FindDynamicSymbolAddress.
100 // 4) PreSetup() for any steps that should be done before the final setup.
101 // 5) Setup() to complete the procedure.
102
103 class OatFileBase : public OatFile {
104 public:
~OatFileBase()105 virtual ~OatFileBase() {}
106
107 template <typename kOatFileBaseSubType>
108 static OatFileBase* OpenOatFile(int zip_fd,
109 const std::string& vdex_filename,
110 const std::string& elf_filename,
111 const std::string& location,
112 bool writable,
113 bool executable,
114 bool low_4gb,
115 ArrayRef<const std::string> dex_filenames,
116 ArrayRef<const int> dex_fds,
117 /*inout*/MemMap* reservation, // Where to load if not null.
118 /*out*/std::string* error_msg);
119
120 template <typename kOatFileBaseSubType>
121 static OatFileBase* OpenOatFile(int zip_fd,
122 int vdex_fd,
123 int oat_fd,
124 const std::string& vdex_filename,
125 const std::string& oat_filename,
126 bool writable,
127 bool executable,
128 bool low_4gb,
129 ArrayRef<const std::string> dex_filenames,
130 ArrayRef<const int> dex_fds,
131 /*inout*/MemMap* reservation, // Where to load if not null.
132 /*out*/std::string* error_msg);
133
134 protected:
OatFileBase(const std::string & filename,bool executable)135 OatFileBase(const std::string& filename, bool executable) : OatFile(filename, executable) {}
136
137 virtual const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name,
138 std::string* error_msg) const = 0;
139
140 virtual void PreLoad() = 0;
141
142 bool LoadVdex(const std::string& vdex_filename,
143 bool writable,
144 bool low_4gb,
145 std::string* error_msg);
146
147 bool LoadVdex(int vdex_fd,
148 const std::string& vdex_filename,
149 bool writable,
150 bool low_4gb,
151 std::string* error_msg);
152
153 virtual bool Load(const std::string& elf_filename,
154 bool writable,
155 bool executable,
156 bool low_4gb,
157 /*inout*/MemMap* reservation, // Where to load if not null.
158 /*out*/std::string* error_msg) = 0;
159
160 virtual bool Load(int oat_fd,
161 bool writable,
162 bool executable,
163 bool low_4gb,
164 /*inout*/MemMap* reservation, // Where to load if not null.
165 /*out*/std::string* error_msg) = 0;
166
167 bool ComputeFields(const std::string& file_path, std::string* error_msg);
168
169 virtual void PreSetup(const std::string& elf_filename) = 0;
170
171 bool Setup(int zip_fd,
172 ArrayRef<const std::string> dex_filenames,
173 ArrayRef<const int> dex_fds,
174 std::string* error_msg);
175
176 bool Setup(const std::vector<const DexFile*>& dex_files, std::string* error_msg);
177
178 // Setters exposed for ElfOatFile.
179
SetBegin(const uint8_t * begin)180 void SetBegin(const uint8_t* begin) {
181 begin_ = begin;
182 }
183
SetEnd(const uint8_t * end)184 void SetEnd(const uint8_t* end) {
185 end_ = end;
186 }
187
SetVdex(VdexFile * vdex)188 void SetVdex(VdexFile* vdex) {
189 vdex_.reset(vdex);
190 }
191
192 private:
193 DISALLOW_COPY_AND_ASSIGN(OatFileBase);
194 };
195
196 template <typename kOatFileBaseSubType>
OpenOatFile(int zip_fd,const std::string & vdex_filename,const std::string & elf_filename,const std::string & location,bool writable,bool executable,bool low_4gb,ArrayRef<const std::string> dex_filenames,ArrayRef<const int> dex_fds,MemMap * reservation,std::string * error_msg)197 OatFileBase* OatFileBase::OpenOatFile(int zip_fd,
198 const std::string& vdex_filename,
199 const std::string& elf_filename,
200 const std::string& location,
201 bool writable,
202 bool executable,
203 bool low_4gb,
204 ArrayRef<const std::string> dex_filenames,
205 ArrayRef<const int> dex_fds,
206 /*inout*/MemMap* reservation,
207 /*out*/std::string* error_msg) {
208 std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(location, executable));
209
210 ret->PreLoad();
211
212 if (!ret->Load(elf_filename,
213 writable,
214 executable,
215 low_4gb,
216 reservation,
217 error_msg)) {
218 return nullptr;
219 }
220
221 if (!ret->ComputeFields(elf_filename, error_msg)) {
222 return nullptr;
223 }
224
225 ret->PreSetup(elf_filename);
226
227 if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
228 return nullptr;
229 }
230
231 if (!ret->Setup(zip_fd, dex_filenames, dex_fds, error_msg)) {
232 return nullptr;
233 }
234
235 return ret.release();
236 }
237
238 template <typename kOatFileBaseSubType>
OpenOatFile(int zip_fd,int vdex_fd,int oat_fd,const std::string & vdex_location,const std::string & oat_location,bool writable,bool executable,bool low_4gb,ArrayRef<const std::string> dex_filenames,ArrayRef<const int> dex_fds,MemMap * reservation,std::string * error_msg)239 OatFileBase* OatFileBase::OpenOatFile(int zip_fd,
240 int vdex_fd,
241 int oat_fd,
242 const std::string& vdex_location,
243 const std::string& oat_location,
244 bool writable,
245 bool executable,
246 bool low_4gb,
247 ArrayRef<const std::string> dex_filenames,
248 ArrayRef<const int> dex_fds,
249 /*inout*/MemMap* reservation,
250 /*out*/std::string* error_msg) {
251 std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(oat_location, executable));
252
253 if (!ret->Load(oat_fd,
254 writable,
255 executable,
256 low_4gb,
257 reservation,
258 error_msg)) {
259 return nullptr;
260 }
261
262 if (!ret->ComputeFields(oat_location, error_msg)) {
263 return nullptr;
264 }
265
266 ret->PreSetup(oat_location);
267
268 if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
269 return nullptr;
270 }
271
272 if (!ret->Setup(zip_fd, dex_filenames, dex_fds, error_msg)) {
273 return nullptr;
274 }
275
276 return ret.release();
277 }
278
LoadVdex(const std::string & vdex_filename,bool writable,bool low_4gb,std::string * error_msg)279 bool OatFileBase::LoadVdex(const std::string& vdex_filename,
280 bool writable,
281 bool low_4gb,
282 std::string* error_msg) {
283 vdex_ = VdexFile::OpenAtAddress(vdex_begin_,
284 vdex_end_ - vdex_begin_,
285 /*mmap_reuse=*/ vdex_begin_ != nullptr,
286 vdex_filename,
287 writable,
288 low_4gb,
289 error_msg);
290 if (vdex_.get() == nullptr) {
291 *error_msg = StringPrintf("Failed to load vdex file '%s' %s",
292 vdex_filename.c_str(),
293 error_msg->c_str());
294 return false;
295 }
296 return true;
297 }
298
LoadVdex(int vdex_fd,const std::string & vdex_filename,bool writable,bool low_4gb,std::string * error_msg)299 bool OatFileBase::LoadVdex(int vdex_fd,
300 const std::string& vdex_filename,
301 bool writable,
302 bool low_4gb,
303 std::string* error_msg) {
304 if (vdex_fd != -1) {
305 struct stat s;
306 int rc = TEMP_FAILURE_RETRY(fstat(vdex_fd, &s));
307 if (rc == -1) {
308 PLOG(WARNING) << "Failed getting length of vdex file";
309 } else {
310 vdex_ = VdexFile::OpenAtAddress(
311 vdex_begin_,
312 vdex_end_ - vdex_begin_,
313 /*mmap_reuse=*/ vdex_begin_ != nullptr,
314 vdex_fd,
315 s.st_size,
316 vdex_filename,
317 writable,
318 low_4gb,
319 error_msg);
320 if (vdex_.get() == nullptr) {
321 *error_msg = "Failed opening vdex file.";
322 return false;
323 }
324 }
325 }
326 return true;
327 }
328
ComputeFields(const std::string & file_path,std::string * error_msg)329 bool OatFileBase::ComputeFields(const std::string& file_path, std::string* error_msg) {
330 std::string symbol_error_msg;
331 begin_ = FindDynamicSymbolAddress("oatdata", &symbol_error_msg);
332 if (begin_ == nullptr) {
333 *error_msg = StringPrintf("Failed to find oatdata symbol in '%s' %s",
334 file_path.c_str(),
335 symbol_error_msg.c_str());
336 return false;
337 }
338 end_ = FindDynamicSymbolAddress("oatlastword", &symbol_error_msg);
339 if (end_ == nullptr) {
340 *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s' %s",
341 file_path.c_str(),
342 symbol_error_msg.c_str());
343 return false;
344 }
345 // Readjust to be non-inclusive upper bound.
346 end_ += sizeof(uint32_t);
347
348 data_bimg_rel_ro_begin_ = FindDynamicSymbolAddress("oatdatabimgrelro", &symbol_error_msg);
349 if (data_bimg_rel_ro_begin_ != nullptr) {
350 data_bimg_rel_ro_end_ =
351 FindDynamicSymbolAddress("oatdatabimgrelrolastword", &symbol_error_msg);
352 if (data_bimg_rel_ro_end_ == nullptr) {
353 *error_msg =
354 StringPrintf("Failed to find oatdatabimgrelrolastword symbol in '%s'", file_path.c_str());
355 return false;
356 }
357 // Readjust to be non-inclusive upper bound.
358 data_bimg_rel_ro_end_ += sizeof(uint32_t);
359 }
360
361 bss_begin_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbss", &symbol_error_msg));
362 if (bss_begin_ == nullptr) {
363 // No .bss section.
364 bss_end_ = nullptr;
365 } else {
366 bss_end_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbsslastword", &symbol_error_msg));
367 if (bss_end_ == nullptr) {
368 *error_msg = StringPrintf("Failed to find oatbsslastword symbol in '%s'", file_path.c_str());
369 return false;
370 }
371 // Readjust to be non-inclusive upper bound.
372 bss_end_ += sizeof(uint32_t);
373 // Find bss methods if present.
374 bss_methods_ =
375 const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbssmethods", &symbol_error_msg));
376 // Find bss roots if present.
377 bss_roots_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbssroots", &symbol_error_msg));
378 }
379
380 vdex_begin_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatdex", &symbol_error_msg));
381 if (vdex_begin_ == nullptr) {
382 // No .vdex section.
383 vdex_end_ = nullptr;
384 } else {
385 vdex_end_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatdexlastword", &symbol_error_msg));
386 if (vdex_end_ == nullptr) {
387 *error_msg = StringPrintf("Failed to find oatdexlastword symbol in '%s'", file_path.c_str());
388 return false;
389 }
390 // Readjust to be non-inclusive upper bound.
391 vdex_end_ += sizeof(uint32_t);
392 }
393
394 return true;
395 }
396
397 // Read an unaligned entry from the OatDexFile data in OatFile and advance the read
398 // position by the number of bytes read, i.e. sizeof(T).
399 // Return true on success, false if the read would go beyond the end of the OatFile.
400 template <typename T>
ReadOatDexFileData(const OatFile & oat_file,const uint8_t ** oat,T * value)401 inline static bool ReadOatDexFileData(const OatFile& oat_file,
402 /*inout*/const uint8_t** oat,
403 /*out*/T* value) {
404 DCHECK(oat != nullptr);
405 DCHECK(value != nullptr);
406 DCHECK_LE(*oat, oat_file.End());
407 if (UNLIKELY(static_cast<size_t>(oat_file.End() - *oat) < sizeof(T))) {
408 return false;
409 }
410 static_assert(std::is_trivial<T>::value, "T must be a trivial type");
411 using unaligned_type __attribute__((__aligned__(1))) = T;
412 *value = *reinterpret_cast<const unaligned_type*>(*oat);
413 *oat += sizeof(T);
414 return true;
415 }
416
ReadIndexBssMapping(OatFile * oat_file,const uint8_t ** oat,size_t dex_file_index,const std::string & dex_file_location,const char * tag,const IndexBssMapping ** mapping,std::string * error_msg)417 static bool ReadIndexBssMapping(OatFile* oat_file,
418 /*inout*/const uint8_t** oat,
419 size_t dex_file_index,
420 const std::string& dex_file_location,
421 const char* tag,
422 /*out*/const IndexBssMapping** mapping,
423 std::string* error_msg) {
424 uint32_t index_bss_mapping_offset;
425 if (UNLIKELY(!ReadOatDexFileData(*oat_file, oat, &index_bss_mapping_offset))) {
426 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated "
427 "after %s bss mapping offset",
428 oat_file->GetLocation().c_str(),
429 dex_file_index,
430 dex_file_location.c_str(),
431 tag);
432 return false;
433 }
434 const bool readable_index_bss_mapping_size =
435 index_bss_mapping_offset != 0u &&
436 index_bss_mapping_offset <= oat_file->Size() &&
437 IsAligned<alignof(IndexBssMapping)>(index_bss_mapping_offset) &&
438 oat_file->Size() - index_bss_mapping_offset >= IndexBssMapping::ComputeSize(0);
439 const IndexBssMapping* index_bss_mapping = readable_index_bss_mapping_size
440 ? reinterpret_cast<const IndexBssMapping*>(oat_file->Begin() + index_bss_mapping_offset)
441 : nullptr;
442 if (index_bss_mapping_offset != 0u &&
443 (UNLIKELY(index_bss_mapping == nullptr) ||
444 UNLIKELY(index_bss_mapping->size() == 0u) ||
445 UNLIKELY(oat_file->Size() - index_bss_mapping_offset <
446 IndexBssMapping::ComputeSize(index_bss_mapping->size())))) {
447 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with unaligned or "
448 " truncated %s bss mapping, offset %u of %zu, length %zu",
449 oat_file->GetLocation().c_str(),
450 dex_file_index,
451 dex_file_location.c_str(),
452 tag,
453 index_bss_mapping_offset,
454 oat_file->Size(),
455 index_bss_mapping != nullptr ? index_bss_mapping->size() : 0u);
456 return false;
457 }
458
459 *mapping = index_bss_mapping;
460 return true;
461 }
462
ComputeAndCheckTypeLookupTableData(const DexFile::Header & header,const uint8_t * type_lookup_table_start,const VdexFile * vdex_file,const uint8_t ** type_lookup_table_data,std::string * error_msg)463 static bool ComputeAndCheckTypeLookupTableData(const DexFile::Header& header,
464 const uint8_t* type_lookup_table_start,
465 const VdexFile* vdex_file,
466 const uint8_t** type_lookup_table_data,
467 std::string* error_msg) {
468 if (type_lookup_table_start == nullptr ||
469 reinterpret_cast<const uint32_t*>(type_lookup_table_start)[0] == 0) {
470 *type_lookup_table_data = nullptr;
471 return true;
472 }
473
474 *type_lookup_table_data = type_lookup_table_start + sizeof(uint32_t);
475 size_t expected_table_size = TypeLookupTable::RawDataLength(header.class_defs_size_);
476 size_t found_size = reinterpret_cast<const uint32_t*>(type_lookup_table_start)[0];
477 if (UNLIKELY(found_size != expected_table_size)) {
478 *error_msg =
479 StringPrintf("In vdex file '%s' unexpected type lookup table size: found %zu, expected %zu",
480 vdex_file->GetName().c_str(),
481 found_size,
482 expected_table_size);
483 return false;
484 }
485 if (UNLIKELY(!vdex_file->Contains(*type_lookup_table_data))) {
486 *error_msg =
487 StringPrintf("In vdex file '%s' found invalid type lookup table pointer %p not in [%p, %p]",
488 vdex_file->GetName().c_str(),
489 type_lookup_table_data,
490 vdex_file->Begin(),
491 vdex_file->End());
492 return false;
493 }
494 if (UNLIKELY(!vdex_file->Contains(*type_lookup_table_data + expected_table_size - 1))) {
495 *error_msg =
496 StringPrintf("In vdex file '%s' found overflowing type lookup table %p not in [%p, %p]",
497 vdex_file->GetName().c_str(),
498 type_lookup_table_data + expected_table_size,
499 vdex_file->Begin(),
500 vdex_file->End());
501 return false;
502 }
503 if (UNLIKELY(!IsAligned<4>(type_lookup_table_start))) {
504 *error_msg =
505 StringPrintf("In vdex file '%s' found invalid type lookup table alignment %p",
506 vdex_file->GetName().c_str(),
507 type_lookup_table_start);
508 return false;
509 }
510 return true;
511 }
512
Setup(const std::vector<const DexFile * > & dex_files,std::string * error_msg)513 bool OatFileBase::Setup(const std::vector<const DexFile*>& dex_files, std::string* error_msg) {
514 uint32_t i = 0;
515 const uint8_t* type_lookup_table_start = nullptr;
516 for (const DexFile* dex_file : dex_files) {
517 std::string dex_location = dex_file->GetLocation();
518 std::string canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location.c_str());
519
520 type_lookup_table_start = vdex_->GetNextTypeLookupTableData(type_lookup_table_start, i++);
521 const uint8_t* type_lookup_table_data = nullptr;
522 if (!ComputeAndCheckTypeLookupTableData(dex_file->GetHeader(),
523 type_lookup_table_start,
524 vdex_.get(),
525 &type_lookup_table_data,
526 error_msg)) {
527 return false;
528 }
529 // Create an OatDexFile and add it to the owning container.
530 OatDexFile* oat_dex_file = new OatDexFile(
531 this,
532 dex_file->Begin(),
533 dex_file->GetLocationChecksum(),
534 dex_location,
535 canonical_location,
536 type_lookup_table_data);
537 oat_dex_files_storage_.push_back(oat_dex_file);
538
539 // Add the location and canonical location (if different) to the oat_dex_files_ table.
540 std::string_view key(oat_dex_file->GetDexFileLocation());
541 oat_dex_files_.Put(key, oat_dex_file);
542 if (canonical_location != dex_location) {
543 std::string_view canonical_key(oat_dex_file->GetCanonicalDexFileLocation());
544 oat_dex_files_.Put(canonical_key, oat_dex_file);
545 }
546 }
547 // Now that we've created all the OatDexFile, update the dex files.
548 for (i = 0; i < dex_files.size(); ++i) {
549 dex_files[i]->SetOatDexFile(oat_dex_files_storage_[i]);
550 }
551 return true;
552 }
553
Setup(int zip_fd,ArrayRef<const std::string> dex_filenames,ArrayRef<const int> dex_fds,std::string * error_msg)554 bool OatFileBase::Setup(int zip_fd,
555 ArrayRef<const std::string> dex_filenames,
556 ArrayRef<const int> dex_fds,
557 std::string* error_msg) {
558 if (!GetOatHeader().IsValid()) {
559 std::string cause = GetOatHeader().GetValidationErrorMessage();
560 *error_msg = StringPrintf("Invalid oat header for '%s': %s",
561 GetLocation().c_str(),
562 cause.c_str());
563 return false;
564 }
565 PointerSize pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet());
566 size_t key_value_store_size =
567 (Size() >= sizeof(OatHeader)) ? GetOatHeader().GetKeyValueStoreSize() : 0u;
568 if (Size() < sizeof(OatHeader) + key_value_store_size) {
569 *error_msg = StringPrintf("In oat file '%s' found truncated OatHeader, "
570 "size = %zu < %zu + %zu",
571 GetLocation().c_str(),
572 Size(),
573 sizeof(OatHeader),
574 key_value_store_size);
575 return false;
576 }
577
578 size_t oat_dex_files_offset = GetOatHeader().GetOatDexFilesOffset();
579 if (oat_dex_files_offset < GetOatHeader().GetHeaderSize() || oat_dex_files_offset > Size()) {
580 *error_msg = StringPrintf("In oat file '%s' found invalid oat dex files offset: "
581 "%zu is not in [%zu, %zu]",
582 GetLocation().c_str(),
583 oat_dex_files_offset,
584 GetOatHeader().GetHeaderSize(),
585 Size());
586 return false;
587 }
588 const uint8_t* oat = Begin() + oat_dex_files_offset; // Jump to the OatDexFile records.
589
590 if (!IsAligned<sizeof(uint32_t)>(data_bimg_rel_ro_begin_) ||
591 !IsAligned<sizeof(uint32_t)>(data_bimg_rel_ro_end_) ||
592 data_bimg_rel_ro_begin_ > data_bimg_rel_ro_end_) {
593 *error_msg = StringPrintf("In oat file '%s' found unaligned or unordered databimgrelro "
594 "symbol(s): begin = %p, end = %p",
595 GetLocation().c_str(),
596 data_bimg_rel_ro_begin_,
597 data_bimg_rel_ro_end_);
598 return false;
599 }
600
601 DCHECK_GE(static_cast<size_t>(pointer_size), alignof(GcRoot<mirror::Object>));
602 if (!IsAligned<kPageSize>(bss_begin_) ||
603 !IsAlignedParam(bss_methods_, static_cast<size_t>(pointer_size)) ||
604 !IsAlignedParam(bss_roots_, static_cast<size_t>(pointer_size)) ||
605 !IsAligned<alignof(GcRoot<mirror::Object>)>(bss_end_)) {
606 *error_msg = StringPrintf("In oat file '%s' found unaligned bss symbol(s): "
607 "begin = %p, methods_ = %p, roots = %p, end = %p",
608 GetLocation().c_str(),
609 bss_begin_,
610 bss_methods_,
611 bss_roots_,
612 bss_end_);
613 return false;
614 }
615
616 if ((bss_methods_ != nullptr && (bss_methods_ < bss_begin_ || bss_methods_ > bss_end_)) ||
617 (bss_roots_ != nullptr && (bss_roots_ < bss_begin_ || bss_roots_ > bss_end_)) ||
618 (bss_methods_ != nullptr && bss_roots_ != nullptr && bss_methods_ > bss_roots_)) {
619 *error_msg = StringPrintf("In oat file '%s' found bss symbol(s) outside .bss or unordered: "
620 "begin = %p, methods = %p, roots = %p, end = %p",
621 GetLocation().c_str(),
622 bss_begin_,
623 bss_methods_,
624 bss_roots_,
625 bss_end_);
626 return false;
627 }
628
629 if (bss_methods_ != nullptr && bss_methods_ != bss_begin_) {
630 *error_msg = StringPrintf("In oat file '%s' found unexpected .bss gap before 'oatbssmethods': "
631 "begin = %p, methods = %p",
632 GetLocation().c_str(),
633 bss_begin_,
634 bss_methods_);
635 return false;
636 }
637
638 std::string_view primary_location;
639 std::string_view primary_location_replacement;
640 int dex_fd = -1;
641 size_t dex_filenames_pos = 0u;
642 uint32_t dex_file_count = GetOatHeader().GetDexFileCount();
643 oat_dex_files_storage_.reserve(dex_file_count);
644 for (size_t i = 0; i < dex_file_count; i++) {
645 uint32_t dex_file_location_size;
646 if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_location_size))) {
647 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu truncated after dex file "
648 "location size",
649 GetLocation().c_str(),
650 i);
651 return false;
652 }
653 if (UNLIKELY(dex_file_location_size == 0U)) {
654 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu with empty location name",
655 GetLocation().c_str(),
656 i);
657 return false;
658 }
659 if (UNLIKELY(static_cast<size_t>(End() - oat) < dex_file_location_size)) {
660 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu with truncated dex file "
661 "location",
662 GetLocation().c_str(),
663 i);
664 return false;
665 }
666 const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
667 oat += dex_file_location_size;
668
669 // Location encoded in the oat file. We will use this for multidex naming.
670 std::string_view oat_dex_file_location(dex_file_location_data, dex_file_location_size);
671 std::string dex_file_location(oat_dex_file_location);
672 bool is_multidex = DexFileLoader::IsMultiDexLocation(dex_file_location.c_str());
673 // Check that `is_multidex` does not clash with other indicators. The first dex location
674 // must be primary location and, if we're opening external dex files, the location must
675 // be multi-dex if and only if we already have a dex file opened for it.
676 if ((i == 0 && is_multidex) ||
677 (!external_dex_files_.empty() && (is_multidex != (i < external_dex_files_.size())))) {
678 *error_msg = StringPrintf("In oat file '%s' found unexpected %s location '%s'",
679 GetLocation().c_str(),
680 is_multidex ? "multi-dex" : "primary",
681 dex_file_location.c_str());
682 return false;
683 }
684 // Remember the primary location and, if provided, the replacement from `dex_filenames`.
685 if (!is_multidex) {
686 primary_location = oat_dex_file_location;
687 if (!dex_filenames.empty()) {
688 if (dex_filenames_pos == dex_filenames.size()) {
689 *error_msg = StringPrintf("In oat file '%s' found excessive primary location '%s'"
690 ", expected only %zu primary locations",
691 GetLocation().c_str(),
692 dex_file_location.c_str(),
693 dex_filenames.size());
694 return false;
695 }
696 primary_location_replacement = dex_filenames[dex_filenames_pos];
697 dex_fd = dex_filenames_pos < dex_fds.size() ? dex_fds[dex_filenames_pos] : -1;
698 ++dex_filenames_pos;
699 }
700 }
701 // Check that the base location of a multidex location matches the last seen primary location.
702 if (is_multidex &&
703 (!StartsWith(dex_file_location, primary_location) ||
704 dex_file_location[primary_location.size()] != DexFileLoader::kMultiDexSeparator)) {
705 *error_msg = StringPrintf("In oat file '%s' found unexpected multidex location '%s',"
706 " unrelated to '%s'",
707 GetLocation().c_str(),
708 dex_file_location.c_str(),
709 std::string(primary_location).c_str());
710 return false;
711 }
712 std::string dex_file_name = dex_file_location;
713 if (!dex_filenames.empty()) {
714 dex_file_name.replace(/*pos*/ 0u, primary_location.size(), primary_location_replacement);
715 // If the location does not contain path and matches the file name component,
716 // use the provided file name also as the location.
717 // TODO: Do we need this for anything other than tests?
718 if (dex_file_location.find('/') == std::string::npos &&
719 dex_file_name.size() > dex_file_location.size() &&
720 dex_file_name[dex_file_name.size() - dex_file_location.size() - 1u] == '/' &&
721 EndsWith(dex_file_name, dex_file_location)) {
722 dex_file_location = dex_file_name;
723 }
724 }
725
726 uint32_t dex_file_checksum;
727 if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_checksum))) {
728 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' truncated after "
729 "dex file checksum",
730 GetLocation().c_str(),
731 i,
732 dex_file_location.c_str());
733 return false;
734 }
735
736 uint32_t dex_file_offset;
737 if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_offset))) {
738 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' truncated "
739 "after dex file offsets",
740 GetLocation().c_str(),
741 i,
742 dex_file_location.c_str());
743 return false;
744 }
745 if (UNLIKELY(dex_file_offset > DexSize())) {
746 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file "
747 "offset %u > %zu",
748 GetLocation().c_str(),
749 i,
750 dex_file_location.c_str(),
751 dex_file_offset,
752 DexSize());
753 return false;
754 }
755 const uint8_t* dex_file_pointer = nullptr;
756 if (UNLIKELY(dex_file_offset == 0U)) {
757 // Do not support mixed-mode oat files.
758 if (i != 0u && external_dex_files_.empty()) {
759 *error_msg = StringPrintf("In oat file '%s', unsupported uncompressed-dex-file for dex "
760 "file %zu (%s)",
761 GetLocation().c_str(),
762 i,
763 dex_file_location.c_str());
764 return false;
765 }
766 DCHECK_LE(i, external_dex_files_.size());
767 if (i == external_dex_files_.size()) {
768 std::vector<std::unique_ptr<const DexFile>> new_dex_files;
769 // No dex files, load it from location.
770 const ArtDexFileLoader dex_file_loader;
771 bool loaded = false;
772 CHECK(zip_fd == -1 || dex_fds.empty()); // Allow only the supported combinations.
773 if (zip_fd != -1) {
774 loaded = dex_file_loader.OpenZip(zip_fd,
775 dex_file_location,
776 /*verify=*/ false,
777 /*verify_checksum=*/ false,
778 error_msg,
779 &new_dex_files);
780 } else if (dex_fd != -1) {
781 // Note that we assume dex_fds are backing by jars.
782 loaded = dex_file_loader.OpenZipFromOwnedFd(dex_fd,
783 dex_file_location,
784 /*verify=*/ false,
785 /*verify_checksum=*/ false,
786 error_msg,
787 &new_dex_files);
788 } else {
789 loaded = dex_file_loader.Open(dex_file_name.c_str(),
790 dex_file_location,
791 /*verify=*/ false,
792 /*verify_checksum=*/ false,
793 error_msg,
794 &new_dex_files);
795 }
796 if (!loaded) {
797 if (Runtime::Current() == nullptr) {
798 // If there's no runtime, we're running oatdump, so return
799 // a half constructed oat file that oatdump knows how to deal with.
800 LOG(WARNING) << "Could not find associated dex files of oat file. "
801 << "Oatdump will only dump the header.";
802 return true;
803 } else {
804 return false;
805 }
806 }
807 // The oat file may be out of date wrt/ the dex-file location. We need to be defensive
808 // here and ensure that at least the number of dex files still matches.
809 // If we have a zip_fd, or reached the end of provided `dex_filenames`, we must
810 // load all dex files from that file, otherwise we may open multiple files.
811 // Note: actual checksum comparisons are the duty of the OatFileAssistant and will be
812 // done after loading the OatFile.
813 size_t max_dex_files = dex_file_count - external_dex_files_.size();
814 bool expect_all =
815 (zip_fd != -1) || (!dex_filenames.empty() && dex_filenames_pos == dex_filenames.size());
816 if (expect_all ? new_dex_files.size() != max_dex_files
817 : new_dex_files.size() > max_dex_files) {
818 *error_msg = StringPrintf("In oat file '%s', expected %s%zu uncompressed dex files, but "
819 "found %zu in '%s'",
820 GetLocation().c_str(),
821 (expect_all ? "" : "<="),
822 max_dex_files,
823 new_dex_files.size(),
824 dex_file_location.c_str());
825 return false;
826 }
827 for (std::unique_ptr<const DexFile>& dex_file : new_dex_files) {
828 external_dex_files_.push_back(std::move(dex_file));
829 }
830 }
831 // Defensively verify external dex file checksum.
832 if (dex_file_checksum != external_dex_files_[i]->GetLocationChecksum()) {
833 *error_msg = StringPrintf("In oat file '%s', dex file checksum 0x%08x does not match"
834 " checksum 0x%08x of external dex file '%s'",
835 GetLocation().c_str(),
836 dex_file_checksum,
837 external_dex_files_[i]->GetLocationChecksum(),
838 external_dex_files_[i]->GetLocation().c_str());
839 return false;
840 }
841 dex_file_pointer = external_dex_files_[i]->Begin();
842 } else {
843 // Do not support mixed-mode oat files.
844 if (!external_dex_files_.empty()) {
845 *error_msg = StringPrintf("In oat file '%s', unsupported embedded dex-file for dex file "
846 "%zu (%s)",
847 GetLocation().c_str(),
848 i,
849 dex_file_location.c_str());
850 return false;
851 }
852 if (UNLIKELY(DexSize() - dex_file_offset < sizeof(DexFile::Header))) {
853 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file "
854 "offset %u of %zu but the size of dex file header is %zu",
855 GetLocation().c_str(),
856 i,
857 dex_file_location.c_str(),
858 dex_file_offset,
859 DexSize(),
860 sizeof(DexFile::Header));
861 return false;
862 }
863 dex_file_pointer = DexBegin() + dex_file_offset;
864 }
865
866 const bool valid_magic = DexFileLoader::IsMagicValid(dex_file_pointer);
867 if (UNLIKELY(!valid_magic)) {
868 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid "
869 "dex file magic",
870 GetLocation().c_str(),
871 i,
872 dex_file_location.c_str());
873 return false;
874 }
875 if (UNLIKELY(!DexFileLoader::IsVersionAndMagicValid(dex_file_pointer))) {
876 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid "
877 "dex file version",
878 GetLocation().c_str(),
879 i,
880 dex_file_location.c_str());
881 return false;
882 }
883 const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer);
884 if (dex_file_offset != 0 && (DexSize() - dex_file_offset < header->file_size_)) {
885 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file "
886 "offset %u and size %u truncated at %zu",
887 GetLocation().c_str(),
888 i,
889 dex_file_location.c_str(),
890 dex_file_offset,
891 header->file_size_,
892 DexSize());
893 return false;
894 }
895
896 uint32_t class_offsets_offset;
897 if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &class_offsets_offset))) {
898 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' truncated "
899 "after class offsets offset",
900 GetLocation().c_str(),
901 i,
902 dex_file_location.c_str());
903 return false;
904 }
905 if (UNLIKELY(class_offsets_offset > Size()) ||
906 UNLIKELY((Size() - class_offsets_offset) / sizeof(uint32_t) < header->class_defs_size_)) {
907 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with truncated "
908 "class offsets, offset %u of %zu, class defs %u",
909 GetLocation().c_str(),
910 i,
911 dex_file_location.c_str(),
912 class_offsets_offset,
913 Size(),
914 header->class_defs_size_);
915 return false;
916 }
917 if (UNLIKELY(!IsAligned<alignof(uint32_t)>(class_offsets_offset))) {
918 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with unaligned "
919 "class offsets, offset %u",
920 GetLocation().c_str(),
921 i,
922 dex_file_location.c_str(),
923 class_offsets_offset);
924 return false;
925 }
926 const uint32_t* class_offsets_pointer =
927 reinterpret_cast<const uint32_t*>(Begin() + class_offsets_offset);
928
929 uint32_t lookup_table_offset;
930 if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &lookup_table_offset))) {
931 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated "
932 "after lookup table offset",
933 GetLocation().c_str(),
934 i,
935 dex_file_location.c_str());
936 return false;
937 }
938 const uint8_t* lookup_table_data = lookup_table_offset != 0u
939 ? DexBegin() + lookup_table_offset
940 : nullptr;
941 if (lookup_table_offset != 0u &&
942 (UNLIKELY(lookup_table_offset > DexSize()) ||
943 UNLIKELY(DexSize() - lookup_table_offset <
944 TypeLookupTable::RawDataLength(header->class_defs_size_)))) {
945 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with truncated "
946 "type lookup table, offset %u of %zu, class defs %u",
947 GetLocation().c_str(),
948 i,
949 dex_file_location.c_str(),
950 lookup_table_offset,
951 Size(),
952 header->class_defs_size_);
953 return false;
954 }
955
956 uint32_t dex_layout_sections_offset;
957 if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_layout_sections_offset))) {
958 *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated "
959 "after dex layout sections offset",
960 GetLocation().c_str(),
961 i,
962 dex_file_location.c_str());
963 return false;
964 }
965 const DexLayoutSections* const dex_layout_sections = dex_layout_sections_offset != 0
966 ? reinterpret_cast<const DexLayoutSections*>(Begin() + dex_layout_sections_offset)
967 : nullptr;
968
969 const IndexBssMapping* method_bss_mapping;
970 const IndexBssMapping* type_bss_mapping;
971 const IndexBssMapping* public_type_bss_mapping;
972 const IndexBssMapping* package_type_bss_mapping;
973 const IndexBssMapping* string_bss_mapping;
974 auto read_index_bss_mapping = [&](const char* tag, /*out*/const IndexBssMapping** mapping) {
975 return ReadIndexBssMapping(this, &oat, i, dex_file_location, tag, mapping, error_msg);
976 };
977 if (!read_index_bss_mapping("method", &method_bss_mapping) ||
978 !read_index_bss_mapping("type", &type_bss_mapping) ||
979 !read_index_bss_mapping("public type", &public_type_bss_mapping) ||
980 !read_index_bss_mapping("package type", &package_type_bss_mapping) ||
981 !read_index_bss_mapping("string", &string_bss_mapping)) {
982 return false;
983 }
984
985 // Create the OatDexFile and add it to the owning container.
986 OatDexFile* oat_dex_file = new OatDexFile(
987 this,
988 dex_file_location,
989 DexFileLoader::GetDexCanonicalLocation(dex_file_name.c_str()),
990 dex_file_checksum,
991 dex_file_pointer,
992 lookup_table_data,
993 method_bss_mapping,
994 type_bss_mapping,
995 public_type_bss_mapping,
996 package_type_bss_mapping,
997 string_bss_mapping,
998 class_offsets_pointer,
999 dex_layout_sections);
1000 oat_dex_files_storage_.push_back(oat_dex_file);
1001
1002 // Add the location and canonical location (if different) to the oat_dex_files_ table.
1003 // Note: We do not add the non-canonical `dex_file_name`. If it is different from both
1004 // the location and canonical location, GetOatDexFile() shall canonicalize it when
1005 // requested and match the canonical path.
1006 std::string_view key = oat_dex_file_location; // References oat file data.
1007 std::string_view canonical_key(oat_dex_file->GetCanonicalDexFileLocation());
1008 oat_dex_files_.Put(key, oat_dex_file);
1009 if (canonical_key != key) {
1010 oat_dex_files_.Put(canonical_key, oat_dex_file);
1011 }
1012 }
1013
1014 size_t bcp_info_offset = GetOatHeader().GetBcpBssInfoOffset();
1015 // `bcp_info_offset` will be 0 for multi-image, or for the case of no mappings.
1016 if (bcp_info_offset != 0) {
1017 // Consistency check.
1018 if (bcp_info_offset < GetOatHeader().GetHeaderSize() || bcp_info_offset > Size()) {
1019 *error_msg = StringPrintf(
1020 "In oat file '%s' found invalid bcp info offset: "
1021 "%zu is not in [%zu, %zu]",
1022 GetLocation().c_str(),
1023 bcp_info_offset,
1024 GetOatHeader().GetHeaderSize(),
1025 Size());
1026 return false;
1027 }
1028 const uint8_t* bcp_info_begin = Begin() + bcp_info_offset; // Jump to the BCP_info records.
1029
1030 uint32_t number_of_bcp_dexfiles;
1031 if (UNLIKELY(!ReadOatDexFileData(*this, &bcp_info_begin, &number_of_bcp_dexfiles))) {
1032 *error_msg = StringPrintf("Failed to read the number of BCP dex files");
1033 return false;
1034 }
1035 Runtime* const runtime = Runtime::Current();
1036 ClassLinker* const linker = runtime != nullptr ? runtime->GetClassLinker() : nullptr;
1037 if (linker != nullptr && UNLIKELY(number_of_bcp_dexfiles > linker->GetBootClassPath().size())) {
1038 // If we compiled with more DexFiles than what we have at runtime, we expect to discard this
1039 // OatFile after verifying its checksum in OatFileAssistant. Therefore, we set
1040 // `number_of_bcp_dexfiles` to 0 to avoid reading data that will ultimately be discarded.
1041 number_of_bcp_dexfiles = 0;
1042 }
1043
1044 DCHECK(bcp_bss_info_.empty());
1045 bcp_bss_info_.resize(number_of_bcp_dexfiles);
1046 // At runtime, there might be more DexFiles added to the BCP that we didn't compile with.
1047 // We only care about the ones in [0..number_of_bcp_dexfiles).
1048 for (size_t i = 0, size = number_of_bcp_dexfiles; i != size; ++i) {
1049 const std::string& dex_file_location = linker != nullptr ?
1050 linker->GetBootClassPath()[i]->GetLocation() :
1051 "No runtime/linker therefore no DexFile location";
1052 auto read_index_bss_mapping = [&](const char* tag, /*out*/const IndexBssMapping** mapping) {
1053 return ReadIndexBssMapping(
1054 this, &bcp_info_begin, i, dex_file_location, tag, mapping, error_msg);
1055 };
1056 if (!read_index_bss_mapping("method", &bcp_bss_info_[i].method_bss_mapping) ||
1057 !read_index_bss_mapping("type", &bcp_bss_info_[i].type_bss_mapping) ||
1058 !read_index_bss_mapping("public type", &bcp_bss_info_[i].public_type_bss_mapping) ||
1059 !read_index_bss_mapping("package type", &bcp_bss_info_[i].package_type_bss_mapping) ||
1060 !read_index_bss_mapping("string", &bcp_bss_info_[i].string_bss_mapping)) {
1061 return false;
1062 }
1063 }
1064 }
1065
1066 if (!dex_filenames.empty() && dex_filenames_pos != dex_filenames.size()) {
1067 *error_msg = StringPrintf("Oat file '%s' contains only %zu primary dex locations, expected %zu",
1068 GetLocation().c_str(),
1069 dex_filenames_pos,
1070 dex_filenames.size());
1071 return false;
1072 }
1073
1074 if (DataBimgRelRoBegin() != nullptr) {
1075 // Make .data.bimg.rel.ro read only. ClassLinker shall temporarily make it writable for
1076 // relocation when we register a dex file from this oat file. We do not do the relocation
1077 // here to avoid dirtying the pages if the code is never actually ready to be executed.
1078 uint8_t* reloc_begin = const_cast<uint8_t*>(DataBimgRelRoBegin());
1079 CheckedCall(mprotect, "protect relocations", reloc_begin, DataBimgRelRoSize(), PROT_READ);
1080 // Make sure the file lists a boot image dependency, otherwise the .data.bimg.rel.ro
1081 // section is bogus. The full dependency is checked before the code is executed.
1082 // We cannot do this check if we do not have a key-value store, i.e. for secondary
1083 // oat files for boot image extensions.
1084 if (GetOatHeader().GetKeyValueStoreSize() != 0u) {
1085 const char* boot_class_path_checksum =
1086 GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
1087 if (boot_class_path_checksum == nullptr ||
1088 boot_class_path_checksum[0] != gc::space::ImageSpace::kImageChecksumPrefix) {
1089 *error_msg = StringPrintf("Oat file '%s' contains .data.bimg.rel.ro section "
1090 "without boot image dependency.",
1091 GetLocation().c_str());
1092 return false;
1093 }
1094 }
1095 }
1096
1097 return true;
1098 }
1099
1100 ////////////////////////
1101 // OatFile via dlopen //
1102 ////////////////////////
1103
1104 class DlOpenOatFile final : public OatFileBase {
1105 public:
DlOpenOatFile(const std::string & filename,bool executable)1106 DlOpenOatFile(const std::string& filename, bool executable)
1107 : OatFileBase(filename, executable),
1108 dlopen_handle_(nullptr),
1109 shared_objects_before_(0) {
1110 }
1111
~DlOpenOatFile()1112 ~DlOpenOatFile() {
1113 if (dlopen_handle_ != nullptr) {
1114 if (!kIsTargetBuild) {
1115 MutexLock mu(Thread::Current(), *Locks::host_dlopen_handles_lock_);
1116 host_dlopen_handles_.erase(dlopen_handle_);
1117 dlclose(dlopen_handle_);
1118 } else {
1119 dlclose(dlopen_handle_);
1120 }
1121 }
1122 }
1123
1124 protected:
FindDynamicSymbolAddress(const std::string & symbol_name,std::string * error_msg) const1125 const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name,
1126 std::string* error_msg) const override {
1127 const uint8_t* ptr =
1128 reinterpret_cast<const uint8_t*>(dlsym(dlopen_handle_, symbol_name.c_str()));
1129 if (ptr == nullptr) {
1130 *error_msg = dlerror();
1131 }
1132 return ptr;
1133 }
1134
1135 void PreLoad() override;
1136
1137 bool Load(const std::string& elf_filename,
1138 bool writable,
1139 bool executable,
1140 bool low_4gb,
1141 /*inout*/MemMap* reservation, // Where to load if not null.
1142 /*out*/std::string* error_msg) override;
1143
Load(int oat_fd ATTRIBUTE_UNUSED,bool writable ATTRIBUTE_UNUSED,bool executable ATTRIBUTE_UNUSED,bool low_4gb ATTRIBUTE_UNUSED,MemMap * reservation ATTRIBUTE_UNUSED,std::string * error_msg ATTRIBUTE_UNUSED)1144 bool Load(int oat_fd ATTRIBUTE_UNUSED,
1145 bool writable ATTRIBUTE_UNUSED,
1146 bool executable ATTRIBUTE_UNUSED,
1147 bool low_4gb ATTRIBUTE_UNUSED,
1148 /*inout*/MemMap* reservation ATTRIBUTE_UNUSED,
1149 /*out*/std::string* error_msg ATTRIBUTE_UNUSED) override {
1150 return false;
1151 }
1152
1153 // Ask the linker where it mmaped the file and notify our mmap wrapper of the regions.
1154 void PreSetup(const std::string& elf_filename) override;
1155
1156 private:
1157 bool Dlopen(const std::string& elf_filename,
1158 /*inout*/MemMap* reservation, // Where to load if not null.
1159 /*out*/std::string* error_msg);
1160
1161 // On the host, if the same library is loaded again with dlopen the same
1162 // file handle is returned. This differs from the behavior of dlopen on the
1163 // target, where dlopen reloads the library at a different address every
1164 // time you load it. The runtime relies on the target behavior to ensure
1165 // each instance of the loaded library has a unique dex cache. To avoid
1166 // problems, we fall back to our own linker in the case when the same
1167 // library is opened multiple times on host. dlopen_handles_ is used to
1168 // detect that case.
1169 // Guarded by host_dlopen_handles_lock_;
1170 static std::unordered_set<void*> host_dlopen_handles_;
1171
1172 // Reservation and placeholder memory map objects corresponding to the regions mapped by dlopen.
1173 // Note: Must be destroyed after dlclose() as it can hold the owning reservation.
1174 std::vector<MemMap> dlopen_mmaps_;
1175
1176 // dlopen handle during runtime.
1177 void* dlopen_handle_; // TODO: Unique_ptr with custom deleter.
1178
1179 // The number of shared objects the linker told us about before loading. Used to
1180 // (optimistically) optimize the PreSetup stage (see comment there).
1181 size_t shared_objects_before_;
1182
1183 DISALLOW_COPY_AND_ASSIGN(DlOpenOatFile);
1184 };
1185
1186 std::unordered_set<void*> DlOpenOatFile::host_dlopen_handles_;
1187
PreLoad()1188 void DlOpenOatFile::PreLoad() {
1189 #ifdef __APPLE__
1190 UNUSED(shared_objects_before_);
1191 LOG(FATAL) << "Should not reach here.";
1192 UNREACHABLE();
1193 #else
1194 // Count the entries in dl_iterate_phdr we get at this point in time.
1195 struct dl_iterate_context {
1196 static int callback(dl_phdr_info* info ATTRIBUTE_UNUSED,
1197 size_t size ATTRIBUTE_UNUSED,
1198 void* data) {
1199 reinterpret_cast<dl_iterate_context*>(data)->count++;
1200 return 0; // Continue iteration.
1201 }
1202 size_t count = 0;
1203 } context;
1204
1205 dl_iterate_phdr(dl_iterate_context::callback, &context);
1206 shared_objects_before_ = context.count;
1207 #endif
1208 }
1209
Load(const std::string & elf_filename,bool writable,bool executable,bool low_4gb,MemMap * reservation,std::string * error_msg)1210 bool DlOpenOatFile::Load(const std::string& elf_filename,
1211 bool writable,
1212 bool executable,
1213 bool low_4gb,
1214 /*inout*/MemMap* reservation, // Where to load if not null.
1215 /*out*/std::string* error_msg) {
1216 // Use dlopen only when flagged to do so, and when it's OK to load things executable.
1217 // TODO: Also try when not executable? The issue here could be re-mapping as writable (as
1218 // !executable is a sign that we may want to patch), which may not be allowed for
1219 // various reasons.
1220 if (!kUseDlopen) {
1221 *error_msg = "DlOpen is disabled.";
1222 return false;
1223 }
1224 if (low_4gb) {
1225 *error_msg = "DlOpen does not support low 4gb loading.";
1226 return false;
1227 }
1228 if (writable) {
1229 *error_msg = "DlOpen does not support writable loading.";
1230 return false;
1231 }
1232 if (!executable) {
1233 *error_msg = "DlOpen does not support non-executable loading.";
1234 return false;
1235 }
1236
1237 // dlopen always returns the same library if it is already opened on the host. For this reason
1238 // we only use dlopen if we are the target or we do not already have the dex file opened. Having
1239 // the same library loaded multiple times at different addresses is required for class unloading
1240 // and for having dex caches arrays in the .bss section.
1241 if (!kIsTargetBuild) {
1242 if (!kUseDlopenOnHost) {
1243 *error_msg = "DlOpen disabled for host.";
1244 return false;
1245 }
1246 }
1247
1248 bool success = Dlopen(elf_filename, reservation, error_msg);
1249 DCHECK_IMPLIES(dlopen_handle_ == nullptr, !success);
1250
1251 return success;
1252 }
1253
1254 #ifdef ART_TARGET_ANDROID
GetSystemLinkerNamespace()1255 static struct android_namespace_t* GetSystemLinkerNamespace() {
1256 static struct android_namespace_t* system_ns = []() {
1257 // The system namespace is called "default" for binaries in /system and
1258 // "system" for those in the ART APEX. Try "system" first since "default"
1259 // always exists.
1260 // TODO(b/185587109): Get rid of this error prone logic.
1261 struct android_namespace_t* ns = android_get_exported_namespace("system");
1262 if (ns == nullptr) {
1263 ns = android_get_exported_namespace("default");
1264 if (ns == nullptr) {
1265 LOG(FATAL) << "Failed to get system namespace for loading OAT files";
1266 }
1267 }
1268 return ns;
1269 }();
1270 return system_ns;
1271 }
1272 #endif // ART_TARGET_ANDROID
1273
Dlopen(const std::string & elf_filename,MemMap * reservation,std::string * error_msg)1274 bool DlOpenOatFile::Dlopen(const std::string& elf_filename,
1275 /*inout*/MemMap* reservation,
1276 /*out*/std::string* error_msg) {
1277 #ifdef __APPLE__
1278 // The dl_iterate_phdr syscall is missing. There is similar API on OSX,
1279 // but let's fallback to the custom loading code for the time being.
1280 UNUSED(elf_filename, reservation);
1281 *error_msg = "Dlopen unsupported on Mac.";
1282 return false;
1283 #else
1284 {
1285 UniqueCPtr<char> absolute_path(realpath(elf_filename.c_str(), nullptr));
1286 if (absolute_path == nullptr) {
1287 *error_msg = StringPrintf("Failed to find absolute path for '%s'", elf_filename.c_str());
1288 return false;
1289 }
1290 #ifdef ART_TARGET_ANDROID
1291 android_dlextinfo extinfo = {};
1292 extinfo.flags = ANDROID_DLEXT_FORCE_LOAD; // Force-load, don't reuse handle
1293 // (open oat files multiple times).
1294 if (reservation != nullptr) {
1295 if (!reservation->IsValid()) {
1296 *error_msg = StringPrintf("Invalid reservation for %s", elf_filename.c_str());
1297 return false;
1298 }
1299 extinfo.flags |= ANDROID_DLEXT_RESERVED_ADDRESS; // Use the reserved memory range.
1300 extinfo.reserved_addr = reservation->Begin();
1301 extinfo.reserved_size = reservation->Size();
1302 }
1303
1304 if (strncmp(kAndroidArtApexDefaultPath,
1305 absolute_path.get(),
1306 sizeof(kAndroidArtApexDefaultPath) - 1) != 0 ||
1307 absolute_path.get()[sizeof(kAndroidArtApexDefaultPath) - 1] != '/') {
1308 // Use the system namespace for OAT files outside the ART APEX. Search
1309 // paths and links don't matter here, but permitted paths do, and the
1310 // system namespace is configured to allow loading from all appropriate
1311 // locations.
1312 extinfo.flags |= ANDROID_DLEXT_USE_NAMESPACE;
1313 extinfo.library_namespace = GetSystemLinkerNamespace();
1314 }
1315
1316 dlopen_handle_ = android_dlopen_ext(absolute_path.get(), RTLD_NOW, &extinfo);
1317 if (reservation != nullptr && dlopen_handle_ != nullptr) {
1318 // Find used pages from the reservation.
1319 struct dl_iterate_context {
1320 static int callback(dl_phdr_info* info, size_t size ATTRIBUTE_UNUSED, void* data) {
1321 auto* context = reinterpret_cast<dl_iterate_context*>(data);
1322 static_assert(std::is_same<Elf32_Half, Elf64_Half>::value, "Half must match");
1323 using Elf_Half = Elf64_Half;
1324
1325 // See whether this callback corresponds to the file which we have just loaded.
1326 uint8_t* reservation_begin = context->reservation->Begin();
1327 bool contained_in_reservation = false;
1328 for (Elf_Half i = 0; i < info->dlpi_phnum; i++) {
1329 if (info->dlpi_phdr[i].p_type == PT_LOAD) {
1330 uint8_t* vaddr = reinterpret_cast<uint8_t*>(info->dlpi_addr +
1331 info->dlpi_phdr[i].p_vaddr);
1332 size_t memsz = info->dlpi_phdr[i].p_memsz;
1333 size_t offset = static_cast<size_t>(vaddr - reservation_begin);
1334 if (offset < context->reservation->Size()) {
1335 contained_in_reservation = true;
1336 DCHECK_LE(memsz, context->reservation->Size() - offset);
1337 } else if (vaddr < reservation_begin) {
1338 // Check that there's no overlap with the reservation.
1339 DCHECK_LE(memsz, static_cast<size_t>(reservation_begin - vaddr));
1340 }
1341 break; // It is sufficient to check the first PT_LOAD header.
1342 }
1343 }
1344
1345 if (contained_in_reservation) {
1346 for (Elf_Half i = 0; i < info->dlpi_phnum; i++) {
1347 if (info->dlpi_phdr[i].p_type == PT_LOAD) {
1348 uint8_t* vaddr = reinterpret_cast<uint8_t*>(info->dlpi_addr +
1349 info->dlpi_phdr[i].p_vaddr);
1350 size_t memsz = info->dlpi_phdr[i].p_memsz;
1351 size_t offset = static_cast<size_t>(vaddr - reservation_begin);
1352 DCHECK_LT(offset, context->reservation->Size());
1353 DCHECK_LE(memsz, context->reservation->Size() - offset);
1354 context->max_size = std::max(context->max_size, offset + memsz);
1355 }
1356 }
1357
1358 return 1; // Stop iteration and return 1 from dl_iterate_phdr.
1359 }
1360 return 0; // Continue iteration and return 0 from dl_iterate_phdr when finished.
1361 }
1362
1363 const MemMap* const reservation;
1364 size_t max_size = 0u;
1365 };
1366 dl_iterate_context context = { reservation };
1367
1368 if (dl_iterate_phdr(dl_iterate_context::callback, &context) == 0) {
1369 LOG(FATAL) << "Could not find the shared object mmapped to the reservation.";
1370 UNREACHABLE();
1371 }
1372
1373 // Take ownership of the memory used by the shared object. dlopen() does not assume
1374 // full ownership of this memory and dlclose() shall just remap it as zero pages with
1375 // PROT_NONE. We need to unmap the memory when destroying this oat file.
1376 dlopen_mmaps_.push_back(reservation->TakeReservedMemory(context.max_size));
1377 }
1378 #else
1379 static_assert(!kIsTargetBuild || kIsTargetLinux || kIsTargetFuchsia,
1380 "host_dlopen_handles_ will leak handles");
1381 if (reservation != nullptr) {
1382 *error_msg = StringPrintf("dlopen() into reserved memory is unsupported on host for '%s'.",
1383 elf_filename.c_str());
1384 return false;
1385 }
1386 MutexLock mu(Thread::Current(), *Locks::host_dlopen_handles_lock_);
1387 dlopen_handle_ = dlopen(absolute_path.get(), RTLD_NOW);
1388 if (dlopen_handle_ != nullptr) {
1389 if (!host_dlopen_handles_.insert(dlopen_handle_).second) {
1390 dlclose(dlopen_handle_);
1391 dlopen_handle_ = nullptr;
1392 *error_msg = StringPrintf("host dlopen re-opened '%s'", elf_filename.c_str());
1393 return false;
1394 }
1395 }
1396 #endif // ART_TARGET_ANDROID
1397 }
1398 if (dlopen_handle_ == nullptr) {
1399 *error_msg = StringPrintf("Failed to dlopen '%s': %s", elf_filename.c_str(), dlerror());
1400 return false;
1401 }
1402 return true;
1403 #endif
1404 }
1405
PreSetup(const std::string & elf_filename)1406 void DlOpenOatFile::PreSetup(const std::string& elf_filename) {
1407 #ifdef __APPLE__
1408 UNUSED(elf_filename);
1409 LOG(FATAL) << "Should not reach here.";
1410 UNREACHABLE();
1411 #else
1412 struct PlaceholderMapData {
1413 const char* name;
1414 uint8_t* vaddr;
1415 size_t memsz;
1416 };
1417 struct dl_iterate_context {
1418 static int callback(dl_phdr_info* info, size_t size ATTRIBUTE_UNUSED, void* data) {
1419 auto* context = reinterpret_cast<dl_iterate_context*>(data);
1420 static_assert(std::is_same<Elf32_Half, Elf64_Half>::value, "Half must match");
1421 using Elf_Half = Elf64_Half;
1422
1423 context->shared_objects_seen++;
1424 if (context->shared_objects_seen < context->shared_objects_before) {
1425 // We haven't been called yet for anything we haven't seen before. Just continue.
1426 // Note: this is aggressively optimistic. If another thread was unloading a library,
1427 // we may miss out here. However, this does not happen often in practice.
1428 return 0;
1429 }
1430
1431 // See whether this callback corresponds to the file which we have just loaded.
1432 bool contains_begin = false;
1433 for (Elf_Half i = 0; i < info->dlpi_phnum; i++) {
1434 if (info->dlpi_phdr[i].p_type == PT_LOAD) {
1435 uint8_t* vaddr = reinterpret_cast<uint8_t*>(info->dlpi_addr +
1436 info->dlpi_phdr[i].p_vaddr);
1437 size_t memsz = info->dlpi_phdr[i].p_memsz;
1438 if (vaddr <= context->begin_ && context->begin_ < vaddr + memsz) {
1439 contains_begin = true;
1440 break;
1441 }
1442 }
1443 }
1444 // Add placeholder mmaps for this file.
1445 if (contains_begin) {
1446 for (Elf_Half i = 0; i < info->dlpi_phnum; i++) {
1447 if (info->dlpi_phdr[i].p_type == PT_LOAD) {
1448 uint8_t* vaddr = reinterpret_cast<uint8_t*>(info->dlpi_addr +
1449 info->dlpi_phdr[i].p_vaddr);
1450 size_t memsz = info->dlpi_phdr[i].p_memsz;
1451 size_t name_size = strlen(info->dlpi_name) + 1u;
1452 std::vector<char>* placeholder_maps_names = context->placeholder_maps_names_;
1453 // We must not allocate any memory in the callback, see b/156312036 .
1454 if (name_size < placeholder_maps_names->capacity() - placeholder_maps_names->size() &&
1455 context->placeholder_maps_data_->size() <
1456 context->placeholder_maps_data_->capacity()) {
1457 placeholder_maps_names->insert(
1458 placeholder_maps_names->end(), info->dlpi_name, info->dlpi_name + name_size);
1459 const char* name =
1460 &(*placeholder_maps_names)[placeholder_maps_names->size() - name_size];
1461 context->placeholder_maps_data_->push_back({ name, vaddr, memsz });
1462 }
1463 context->num_placeholder_maps_ += 1u;
1464 context->placeholder_maps_names_size_ += name_size;
1465 }
1466 }
1467 return 1; // Stop iteration and return 1 from dl_iterate_phdr.
1468 }
1469 return 0; // Continue iteration and return 0 from dl_iterate_phdr when finished.
1470 }
1471 const uint8_t* const begin_;
1472 std::vector<PlaceholderMapData>* placeholder_maps_data_;
1473 size_t num_placeholder_maps_;
1474 std::vector<char>* placeholder_maps_names_;
1475 size_t placeholder_maps_names_size_;
1476 size_t shared_objects_before;
1477 size_t shared_objects_seen;
1478 };
1479
1480 // We must not allocate any memory in the callback, see b/156312036 .
1481 // Therefore we pre-allocate storage for the data we need for creating the placeholder maps.
1482 std::vector<PlaceholderMapData> placeholder_maps_data;
1483 placeholder_maps_data.reserve(32); // 32 should be enough. If not, we'll retry.
1484 std::vector<char> placeholder_maps_names;
1485 placeholder_maps_names.reserve(4 * KB); // 4KiB should be enough. If not, we'll retry.
1486
1487 dl_iterate_context context = {
1488 Begin(),
1489 &placeholder_maps_data,
1490 /*num_placeholder_maps_*/ 0u,
1491 &placeholder_maps_names,
1492 /*placeholder_maps_names_size_*/ 0u,
1493 shared_objects_before_,
1494 /*shared_objects_seen*/ 0u
1495 };
1496
1497 if (dl_iterate_phdr(dl_iterate_context::callback, &context) == 0) {
1498 // Hm. Maybe our optimization went wrong. Try another time with shared_objects_before == 0
1499 // before giving up. This should be unusual.
1500 VLOG(oat) << "Need a second run in PreSetup, didn't find with shared_objects_before="
1501 << shared_objects_before_;
1502 DCHECK(placeholder_maps_data.empty());
1503 DCHECK_EQ(context.num_placeholder_maps_, 0u);
1504 DCHECK(placeholder_maps_names.empty());
1505 DCHECK_EQ(context.placeholder_maps_names_size_, 0u);
1506 context.shared_objects_before = 0u;
1507 context.shared_objects_seen = 0u;
1508 if (dl_iterate_phdr(dl_iterate_context::callback, &context) == 0) {
1509 // OK, give up and print an error.
1510 PrintFileToLog("/proc/self/maps", android::base::LogSeverity::WARNING);
1511 LOG(ERROR) << "File " << elf_filename << " loaded with dlopen but cannot find its mmaps.";
1512 }
1513 }
1514
1515 if (placeholder_maps_data.size() < context.num_placeholder_maps_) {
1516 // Insufficient capacity. Reserve more space and retry.
1517 placeholder_maps_data.clear();
1518 placeholder_maps_data.reserve(context.num_placeholder_maps_);
1519 context.num_placeholder_maps_ = 0u;
1520 placeholder_maps_names.clear();
1521 placeholder_maps_names.reserve(context.placeholder_maps_names_size_);
1522 context.placeholder_maps_names_size_ = 0u;
1523 context.shared_objects_before = 0u;
1524 context.shared_objects_seen = 0u;
1525 bool success = (dl_iterate_phdr(dl_iterate_context::callback, &context) != 0);
1526 CHECK(success);
1527 }
1528
1529 CHECK_EQ(placeholder_maps_data.size(), context.num_placeholder_maps_);
1530 CHECK_EQ(placeholder_maps_names.size(), context.placeholder_maps_names_size_);
1531 DCHECK_EQ(static_cast<size_t>(std::count(placeholder_maps_names.begin(),
1532 placeholder_maps_names.end(), '\0')),
1533 context.num_placeholder_maps_);
1534 for (const PlaceholderMapData& data : placeholder_maps_data) {
1535 MemMap mmap = MemMap::MapPlaceholder(data.name, data.vaddr, data.memsz);
1536 dlopen_mmaps_.push_back(std::move(mmap));
1537 }
1538 #endif
1539 }
1540
1541 ////////////////////////////////////////////////
1542 // OatFile via our own ElfFile implementation //
1543 ////////////////////////////////////////////////
1544
1545 class ElfOatFile final : public OatFileBase {
1546 public:
ElfOatFile(const std::string & filename,bool executable)1547 ElfOatFile(const std::string& filename, bool executable) : OatFileBase(filename, executable) {}
1548
1549 bool InitializeFromElfFile(int zip_fd,
1550 ElfFile* elf_file,
1551 VdexFile* vdex_file,
1552 ArrayRef<const std::string> dex_filenames,
1553 std::string* error_msg);
1554
1555 protected:
FindDynamicSymbolAddress(const std::string & symbol_name,std::string * error_msg) const1556 const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name,
1557 std::string* error_msg) const override {
1558 const uint8_t* ptr = elf_file_->FindDynamicSymbolAddress(symbol_name);
1559 if (ptr == nullptr) {
1560 *error_msg = "(Internal implementation could not find symbol)";
1561 }
1562 return ptr;
1563 }
1564
PreLoad()1565 void PreLoad() override {
1566 }
1567
1568 bool Load(const std::string& elf_filename,
1569 bool writable,
1570 bool executable,
1571 bool low_4gb,
1572 /*inout*/MemMap* reservation, // Where to load if not null.
1573 /*out*/std::string* error_msg) override;
1574
1575 bool Load(int oat_fd,
1576 bool writable,
1577 bool executable,
1578 bool low_4gb,
1579 /*inout*/MemMap* reservation, // Where to load if not null.
1580 /*out*/std::string* error_msg) override;
1581
PreSetup(const std::string & elf_filename ATTRIBUTE_UNUSED)1582 void PreSetup(const std::string& elf_filename ATTRIBUTE_UNUSED) override {
1583 }
1584
1585 private:
1586 bool ElfFileOpen(File* file,
1587 bool writable,
1588 bool executable,
1589 bool low_4gb,
1590 /*inout*/MemMap* reservation, // Where to load if not null.
1591 /*out*/std::string* error_msg);
1592
1593 private:
1594 // Backing memory map for oat file during cross compilation.
1595 std::unique_ptr<ElfFile> elf_file_;
1596
1597 DISALLOW_COPY_AND_ASSIGN(ElfOatFile);
1598 };
1599
InitializeFromElfFile(int zip_fd,ElfFile * elf_file,VdexFile * vdex_file,ArrayRef<const std::string> dex_filenames,std::string * error_msg)1600 bool ElfOatFile::InitializeFromElfFile(int zip_fd,
1601 ElfFile* elf_file,
1602 VdexFile* vdex_file,
1603 ArrayRef<const std::string> dex_filenames,
1604 std::string* error_msg) {
1605 ScopedTrace trace(__PRETTY_FUNCTION__);
1606 if (IsExecutable()) {
1607 *error_msg = "Cannot initialize from elf file in executable mode.";
1608 return false;
1609 }
1610 elf_file_.reset(elf_file);
1611 SetVdex(vdex_file);
1612 uint64_t offset, size;
1613 bool has_section = elf_file->GetSectionOffsetAndSize(".rodata", &offset, &size);
1614 CHECK(has_section);
1615 SetBegin(elf_file->Begin() + offset);
1616 SetEnd(elf_file->Begin() + size + offset);
1617 // Ignore the optional .bss section when opening non-executable.
1618 return Setup(zip_fd, dex_filenames, /*dex_fds=*/ArrayRef<const int>(), error_msg);
1619 }
1620
Load(const std::string & elf_filename,bool writable,bool executable,bool low_4gb,MemMap * reservation,std::string * error_msg)1621 bool ElfOatFile::Load(const std::string& elf_filename,
1622 bool writable,
1623 bool executable,
1624 bool low_4gb,
1625 /*inout*/MemMap* reservation,
1626 /*out*/std::string* error_msg) {
1627 ScopedTrace trace(__PRETTY_FUNCTION__);
1628 std::unique_ptr<File> file(OS::OpenFileForReading(elf_filename.c_str()));
1629 if (file == nullptr) {
1630 *error_msg = StringPrintf("Failed to open oat filename for reading: %s", strerror(errno));
1631 return false;
1632 }
1633 return ElfOatFile::ElfFileOpen(file.get(),
1634 writable,
1635 executable,
1636 low_4gb,
1637 reservation,
1638 error_msg);
1639 }
1640
Load(int oat_fd,bool writable,bool executable,bool low_4gb,MemMap * reservation,std::string * error_msg)1641 bool ElfOatFile::Load(int oat_fd,
1642 bool writable,
1643 bool executable,
1644 bool low_4gb,
1645 /*inout*/MemMap* reservation,
1646 /*out*/std::string* error_msg) {
1647 ScopedTrace trace(__PRETTY_FUNCTION__);
1648 if (oat_fd != -1) {
1649 int duped_fd = DupCloexec(oat_fd);
1650 std::unique_ptr<File> file = std::make_unique<File>(duped_fd, false);
1651 if (file == nullptr) {
1652 *error_msg = StringPrintf("Failed to open oat filename for reading: %s",
1653 strerror(errno));
1654 return false;
1655 }
1656 return ElfOatFile::ElfFileOpen(file.get(),
1657 writable,
1658 executable,
1659 low_4gb,
1660 reservation,
1661 error_msg);
1662 }
1663 return false;
1664 }
1665
ElfFileOpen(File * file,bool writable,bool executable,bool low_4gb,MemMap * reservation,std::string * error_msg)1666 bool ElfOatFile::ElfFileOpen(File* file,
1667 bool writable,
1668 bool executable,
1669 bool low_4gb,
1670 /*inout*/MemMap* reservation,
1671 /*out*/std::string* error_msg) {
1672 ScopedTrace trace(__PRETTY_FUNCTION__);
1673 elf_file_.reset(ElfFile::Open(file,
1674 writable,
1675 /*program_header_only=*/ true,
1676 low_4gb,
1677 error_msg));
1678 if (elf_file_ == nullptr) {
1679 DCHECK(!error_msg->empty());
1680 return false;
1681 }
1682 bool loaded = elf_file_->Load(file, executable, low_4gb, reservation, error_msg);
1683 DCHECK(loaded || !error_msg->empty());
1684 return loaded;
1685 }
1686
1687 class OatFileBackedByVdex final : public OatFileBase {
1688 public:
OatFileBackedByVdex(const std::string & filename)1689 explicit OatFileBackedByVdex(const std::string& filename)
1690 : OatFileBase(filename, /*executable=*/ false) {}
1691
Open(const std::vector<const DexFile * > & dex_files,std::unique_ptr<VdexFile> && vdex_file,const std::string & location)1692 static OatFileBackedByVdex* Open(const std::vector<const DexFile*>& dex_files,
1693 std::unique_ptr<VdexFile>&& vdex_file,
1694 const std::string& location) {
1695 std::unique_ptr<OatFileBackedByVdex> oat_file(new OatFileBackedByVdex(location));
1696 // SetVdex will take ownership of the VdexFile.
1697 oat_file->SetVdex(vdex_file.release());
1698 oat_file->SetupHeader(dex_files.size());
1699 // Initialize OatDexFiles.
1700 std::string error_msg;
1701 if (!oat_file->Setup(dex_files, &error_msg)) {
1702 LOG(WARNING) << "Could not create in-memory vdex file: " << error_msg;
1703 return nullptr;
1704 }
1705 return oat_file.release();
1706 }
1707
Open(int zip_fd,std::unique_ptr<VdexFile> && unique_vdex_file,const std::string & dex_location,std::string * error_msg)1708 static OatFileBackedByVdex* Open(int zip_fd,
1709 std::unique_ptr<VdexFile>&& unique_vdex_file,
1710 const std::string& dex_location,
1711 std::string* error_msg) {
1712 VdexFile* vdex_file = unique_vdex_file.get();
1713 std::unique_ptr<OatFileBackedByVdex> oat_file(new OatFileBackedByVdex(vdex_file->GetName()));
1714 // SetVdex will take ownership of the VdexFile.
1715 oat_file->SetVdex(unique_vdex_file.release());
1716 if (vdex_file->HasDexSection()) {
1717 uint32_t i = 0;
1718 const uint8_t* type_lookup_table_start = nullptr;
1719 for (const uint8_t* dex_file_start = vdex_file->GetNextDexFileData(nullptr, i);
1720 dex_file_start != nullptr;
1721 dex_file_start = vdex_file->GetNextDexFileData(dex_file_start, ++i)) {
1722 const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_start);
1723 if (UNLIKELY(!vdex_file->Contains(dex_file_start))) {
1724 *error_msg =
1725 StringPrintf("In vdex file '%s' found invalid dex file pointer %p not in [%p, %p]",
1726 dex_location.c_str(),
1727 dex_file_start,
1728 vdex_file->Begin(),
1729 vdex_file->End());
1730 return nullptr;
1731 }
1732 if (UNLIKELY(!vdex_file->Contains(dex_file_start + header->file_size_ - 1))) {
1733 *error_msg =
1734 StringPrintf("In vdex file '%s' found overflowing dex file %p not in [%p, %p]",
1735 dex_location.c_str(),
1736 dex_file_start + header->file_size_,
1737 vdex_file->Begin(),
1738 vdex_file->End());
1739 return nullptr;
1740 }
1741 if (UNLIKELY(!DexFileLoader::IsVersionAndMagicValid(dex_file_start))) {
1742 *error_msg =
1743 StringPrintf("In vdex file '%s' found dex file with invalid dex file version",
1744 dex_location.c_str());
1745 return nullptr;
1746 }
1747 // Create the OatDexFile and add it to the owning container.
1748 std::string location = DexFileLoader::GetMultiDexLocation(i, dex_location.c_str());
1749 std::string canonical_location = DexFileLoader::GetDexCanonicalLocation(location.c_str());
1750 type_lookup_table_start = vdex_file->GetNextTypeLookupTableData(type_lookup_table_start, i);
1751 const uint8_t* type_lookup_table_data = nullptr;
1752 if (!ComputeAndCheckTypeLookupTableData(*header,
1753 type_lookup_table_start,
1754 vdex_file,
1755 &type_lookup_table_data,
1756 error_msg)) {
1757 return nullptr;
1758 }
1759
1760 OatDexFile* oat_dex_file = new OatDexFile(oat_file.get(),
1761 dex_file_start,
1762 vdex_file->GetLocationChecksum(i),
1763 location,
1764 canonical_location,
1765 type_lookup_table_data);
1766 oat_file->oat_dex_files_storage_.push_back(oat_dex_file);
1767
1768 std::string_view key(oat_dex_file->GetDexFileLocation());
1769 oat_file->oat_dex_files_.Put(key, oat_dex_file);
1770 if (canonical_location != location) {
1771 std::string_view canonical_key(oat_dex_file->GetCanonicalDexFileLocation());
1772 oat_file->oat_dex_files_.Put(canonical_key, oat_dex_file);
1773 }
1774 }
1775 oat_file->SetupHeader(oat_file->oat_dex_files_storage_.size());
1776 } else {
1777 // No need for any verification when loading dex files as we already have
1778 // a vdex file.
1779 const ArtDexFileLoader dex_file_loader;
1780 bool loaded = false;
1781 if (zip_fd != -1) {
1782 loaded = dex_file_loader.OpenZip(zip_fd,
1783 dex_location,
1784 /*verify=*/ false,
1785 /*verify_checksum=*/ false,
1786 error_msg,
1787 &oat_file->external_dex_files_);
1788 } else {
1789 loaded = dex_file_loader.Open(dex_location.c_str(),
1790 dex_location,
1791 /*verify=*/ false,
1792 /*verify_checksum=*/ false,
1793 error_msg,
1794 &oat_file->external_dex_files_);
1795 }
1796 if (!loaded) {
1797 return nullptr;
1798 }
1799 oat_file->SetupHeader(oat_file->external_dex_files_.size());
1800 if (!oat_file->Setup(MakeNonOwningPointerVector(oat_file->external_dex_files_), error_msg)) {
1801 return nullptr;
1802 }
1803 }
1804
1805 return oat_file.release();
1806 }
1807
SetupHeader(size_t number_of_dex_files)1808 void SetupHeader(size_t number_of_dex_files) {
1809 DCHECK(!IsExecutable());
1810
1811 // Create a fake OatHeader with a key store to help debugging.
1812 std::unique_ptr<const InstructionSetFeatures> isa_features =
1813 InstructionSetFeatures::FromCppDefines();
1814 SafeMap<std::string, std::string> store;
1815 store.Put(OatHeader::kCompilerFilter, CompilerFilter::NameOfFilter(CompilerFilter::kVerify));
1816 store.Put(OatHeader::kCompilationReasonKey, "vdex");
1817 store.Put(OatHeader::kConcurrentCopying,
1818 kUseReadBarrier ? OatHeader::kTrueValue : OatHeader::kFalseValue);
1819 oat_header_.reset(OatHeader::Create(kRuntimeISA,
1820 isa_features.get(),
1821 number_of_dex_files,
1822 &store));
1823 const uint8_t* begin = reinterpret_cast<const uint8_t*>(oat_header_.get());
1824 SetBegin(begin);
1825 SetEnd(begin + oat_header_->GetHeaderSize());
1826 }
1827
1828 protected:
PreLoad()1829 void PreLoad() override {}
1830
Load(const std::string & elf_filename ATTRIBUTE_UNUSED,bool writable ATTRIBUTE_UNUSED,bool executable ATTRIBUTE_UNUSED,bool low_4gb ATTRIBUTE_UNUSED,MemMap * reservation ATTRIBUTE_UNUSED,std::string * error_msg ATTRIBUTE_UNUSED)1831 bool Load(const std::string& elf_filename ATTRIBUTE_UNUSED,
1832 bool writable ATTRIBUTE_UNUSED,
1833 bool executable ATTRIBUTE_UNUSED,
1834 bool low_4gb ATTRIBUTE_UNUSED,
1835 MemMap* reservation ATTRIBUTE_UNUSED,
1836 std::string* error_msg ATTRIBUTE_UNUSED) override {
1837 LOG(FATAL) << "Unsupported";
1838 UNREACHABLE();
1839 }
1840
Load(int oat_fd ATTRIBUTE_UNUSED,bool writable ATTRIBUTE_UNUSED,bool executable ATTRIBUTE_UNUSED,bool low_4gb ATTRIBUTE_UNUSED,MemMap * reservation ATTRIBUTE_UNUSED,std::string * error_msg ATTRIBUTE_UNUSED)1841 bool Load(int oat_fd ATTRIBUTE_UNUSED,
1842 bool writable ATTRIBUTE_UNUSED,
1843 bool executable ATTRIBUTE_UNUSED,
1844 bool low_4gb ATTRIBUTE_UNUSED,
1845 MemMap* reservation ATTRIBUTE_UNUSED,
1846 std::string* error_msg ATTRIBUTE_UNUSED) override {
1847 LOG(FATAL) << "Unsupported";
1848 UNREACHABLE();
1849 }
1850
PreSetup(const std::string & elf_filename ATTRIBUTE_UNUSED)1851 void PreSetup(const std::string& elf_filename ATTRIBUTE_UNUSED) override {}
1852
FindDynamicSymbolAddress(const std::string & symbol_name ATTRIBUTE_UNUSED,std::string * error_msg) const1853 const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name ATTRIBUTE_UNUSED,
1854 std::string* error_msg) const override {
1855 *error_msg = "Unsupported";
1856 return nullptr;
1857 }
1858
1859 private:
1860 std::unique_ptr<OatHeader> oat_header_;
1861
1862 DISALLOW_COPY_AND_ASSIGN(OatFileBackedByVdex);
1863 };
1864
1865 //////////////////////////
1866 // General OatFile code //
1867 //////////////////////////
1868
CheckLocation(const std::string & location)1869 static void CheckLocation(const std::string& location) {
1870 CHECK(!location.empty());
1871 }
1872
Open(int zip_fd,const std::string & oat_filename,const std::string & oat_location,bool executable,bool low_4gb,ArrayRef<const std::string> dex_filenames,ArrayRef<const int> dex_fds,MemMap * reservation,std::string * error_msg)1873 OatFile* OatFile::Open(int zip_fd,
1874 const std::string& oat_filename,
1875 const std::string& oat_location,
1876 bool executable,
1877 bool low_4gb,
1878 ArrayRef<const std::string> dex_filenames,
1879 ArrayRef<const int> dex_fds,
1880 /*inout*/MemMap* reservation,
1881 /*out*/std::string* error_msg) {
1882 ScopedTrace trace("Open oat file " + oat_location);
1883 CHECK(!oat_filename.empty()) << oat_location;
1884 CheckLocation(oat_location);
1885
1886 std::string vdex_filename = GetVdexFilename(oat_filename);
1887
1888 // Check that the vdex file even exists, fast-fail. We don't check the odex
1889 // file as we use the absence of an odex file for test the functionality of
1890 // vdex-only.
1891 if (!OS::FileExists(vdex_filename.c_str())) {
1892 *error_msg = StringPrintf("File %s does not exist.", vdex_filename.c_str());
1893 return nullptr;
1894 }
1895
1896 // Try dlopen first, as it is required for native debuggability. This will fail fast if dlopen is
1897 // disabled.
1898 OatFile* with_dlopen = OatFileBase::OpenOatFile<DlOpenOatFile>(zip_fd,
1899 vdex_filename,
1900 oat_filename,
1901 oat_location,
1902 /*writable=*/ false,
1903 executable,
1904 low_4gb,
1905 dex_filenames,
1906 dex_fds,
1907 reservation,
1908 error_msg);
1909 if (with_dlopen != nullptr) {
1910 Runtime* runtime = Runtime::Current();
1911 // The runtime might not be available at this point if we're running
1912 // dex2oat or oatdump.
1913 if (runtime != nullptr) {
1914 size_t madvise_size_limit = runtime->GetMadviseWillNeedSizeOdex();
1915 Runtime::MadviseFileForRange(madvise_size_limit,
1916 with_dlopen->Size(),
1917 with_dlopen->Begin(),
1918 with_dlopen->End(),
1919 oat_location);
1920 }
1921 return with_dlopen;
1922 }
1923 if (kPrintDlOpenErrorMessage) {
1924 LOG(ERROR) << "Failed to dlopen: " << oat_filename << " with error " << *error_msg;
1925 }
1926 // If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons:
1927 //
1928 // On target, dlopen may fail when compiling due to selinux restrictions on installd.
1929 //
1930 // We use our own ELF loader for Quick to deal with legacy apps that
1931 // open a generated dex file by name, remove the file, then open
1932 // another generated dex file with the same name. http://b/10614658
1933 //
1934 // On host, dlopen is expected to fail when cross compiling, so fall back to ElfOatFile.
1935 //
1936 //
1937 // Another independent reason is the absolute placement of boot.oat. dlopen on the host usually
1938 // does honor the virtual address encoded in the ELF file only for ET_EXEC files, not ET_DYN.
1939 OatFile* with_internal = OatFileBase::OpenOatFile<ElfOatFile>(zip_fd,
1940 vdex_filename,
1941 oat_filename,
1942 oat_location,
1943 /*writable=*/ false,
1944 executable,
1945 low_4gb,
1946 dex_filenames,
1947 dex_fds,
1948 reservation,
1949 error_msg);
1950 return with_internal;
1951 }
1952
Open(int zip_fd,int vdex_fd,int oat_fd,const std::string & oat_location,bool executable,bool low_4gb,ArrayRef<const std::string> dex_filenames,ArrayRef<const int> dex_fds,MemMap * reservation,std::string * error_msg)1953 OatFile* OatFile::Open(int zip_fd,
1954 int vdex_fd,
1955 int oat_fd,
1956 const std::string& oat_location,
1957 bool executable,
1958 bool low_4gb,
1959 ArrayRef<const std::string> dex_filenames,
1960 ArrayRef<const int> dex_fds,
1961 /*inout*/MemMap* reservation,
1962 /*out*/std::string* error_msg) {
1963 CHECK(!oat_location.empty()) << oat_location;
1964
1965 std::string vdex_location = GetVdexFilename(oat_location);
1966
1967 OatFile* with_internal = OatFileBase::OpenOatFile<ElfOatFile>(zip_fd,
1968 vdex_fd,
1969 oat_fd,
1970 vdex_location,
1971 oat_location,
1972 /*writable=*/ false,
1973 executable,
1974 low_4gb,
1975 dex_filenames,
1976 dex_fds,
1977 reservation,
1978 error_msg);
1979 return with_internal;
1980 }
1981
OpenFromVdex(const std::vector<const DexFile * > & dex_files,std::unique_ptr<VdexFile> && vdex_file,const std::string & location)1982 OatFile* OatFile::OpenFromVdex(const std::vector<const DexFile*>& dex_files,
1983 std::unique_ptr<VdexFile>&& vdex_file,
1984 const std::string& location) {
1985 CheckLocation(location);
1986 return OatFileBackedByVdex::Open(dex_files, std::move(vdex_file), location);
1987 }
1988
OpenFromVdex(int zip_fd,std::unique_ptr<VdexFile> && vdex_file,const std::string & location,std::string * error_msg)1989 OatFile* OatFile::OpenFromVdex(int zip_fd,
1990 std::unique_ptr<VdexFile>&& vdex_file,
1991 const std::string& location,
1992 std::string* error_msg) {
1993 CheckLocation(location);
1994 return OatFileBackedByVdex::Open(zip_fd, std::move(vdex_file), location, error_msg);
1995 }
1996
OatFile(const std::string & location,bool is_executable)1997 OatFile::OatFile(const std::string& location, bool is_executable)
1998 : location_(location),
1999 vdex_(nullptr),
2000 begin_(nullptr),
2001 end_(nullptr),
2002 data_bimg_rel_ro_begin_(nullptr),
2003 data_bimg_rel_ro_end_(nullptr),
2004 bss_begin_(nullptr),
2005 bss_end_(nullptr),
2006 bss_methods_(nullptr),
2007 bss_roots_(nullptr),
2008 is_executable_(is_executable),
2009 vdex_begin_(nullptr),
2010 vdex_end_(nullptr),
2011 secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) {
2012 CHECK(!location_.empty());
2013 }
2014
~OatFile()2015 OatFile::~OatFile() {
2016 STLDeleteElements(&oat_dex_files_storage_);
2017 }
2018
GetOatHeader() const2019 const OatHeader& OatFile::GetOatHeader() const {
2020 return *reinterpret_cast<const OatHeader*>(Begin());
2021 }
2022
Begin() const2023 const uint8_t* OatFile::Begin() const {
2024 CHECK(begin_ != nullptr);
2025 return begin_;
2026 }
2027
End() const2028 const uint8_t* OatFile::End() const {
2029 CHECK(end_ != nullptr);
2030 return end_;
2031 }
2032
DexBegin() const2033 const uint8_t* OatFile::DexBegin() const {
2034 return vdex_->Begin();
2035 }
2036
DexEnd() const2037 const uint8_t* OatFile::DexEnd() const {
2038 return vdex_->End();
2039 }
2040
GetBootImageRelocations() const2041 ArrayRef<const uint32_t> OatFile::GetBootImageRelocations() const {
2042 if (data_bimg_rel_ro_begin_ != nullptr) {
2043 const uint32_t* relocations = reinterpret_cast<const uint32_t*>(data_bimg_rel_ro_begin_);
2044 const uint32_t* relocations_end = reinterpret_cast<const uint32_t*>(data_bimg_rel_ro_end_);
2045 return ArrayRef<const uint32_t>(relocations, relocations_end - relocations);
2046 } else {
2047 return ArrayRef<const uint32_t>();
2048 }
2049 }
2050
GetBssMethods() const2051 ArrayRef<ArtMethod*> OatFile::GetBssMethods() const {
2052 if (bss_methods_ != nullptr) {
2053 ArtMethod** methods = reinterpret_cast<ArtMethod**>(bss_methods_);
2054 ArtMethod** methods_end =
2055 reinterpret_cast<ArtMethod**>(bss_roots_ != nullptr ? bss_roots_ : bss_end_);
2056 return ArrayRef<ArtMethod*>(methods, methods_end - methods);
2057 } else {
2058 return ArrayRef<ArtMethod*>();
2059 }
2060 }
2061
GetBssGcRoots() const2062 ArrayRef<GcRoot<mirror::Object>> OatFile::GetBssGcRoots() const {
2063 if (bss_roots_ != nullptr) {
2064 auto* roots = reinterpret_cast<GcRoot<mirror::Object>*>(bss_roots_);
2065 auto* roots_end = reinterpret_cast<GcRoot<mirror::Object>*>(bss_end_);
2066 return ArrayRef<GcRoot<mirror::Object>>(roots, roots_end - roots);
2067 } else {
2068 return ArrayRef<GcRoot<mirror::Object>>();
2069 }
2070 }
2071
GetOatDexFile(const char * dex_location,const uint32_t * dex_location_checksum,std::string * error_msg) const2072 const OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
2073 const uint32_t* dex_location_checksum,
2074 std::string* error_msg) const {
2075 // NOTE: We assume here that the canonical location for a given dex_location never
2076 // changes. If it does (i.e. some symlink used by the filename changes) we may return
2077 // an incorrect OatDexFile. As long as we have a checksum to check, we shall return
2078 // an identical file or fail; otherwise we may see some unpredictable failures.
2079
2080 // TODO: Additional analysis of usage patterns to see if this can be simplified
2081 // without any performance loss, for example by not doing the first lock-free lookup.
2082
2083 const OatDexFile* oat_dex_file = nullptr;
2084 std::string_view key(dex_location);
2085 // Try to find the key cheaply in the oat_dex_files_ map which holds dex locations
2086 // directly mentioned in the oat file and doesn't require locking.
2087 auto primary_it = oat_dex_files_.find(key);
2088 if (primary_it != oat_dex_files_.end()) {
2089 oat_dex_file = primary_it->second;
2090 DCHECK(oat_dex_file != nullptr);
2091 } else {
2092 // This dex_location is not one of the dex locations directly mentioned in the
2093 // oat file. The correct lookup is via the canonical location but first see in
2094 // the secondary_oat_dex_files_ whether we've looked up this location before.
2095 MutexLock mu(Thread::Current(), secondary_lookup_lock_);
2096 auto secondary_lb = secondary_oat_dex_files_.lower_bound(key);
2097 if (secondary_lb != secondary_oat_dex_files_.end() && key == secondary_lb->first) {
2098 oat_dex_file = secondary_lb->second; // May be null.
2099 } else {
2100 // We haven't seen this dex_location before, we must check the canonical location.
2101 std::string dex_canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location);
2102 if (dex_canonical_location != dex_location) {
2103 std::string_view canonical_key(dex_canonical_location);
2104 auto canonical_it = oat_dex_files_.find(canonical_key);
2105 if (canonical_it != oat_dex_files_.end()) {
2106 oat_dex_file = canonical_it->second;
2107 } // else keep null.
2108 } // else keep null.
2109
2110 // Copy the key to the string_cache_ and store the result in secondary map.
2111 string_cache_.emplace_back(key.data(), key.length());
2112 std::string_view key_copy(string_cache_.back());
2113 secondary_oat_dex_files_.PutBefore(secondary_lb, key_copy, oat_dex_file);
2114 }
2115 }
2116
2117 if (oat_dex_file == nullptr) {
2118 if (error_msg != nullptr) {
2119 std::string dex_canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location);
2120 *error_msg = "Failed to find OatDexFile for DexFile " + std::string(dex_location)
2121 + " (canonical path " + dex_canonical_location + ") in OatFile " + GetLocation();
2122 }
2123 return nullptr;
2124 }
2125
2126 if (dex_location_checksum != nullptr &&
2127 oat_dex_file->GetDexFileLocationChecksum() != *dex_location_checksum) {
2128 if (error_msg != nullptr) {
2129 std::string dex_canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location);
2130 std::string checksum = StringPrintf("0x%08x", oat_dex_file->GetDexFileLocationChecksum());
2131 std::string required_checksum = StringPrintf("0x%08x", *dex_location_checksum);
2132 *error_msg = "OatDexFile for DexFile " + std::string(dex_location)
2133 + " (canonical path " + dex_canonical_location + ") in OatFile " + GetLocation()
2134 + " has checksum " + checksum + " but " + required_checksum + " was required";
2135 }
2136 return nullptr;
2137 }
2138 return oat_dex_file;
2139 }
2140
OatDexFile(const OatFile * oat_file,const std::string & dex_file_location,const std::string & canonical_dex_file_location,uint32_t dex_file_location_checksum,const uint8_t * dex_file_pointer,const uint8_t * lookup_table_data,const IndexBssMapping * method_bss_mapping_data,const IndexBssMapping * type_bss_mapping_data,const IndexBssMapping * public_type_bss_mapping_data,const IndexBssMapping * package_type_bss_mapping_data,const IndexBssMapping * string_bss_mapping_data,const uint32_t * oat_class_offsets_pointer,const DexLayoutSections * dex_layout_sections)2141 OatDexFile::OatDexFile(const OatFile* oat_file,
2142 const std::string& dex_file_location,
2143 const std::string& canonical_dex_file_location,
2144 uint32_t dex_file_location_checksum,
2145 const uint8_t* dex_file_pointer,
2146 const uint8_t* lookup_table_data,
2147 const IndexBssMapping* method_bss_mapping_data,
2148 const IndexBssMapping* type_bss_mapping_data,
2149 const IndexBssMapping* public_type_bss_mapping_data,
2150 const IndexBssMapping* package_type_bss_mapping_data,
2151 const IndexBssMapping* string_bss_mapping_data,
2152 const uint32_t* oat_class_offsets_pointer,
2153 const DexLayoutSections* dex_layout_sections)
2154 : oat_file_(oat_file),
2155 dex_file_location_(dex_file_location),
2156 canonical_dex_file_location_(canonical_dex_file_location),
2157 dex_file_location_checksum_(dex_file_location_checksum),
2158 dex_file_pointer_(dex_file_pointer),
2159 lookup_table_data_(lookup_table_data),
2160 method_bss_mapping_(method_bss_mapping_data),
2161 type_bss_mapping_(type_bss_mapping_data),
2162 public_type_bss_mapping_(public_type_bss_mapping_data),
2163 package_type_bss_mapping_(package_type_bss_mapping_data),
2164 string_bss_mapping_(string_bss_mapping_data),
2165 oat_class_offsets_pointer_(oat_class_offsets_pointer),
2166 lookup_table_(),
2167 dex_layout_sections_(dex_layout_sections) {
2168 InitializeTypeLookupTable();
2169 DCHECK(!IsBackedByVdexOnly());
2170 }
2171
InitializeTypeLookupTable()2172 void OatDexFile::InitializeTypeLookupTable() {
2173 // Initialize TypeLookupTable.
2174 if (lookup_table_data_ != nullptr) {
2175 // Peek the number of classes from the DexFile.
2176 const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer_);
2177 const uint32_t num_class_defs = dex_header->class_defs_size_;
2178 if (lookup_table_data_ + TypeLookupTable::RawDataLength(num_class_defs) >
2179 GetOatFile()->DexEnd()) {
2180 LOG(WARNING) << "found truncated lookup table in " << dex_file_location_;
2181 } else {
2182 const uint8_t* dex_data = dex_file_pointer_;
2183 // TODO: Clean this up to create the type lookup table after the dex file has been created?
2184 if (CompactDexFile::IsMagicValid(dex_header->magic_)) {
2185 dex_data += dex_header->data_off_;
2186 }
2187 lookup_table_ = TypeLookupTable::Open(dex_data, lookup_table_data_, num_class_defs);
2188 }
2189 }
2190 }
2191
OatDexFile(const OatFile * oat_file,const uint8_t * dex_file_pointer,uint32_t dex_file_location_checksum,const std::string & dex_file_location,const std::string & canonical_dex_file_location,const uint8_t * lookup_table_data)2192 OatDexFile::OatDexFile(const OatFile* oat_file,
2193 const uint8_t* dex_file_pointer,
2194 uint32_t dex_file_location_checksum,
2195 const std::string& dex_file_location,
2196 const std::string& canonical_dex_file_location,
2197 const uint8_t* lookup_table_data)
2198 : oat_file_(oat_file),
2199 dex_file_location_(dex_file_location),
2200 canonical_dex_file_location_(canonical_dex_file_location),
2201 dex_file_location_checksum_(dex_file_location_checksum),
2202 dex_file_pointer_(dex_file_pointer),
2203 lookup_table_data_(lookup_table_data) {
2204 InitializeTypeLookupTable();
2205 DCHECK(IsBackedByVdexOnly());
2206 }
2207
OatDexFile(TypeLookupTable && lookup_table)2208 OatDexFile::OatDexFile(TypeLookupTable&& lookup_table) : lookup_table_(std::move(lookup_table)) {
2209 // Stripped-down OatDexFile only allowed in the compiler, the zygote, or the system server.
2210 CHECK(Runtime::Current() == nullptr ||
2211 Runtime::Current()->IsAotCompiler() ||
2212 Runtime::Current()->IsZygote() ||
2213 Runtime::Current()->IsSystemServer());
2214 }
2215
~OatDexFile()2216 OatDexFile::~OatDexFile() {}
2217
FileSize() const2218 size_t OatDexFile::FileSize() const {
2219 DCHECK(dex_file_pointer_ != nullptr);
2220 return reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_;
2221 }
2222
OpenDexFile(std::string * error_msg) const2223 std::unique_ptr<const DexFile> OatDexFile::OpenDexFile(std::string* error_msg) const {
2224 ScopedTrace trace(__PRETTY_FUNCTION__);
2225 static constexpr bool kVerify = false;
2226 static constexpr bool kVerifyChecksum = false;
2227 const ArtDexFileLoader dex_file_loader;
2228 return dex_file_loader.Open(dex_file_pointer_,
2229 FileSize(),
2230 dex_file_location_,
2231 dex_file_location_checksum_,
2232 this,
2233 kVerify,
2234 kVerifyChecksum,
2235 error_msg);
2236 }
2237
GetOatClassOffset(uint16_t class_def_index) const2238 uint32_t OatDexFile::GetOatClassOffset(uint16_t class_def_index) const {
2239 DCHECK(oat_class_offsets_pointer_ != nullptr);
2240 return oat_class_offsets_pointer_[class_def_index];
2241 }
2242
IsBackedByVdexOnly() const2243 bool OatDexFile::IsBackedByVdexOnly() const {
2244 return oat_class_offsets_pointer_ == nullptr;
2245 }
2246
GetOatClass(uint16_t class_def_index) const2247 OatFile::OatClass OatDexFile::GetOatClass(uint16_t class_def_index) const {
2248 if (IsBackedByVdexOnly()) {
2249 // If there is only a vdex file, return that the class is not ready. The
2250 // caller will have to call `VdexFile::ComputeClassStatus` to compute the
2251 // actual class status, because we need to do the assignability type checks.
2252 return OatFile::OatClass(oat_file_,
2253 ClassStatus::kNotReady,
2254 /* type= */ OatClassType::kNoneCompiled,
2255 /* bitmap_size= */ 0u,
2256 /* bitmap_pointer= */ nullptr,
2257 /* methods_pointer= */ nullptr);
2258 }
2259
2260 uint32_t oat_class_offset = GetOatClassOffset(class_def_index);
2261 CHECK_GE(oat_class_offset, sizeof(OatHeader)) << oat_file_->GetLocation();
2262 CHECK_LT(oat_class_offset, oat_file_->Size()) << oat_file_->GetLocation();
2263 CHECK_LE(/* status */ sizeof(uint16_t) + /* type */ sizeof(uint16_t),
2264 oat_file_->Size() - oat_class_offset) << oat_file_->GetLocation();
2265 const uint8_t* current_pointer = oat_file_->Begin() + oat_class_offset;
2266
2267 uint16_t status_value = *reinterpret_cast<const uint16_t*>(current_pointer);
2268 current_pointer += sizeof(uint16_t);
2269 uint16_t type_value = *reinterpret_cast<const uint16_t*>(current_pointer);
2270 current_pointer += sizeof(uint16_t);
2271 CHECK_LE(status_value, enum_cast<uint8_t>(ClassStatus::kLast))
2272 << static_cast<uint32_t>(status_value) << " at " << oat_file_->GetLocation();
2273 CHECK_LT(type_value, enum_cast<uint8_t>(OatClassType::kOatClassMax)) << oat_file_->GetLocation();
2274 ClassStatus status = enum_cast<ClassStatus>(status_value);
2275 OatClassType type = enum_cast<OatClassType>(type_value);
2276
2277 uint32_t num_methods = 0;
2278 const uint32_t* bitmap_pointer = nullptr;
2279 const OatMethodOffsets* methods_pointer = nullptr;
2280 if (type != OatClassType::kNoneCompiled) {
2281 CHECK_LE(sizeof(uint32_t), static_cast<size_t>(oat_file_->End() - current_pointer))
2282 << oat_file_->GetLocation();
2283 num_methods = *reinterpret_cast<const uint32_t*>(current_pointer);
2284 current_pointer += sizeof(uint32_t);
2285 CHECK_NE(num_methods, 0u) << oat_file_->GetLocation();
2286 uint32_t num_method_offsets;
2287 if (type == OatClassType::kSomeCompiled) {
2288 uint32_t bitmap_size = BitVector::BitsToWords(num_methods) * BitVector::kWordBytes;
2289 CHECK_LE(bitmap_size, static_cast<size_t>(oat_file_->End() - current_pointer))
2290 << oat_file_->GetLocation();
2291 bitmap_pointer = reinterpret_cast<const uint32_t*>(current_pointer);
2292 current_pointer += bitmap_size;
2293 // Note: The bits in range [num_methods, bitmap_size * kBitsPerByte)
2294 // should be zero but we're not verifying that.
2295 num_method_offsets = BitVector::NumSetBits(bitmap_pointer, num_methods);
2296 } else {
2297 num_method_offsets = num_methods;
2298 }
2299 CHECK_LE(num_method_offsets,
2300 static_cast<size_t>(oat_file_->End() - current_pointer) / sizeof(OatMethodOffsets))
2301 << oat_file_->GetLocation();
2302 methods_pointer = reinterpret_cast<const OatMethodOffsets*>(current_pointer);
2303 }
2304
2305 return OatFile::OatClass(oat_file_, status, type, num_methods, bitmap_pointer, methods_pointer);
2306 }
2307
FindClassDef(const DexFile & dex_file,const char * descriptor,size_t hash)2308 const dex::ClassDef* OatDexFile::FindClassDef(const DexFile& dex_file,
2309 const char* descriptor,
2310 size_t hash) {
2311 const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
2312 DCHECK_EQ(ComputeModifiedUtf8Hash(descriptor), hash);
2313 bool used_lookup_table = false;
2314 const dex::ClassDef* lookup_table_classdef = nullptr;
2315 if (LIKELY((oat_dex_file != nullptr) && oat_dex_file->GetTypeLookupTable().Valid())) {
2316 used_lookup_table = true;
2317 const uint32_t class_def_idx = oat_dex_file->GetTypeLookupTable().Lookup(descriptor, hash);
2318 if (class_def_idx != dex::kDexNoIndex) {
2319 CHECK_LT(class_def_idx, dex_file.NumClassDefs()) << oat_dex_file->GetOatFile()->GetLocation();
2320 lookup_table_classdef = &dex_file.GetClassDef(class_def_idx);
2321 }
2322 if (!kIsDebugBuild) {
2323 return lookup_table_classdef;
2324 }
2325 }
2326 // Fast path for rare no class defs case.
2327 const uint32_t num_class_defs = dex_file.NumClassDefs();
2328 if (num_class_defs == 0) {
2329 DCHECK(!used_lookup_table);
2330 return nullptr;
2331 }
2332 const dex::TypeId* type_id = dex_file.FindTypeId(descriptor);
2333 if (type_id != nullptr) {
2334 dex::TypeIndex type_idx = dex_file.GetIndexForTypeId(*type_id);
2335 const dex::ClassDef* found_class_def = dex_file.FindClassDef(type_idx);
2336 if (kIsDebugBuild && used_lookup_table) {
2337 DCHECK_EQ(found_class_def, lookup_table_classdef);
2338 }
2339 return found_class_def;
2340 }
2341 return nullptr;
2342 }
2343
2344 // Madvise the dex file based on the state we are moving to.
MadviseDexFileAtLoad(const DexFile & dex_file)2345 void OatDexFile::MadviseDexFileAtLoad(const DexFile& dex_file) {
2346 Runtime* const runtime = Runtime::Current();
2347 const bool low_ram = runtime->GetHeap()->IsLowMemoryMode();
2348 // TODO(b/196052575): Revisit low-ram madvise behavior in light of vdex/odex/art madvise hints.
2349 if (!low_ram) {
2350 return;
2351 }
2352 if (runtime->MAdviseRandomAccess()) {
2353 // Default every dex file to MADV_RANDOM when its loaded by default for low ram devices.
2354 // Other devices have enough page cache to get performance benefits from loading more pages
2355 // into the page cache.
2356 DexLayoutSection::MadviseLargestPageAlignedRegion(dex_file.Begin(),
2357 dex_file.Begin() + dex_file.Size(),
2358 MADV_RANDOM);
2359 }
2360 const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
2361 if (oat_dex_file != nullptr) {
2362 // Should always be there.
2363 const DexLayoutSections* const sections = oat_dex_file->GetDexLayoutSections();
2364 if (sections != nullptr) {
2365 sections->MadviseAtLoad(&dex_file);
2366 } else {
2367 DCHECK(oat_dex_file->IsBackedByVdexOnly());
2368 }
2369 }
2370 }
2371
OatClass(const OatFile * oat_file,ClassStatus status,OatClassType type,uint32_t num_methods,const uint32_t * bitmap_pointer,const OatMethodOffsets * methods_pointer)2372 OatFile::OatClass::OatClass(const OatFile* oat_file,
2373 ClassStatus status,
2374 OatClassType type,
2375 uint32_t num_methods,
2376 const uint32_t* bitmap_pointer,
2377 const OatMethodOffsets* methods_pointer)
2378 : oat_file_(oat_file),
2379 status_(status),
2380 type_(type),
2381 num_methods_(num_methods),
2382 bitmap_(bitmap_pointer),
2383 methods_pointer_(methods_pointer) {
2384 DCHECK_EQ(num_methods != 0u, type != OatClassType::kNoneCompiled);
2385 DCHECK_EQ(bitmap_pointer != nullptr, type == OatClassType::kSomeCompiled);
2386 DCHECK_EQ(methods_pointer != nullptr, type != OatClassType::kNoneCompiled);
2387 }
2388
GetOatMethodOffsetsOffset(uint32_t method_index) const2389 uint32_t OatFile::OatClass::GetOatMethodOffsetsOffset(uint32_t method_index) const {
2390 const OatMethodOffsets* oat_method_offsets = GetOatMethodOffsets(method_index);
2391 if (oat_method_offsets == nullptr) {
2392 return 0u;
2393 }
2394 return reinterpret_cast<const uint8_t*>(oat_method_offsets) - oat_file_->Begin();
2395 }
2396
GetOatMethodOffsets(uint32_t method_index) const2397 const OatMethodOffsets* OatFile::OatClass::GetOatMethodOffsets(uint32_t method_index) const {
2398 // NOTE: We don't keep the number of methods for `kNoneCompiled` and cannot do
2399 // a bounds check for `method_index` in that case.
2400 if (methods_pointer_ == nullptr) {
2401 CHECK_EQ(OatClassType::kNoneCompiled, type_);
2402 return nullptr;
2403 }
2404 CHECK_LT(method_index, num_methods_) << oat_file_->GetLocation();
2405 size_t methods_pointer_index;
2406 if (bitmap_ == nullptr) {
2407 CHECK_EQ(OatClassType::kAllCompiled, type_);
2408 methods_pointer_index = method_index;
2409 } else {
2410 CHECK_EQ(OatClassType::kSomeCompiled, type_);
2411 if (!BitVector::IsBitSet(bitmap_, method_index)) {
2412 return nullptr;
2413 }
2414 size_t num_set_bits = BitVector::NumSetBits(bitmap_, method_index);
2415 methods_pointer_index = num_set_bits;
2416 }
2417 if (kIsDebugBuild) {
2418 size_t size_until_end = dchecked_integral_cast<size_t>(
2419 oat_file_->End() - reinterpret_cast<const uint8_t*>(methods_pointer_));
2420 CHECK_LE(methods_pointer_index, size_until_end / sizeof(OatMethodOffsets))
2421 << oat_file_->GetLocation();
2422 }
2423 const OatMethodOffsets& oat_method_offsets = methods_pointer_[methods_pointer_index];
2424 return &oat_method_offsets;
2425 }
2426
GetOatMethod(uint32_t method_index) const2427 const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
2428 const OatMethodOffsets* oat_method_offsets = GetOatMethodOffsets(method_index);
2429 if (oat_method_offsets == nullptr) {
2430 return OatMethod(nullptr, 0);
2431 }
2432 if (oat_file_->IsExecutable() ||
2433 Runtime::Current() == nullptr || // This case applies for oatdump.
2434 Runtime::Current()->IsAotCompiler()) {
2435 return OatMethod(oat_file_->Begin(), oat_method_offsets->code_offset_);
2436 }
2437 // We aren't allowed to use the compiled code. We just force it down the interpreted / jit
2438 // version.
2439 return OatMethod(oat_file_->Begin(), 0);
2440 }
2441
IsDebuggable() const2442 bool OatFile::IsDebuggable() const {
2443 return GetOatHeader().IsDebuggable();
2444 }
2445
GetCompilerFilter() const2446 CompilerFilter::Filter OatFile::GetCompilerFilter() const {
2447 return GetOatHeader().GetCompilerFilter();
2448 }
2449
GetClassLoaderContext() const2450 std::string OatFile::GetClassLoaderContext() const {
2451 return GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey);
2452 }
2453
GetCompilationReason() const2454 const char* OatFile::GetCompilationReason() const {
2455 return GetOatHeader().GetStoreValueByKey(OatHeader::kCompilationReasonKey);
2456 }
2457
FindOatClass(const DexFile & dex_file,uint16_t class_def_idx,bool * found)2458 OatFile::OatClass OatFile::FindOatClass(const DexFile& dex_file,
2459 uint16_t class_def_idx,
2460 bool* found) {
2461 CHECK_LT(class_def_idx, dex_file.NumClassDefs());
2462 const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
2463 if (oat_dex_file == nullptr || oat_dex_file->GetOatFile() == nullptr) {
2464 *found = false;
2465 return OatFile::OatClass::Invalid();
2466 }
2467 *found = true;
2468 return oat_dex_file->GetOatClass(class_def_idx);
2469 }
2470
RequiresImage() const2471 bool OatFile::RequiresImage() const { return GetOatHeader().RequiresImage(); }
2472
DCheckIndexToBssMapping(const OatFile * oat_file,uint32_t number_of_indexes,size_t slot_size,const IndexBssMapping * index_bss_mapping)2473 static void DCheckIndexToBssMapping(const OatFile* oat_file,
2474 uint32_t number_of_indexes,
2475 size_t slot_size,
2476 const IndexBssMapping* index_bss_mapping) {
2477 if (kIsDebugBuild && index_bss_mapping != nullptr) {
2478 size_t index_bits = IndexBssMappingEntry::IndexBits(number_of_indexes);
2479 const IndexBssMappingEntry* prev_entry = nullptr;
2480 for (const IndexBssMappingEntry& entry : *index_bss_mapping) {
2481 CHECK_ALIGNED_PARAM(entry.bss_offset, slot_size);
2482 CHECK_LT(entry.bss_offset, oat_file->BssSize());
2483 uint32_t mask = entry.GetMask(index_bits);
2484 CHECK_LE(POPCOUNT(mask) * slot_size, entry.bss_offset);
2485 size_t index_mask_span = (mask != 0u) ? 32u - index_bits - CTZ(mask) : 0u;
2486 CHECK_LE(index_mask_span, entry.GetIndex(index_bits));
2487 if (prev_entry != nullptr) {
2488 CHECK_LT(prev_entry->GetIndex(index_bits), entry.GetIndex(index_bits) - index_mask_span);
2489 }
2490 prev_entry = &entry;
2491 }
2492 CHECK(prev_entry != nullptr);
2493 CHECK_LT(prev_entry->GetIndex(index_bits), number_of_indexes);
2494 }
2495 }
2496
InitializeRelocations() const2497 void OatFile::InitializeRelocations() const {
2498 DCHECK(IsExecutable());
2499
2500 // Initialize the .data.bimg.rel.ro section.
2501 if (!GetBootImageRelocations().empty()) {
2502 uint8_t* reloc_begin = const_cast<uint8_t*>(DataBimgRelRoBegin());
2503 CheckedCall(mprotect,
2504 "un-protect boot image relocations",
2505 reloc_begin,
2506 DataBimgRelRoSize(),
2507 PROT_READ | PROT_WRITE);
2508 uint32_t boot_image_begin = Runtime::Current()->GetHeap()->GetBootImagesStartAddress();
2509 for (const uint32_t& relocation : GetBootImageRelocations()) {
2510 const_cast<uint32_t&>(relocation) += boot_image_begin;
2511 }
2512 CheckedCall(mprotect,
2513 "protect boot image relocations",
2514 reloc_begin,
2515 DataBimgRelRoSize(),
2516 PROT_READ);
2517 }
2518
2519 // Before initializing .bss, check the .bss mappings in debug mode.
2520 if (kIsDebugBuild) {
2521 PointerSize pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet());
2522 for (const OatDexFile* odf : GetOatDexFiles()) {
2523 const DexFile::Header* header =
2524 reinterpret_cast<const DexFile::Header*>(odf->GetDexFilePointer());
2525 DCheckIndexToBssMapping(this,
2526 header->method_ids_size_,
2527 static_cast<size_t>(pointer_size),
2528 odf->GetMethodBssMapping());
2529 DCheckIndexToBssMapping(this,
2530 header->type_ids_size_,
2531 sizeof(GcRoot<mirror::Class>),
2532 odf->GetTypeBssMapping());
2533 DCheckIndexToBssMapping(this,
2534 header->string_ids_size_,
2535 sizeof(GcRoot<mirror::String>),
2536 odf->GetStringBssMapping());
2537 }
2538 }
2539
2540 // Initialize the .bss section.
2541 // TODO: Pre-initialize from boot/app image?
2542 ArtMethod* resolution_method = Runtime::Current()->GetResolutionMethod();
2543 for (ArtMethod*& entry : GetBssMethods()) {
2544 entry = resolution_method;
2545 }
2546 }
2547
AssertAotCompiler()2548 void OatDexFile::AssertAotCompiler() {
2549 CHECK(Runtime::Current()->IsAotCompiler());
2550 }
2551
IsBackedByVdexOnly() const2552 bool OatFile::IsBackedByVdexOnly() const {
2553 return oat_dex_files_storage_.size() >= 1 && oat_dex_files_storage_[0]->IsBackedByVdexOnly();
2554 }
2555
2556 } // namespace art
2557