Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
snapshot_utils.cc
Go to the documentation of this file.
1// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include <memory>
6
8
9#include "bin/dartutils.h"
10#include "bin/dfe.h"
11#include "bin/elf_loader.h"
12#include "bin/error_exit.h"
13#include "bin/file.h"
14#include "bin/platform.h"
15#include "include/dart_api.h"
16#if defined(DART_TARGET_OS_MACOS)
17#include <platform/mach_o.h>
18#endif
19#if defined(DART_TARGET_OS_WINDOWS)
20#include <platform/pe.h>
21#endif
22#include "platform/utils.h"
23
24#define LOG_SECTION_BOUNDARIES false
25
26namespace dart {
27namespace bin {
28
29static constexpr int64_t kAppSnapshotHeaderSize = 4 * kInt64Size;
30static constexpr int64_t kAppSnapshotPageSize = 16 * KB;
31
32static const char kMachOAppSnapshotNoteName[] DART_UNUSED = "__dart_app_snap";
33
34#if !defined(DART_PRECOMPILED_RUNTIME)
35class DummySnapshot : public AppSnapshot {
36 public:
38
40
41 void SetBuffers(const uint8_t** vm_data_buffer,
42 const uint8_t** vm_instructions_buffer,
43 const uint8_t** isolate_data_buffer,
44 const uint8_t** isolate_instructions_buffer) {
46 }
47
48 private:
49};
50#endif // !defined(DART_PRECOMPILED_RUNTIME)
51
53 public:
63
65 delete vm_data_mapping_;
66 delete vm_instructions_mapping_;
67 delete isolate_data_mapping_;
68 delete isolate_instructions_mapping_;
69 }
70
71 void SetBuffers(const uint8_t** vm_data_buffer,
72 const uint8_t** vm_instructions_buffer,
73 const uint8_t** isolate_data_buffer,
74 const uint8_t** isolate_instructions_buffer) {
75 if (vm_data_mapping_ != nullptr) {
76 *vm_data_buffer =
77 reinterpret_cast<const uint8_t*>(vm_data_mapping_->address());
78 }
79 if (vm_instructions_mapping_ != nullptr) {
80 *vm_instructions_buffer =
81 reinterpret_cast<const uint8_t*>(vm_instructions_mapping_->address());
82 }
83 if (isolate_data_mapping_ != nullptr) {
84 *isolate_data_buffer =
85 reinterpret_cast<const uint8_t*>(isolate_data_mapping_->address());
86 }
87 if (isolate_instructions_mapping_ != nullptr) {
88 *isolate_instructions_buffer = reinterpret_cast<const uint8_t*>(
89 isolate_instructions_mapping_->address());
90 }
91 }
92
93 private:
94 MappedMemory* vm_data_mapping_;
95 MappedMemory* vm_instructions_mapping_;
96 MappedMemory* isolate_data_mapping_;
97 MappedMemory* isolate_instructions_mapping_;
98};
99
100static AppSnapshot* TryReadAppSnapshotBlobs(const char* script_name,
101 File* file) {
102 if ((file->Length() - file->Position()) < kAppSnapshotHeaderSize) {
103 return nullptr;
104 }
105
106 int64_t header[4];
108 if (!file->ReadFully(&header, kAppSnapshotHeaderSize)) {
109 return nullptr;
110 }
111 int64_t vm_data_size = header[0];
112 int64_t vm_data_position =
113 Utils::RoundUp(file->Position(), kAppSnapshotPageSize);
114 int64_t vm_instructions_size = header[1];
115 int64_t vm_instructions_position = vm_data_position + vm_data_size;
116 if (vm_instructions_size != 0) {
117 vm_instructions_position =
118 Utils::RoundUp(vm_instructions_position, kAppSnapshotPageSize);
119 }
120 int64_t isolate_data_size = header[2];
121 int64_t isolate_data_position = Utils::RoundUp(
122 vm_instructions_position + vm_instructions_size, kAppSnapshotPageSize);
123 int64_t isolate_instructions_size = header[3];
124 int64_t isolate_instructions_position =
125 isolate_data_position + isolate_data_size;
126 if (isolate_instructions_size != 0) {
127 isolate_instructions_position =
128 Utils::RoundUp(isolate_instructions_position, kAppSnapshotPageSize);
129 }
130
131 MappedMemory* vm_data_mapping = nullptr;
132 if (vm_data_size != 0) {
133 vm_data_mapping =
134 file->Map(File::kReadOnly, vm_data_position, vm_data_size);
135 if (vm_data_mapping == nullptr) {
136 FATAL("Failed to memory map snapshot: %s\n", script_name);
137 }
138 }
139
140 MappedMemory* vm_instr_mapping = nullptr;
141 if (vm_instructions_size != 0) {
142 vm_instr_mapping = file->Map(File::kReadExecute, vm_instructions_position,
143 vm_instructions_size);
144 if (vm_instr_mapping == nullptr) {
145 FATAL("Failed to memory map snapshot: %s\n", script_name);
146 }
147 }
148
149 MappedMemory* isolate_data_mapping = nullptr;
150 if (isolate_data_size != 0) {
151 isolate_data_mapping =
152 file->Map(File::kReadOnly, isolate_data_position, isolate_data_size);
153 if (isolate_data_mapping == nullptr) {
154 FATAL("Failed to memory map snapshot: %s\n", script_name);
155 }
156 }
157
158 MappedMemory* isolate_instr_mapping = nullptr;
159 if (isolate_instructions_size != 0) {
160 isolate_instr_mapping =
161 file->Map(File::kReadExecute, isolate_instructions_position,
162 isolate_instructions_size);
163 if (isolate_instr_mapping == nullptr) {
164 FATAL("Failed to memory map snapshot: %s\n", script_name);
165 }
166 }
167
168 auto app_snapshot =
169 new MappedAppSnapshot(vm_data_mapping, vm_instr_mapping,
170 isolate_data_mapping, isolate_instr_mapping);
171 return app_snapshot;
172}
173
174#if defined(DART_PRECOMPILED_RUNTIME)
175class ElfAppSnapshot : public AppSnapshot {
176 public:
177 ElfAppSnapshot(Dart_LoadedElf* elf,
178 const uint8_t* vm_snapshot_data,
179 const uint8_t* vm_snapshot_instructions,
180 const uint8_t* isolate_snapshot_data,
181 const uint8_t* isolate_snapshot_instructions)
182 : AppSnapshot{DartUtils::kAotELFMagicNumber},
183 elf_(elf),
184 vm_snapshot_data_(vm_snapshot_data),
185 vm_snapshot_instructions_(vm_snapshot_instructions),
186 isolate_snapshot_data_(isolate_snapshot_data),
187 isolate_snapshot_instructions_(isolate_snapshot_instructions) {}
188
189 virtual ~ElfAppSnapshot() { Dart_UnloadELF(elf_); }
190
191 void SetBuffers(const uint8_t** vm_data_buffer,
192 const uint8_t** vm_instructions_buffer,
193 const uint8_t** isolate_data_buffer,
194 const uint8_t** isolate_instructions_buffer) {
195 *vm_data_buffer = vm_snapshot_data_;
196 *vm_instructions_buffer = vm_snapshot_instructions_;
197 *isolate_data_buffer = isolate_snapshot_data_;
198 *isolate_instructions_buffer = isolate_snapshot_instructions_;
199 }
200
201 private:
202 Dart_LoadedElf* elf_;
203 const uint8_t* vm_snapshot_data_;
204 const uint8_t* vm_snapshot_instructions_;
205 const uint8_t* isolate_snapshot_data_;
206 const uint8_t* isolate_snapshot_instructions_;
207};
208
209static AppSnapshot* TryReadAppSnapshotElf(
210 const char* script_name,
211 uint64_t file_offset,
212 bool force_load_elf_from_memory = false) {
213 const char* error = nullptr;
214 const uint8_t *vm_data_buffer = nullptr, *vm_instructions_buffer = nullptr,
215 *isolate_data_buffer = nullptr,
216 *isolate_instructions_buffer = nullptr;
217 Dart_LoadedElf* handle = nullptr;
218#if !defined(DART_HOST_OS_FUCHSIA)
219 if (force_load_elf_from_memory) {
220#endif
221 File* const file =
222 File::Open(/*namespc=*/nullptr, script_name, File::kRead);
223 if (file == nullptr) return nullptr;
224 MappedMemory* memory = file->Map(File::kReadOnly, /*position=*/0,
225 /*length=*/file->Length());
226 if (memory == nullptr) return nullptr;
227 const uint8_t* address =
228 reinterpret_cast<const uint8_t*>(memory->address());
229 handle =
230 Dart_LoadELF_Memory(address + file_offset, file->Length(), &error,
231 &vm_data_buffer, &vm_instructions_buffer,
232 &isolate_data_buffer, &isolate_instructions_buffer);
233 delete memory;
234 file->Release();
235#if !defined(DART_HOST_OS_FUCHSIA)
236 } else {
237 handle = Dart_LoadELF(script_name, file_offset, &error, &vm_data_buffer,
238 &vm_instructions_buffer, &isolate_data_buffer,
239 &isolate_instructions_buffer);
240 }
241#endif
242 if (handle == nullptr) {
243 Syslog::PrintErr("Loading failed: %s\n", error);
244 return nullptr;
245 }
246 return new ElfAppSnapshot(handle, vm_data_buffer, vm_instructions_buffer,
247 isolate_data_buffer, isolate_instructions_buffer);
248}
249
250#if defined(DART_TARGET_OS_MACOS)
251AppSnapshot* Snapshot::TryReadAppendedAppSnapshotElfFromMachO(
252 const char* container_path) {
253 // Ensure file is actually MachO-formatted.
254 if (!IsMachOFormattedBinary(container_path)) {
255 Syslog::PrintErr("Expected a Mach-O binary.\n");
256 return nullptr;
257 }
258
259 File* file = File::Open(nullptr, container_path, File::kRead);
260 if (file == nullptr) {
261 return nullptr;
262 }
263 RefCntReleaseScope<File> rs(file);
264
265 // Read in the Mach-O header. Note that the 64-bit header is the same layout
266 // as the 32-bit header, just with an extra field for alignment, so we can
267 // safely load a 32-bit header to get all the information we need.
268 mach_o::mach_header header;
269 file->ReadFully(&header, sizeof(header));
270
271 if (header.magic == mach_o::MH_CIGAM || header.magic == mach_o::MH_CIGAM_64) {
273 "Expected a host endian header but found a byte-swapped header.\n");
274 return nullptr;
275 }
276
277 if (header.magic == mach_o::MH_MAGIC_64) {
278 // Set the file position as if we had read a 64-bit header.
279 file->SetPosition(sizeof(mach_o::mach_header_64));
280 }
281
282 // Now we search through the load commands to find our snapshot note, which
283 // has a data_owner field of kMachOAppSnapshotNoteName.
284 for (uint32_t i = 0; i < header.ncmds; ++i) {
285 mach_o::load_command command;
286 file->ReadFully(&command, sizeof(mach_o::load_command));
287
288 file->SetPosition(file->Position() - sizeof(command));
289 if (command.cmd != mach_o::LC_NOTE) {
290 file->SetPosition(file->Position() + command.cmdsize);
291 continue;
292 }
293
294 mach_o::note_command note;
295 file->ReadFully(&note, sizeof(note));
296
297 if (strcmp(note.data_owner, kMachOAppSnapshotNoteName) != 0) {
298 file->SetPosition(file->Position() + command.cmdsize);
299 continue;
300 }
301
302 // A note with the correct name was found, so we assume that the
303 // file contents for that note contains an ELF snapshot.
304 return TryReadAppSnapshotElf(container_path, note.offset);
305 }
306
307 return nullptr;
308}
309#endif // defined(DART_TARGET_OS_MACOS)
310
311#if defined(DART_TARGET_OS_WINDOWS)
312// Keep in sync with CoffSectionTable._snapshotSectionName from
313// pkg/dart2native/lib/dart2native_pe.dart.
314static const char kSnapshotSectionName[] = "snapshot";
315// Ignore the null terminator, as it won't be present if the string length is
316// exactly pe::kCoffSectionNameSize.
317static_assert(sizeof(kSnapshotSectionName) - 1 <= pe::kCoffSectionNameSize,
318 "Section name of snapshot too large");
319
320AppSnapshot* Snapshot::TryReadAppendedAppSnapshotElfFromPE(
321 const char* container_path) {
322 File* const file = File::Open(nullptr, container_path, File::kRead);
323 if (file == nullptr) {
324 return nullptr;
325 }
326 RefCntReleaseScope<File> rs(file);
327
328 // Ensure file is actually PE-formatted.
329 if (!IsPEFormattedBinary(container_path)) {
331 "Attempted load target was not formatted as expected: "
332 "expected PE32 or PE32+ image file.\n");
333 return nullptr;
334 }
335
336 // Parse the offset into the PE contents (i.e., skipping the MS-DOS stub).
337 uint32_t pe_offset;
338 file->SetPosition(pe::kPEOffsetOffset);
339 file->ReadFully(&pe_offset, sizeof(pe_offset));
340
341 // Skip past the magic bytes to the COFF file header and COFF optional header.
342 const intptr_t coff_offset = pe_offset + sizeof(pe::kPEMagic);
343 file->SetPosition(coff_offset);
344 pe::coff_file_header file_header;
345 file->ReadFully(&file_header, sizeof(file_header));
346 // The optional header follows directly after the file header.
347 pe::coff_optional_header opt_header;
348 file->ReadFully(&opt_header, sizeof(opt_header));
349
350 // Skip to the section table.
351 const intptr_t coff_symbol_table_offset =
352 coff_offset + sizeof(file_header) + file_header.optional_header_size;
353 file->SetPosition(coff_symbol_table_offset);
354 for (intptr_t i = 0; i < file_header.num_sections; i++) {
355 pe::coff_section_header section_header;
356 file->ReadFully(&section_header, sizeof(section_header));
357 if (strncmp(section_header.name, kSnapshotSectionName,
359 // We have to do the loading manually even though currently the snapshot
360 // data is at the end of the file because the file alignment for
361 // PE sections can be less than the page size, and TryReadAppSnapshotElf
362 // won't work if the file offset isn't page-aligned.
363 const char* error = nullptr;
364 const uint8_t* vm_data_buffer = nullptr;
365 const uint8_t* vm_instructions_buffer = nullptr;
366 const uint8_t* isolate_data_buffer = nullptr;
367 const uint8_t* isolate_instructions_buffer = nullptr;
368
369 const intptr_t offset = section_header.file_offset;
370 const intptr_t size = section_header.file_size;
371
372 std::unique_ptr<uint8_t[]> snapshot(new uint8_t[size]);
373 file->SetPosition(offset);
374 file->ReadFully(snapshot.get(), sizeof(uint8_t) * size);
375
376 Dart_LoadedElf* const handle =
377 Dart_LoadELF_Memory(snapshot.get(), size, &error, &vm_data_buffer,
378 &vm_instructions_buffer, &isolate_data_buffer,
379 &isolate_instructions_buffer);
380
381 if (handle == nullptr) {
382 Syslog::PrintErr("Loading failed: %s\n", error);
383 return nullptr;
384 }
385
386 return new ElfAppSnapshot(handle, vm_data_buffer, vm_instructions_buffer,
387 isolate_data_buffer,
388 isolate_instructions_buffer);
389 }
390 }
391
392 return nullptr;
393}
394#endif // defined(DART_TARGET_OS_WINDOWS)
395
397 const char* container_path) {
398#if defined(DART_TARGET_OS_MACOS)
399 if (IsMachOFormattedBinary(container_path)) {
400 return TryReadAppendedAppSnapshotElfFromMachO(container_path);
401 }
402#elif defined(DART_TARGET_OS_WINDOWS)
403 if (IsPEFormattedBinary(container_path)) {
404 return TryReadAppendedAppSnapshotElfFromPE(container_path);
405 }
406#endif
407
408 File* file = File::Open(nullptr, container_path, File::kRead);
409 if (file == nullptr) {
410 return nullptr;
411 }
412 RefCntReleaseScope<File> rs(file);
413
414 // Check for payload appended at the end of the container file.
415 // If header is found, jump to payload offset.
416 int64_t appended_header[2];
417 if (!file->SetPosition(file->Length() - sizeof(appended_header))) {
418 return nullptr;
419 }
420 if (!file->ReadFully(&appended_header, sizeof(appended_header))) {
421 return nullptr;
422 }
423 // Length is always encoded as Little Endian.
424 const uint64_t appended_offset =
425 Utils::LittleEndianToHost64(appended_header[0]);
426 if (memcmp(&appended_header[1], appjit_magic_number.bytes,
428 appended_offset <= 0) {
429 return nullptr;
430 }
431
432 return TryReadAppSnapshotElf(container_path, appended_offset);
433}
434
435class DylibAppSnapshot : public AppSnapshot {
436 public:
437 DylibAppSnapshot(void* library,
438 const uint8_t* vm_snapshot_data,
439 const uint8_t* vm_snapshot_instructions,
440 const uint8_t* isolate_snapshot_data,
441 const uint8_t* isolate_snapshot_instructions)
442 : AppSnapshot(DartUtils::kAotELFMagicNumber),
443 library_(library),
444 vm_snapshot_data_(vm_snapshot_data),
445 vm_snapshot_instructions_(vm_snapshot_instructions),
446 isolate_snapshot_data_(isolate_snapshot_data),
447 isolate_snapshot_instructions_(isolate_snapshot_instructions) {}
448
449 ~DylibAppSnapshot() { Utils::UnloadDynamicLibrary(library_); }
450
451 void SetBuffers(const uint8_t** vm_data_buffer,
452 const uint8_t** vm_instructions_buffer,
453 const uint8_t** isolate_data_buffer,
454 const uint8_t** isolate_instructions_buffer) {
455 *vm_data_buffer = vm_snapshot_data_;
456 *vm_instructions_buffer = vm_snapshot_instructions_;
457 *isolate_data_buffer = isolate_snapshot_data_;
458 *isolate_instructions_buffer = isolate_snapshot_instructions_;
459 }
460
461 private:
462 void* library_;
463 const uint8_t* vm_snapshot_data_;
464 const uint8_t* vm_snapshot_instructions_;
465 const uint8_t* isolate_snapshot_data_;
466 const uint8_t* isolate_snapshot_instructions_;
467};
468
469static AppSnapshot* TryReadAppSnapshotDynamicLibrary(const char* script_name) {
470 void* library = Utils::LoadDynamicLibrary(script_name);
471 if (library == nullptr) {
472 return nullptr;
473 }
474
475 const uint8_t* vm_data_buffer = reinterpret_cast<const uint8_t*>(
477
478 const uint8_t* vm_instructions_buffer =
479 reinterpret_cast<const uint8_t*>(Utils::ResolveSymbolInDynamicLibrary(
481
482 const uint8_t* isolate_data_buffer =
483 reinterpret_cast<const uint8_t*>(Utils::ResolveSymbolInDynamicLibrary(
485 if (isolate_data_buffer == nullptr) {
486 FATAL("Failed to resolve symbol '%s'\n", kIsolateSnapshotDataCSymbol);
487 }
488
489 const uint8_t* isolate_instructions_buffer =
490 reinterpret_cast<const uint8_t*>(Utils::ResolveSymbolInDynamicLibrary(
492 if (isolate_instructions_buffer == nullptr) {
493 FATAL("Failed to resolve symbol '%s'\n",
495 }
496
497 return new DylibAppSnapshot(library, vm_data_buffer, vm_instructions_buffer,
498 isolate_data_buffer, isolate_instructions_buffer);
499}
500
501#endif // defined(DART_PRECOMPILED_RUNTIME)
502
503#if defined(DART_TARGET_OS_MACOS)
504bool Snapshot::IsMachOFormattedBinary(const char* filename) {
505 File* file = File::Open(nullptr, filename, File::kRead);
506 if (file == nullptr) {
507 return false;
508 }
509 RefCntReleaseScope<File> rs(file);
510
511 const uint64_t size = file->Length();
512 // Parse the first 4 bytes and check the magic numbers.
513 uint32_t magic;
514 if (size < sizeof(magic)) {
515 // The file isn't long enough to contain the magic bytes.
516 return false;
517 }
518 file->SetPosition(0);
519 file->ReadFully(&magic, sizeof(magic));
520
521 // Depending on the magic numbers, check that the size of the file is
522 // large enough for either a 32-bit or 64-bit header.
523 switch (magic) {
524 case mach_o::MH_MAGIC:
525 case mach_o::MH_CIGAM:
526 return size >= sizeof(mach_o::mach_header);
529 return size >= sizeof(mach_o::mach_header_64);
530 default:
531 // Not a Mach-O formatted file.
532 return false;
533 }
534}
535#endif // defined(DART_TARGET_OS_MACOS)
536
537#if defined(DART_TARGET_OS_WINDOWS)
538bool Snapshot::IsPEFormattedBinary(const char* filename) {
539 File* file = File::Open(nullptr, filename, File::kRead);
540 if (file == nullptr) {
541 return false;
542 }
543 RefCntReleaseScope<File> rs(file);
544
545 // Parse the PE offset.
546 uint32_t pe_offset;
547 // Ensure the file is long enough to contain the PE offset.
548 if (file->Length() <
549 static_cast<intptr_t>(pe::kPEOffsetOffset + sizeof(pe_offset))) {
550 return false;
551 }
552 file->SetPosition(pe::kPEOffsetOffset);
553 file->Read(&pe_offset, sizeof(pe_offset));
554
555 // Ensure the file is long enough to contain the PE magic bytes.
556 if (file->Length() <
557 static_cast<intptr_t>(pe_offset + sizeof(pe::kPEMagic))) {
558 return false;
559 }
560 // Check the magic bytes.
561 file->SetPosition(pe_offset);
562 for (size_t i = 0; i < sizeof(pe::kPEMagic); i++) {
563 char c;
564 file->Read(&c, sizeof(c));
565 if (c != pe::kPEMagic[i]) {
566 return false;
567 }
568 }
569
570 // Check that there is a coff optional header.
571 pe::coff_file_header file_header;
572 pe::coff_optional_header opt_header;
573 file->Read(&file_header, sizeof(file_header));
574 if (file_header.optional_header_size < sizeof(opt_header)) {
575 return false;
576 }
577 file->Read(&opt_header, sizeof(opt_header));
578 // Check the magic bytes in the coff optional header.
579 if (opt_header.magic != pe::kPE32Magic &&
580 opt_header.magic != pe::kPE32PlusMagic) {
581 return false;
582 }
583
584 return true;
585}
586#endif // defined(DART_TARGET_OS_WINDOWS)
587
589 bool force_load_elf_from_memory,
590 bool decode_uri) {
591 Utils::CStringUniquePtr decoded_path(nullptr, std::free);
592 const char* script_name = nullptr;
593 if (decode_uri) {
594 decoded_path = File::UriToPath(script_uri);
595 if (decoded_path == nullptr) {
596 return nullptr;
597 }
598 script_name = decoded_path.get();
599 } else {
600 script_name = script_uri;
601 }
602 if (File::GetType(nullptr, script_name, true) != File::kIsFile) {
603 // If 'script_name' refers to a pipe, don't read to check for an app
604 // snapshot since we cannot rewind if it isn't (and couldn't mmap it in
605 // anyway if it was).
606 return nullptr;
607 }
608 File* file = File::Open(nullptr, script_name, File::kRead);
609 if (file == nullptr) {
610 return nullptr;
611 }
613 if ((file->Length() - file->Position()) < DartUtils::kMaxMagicNumberSize) {
614 return nullptr;
615 }
616
619 if (!file->ReadFully(&header, DartUtils::kMaxMagicNumberSize)) {
620 return nullptr;
621 }
622 DartUtils::MagicNumber magic_number =
624 if (magic_number == DartUtils::kAppJITMagicNumber) {
625 // Return the JIT snapshot.
626 return TryReadAppSnapshotBlobs(script_name, file);
627 }
628#if defined(DART_PRECOMPILED_RUNTIME)
629 if (!DartUtils::IsAotMagicNumber(magic_number)) {
630 return nullptr;
631 }
632
633 // For testing AOT with the standalone embedder, we also support loading
634 // from a dynamic library to simulate what happens on iOS.
635
636#if defined(DART_TARGET_OS_LINUX) || defined(DART_TARGET_OS_MACOS)
637 // On Linux and OSX, resolve the script path before passing into dlopen()
638 // since dlopen will not search the filesystem for paths like 'libtest.so'.
639 std::unique_ptr<char, decltype(std::free)*> absolute_path{
640 realpath(script_name, nullptr), std::free};
641 script_name = absolute_path.get();
642#endif
643
644 AppSnapshot* snapshot = nullptr;
645 if (!force_load_elf_from_memory) {
646 snapshot = TryReadAppSnapshotDynamicLibrary(script_name);
647 if (snapshot != nullptr) {
648 return snapshot;
649 }
650 }
651 return TryReadAppSnapshotElf(script_name, /*file_offset=*/0,
652 force_load_elf_from_memory);
653#else
654 // We create a dummy snapshot object just to remember the type which
655 // has already been identified by sniffing the magic number.
656 return new DummySnapshot(magic_number);
657#endif // defined(DART_PRECOMPILED_RUNTIME)
658
659 return nullptr;
660}
661
662#if !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) && !defined(TESTING)
663static void WriteSnapshotFile(const char* filename,
664 const uint8_t* buffer,
665 const intptr_t size) {
666 File* file = File::Open(nullptr, filename, File::kWriteTruncate);
667 if (file == nullptr) {
668 ErrorExit(kErrorExitCode, "Unable to open file %s for writing snapshot\n",
669 filename);
670 }
671
672 if (!file->WriteFully(buffer, size)) {
673 ErrorExit(kErrorExitCode, "Unable to write file %s for writing snapshot\n",
674 filename);
675 }
676 file->Release();
677}
678#endif
679
680static bool WriteInt64(File* file, int64_t size) {
681 return file->WriteFully(&size, sizeof(size));
682}
683
684void Snapshot::WriteAppSnapshot(const char* filename,
685 uint8_t* vm_data_buffer,
686 intptr_t vm_data_size,
687 uint8_t* vm_instructions_buffer,
688 intptr_t vm_instructions_size,
689 uint8_t* isolate_data_buffer,
690 intptr_t isolate_data_size,
691 uint8_t* isolate_instructions_buffer,
692 intptr_t isolate_instructions_size) {
693 File* file = File::Open(nullptr, filename, File::kWriteTruncate);
694 if (file == nullptr) {
695 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
696 }
697
699 WriteInt64(file, vm_data_size);
700 WriteInt64(file, vm_instructions_size);
701 WriteInt64(file, isolate_data_size);
702 WriteInt64(file, isolate_instructions_size);
703 ASSERT(file->Position() ==
705
706 file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
708 Syslog::PrintErr("%" Px64 ": VM Data\n", file->Position());
709 }
710 if (!file->WriteFully(vm_data_buffer, vm_data_size)) {
711 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
712 }
713
714 if (vm_instructions_size != 0) {
715 file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
717 Syslog::PrintErr("%" Px64 ": VM Instructions\n", file->Position());
718 }
719 if (!file->WriteFully(vm_instructions_buffer, vm_instructions_size)) {
720 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n",
721 filename);
722 }
723 }
724
725 file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
727 Syslog::PrintErr("%" Px64 ": Isolate Data\n", file->Position());
728 }
729 if (!file->WriteFully(isolate_data_buffer, isolate_data_size)) {
730 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
731 }
732
733 if (isolate_instructions_size != 0) {
734 file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
736 Syslog::PrintErr("%" Px64 ": Isolate Instructions\n", file->Position());
737 }
738 if (!file->WriteFully(isolate_instructions_buffer,
739 isolate_instructions_size)) {
740 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n",
741 filename);
742 }
743 }
744
745 file->Flush();
746 file->Release();
747}
748
749void Snapshot::GenerateKernel(const char* snapshot_filename,
750 const char* script_name,
751 const char* package_config) {
752#if !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) && !defined(TESTING)
753 ASSERT(Dart_CurrentIsolate() == nullptr);
754
755 uint8_t* kernel_buffer = nullptr;
756 intptr_t kernel_buffer_size = 0;
757 dfe.ReadScript(script_name, nullptr, &kernel_buffer, &kernel_buffer_size);
758 if (kernel_buffer != nullptr) {
759 WriteSnapshotFile(snapshot_filename, kernel_buffer, kernel_buffer_size);
760 free(kernel_buffer);
761 } else {
763 dfe.CompileScript(script_name, /*incremental*/ false, package_config,
764 /*snapshot=*/true, /*embedd_sources=*/true);
766 Syslog::PrintErr("%s\n", result.error);
768 }
769 WriteSnapshotFile(snapshot_filename, result.kernel, result.kernel_size);
770 free(result.kernel);
771 }
772#else
773 UNREACHABLE();
774#endif // !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) && !defined(TESTING)
775}
776
777void Snapshot::GenerateAppJIT(const char* snapshot_filename) {
778#if defined(TARGET_ARCH_IA32)
779 // Snapshots with code are not supported on IA32.
780 uint8_t* isolate_buffer = nullptr;
781 intptr_t isolate_size = 0;
782
783 Dart_Handle result = Dart_CreateSnapshot(nullptr, nullptr, &isolate_buffer,
784 &isolate_size, /*is_core=*/false);
785 if (Dart_IsError(result)) {
787 }
788
789 WriteAppSnapshot(snapshot_filename, nullptr, 0, nullptr, 0, isolate_buffer,
790 isolate_size, nullptr, 0);
791#else
792 uint8_t* isolate_data_buffer = nullptr;
793 intptr_t isolate_data_size = 0;
794 uint8_t* isolate_instructions_buffer = nullptr;
795 intptr_t isolate_instructions_size = 0;
797 &isolate_data_buffer, &isolate_data_size, &isolate_instructions_buffer,
798 &isolate_instructions_size);
799 if (Dart_IsError(result)) {
801 }
802 WriteAppSnapshot(snapshot_filename, nullptr, 0, nullptr, 0,
803 isolate_data_buffer, isolate_data_size,
804 isolate_instructions_buffer, isolate_instructions_size);
805#endif
806}
807
808static void StreamingWriteCallback(void* callback_data,
809 const uint8_t* buffer,
810 intptr_t size) {
811 File* file = reinterpret_cast<File*>(callback_data);
812 if (!file->WriteFully(buffer, size)) {
813 ErrorExit(kErrorExitCode, "Unable to write snapshot file\n");
814 }
815}
816
817void Snapshot::GenerateAppAOTAsAssembly(const char* snapshot_filename) {
818 File* file = File::Open(nullptr, snapshot_filename, File::kWriteTruncate);
820 if (file == nullptr) {
821 ErrorExit(kErrorExitCode, "Unable to open file %s for writing snapshot\n",
822 snapshot_filename);
823 }
825 StreamingWriteCallback, file, /*strip=*/false,
826 /*debug_callback_data=*/nullptr);
827 if (Dart_IsError(result)) {
829 }
830}
831
832} // namespace bin
833} // namespace dart
#define UNREACHABLE()
Definition assert.h:248
static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void * LoadDynamicLibrary(const char *library_path, char **error=nullptr)
Definition utils.cc:293
static uint64_t LittleEndianToHost64(uint64_t le_value)
Definition utils.h:506
std::unique_ptr< char, decltype(std::free) * > CStringUniquePtr
Definition utils.h:644
static constexpr T RoundUp(T x, uintptr_t alignment, uintptr_t offset=0)
Definition utils.h:105
static void * ResolveSymbolInDynamicLibrary(void *library_handle, const char *symbol, char **error=nullptr)
Definition utils.cc:326
Dart_KernelCompilationResult CompileScript(const char *script_uri, bool incremental, const char *package_config, bool for_snapshot, bool embedd_sources)
Definition dfe.cc:189
void ReadScript(const char *script_uri, const AppSnapshot *app_snapshot, uint8_t **kernel_buffer, intptr_t *kernel_buffer_size, bool decode_uri=true, std::shared_ptr< uint8_t > *kernel_blob_ptr=nullptr)
Definition dfe.cc:241
static MagicNumber SniffForMagicNumber(const char *filename)
Definition dartutils.cc:407
static bool IsAotMagicNumber(MagicNumber number)
Definition dartutils.h:275
static constexpr int64_t kMaxMagicNumberSize
Definition dartutils.h:271
DummySnapshot(DartUtils::MagicNumber num)
void SetBuffers(const uint8_t **vm_data_buffer, const uint8_t **vm_instructions_buffer, const uint8_t **isolate_data_buffer, const uint8_t **isolate_instructions_buffer)
static Utils::CStringUniquePtr UriToPath(const char *uri)
static File * Open(Namespace *namespc, const char *path, FileOpenMode mode)
@ kWriteTruncate
Definition file.h:60
static Type GetType(Namespace *namespc, const char *path, bool follow_links)
void SetBuffers(const uint8_t **vm_data_buffer, const uint8_t **vm_instructions_buffer, const uint8_t **isolate_data_buffer, const uint8_t **isolate_instructions_buffer)
MappedAppSnapshot(MappedMemory *vm_snapshot_data, MappedMemory *vm_snapshot_instructions, MappedMemory *isolate_snapshot_data, MappedMemory *isolate_snapshot_instructions)
void * address() const
Definition file.h:34
static DART_NORETURN void Exit(int exit_code)
static void GenerateAppAOTAsAssembly(const char *snapshot_filename)
static AppSnapshot * TryReadAppSnapshot(const char *script_uri, bool force_load_elf_from_memory=false, bool decode_uri=true)
static AppSnapshot * TryReadAppendedAppSnapshotElf(const char *container_path)
static void GenerateKernel(const char *snapshot_filename, const char *script_name, const char *package_config)
static void GenerateAppJIT(const char *snapshot_filename)
static void WriteAppSnapshot(const char *filename, uint8_t *vm_data_buffer, intptr_t vm_data_size, uint8_t *vm_instructions_buffer, intptr_t vm_instructions_size, uint8_t *isolate_data_buffer, intptr_t isolate_data_size, uint8_t *isolate_instructions_buffer, intptr_t isolate_instructions_size)
@ Dart_KernelCompilationStatus_Ok
Definition dart_api.h:3728
struct _Dart_Handle * Dart_Handle
Definition dart_api.h:258
#define kIsolateSnapshotDataCSymbol
Definition dart_api.h:3901
#define kIsolateSnapshotInstructionsCSymbol
Definition dart_api.h:3902
#define kVmSnapshotDataCSymbol
Definition dart_api.h:3898
#define kVmSnapshotInstructionsCSymbol
Definition dart_api.h:3899
#define ASSERT(E)
#define FATAL(error)
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
constexpr int kCompilationErrorExitCode
Definition error_exit.h:16
const uint8_t * isolate_snapshot_data
MagicNumberData appjit_magic_number
Definition dartutils.cc:39
static constexpr int64_t kAppSnapshotPageSize
const uint8_t * vm_snapshot_data
Definition main_impl.cc:56
DFE dfe
Definition dfe.cc:59
const uint8_t * vm_snapshot_instructions
Definition main_impl.cc:57
static constexpr int64_t kAppSnapshotHeaderSize
static void StreamingWriteCallback(void *callback_data, const uint8_t *buffer, intptr_t size)
static AppSnapshot * TryReadAppSnapshotBlobs(const char *script_name, File *file)
constexpr int kErrorExitCode
Definition error_exit.h:18
static const char kMachOAppSnapshotNoteName[] DART_UNUSED
void ErrorExit(int exit_code, const char *format,...)
Definition error_exit.cc:18
static void WriteSnapshotFile(const char *filename, const uint8_t *buffer, const intptr_t size)
static bool WriteInt64(File *file, int64_t size)
const uint8_t * isolate_snapshot_instructions
static constexpr uint32_t MH_CIGAM
Definition mach_o.h:31
static constexpr uint32_t MH_CIGAM_64
Definition mach_o.h:45
static constexpr uint32_t MH_MAGIC_64
Definition mach_o.h:44
static constexpr uint32_t MH_MAGIC
Definition mach_o.h:30
static constexpr uint32_t LC_NOTE
Definition mach_o.h:52
static const char kPEMagic[]
Definition pe.h:17
static constexpr intptr_t kPEOffsetOffset
Definition pe.h:16
static constexpr uint16_t kPE32Magic
Definition pe.h:42
static constexpr intptr_t kCoffSectionNameSize
Definition pe.h:45
static constexpr uint16_t kPE32PlusMagic
Definition pe.h:43
constexpr intptr_t kInt64Size
Definition globals.h:453
DART_EXPORT const char * Dart_GetError(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_CreateAppJITSnapshotAsBlobs(uint8_t **isolate_snapshot_data_buffer, intptr_t *isolate_snapshot_data_size, uint8_t **isolate_snapshot_instructions_buffer, intptr_t *isolate_snapshot_instructions_size)
constexpr intptr_t KB
Definition globals.h:528
DART_EXPORT Dart_Isolate Dart_CurrentIsolate()
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, void *callback_data, bool strip, void *debug_callback_data)
DART_EXPORT Dart_Handle Dart_CreateSnapshot(uint8_t **vm_snapshot_data_buffer, intptr_t *vm_snapshot_data_size, uint8_t **isolate_snapshot_data_buffer, intptr_t *isolate_snapshot_data_size, bool is_core)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259
list command
Definition valgrind.py:24
#define Px64
Definition globals.h:418
static const char header[]
Definition skpbench.cpp:88
#define LOG_SECTION_BOUNDARIES
Point offset
const uint8_t bytes[kMaxLength]
Definition dartutils.h:657
DART_EXPORT Dart_LoadedElf * Dart_LoadELF_Memory(const uint8_t *snapshot, uint64_t snapshot_size, const char **error, const uint8_t **vm_snapshot_data, const uint8_t **vm_snapshot_instrs, const uint8_t **vm_isolate_data, const uint8_t **vm_isolate_instrs)
Please see documentation for Dart_LoadElf_Fd.
DART_EXPORT Dart_LoadedElf * Dart_LoadELF(const char *filename, uint64_t file_offset, const char **error, const uint8_t **vm_snapshot_data, const uint8_t **vm_snapshot_instrs, const uint8_t **vm_isolate_data, const uint8_t **vm_isolate_instrs)
Please see documentation for Dart_LoadElf_Fd.
DART_EXPORT void Dart_UnloadELF(Dart_LoadedElf *loaded)