Flutter Engine
The Flutter Engine
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 = 2 * kInt64Size;
30// The largest possible page size among the platforms we support (Linux ARM64).
31static constexpr int64_t kAppSnapshotPageSize = 64 * KB;
32
33static const char kMachOAppSnapshotNoteName[] DART_UNUSED = "__dart_app_snap";
34
35#if !defined(DART_PRECOMPILED_RUNTIME)
36class DummySnapshot : public AppSnapshot {
37 public:
39
41
42 void SetBuffers(const uint8_t** vm_data_buffer,
43 const uint8_t** vm_instructions_buffer,
44 const uint8_t** isolate_data_buffer,
45 const uint8_t** isolate_instructions_buffer) {
47 }
48
49 private:
50};
51#endif // !defined(DART_PRECOMPILED_RUNTIME)
52
54 public:
59 : AppSnapshot(DartUtils::kAppJITMagicNumber),
60 vm_data_mapping_(vm_snapshot_data),
61 vm_instructions_mapping_(vm_snapshot_instructions),
62 isolate_data_mapping_(isolate_snapshot_data),
63 isolate_instructions_mapping_(isolate_snapshot_instructions) {}
64
66 delete vm_data_mapping_;
67 delete vm_instructions_mapping_;
68 delete isolate_data_mapping_;
69 delete isolate_instructions_mapping_;
70 }
71
72 void SetBuffers(const uint8_t** vm_data_buffer,
73 const uint8_t** vm_instructions_buffer,
74 const uint8_t** isolate_data_buffer,
75 const uint8_t** isolate_instructions_buffer) {
76 if (vm_data_mapping_ != nullptr) {
77 *vm_data_buffer =
78 reinterpret_cast<const uint8_t*>(vm_data_mapping_->address());
79 }
80 if (vm_instructions_mapping_ != nullptr) {
81 *vm_instructions_buffer =
82 reinterpret_cast<const uint8_t*>(vm_instructions_mapping_->address());
83 }
84 if (isolate_data_mapping_ != nullptr) {
85 *isolate_data_buffer =
86 reinterpret_cast<const uint8_t*>(isolate_data_mapping_->address());
87 }
88 if (isolate_instructions_mapping_ != nullptr) {
89 *isolate_instructions_buffer = reinterpret_cast<const uint8_t*>(
90 isolate_instructions_mapping_->address());
91 }
92 }
93
94 private:
95 MappedMemory* vm_data_mapping_;
96 MappedMemory* vm_instructions_mapping_;
97 MappedMemory* isolate_data_mapping_;
98 MappedMemory* isolate_instructions_mapping_;
99};
100
101static AppSnapshot* TryReadAppSnapshotBlobs(const char* script_name,
102 File* file) {
103 if ((file->Length() - file->Position()) < kAppSnapshotHeaderSize) {
104 return nullptr;
105 }
106
107 int64_t header[2];
109 if (!file->ReadFully(&header, kAppSnapshotHeaderSize)) {
110 return nullptr;
111 }
112 int64_t isolate_data_size = header[0];
113 int64_t isolate_data_position =
115 int64_t isolate_instructions_size = header[1];
116 int64_t isolate_instructions_position =
117 isolate_data_position + isolate_data_size;
118 if (isolate_instructions_size != 0) {
119 isolate_instructions_position =
120 Utils::RoundUp(isolate_instructions_position, kAppSnapshotPageSize);
121 }
122
123 MappedMemory* isolate_data_mapping = nullptr;
124 if (isolate_data_size != 0) {
125 isolate_data_mapping =
126 file->Map(File::kReadOnly, isolate_data_position, isolate_data_size);
127 if (isolate_data_mapping == nullptr) {
128 FATAL("Failed to memory map snapshot: %s\n", script_name);
129 }
130 }
131
132 MappedMemory* isolate_instr_mapping = nullptr;
133 if (isolate_instructions_size != 0) {
134 isolate_instr_mapping =
135 file->Map(File::kReadExecute, isolate_instructions_position,
136 isolate_instructions_size);
137 if (isolate_instr_mapping == nullptr) {
138 FATAL("Failed to memory map snapshot: %s\n", script_name);
139 }
140 }
141
142 auto app_snapshot = new MappedAppSnapshot(
143 nullptr, nullptr, isolate_data_mapping, isolate_instr_mapping);
144 return app_snapshot;
145}
146
147#if defined(DART_PRECOMPILED_RUNTIME)
148class ElfAppSnapshot : public AppSnapshot {
149 public:
150 ElfAppSnapshot(Dart_LoadedElf* elf,
151 const uint8_t* vm_snapshot_data,
152 const uint8_t* vm_snapshot_instructions,
153 const uint8_t* isolate_snapshot_data,
154 const uint8_t* isolate_snapshot_instructions)
155 : AppSnapshot{DartUtils::kAotELFMagicNumber},
156 elf_(elf),
157 vm_snapshot_data_(vm_snapshot_data),
158 vm_snapshot_instructions_(vm_snapshot_instructions),
159 isolate_snapshot_data_(isolate_snapshot_data),
160 isolate_snapshot_instructions_(isolate_snapshot_instructions) {}
161
162 virtual ~ElfAppSnapshot() { Dart_UnloadELF(elf_); }
163
164 void SetBuffers(const uint8_t** vm_data_buffer,
165 const uint8_t** vm_instructions_buffer,
166 const uint8_t** isolate_data_buffer,
167 const uint8_t** isolate_instructions_buffer) {
168 *vm_data_buffer = vm_snapshot_data_;
169 *vm_instructions_buffer = vm_snapshot_instructions_;
170 *isolate_data_buffer = isolate_snapshot_data_;
171 *isolate_instructions_buffer = isolate_snapshot_instructions_;
172 }
173
174 private:
175 Dart_LoadedElf* elf_;
176 const uint8_t* vm_snapshot_data_;
177 const uint8_t* vm_snapshot_instructions_;
178 const uint8_t* isolate_snapshot_data_;
179 const uint8_t* isolate_snapshot_instructions_;
180};
181
182static AppSnapshot* TryReadAppSnapshotElf(
183 const char* script_name,
184 uint64_t file_offset,
185 bool force_load_elf_from_memory = false) {
186 const char* error = nullptr;
187 const uint8_t *vm_data_buffer = nullptr, *vm_instructions_buffer = nullptr,
188 *isolate_data_buffer = nullptr,
189 *isolate_instructions_buffer = nullptr;
190 Dart_LoadedElf* handle = nullptr;
191#if !defined(DART_HOST_OS_FUCHSIA)
192 if (force_load_elf_from_memory) {
193#endif
194 File* const file =
195 File::Open(/*namespc=*/nullptr, script_name, File::kRead);
196 if (file == nullptr) return nullptr;
197 MappedMemory* memory = file->Map(File::kReadOnly, /*position=*/0,
198 /*length=*/file->Length());
199 if (memory == nullptr) return nullptr;
200 const uint8_t* address =
201 reinterpret_cast<const uint8_t*>(memory->address());
202 handle =
203 Dart_LoadELF_Memory(address + file_offset, file->Length(), &error,
204 &vm_data_buffer, &vm_instructions_buffer,
205 &isolate_data_buffer, &isolate_instructions_buffer);
206 delete memory;
207 file->Release();
208#if !defined(DART_HOST_OS_FUCHSIA)
209 } else {
210 handle = Dart_LoadELF(script_name, file_offset, &error, &vm_data_buffer,
211 &vm_instructions_buffer, &isolate_data_buffer,
212 &isolate_instructions_buffer);
213 }
214#endif
215 if (handle == nullptr) {
216 Syslog::PrintErr("Loading failed: %s\n", error);
217 return nullptr;
218 }
219 return new ElfAppSnapshot(handle, vm_data_buffer, vm_instructions_buffer,
220 isolate_data_buffer, isolate_instructions_buffer);
221}
222
223#if defined(DART_TARGET_OS_MACOS)
224AppSnapshot* Snapshot::TryReadAppendedAppSnapshotElfFromMachO(
225 const char* container_path) {
226 // Ensure file is actually MachO-formatted.
227 if (!IsMachOFormattedBinary(container_path)) {
228 Syslog::PrintErr("Expected a Mach-O binary.\n");
229 return nullptr;
230 }
231
232 File* file = File::Open(nullptr, container_path, File::kRead);
233 if (file == nullptr) {
234 return nullptr;
235 }
236 RefCntReleaseScope<File> rs(file);
237
238 // Read in the Mach-O header. Note that the 64-bit header is the same layout
239 // as the 32-bit header, just with an extra field for alignment, so we can
240 // safely load a 32-bit header to get all the information we need.
241 mach_o::mach_header header;
242 file->ReadFully(&header, sizeof(header));
243
244 if (header.magic == mach_o::MH_CIGAM || header.magic == mach_o::MH_CIGAM_64) {
246 "Expected a host endian header but found a byte-swapped header.\n");
247 return nullptr;
248 }
249
250 if (header.magic == mach_o::MH_MAGIC_64) {
251 // Set the file position as if we had read a 64-bit header.
252 file->SetPosition(sizeof(mach_o::mach_header_64));
253 }
254
255 // Now we search through the load commands to find our snapshot note, which
256 // has a data_owner field of kMachOAppSnapshotNoteName.
257 for (uint32_t i = 0; i < header.ncmds; ++i) {
258 mach_o::load_command command;
259 file->ReadFully(&command, sizeof(mach_o::load_command));
260
261 file->SetPosition(file->Position() - sizeof(command));
262 if (command.cmd != mach_o::LC_NOTE) {
263 file->SetPosition(file->Position() + command.cmdsize);
264 continue;
265 }
266
267 mach_o::note_command note;
268 file->ReadFully(&note, sizeof(note));
269
270 if (strcmp(note.data_owner, kMachOAppSnapshotNoteName) != 0) {
271 file->SetPosition(file->Position() + command.cmdsize);
272 continue;
273 }
274
275 // A note with the correct name was found, so we assume that the
276 // file contents for that note contains an ELF snapshot.
277 return TryReadAppSnapshotElf(container_path, note.offset);
278 }
279
280 return nullptr;
281}
282#endif // defined(DART_TARGET_OS_MACOS)
283
284#if defined(DART_TARGET_OS_WINDOWS)
285// Keep in sync with CoffSectionTable._snapshotSectionName from
286// pkg/dart2native/lib/dart2native_pe.dart.
287static const char kSnapshotSectionName[] = "snapshot";
288// Ignore the null terminator, as it won't be present if the string length is
289// exactly pe::kCoffSectionNameSize.
290static_assert(sizeof(kSnapshotSectionName) - 1 <= pe::kCoffSectionNameSize,
291 "Section name of snapshot too large");
292
293AppSnapshot* Snapshot::TryReadAppendedAppSnapshotElfFromPE(
294 const char* container_path) {
295 File* const file = File::Open(nullptr, container_path, File::kRead);
296 if (file == nullptr) {
297 return nullptr;
298 }
299 RefCntReleaseScope<File> rs(file);
300
301 // Ensure file is actually PE-formatted.
302 if (!IsPEFormattedBinary(container_path)) {
304 "Attempted load target was not formatted as expected: "
305 "expected PE32 or PE32+ image file.\n");
306 return nullptr;
307 }
308
309 // Parse the offset into the PE contents (i.e., skipping the MS-DOS stub).
310 uint32_t pe_offset;
311 file->SetPosition(pe::kPEOffsetOffset);
312 file->ReadFully(&pe_offset, sizeof(pe_offset));
313
314 // Skip past the magic bytes to the COFF file header and COFF optional header.
315 const intptr_t coff_offset = pe_offset + sizeof(pe::kPEMagic);
316 file->SetPosition(coff_offset);
317 pe::coff_file_header file_header;
318 file->ReadFully(&file_header, sizeof(file_header));
319 // The optional header follows directly after the file header.
320 pe::coff_optional_header opt_header;
321 file->ReadFully(&opt_header, sizeof(opt_header));
322
323 // Skip to the section table.
324 const intptr_t coff_symbol_table_offset =
325 coff_offset + sizeof(file_header) + file_header.optional_header_size;
326 file->SetPosition(coff_symbol_table_offset);
327 for (intptr_t i = 0; i < file_header.num_sections; i++) {
328 pe::coff_section_header section_header;
329 file->ReadFully(&section_header, sizeof(section_header));
330 if (strncmp(section_header.name, kSnapshotSectionName,
332 // We have to do the loading manually even though currently the snapshot
333 // data is at the end of the file because the file alignment for
334 // PE sections can be less than the page size, and TryReadAppSnapshotElf
335 // won't work if the file offset isn't page-aligned.
336 const char* error = nullptr;
337 const uint8_t* vm_data_buffer = nullptr;
338 const uint8_t* vm_instructions_buffer = nullptr;
339 const uint8_t* isolate_data_buffer = nullptr;
340 const uint8_t* isolate_instructions_buffer = nullptr;
341
342 const intptr_t offset = section_header.file_offset;
343 const intptr_t size = section_header.file_size;
344
345 std::unique_ptr<uint8_t[]> snapshot(new uint8_t[size]);
346 file->SetPosition(offset);
347 file->ReadFully(snapshot.get(), sizeof(uint8_t) * size);
348
349 Dart_LoadedElf* const handle =
350 Dart_LoadELF_Memory(snapshot.get(), size, &error, &vm_data_buffer,
351 &vm_instructions_buffer, &isolate_data_buffer,
352 &isolate_instructions_buffer);
353
354 if (handle == nullptr) {
355 Syslog::PrintErr("Loading failed: %s\n", error);
356 return nullptr;
357 }
358
359 return new ElfAppSnapshot(handle, vm_data_buffer, vm_instructions_buffer,
360 isolate_data_buffer,
361 isolate_instructions_buffer);
362 }
363 }
364
365 return nullptr;
366}
367#endif // defined(DART_TARGET_OS_WINDOWS)
368
370 const char* container_path) {
371#if defined(DART_TARGET_OS_MACOS)
372 if (IsMachOFormattedBinary(container_path)) {
373 return TryReadAppendedAppSnapshotElfFromMachO(container_path);
374 }
375#elif defined(DART_TARGET_OS_WINDOWS)
376 if (IsPEFormattedBinary(container_path)) {
377 return TryReadAppendedAppSnapshotElfFromPE(container_path);
378 }
379#endif
380
381 File* file = File::Open(nullptr, container_path, File::kRead);
382 if (file == nullptr) {
383 return nullptr;
384 }
385 RefCntReleaseScope<File> rs(file);
386
387 // Check for payload appended at the end of the container file.
388 // If header is found, jump to payload offset.
389 int64_t appended_header[2];
390 if (!file->SetPosition(file->Length() - sizeof(appended_header))) {
391 return nullptr;
392 }
393 if (!file->ReadFully(&appended_header, sizeof(appended_header))) {
394 return nullptr;
395 }
396 // Length is always encoded as Little Endian.
397 const uint64_t appended_offset =
398 Utils::LittleEndianToHost64(appended_header[0]);
399 if (memcmp(&appended_header[1], appjit_magic_number.bytes,
401 appended_offset <= 0) {
402 return nullptr;
403 }
404
405 return TryReadAppSnapshotElf(container_path, appended_offset);
406}
407
408class DylibAppSnapshot : public AppSnapshot {
409 public:
410 DylibAppSnapshot(void* library,
411 const uint8_t* vm_snapshot_data,
412 const uint8_t* vm_snapshot_instructions,
413 const uint8_t* isolate_snapshot_data,
414 const uint8_t* isolate_snapshot_instructions)
415 : AppSnapshot(DartUtils::kAotELFMagicNumber),
416 library_(library),
417 vm_snapshot_data_(vm_snapshot_data),
418 vm_snapshot_instructions_(vm_snapshot_instructions),
419 isolate_snapshot_data_(isolate_snapshot_data),
420 isolate_snapshot_instructions_(isolate_snapshot_instructions) {}
421
422 ~DylibAppSnapshot() { Utils::UnloadDynamicLibrary(library_); }
423
424 void SetBuffers(const uint8_t** vm_data_buffer,
425 const uint8_t** vm_instructions_buffer,
426 const uint8_t** isolate_data_buffer,
427 const uint8_t** isolate_instructions_buffer) {
428 *vm_data_buffer = vm_snapshot_data_;
429 *vm_instructions_buffer = vm_snapshot_instructions_;
430 *isolate_data_buffer = isolate_snapshot_data_;
431 *isolate_instructions_buffer = isolate_snapshot_instructions_;
432 }
433
434 private:
435 void* library_;
436 const uint8_t* vm_snapshot_data_;
437 const uint8_t* vm_snapshot_instructions_;
438 const uint8_t* isolate_snapshot_data_;
439 const uint8_t* isolate_snapshot_instructions_;
440};
441
442static AppSnapshot* TryReadAppSnapshotDynamicLibrary(const char* script_name) {
443 void* library = Utils::LoadDynamicLibrary(script_name);
444 if (library == nullptr) {
445 return nullptr;
446 }
447
448 const uint8_t* vm_data_buffer = reinterpret_cast<const uint8_t*>(
450
451 const uint8_t* vm_instructions_buffer =
452 reinterpret_cast<const uint8_t*>(Utils::ResolveSymbolInDynamicLibrary(
454
455 const uint8_t* isolate_data_buffer =
456 reinterpret_cast<const uint8_t*>(Utils::ResolveSymbolInDynamicLibrary(
458 if (isolate_data_buffer == nullptr) {
459 FATAL("Failed to resolve symbol '%s'\n", kIsolateSnapshotDataCSymbol);
460 }
461
462 const uint8_t* isolate_instructions_buffer =
463 reinterpret_cast<const uint8_t*>(Utils::ResolveSymbolInDynamicLibrary(
465 if (isolate_instructions_buffer == nullptr) {
466 FATAL("Failed to resolve symbol '%s'\n",
468 }
469
470 return new DylibAppSnapshot(library, vm_data_buffer, vm_instructions_buffer,
471 isolate_data_buffer, isolate_instructions_buffer);
472}
473
474#endif // defined(DART_PRECOMPILED_RUNTIME)
475
476#if defined(DART_TARGET_OS_MACOS)
477bool Snapshot::IsMachOFormattedBinary(const char* filename) {
478 File* file = File::Open(nullptr, filename, File::kRead);
479 if (file == nullptr) {
480 return false;
481 }
482 RefCntReleaseScope<File> rs(file);
483
484 const uint64_t size = file->Length();
485 // Parse the first 4 bytes and check the magic numbers.
486 uint32_t magic;
487 if (size < sizeof(magic)) {
488 // The file isn't long enough to contain the magic bytes.
489 return false;
490 }
491 file->SetPosition(0);
492 file->ReadFully(&magic, sizeof(magic));
493
494 // Depending on the magic numbers, check that the size of the file is
495 // large enough for either a 32-bit or 64-bit header.
496 switch (magic) {
497 case mach_o::MH_MAGIC:
498 case mach_o::MH_CIGAM:
499 return size >= sizeof(mach_o::mach_header);
502 return size >= sizeof(mach_o::mach_header_64);
503 default:
504 // Not a Mach-O formatted file.
505 return false;
506 }
507}
508#endif // defined(DART_TARGET_OS_MACOS)
509
510#if defined(DART_TARGET_OS_WINDOWS)
511bool Snapshot::IsPEFormattedBinary(const char* filename) {
512 File* file = File::Open(nullptr, filename, File::kRead);
513 if (file == nullptr) {
514 return false;
515 }
516 RefCntReleaseScope<File> rs(file);
517
518 // Parse the PE offset.
519 uint32_t pe_offset;
520 // Ensure the file is long enough to contain the PE offset.
521 if (file->Length() <
522 static_cast<intptr_t>(pe::kPEOffsetOffset + sizeof(pe_offset))) {
523 return false;
524 }
525 file->SetPosition(pe::kPEOffsetOffset);
526 file->Read(&pe_offset, sizeof(pe_offset));
527
528 // Ensure the file is long enough to contain the PE magic bytes.
529 if (file->Length() <
530 static_cast<intptr_t>(pe_offset + sizeof(pe::kPEMagic))) {
531 return false;
532 }
533 // Check the magic bytes.
534 file->SetPosition(pe_offset);
535 for (size_t i = 0; i < sizeof(pe::kPEMagic); i++) {
536 char c;
537 file->Read(&c, sizeof(c));
538 if (c != pe::kPEMagic[i]) {
539 return false;
540 }
541 }
542
543 // Check that there is a coff optional header.
544 pe::coff_file_header file_header;
545 pe::coff_optional_header opt_header;
546 file->Read(&file_header, sizeof(file_header));
547 if (file_header.optional_header_size < sizeof(opt_header)) {
548 return false;
549 }
550 file->Read(&opt_header, sizeof(opt_header));
551 // Check the magic bytes in the coff optional header.
552 if (opt_header.magic != pe::kPE32Magic &&
553 opt_header.magic != pe::kPE32PlusMagic) {
554 return false;
555 }
556
557 return true;
558}
559#endif // defined(DART_TARGET_OS_WINDOWS)
560
562 bool force_load_elf_from_memory,
563 bool decode_uri) {
564 CStringUniquePtr decoded_path(nullptr);
565 const char* script_name = nullptr;
566 if (decode_uri) {
567 decoded_path = File::UriToPath(script_uri);
568 if (decoded_path == nullptr) {
569 return nullptr;
570 }
571 script_name = decoded_path.get();
572 } else {
573 script_name = script_uri;
574 }
575 if (File::GetType(nullptr, script_name, true) != File::kIsFile) {
576 // If 'script_name' refers to a pipe, don't read to check for an app
577 // snapshot since we cannot rewind if it isn't (and couldn't mmap it in
578 // anyway if it was).
579 return nullptr;
580 }
581 File* file = File::Open(nullptr, script_name, File::kRead);
582 if (file == nullptr) {
583 return nullptr;
584 }
586 if ((file->Length() - file->Position()) < DartUtils::kMaxMagicNumberSize) {
587 return nullptr;
588 }
589
592 if (!file->ReadFully(&header, DartUtils::kMaxMagicNumberSize)) {
593 return nullptr;
594 }
595 DartUtils::MagicNumber magic_number =
597 if (magic_number == DartUtils::kAppJITMagicNumber) {
598 // Return the JIT snapshot.
599 return TryReadAppSnapshotBlobs(script_name, file);
600 }
601#if defined(DART_PRECOMPILED_RUNTIME)
602 if (!DartUtils::IsAotMagicNumber(magic_number)) {
603 return nullptr;
604 }
605
606 // For testing AOT with the standalone embedder, we also support loading
607 // from a dynamic library to simulate what happens on iOS.
608
609#if defined(DART_TARGET_OS_LINUX) || defined(DART_TARGET_OS_MACOS)
610 // On Linux and OSX, resolve the script path before passing into dlopen()
611 // since dlopen will not search the filesystem for paths like 'libtest.so'.
612 CStringUniquePtr absolute_path(realpath(script_name, nullptr));
613 script_name = absolute_path.get();
614#endif
615
616 AppSnapshot* snapshot = nullptr;
617 if (!force_load_elf_from_memory) {
618 snapshot = TryReadAppSnapshotDynamicLibrary(script_name);
619 if (snapshot != nullptr) {
620 return snapshot;
621 }
622 }
623 return TryReadAppSnapshotElf(script_name, /*file_offset=*/0,
624 force_load_elf_from_memory);
625#else
626 // We create a dummy snapshot object just to remember the type which
627 // has already been identified by sniffing the magic number.
628 return new DummySnapshot(magic_number);
629#endif // defined(DART_PRECOMPILED_RUNTIME)
630
631 return nullptr;
632}
633
634#if !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) && !defined(TESTING)
635static void WriteSnapshotFile(const char* filename,
636 const uint8_t* buffer,
637 const intptr_t size) {
638 File* file = File::Open(nullptr, filename, File::kWriteTruncate);
639 if (file == nullptr) {
640 ErrorExit(kErrorExitCode, "Unable to open file %s for writing snapshot\n",
641 filename);
642 }
643
644 if (!file->WriteFully(buffer, size)) {
645 ErrorExit(kErrorExitCode, "Unable to write file %s for writing snapshot\n",
646 filename);
647 }
648 file->Release();
649}
650#endif
651
652static bool WriteInt64(File* file, int64_t size) {
653 return file->WriteFully(&size, sizeof(size));
654}
655
656void Snapshot::WriteAppSnapshot(const char* filename,
657 uint8_t* isolate_data_buffer,
658 intptr_t isolate_data_size,
659 uint8_t* isolate_instructions_buffer,
660 intptr_t isolate_instructions_size) {
661 File* file = File::Open(nullptr, filename, File::kWriteTruncate);
662 if (file == nullptr) {
663 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
664 }
665
667 WriteInt64(file, isolate_data_size);
668 WriteInt64(file, isolate_instructions_size);
669 ASSERT(file->Position() ==
671
672 file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
674 Syslog::PrintErr("%" Px64 ": Isolate Data\n", file->Position());
675 }
676 if (!file->WriteFully(isolate_data_buffer, isolate_data_size)) {
677 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
678 }
679
680 if (isolate_instructions_size != 0) {
681 file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
683 Syslog::PrintErr("%" Px64 ": Isolate Instructions\n", file->Position());
684 }
685 if (!file->WriteFully(isolate_instructions_buffer,
686 isolate_instructions_size)) {
687 ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n",
688 filename);
689 }
690 }
691
692 file->Flush();
693 file->Release();
694}
695
696void Snapshot::GenerateKernel(const char* snapshot_filename,
697 const char* script_name,
698 const char* package_config) {
699#if !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) && !defined(TESTING)
700 ASSERT(Dart_CurrentIsolate() == nullptr);
701
702 uint8_t* kernel_buffer = nullptr;
703 intptr_t kernel_buffer_size = 0;
704 dfe.ReadScript(script_name, nullptr, &kernel_buffer, &kernel_buffer_size);
705 if (kernel_buffer != nullptr) {
706 WriteSnapshotFile(snapshot_filename, kernel_buffer, kernel_buffer_size);
707 free(kernel_buffer);
708 } else {
710 dfe.CompileScript(script_name, /*incremental*/ false, package_config,
711 /*snapshot=*/true, /*embedd_sources=*/true);
713 Syslog::PrintErr("%s\n", result.error);
715 }
716 WriteSnapshotFile(snapshot_filename, result.kernel, result.kernel_size);
717 free(result.kernel);
718 }
719#else
720 UNREACHABLE();
721#endif // !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) && !defined(TESTING)
722}
723
724void Snapshot::GenerateAppJIT(const char* snapshot_filename) {
725#if defined(TARGET_ARCH_IA32)
726 // Snapshots with code are not supported on IA32.
727 uint8_t* isolate_buffer = nullptr;
728 intptr_t isolate_size = 0;
729
730 Dart_Handle result = Dart_CreateSnapshot(nullptr, nullptr, &isolate_buffer,
731 &isolate_size, /*is_core=*/false);
732 if (Dart_IsError(result)) {
734 }
735
736 WriteAppSnapshot(snapshot_filename, isolate_buffer, isolate_size, nullptr, 0);
737#else
738 uint8_t* isolate_data_buffer = nullptr;
739 intptr_t isolate_data_size = 0;
740 uint8_t* isolate_instructions_buffer = nullptr;
741 intptr_t isolate_instructions_size = 0;
743 &isolate_data_buffer, &isolate_data_size, &isolate_instructions_buffer,
744 &isolate_instructions_size);
745 if (Dart_IsError(result)) {
747 }
748 WriteAppSnapshot(snapshot_filename, isolate_data_buffer, isolate_data_size,
749 isolate_instructions_buffer, isolate_instructions_size);
750#endif
751}
752
753static void StreamingWriteCallback(void* callback_data,
754 const uint8_t* buffer,
755 intptr_t size) {
756 File* file = reinterpret_cast<File*>(callback_data);
757 if (!file->WriteFully(buffer, size)) {
758 ErrorExit(kErrorExitCode, "Unable to write snapshot file\n");
759 }
760}
761
762void Snapshot::GenerateAppAOTAsAssembly(const char* snapshot_filename) {
763 File* file = File::Open(nullptr, snapshot_filename, File::kWriteTruncate);
765 if (file == nullptr) {
766 ErrorExit(kErrorExitCode, "Unable to open file %s for writing snapshot\n",
767 snapshot_filename);
768 }
770 StreamingWriteCallback, file, /*strip=*/false,
771 /*debug_callback_data=*/nullptr);
772 if (Dart_IsError(result)) {
774 }
775}
776
777} // namespace bin
778} // 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:289
static uint64_t LittleEndianToHost64(uint64_t le_value)
Definition: utils.h:521
static constexpr T RoundUp(T x, uintptr_t alignment, uintptr_t offset=0)
Definition: utils.h:120
static void UnloadDynamicLibrary(void *library_handle, char **error=nullptr)
Definition: utils.cc:348
static void * ResolveSymbolInDynamicLibrary(void *library_handle, const char *symbol, char **error=nullptr)
Definition: utils.cc:322
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:403
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 CStringUniquePtr UriToPath(const char *uri)
@ kReadExecute
Definition: file.h:122
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 WriteAppSnapshot(const char *filename, uint8_t *isolate_data_buffer, intptr_t isolate_data_size, uint8_t *isolate_instructions_buffer, intptr_t isolate_instructions_size)
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)
@ Dart_KernelCompilationStatus_Ok
Definition: dart_api.h:3785
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
#define kIsolateSnapshotDataCSymbol
Definition: dart_api.h:3958
#define kIsolateSnapshotInstructionsCSymbol
Definition: dart_api.h:3959
#define kVmSnapshotDataCSymbol
Definition: dart_api.h:3955
#define kVmSnapshotInstructionsCSymbol
Definition: dart_api.h:3956
#define ASSERT(E)
#define FATAL(error)
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
Definition: gen_snapshot.cc:69
MagicNumberData appjit_magic_number
Definition: dartutils.cc:35
static constexpr int64_t kAppSnapshotPageSize
const uint8_t * vm_snapshot_data
Definition: main_impl.cc:52
DFE dfe
Definition: dfe.cc:59
const uint8_t * vm_snapshot_instructions
Definition: main_impl.cc:53
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
Definition: gen_snapshot.cc:70
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
Definition: dart_vm.cc:33
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)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
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
SeparatedVector2 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.
Definition: elf_loader.cc:616
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.
Definition: elf_loader.cc:590
DART_EXPORT void Dart_UnloadELF(Dart_LoadedElf *loaded)
Definition: elf_loader.cc:643