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