Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
image_snapshot.h
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#ifndef RUNTIME_VM_IMAGE_SNAPSHOT_H_
6#define RUNTIME_VM_IMAGE_SNAPSHOT_H_
7
8#include <memory>
9#include <utility>
10
11#include "platform/assert.h"
12#include "platform/utils.h"
13#include "vm/allocation.h"
15#include "vm/datastream.h"
16#include "vm/elf.h"
17#include "vm/globals.h"
18#include "vm/growable_array.h"
19#include "vm/hash_map.h"
20#include "vm/object.h"
21#include "vm/reusable_handles.h"
24
25#if defined(DEBUG)
26#define SNAPSHOT_BACKTRACE
27#endif
28
29namespace dart {
30
31// Forward declarations.
32class BitsContainer;
33class Code;
34class Dwarf;
35class Elf;
36class Instructions;
37class Object;
38
40 public:
41 explicit Image(const void* raw_memory)
42 : Image(reinterpret_cast<uword>(raw_memory)) {}
43 explicit Image(const uword raw_memory)
44 : raw_memory_(raw_memory),
45 snapshot_size_(FieldValue(raw_memory, HeaderField::ImageSize)),
46 extra_info_(ExtraInfo(raw_memory_, snapshot_size_)) {
48 }
49
50 // Even though an Image is read-only memory, we must return a void* here.
51 // All objects in an Image are pre-marked, though, so the GC will not attempt
52 // to change the returned memory.
53 void* object_start() const {
54 return reinterpret_cast<void*>(raw_memory_ + kHeaderSize);
55 }
56
57 uword object_size() const { return snapshot_size_ - kHeaderSize; }
58
59 bool contains(uword address) const {
60 uword start = reinterpret_cast<uword>(object_start());
61 return address >= start && (address - start < object_size());
62 }
63
64 // Returns the address of the BSS section, or nullptr if one is not available.
65 // Only has meaning for instructions images from precompiled snapshots.
66 uword* bss() const;
67
68 // Returns the relocated address of the isolate's instructions, or 0 if
69 // one is not available. Only has meaning for instructions images from
70 // precompiled snapshots.
72
73 // Returns the GNU build ID, or nullptr if not available. See
74 // build_id_length() for the length of the returned buffer. Only has meaning
75 // for instructions images from precompiled snapshots.
76 const uint8_t* build_id() const;
77
78 // Returns the length of the GNU build ID returned by build_id(). Only has
79 // meaning for instructions images from precompiled snapshots.
80 intptr_t build_id_length() const;
81
82 // Returns whether this instructions section was compiled to ELF. Only has
83 // meaning for instructions images from precompiled snapshots.
84 bool compiled_to_elf() const;
85
86 private:
87 // Word-sized fields in an Image object header.
88 enum class HeaderField : intptr_t {
89 // The size of the image (total of header and payload).
90 ImageSize,
91 // The offset of the InstructionsSection object in the image. Note this
92 // offset is from the start of the _image_, _not_ from its payload start,
93 // so we can detect images without an InstructionsSection by a 0 value here.
94 InstructionsSectionOffset,
95 // If adding more fields, updating kHeaderFields below. (However, more
96 // fields _can't_ be added on 64-bit architectures, see the restrictions
97 // on kHeaderSize below.)
98 };
99
100 // Number of fields described by the HeaderField enum.
101 static constexpr intptr_t kHeaderFields =
102 static_cast<intptr_t>(HeaderField::InstructionsSectionOffset) + 1;
103
104 static uword FieldValue(uword raw_memory, HeaderField field) {
105 return reinterpret_cast<const uword*>(
106 raw_memory)[static_cast<intptr_t>(field)];
107 }
108
109 // Constants used to denote special values for the offsets in the Image
110 // object header and the fields of the InstructionsSection object.
111 static constexpr intptr_t kNoInstructionsSection = 0;
112 static constexpr intptr_t kNoBssSection = 0;
113 static constexpr intptr_t kNoRelocatedAddress = 0;
114 static constexpr intptr_t kNoBuildId = 0;
115
116 // The size of the Image object header.
117 //
118 // Note: Image::kHeaderSize is _not_ an architecture-dependent constant,
119 // and so there is no compiler::target::Image::kHeaderSize.
120 static constexpr intptr_t kHeaderSize = kObjectStartAlignment;
121 // Explicitly double-checking kHeaderSize is never changed. Increasing the
122 // Image header size would mean objects would not start at a place expected
123 // by parts of the VM (like the GC) that use Image pages as Pages.
124 static_assert(kHeaderSize == kObjectStartAlignment,
125 "Image page cannot be used as Page");
126 // Make sure that the number of fields in the Image header fit both on the
127 // host and target architectures.
128 static_assert(kHeaderFields * kWordSize <= kHeaderSize,
129 "Too many fields in Image header for host architecture");
130 static_assert(kHeaderFields * compiler::target::kWordSize <= kHeaderSize,
131 "Too many fields in Image header for target architecture");
132
133 // We don't use a handle or the tagged pointer because this object cannot be
134 // moved in memory by the GC.
135 static const UntaggedInstructionsSection* ExtraInfo(const uword raw_memory,
136 const uword size);
137
138 // Most internal uses would cast this to uword, so just store it as such.
139 const uword raw_memory_;
140 const intptr_t snapshot_size_;
141 const UntaggedInstructionsSection* const extra_info_;
142
143 // For access to private constants.
145 friend class BitsContainer;
146 friend class BlobImageWriter;
147 friend class ImageWriter;
148
150};
151
153 public:
154 ImageReader(const uint8_t* data_image, const uint8_t* instructions_image);
155
156 ApiErrorPtr VerifyAlignment() const;
157
158 ONLY_IN_PRECOMPILED(uword GetBareInstructionsAt(uint32_t offset) const);
159 ONLY_IN_PRECOMPILED(uword GetBareInstructionsEnd() const);
160 InstructionsPtr GetInstructionsAt(uint32_t offset) const;
161 ObjectPtr GetObjectAt(uint32_t offset) const;
162
163 private:
164 const uint8_t* data_image_;
165 const uint8_t* instructions_image_;
166
168};
169
171 public:
173 ObjectOffsetPair(ObjectPtr obj, int32_t off) : object(obj), offset(off) {}
174
176 int32_t offset;
177};
178
180 public:
181 // Typedefs needed for the DirectChainedHashMap template.
182 typedef ObjectPtr Key;
183 typedef int32_t Value;
185
186 static Key KeyOf(Pair kv) { return kv.object; }
187 static Value ValueOf(Pair kv) { return kv.offset; }
188 static uword Hash(Key key);
189 static inline bool IsKeyEqual(Pair pair, Key key);
190};
191
193
194// A command which instructs the image writer to emit something into the ".text"
195// segment.
196//
197// For now this supports
198//
199// * emitting the instructions of a [Code] object
200// * emitting a trampoline of a certain size
201// * emitting a padding of a certain size
202//
209
214
216 uint8_t* trampoline_bytes,
217 intptr_t trampoline_length)
220 insert_trampoline_bytes({trampoline_bytes, trampoline_length}) {}
221
226
227 // The offset (relative to the very first [ImageWriterCommand]) we expect
228 // this [ImageWriterCommand] to have.
230
232 union {
233 struct {
234 CodePtr code;
236 struct {
237 uint8_t* buffer;
240
241 struct {
244 };
245};
246
247#if defined(DART_PRECOMPILER)
248template <typename T>
249class Trie : public ZoneAllocated {
250 public:
251 // Returns whether [key] is a valid trie key (that is, a C string that
252 // contains only characters for which charIndex returns a non-negative value).
253 static bool IsValidKey(const char* key) {
254 for (intptr_t i = 0; key[i] != '\0'; i++) {
255 if (ChildIndex(key[i]) < 0) return false;
256 }
257 return true;
258 }
259
260 // Adds a binding of [key] to [value] in [trie]. Assumes that the string in
261 // [key] is a valid trie key and does not already have a value in [trie].
262 //
263 // If [trie] is nullptr, then a new trie is created and a pointer to the new
264 // trie is returned. Otherwise, [trie] will be returned.
265 static Trie<T>* AddString(Zone* zone,
266 Trie<T>* trie,
267 const char* key,
268 const T* value);
269
270 // Adds a binding of [key] to [value]. Assumes that the string in [key] is a
271 // valid trie key and does not already have a value in this trie.
272 void AddString(Zone* zone, const char* key, const T* value) {
273 AddString(zone, this, key, value);
274 }
275
276 // Looks up the value stored for [key] in [trie]. If one is not found, then
277 // nullptr is returned.
278 //
279 // If [end] is not nullptr, then the longest prefix of [key] that is a valid
280 // trie key prefix will be used for the lookup and the value pointed to by
281 // [end] is set to the index after that prefix. Otherwise, the whole [key]
282 // is used.
283 static const T* Lookup(const Trie<T>* trie,
284 const char* key,
285 intptr_t* end = nullptr);
286
287 // Looks up the value stored for [key]. If one is not found, then nullptr is
288 // returned.
289 //
290 // If [end] is not nullptr, then the longest prefix of [key] that is a valid
291 // trie key prefix will be used for the lookup and the value pointed to by
292 // [end] is set to the index after that prefix. Otherwise, the whole [key]
293 // is used.
294 const T* Lookup(const char* key, intptr_t* end = nullptr) const {
295 return Lookup(this, key, end);
296 }
297
298 private:
299 // Currently, only the following characters can appear in obfuscated names:
300 // '_', '@', '0-9', 'a-z', 'A-Z'
301 static constexpr intptr_t kNumValidChars = 64;
302
303 Trie() {
304 for (intptr_t i = 0; i < kNumValidChars; i++) {
305 children_[i] = nullptr;
306 }
307 }
308
309 static intptr_t ChildIndex(char c) {
310 if (c == '_') return 0;
311 if (c == '@') return 1;
312 if (c >= '0' && c <= '9') return ('9' - c) + 2;
313 if (c >= 'a' && c <= 'z') return ('z' - c) + 12;
314 if (c >= 'A' && c <= 'Z') return ('Z' - c) + 38;
315 return -1;
316 }
317
318 const T* value_ = nullptr;
319 Trie<T>* children_[kNumValidChars];
320};
321
322template <typename T>
323Trie<T>* Trie<T>::AddString(Zone* zone,
324 Trie<T>* trie,
325 const char* key,
326 const T* value) {
327 ASSERT(key != nullptr);
328 if (trie == nullptr) {
329 trie = new (zone) Trie<T>();
330 }
331 if (*key == '\0') {
332 ASSERT(trie->value_ == nullptr);
333 trie->value_ = value;
334 } else {
335 auto const index = ChildIndex(*key);
336 ASSERT(index >= 0 && index < kNumValidChars);
337 trie->children_[index] =
338 AddString(zone, trie->children_[index], key + 1, value);
339 }
340
341 return trie;
342}
343
344template <typename T>
345const T* Trie<T>::Lookup(const Trie<T>* trie, const char* key, intptr_t* end) {
346 intptr_t i = 0;
347 for (; key[i] != '\0'; i++) {
348 auto const index = ChildIndex(key[i]);
349 ASSERT(index < kNumValidChars);
350 if (index < 0) {
351 if (end == nullptr) return nullptr;
352 break;
353 }
354 // Still find the longest valid trie prefix when no stored value.
355 if (trie == nullptr) continue;
356 trie = trie->children_[index];
357 }
358 if (end != nullptr) {
359 *end = i;
360 }
361 if (trie == nullptr) return nullptr;
362 return trie->value_;
363}
364#endif
365
366class ImageWriter : public ValueObject {
367 public:
368#if defined(DART_PRECOMPILER)
369 ImageWriter(Thread* thread,
370 bool generates_assembly,
371 const Trie<const char>* deobfuscation_trie = nullptr);
372#else
373 ImageWriter(Thread* thread, bool generates_assembly);
374#endif
375 virtual ~ImageWriter() {}
376
377 // Alignment constants used in writing ELF or assembly snapshots.
378
379 // BSS sections contain word-sized data.
380 static constexpr intptr_t kBssAlignment = compiler::target::kWordSize;
381 // ROData sections contain objects wrapped in an Image object.
382 static constexpr intptr_t kRODataAlignment = kObjectStartAlignment;
383 // Text sections contain objects (even in bare instructions mode) wrapped
384 // in an Image object.
385 static constexpr intptr_t kTextAlignment = kObjectStartAlignment;
386
388 next_data_offset_ = Image::kHeaderSize;
389 next_text_offset_ = Image::kHeaderSize;
390#if defined(DART_PRECOMPILER)
391 if (FLAG_precompiled_mode) {
392 // We reserve space for the initial InstructionsSection object. It is
393 // manually serialized since it includes offsets to other snapshot parts.
394 // It contains all the payloads which start directly after the header.
395 next_text_offset_ += compiler::target::InstructionsSection::HeaderSize();
396 }
397#endif
398 objects_.Clear();
399 instructions_.Clear();
400 }
401
402 // Will start preparing the ".text" segment by interpreting the provided
403 // [ImageWriterCommand]s.
405
412 int32_t GetTextOffsetFor(InstructionsPtr instructions, CodePtr code);
413#if defined(SNAPSHOT_BACKTRACE)
414 uint32_t GetDataOffsetFor(ObjectPtr raw_object, ObjectPtr raw_parent);
415#else
416 uint32_t GetDataOffsetFor(ObjectPtr raw_object);
417#endif
418
419 uint32_t AddBytesToData(uint8_t* bytes, intptr_t length);
420
421 void Write(NonStreamingWriteStream* clustered_stream, bool vm);
422 intptr_t data_size() const { return next_data_offset_; }
423 intptr_t text_size() const { return next_text_offset_; }
424 intptr_t GetTextObjectCount() const;
425 void GetTrampolineInfo(intptr_t* count, intptr_t* size) const;
426
428
430 profile_writer_ = profile_writer;
431 }
432
434
435 void TraceInstructions(const Instructions& instructions);
436
437 static intptr_t SizeInSnapshot(ObjectPtr object);
438 static intptr_t SizeInSnapshot(const Object& object) {
439 return SizeInSnapshot(object.ptr());
440 }
441
442 // Returns nullptr if there is no profile writer.
443 const char* ObjectTypeForProfile(const Object& object) const;
444 static const char* TagObjectTypeAsReadOnly(Zone* zone, const char* type);
445
446 enum class ProgramSection {
447 Text, // Instructions.
448 Data, // Read-only data.
449 Bss, // Statically allocated variables initialized at load.
450 BuildId, // GNU build ID (when applicable)
451 // Adjust kNumProgramSections below to use last enum value added.
452 };
453
454 static constexpr intptr_t kNumProgramSections =
455 static_cast<int>(ProgramSection::BuildId) + 1;
456
457#if defined(DART_PRECOMPILER)
458 // Returns a predetermined label for the given section in the VM isolate
459 // (if vm is true) or application isolate (otherwise) section. Some sections
460 // are shared by both.
461 static constexpr intptr_t SectionLabel(ProgramSection section, bool vm) {
462 // Both vm and isolate share the build id section.
463 const bool shared = section == ProgramSection::BuildId;
464 // The initial 1 is to ensure the result is positive.
465 return 1 + 2 * static_cast<int>(section) + ((shared || vm) ? 0 : 1);
466 }
467
468 static Trie<const char>* CreateReverseObfuscationTrie(Thread* thread);
469 static const char* Deobfuscate(Zone* zone,
470 const Trie<const char>* trie,
471 const char* str);
472#endif
473
474 protected:
475 virtual void WriteBss(bool vm) = 0;
476 virtual void WriteROData(NonStreamingWriteStream* clustered_stream, bool vm);
477 void WriteText(bool vm);
478
479 // Returns the standard Dart dynamic symbol name for the given VM isolate (if
480 // vm is true) or application isolate (otherwise) section. Some sections are
481 // shared by both.
482 static const char* SectionSymbol(ProgramSection section, bool vm);
483
485 intptr_t size,
486 bool is_canonical = false);
487 static uword GetMarkedTags(const Object& obj);
488
491
493 InstructionsData(InstructionsPtr insns, CodePtr code, intptr_t text_offset)
494 : raw_insns_(insns),
495 raw_code_(code),
496 text_offset_(text_offset),
497 trampoline_bytes(nullptr),
499
501 intptr_t trampoline_length,
502 intptr_t text_offset)
503 : raw_insns_(nullptr),
504 raw_code_(nullptr),
505 text_offset_(text_offset),
508
509 union {
510 InstructionsPtr raw_insns_;
512 };
513 union {
514 CodePtr raw_code_;
515 const Code* code_;
516 };
517 intptr_t text_offset_;
518
521 };
522
523 struct ObjectData {
524#if defined(SNAPSHOT_BACKTRACE)
525 explicit ObjectData(ObjectPtr raw_obj, ObjectPtr raw_parent)
526 : raw_obj(raw_obj),
527 raw_parent(raw_parent),
530 ObjectData(uint8_t* buf, intptr_t length)
531 : bytes({buf, length}),
532 raw_parent(Object::null()),
535#else
540 ObjectData(uint8_t* buf, intptr_t length)
541 : bytes({buf, length}),
544#endif
545
546 union {
547 struct {
548 uint8_t* buf;
549 intptr_t length;
552 const Object* obj;
553 };
554#if defined(SNAPSHOT_BACKTRACE)
555 union {
556 ObjectPtr raw_parent;
557 const Object* parent;
558 };
559#endif
560 uint8_t flags;
561
562 bool is_object() const { return IsObjectField::decode(flags); }
563 bool is_original_object() const {
565 }
566
567 void set_is_object(bool value) {
569 }
570
574 };
575
576 // Methods abstracting out the particulars of the underlying concrete writer.
577
578 // Marks the entrance into a particular ProgramSection for either the VM
579 // isolate (if vm is true) or application isolate (if not). Returns false if
580 // this section should not be written.
582 bool vm,
583 intptr_t alignment,
584 intptr_t* alignment_padding = nullptr) = 0;
585 // Marks the exit from a particular ProgramSection, allowing subclasses to
586 // do any post-writing work.
587 virtual void ExitSection(ProgramSection name, bool vm, intptr_t size) = 0;
588 // Writes a prologue to the text section that describes how to interpret
589 // Dart stack frames using DWARF's Call Frame Information (CFI).
590 virtual void FrameUnwindPrologue() = 0;
591 // Writes an epilogue to the text section that marks the end of instructions
592 // covered by the CFI information in the prologue.
593 virtual void FrameUnwindEpilogue() = 0;
594 // Writes a target uword-sized value to the section contents.
595 virtual intptr_t WriteTargetWord(word value) = 0;
596 // Writes a sequence of bytes of length [size] from address [bytes] to the
597 // section contents.
598 virtual intptr_t WriteBytes(const void* bytes, intptr_t size) = 0;
599 // Pads the section contents to a given alignment with zeroes.
600 virtual intptr_t Align(intptr_t alignment,
601 intptr_t offset,
602 intptr_t position) = 0;
603#if defined(DART_PRECOMPILER)
604 // Writes a target word-sized value that depends on the final relocated
605 // addresses of the sections named by the two symbols. If T is the final
606 // relocated address of the target section and S is the final relocated
607 // address of the source, the final value is:
608 // (T + target_offset + target_addend) - (S + source_offset)
609 virtual intptr_t Relocation(intptr_t section_offset,
610 intptr_t source_label,
611 intptr_t source_offset,
612 intptr_t target_label,
613 intptr_t target_offset) = 0;
614 // Writes a target word-sized value that contains the relocated address
615 // pointed to by the given symbol.
616 virtual intptr_t RelocatedAddress(intptr_t section_offset,
617 intptr_t label) = 0;
618 // Creates a static symbol for the given Code object when appropriate.
619 virtual void AddCodeSymbol(const Code& code,
620 const char* symbol,
621 intptr_t section_offset) = 0;
622 // Creates a static symbol for a read-only data object when appropriate.
623 virtual void AddDataSymbol(const char* symbol,
624 intptr_t section_offset,
625 size_t size) = 0;
626
627 // Overloaded convenience versions of the above virtual methods.
628
629 // An overload of Relocation where the target and source offsets and
630 // target addend are 0.
631 intptr_t Relocation(intptr_t section_offset,
632 intptr_t source_label,
633 intptr_t target_label) {
634 return Relocation(section_offset, source_label, 0, target_label, 0);
635 }
636#endif
637 // Writes a fixed-sized value of type T to the section contents.
638 template <typename T>
639 intptr_t WriteFixed(T value) {
640 return WriteBytes(&value, sizeof(value));
641 }
642 // Like Align, but instead of padding with zeroes, the appropriate break
643 // instruction for the target architecture is used.
644 intptr_t AlignWithBreakInstructions(intptr_t alignment, intptr_t offset);
645
647 Zone* const zone_;
652
653#if defined(DART_PRECOMPILER)
654 class SnapshotTextObjectNamer : ValueObject {
655 public:
656 explicit SnapshotTextObjectNamer(Zone* zone,
657 const Trie<const char>* deobfuscation_trie,
658 bool for_assembly)
659 : zone_(ASSERT_NOTNULL(zone)),
660 deobfuscation_trie_(deobfuscation_trie),
661 lib_(Library::Handle(zone)),
662 cls_(Class::Handle(zone)),
663 parent_(Function::Handle(zone)),
664 owner_(Object::Handle(zone)),
665 string_(String::Handle(zone)),
666 insns_(Instructions::Handle(zone)),
667 store_(IsolateGroup::Current()->object_store()),
668 for_assembly_(for_assembly),
669 usage_count_(zone) {}
670
671 const char* StubNameForType(const AbstractType& type) const;
672
673 // Returns a unique name for text data to use in symbols. The name is
674 // not assembly-safe and must be appropriately quoted in assembly output.
675 // Assumes that code in the InstructionsData has been allocated a handle.
676 const char* SnapshotNameFor(const InstructionsData& data);
677 // Returns a unique name for read-only data to use in symbols. The name is
678 // not assembly-safe and must be appropriately quoted in assembly output.
679 // Assumes that the ObjectData has already been converted to object handles.
680 const char* SnapshotNameFor(const ObjectData& data);
681
682 private:
683 // Returns a unique name for the given code or read-only data object for use
684 // in symbols. The name is not assembly-safe and must be appropriately
685 // quoted in assembly output.
686 const char* SnapshotNameFor(const Object& object);
687 // Adds a non-unique name for the given object to the given buffer.
688 void AddNonUniqueNameFor(BaseTextBuffer* buffer, const Object& object);
689 // Modifies the symbol name in the buffer as needed for assembly use.
690 void ModifyForAssembly(BaseTextBuffer* buffer);
691
692 Zone* const zone_;
693 const Trie<const char>* const deobfuscation_trie_;
694 Library& lib_;
695 Class& cls_;
696 Function& parent_;
697 Object& owner_;
698 String& string_;
699 Instructions& insns_;
700 ObjectStore* const store_;
701 // Used to decide whether we need to add a uniqueness suffix.
702 bool for_assembly_;
703 CStringIntMap usage_count_;
704
705 DISALLOW_COPY_AND_ASSIGN(SnapshotTextObjectNamer);
706 };
707
708 SnapshotTextObjectNamer namer_;
709
710 // Reserve two positive labels for each of the ProgramSection values (one for
711 // vm, one for isolate).
712 intptr_t next_label_ = 1 + 2 * kNumProgramSections;
713#endif
714
717 const char* const image_type_;
718 const char* const instructions_section_type_;
719 const char* const instructions_type_;
720 const char* const trampoline_type_;
721 const char* const padding_type_;
722
723 template <class T>
725
726 private:
727 static intptr_t SizeInSnapshotForBytes(intptr_t length);
728
730};
731
732#if defined(DART_PRECOMPILER)
733static_assert(ImageWriter::SectionLabel(ImageWriter::ProgramSection::Bss,
734 /*vm=*/true) == Elf::kVmBssLabel,
735 "unexpected label for VM BSS section");
736static_assert(ImageWriter::SectionLabel(ImageWriter::ProgramSection::Bss,
737 /*vm=*/false) == Elf::kIsolateBssLabel,
738 "unexpected label for isolate BSS section");
739static_assert(ImageWriter::SectionLabel(ImageWriter::ProgramSection::BuildId,
740 /*vm=*/true) == Elf::kBuildIdLabel,
741 "unexpected label for build id section");
742static_assert(ImageWriter::SectionLabel(ImageWriter::ProgramSection::BuildId,
743 /*vm=*/false) == Elf::kBuildIdLabel,
744 "unexpected label for build id section");
745
746#define AutoTraceImage(object, section_offset, stream) \
747 TraceImageObjectScope<std::remove_pointer<decltype(stream)>::type> \
748 AutoTraceImageObjectScopeVar##__COUNTER__(this, section_offset, stream, \
749 object);
750
751template <typename T>
752class TraceImageObjectScope : ValueObject {
753 public:
754 TraceImageObjectScope(ImageWriter* writer,
755 intptr_t section_offset,
756 const T* stream,
757 const Object& object)
758 : writer_(ASSERT_NOTNULL(writer)),
759 stream_(ASSERT_NOTNULL(stream)),
760 section_offset_(section_offset),
761 start_offset_(stream_->Position() - section_offset),
762 object_type_(writer->ObjectTypeForProfile(object)),
763 object_name_(object.IsString() ? object.ToCString() : nullptr) {}
764
765 ~TraceImageObjectScope() {
766 if (writer_->profile_writer_ == nullptr) return;
767 ASSERT(writer_->IsROSpace());
768 writer_->profile_writer_->SetObjectTypeAndName(
769 {writer_->offset_space_, start_offset_}, object_type_, object_name_);
770 writer_->profile_writer_->AttributeBytesTo(
771 {writer_->offset_space_, start_offset_},
772 stream_->Position() - section_offset_ - start_offset_);
773 }
774
775 private:
776 ImageWriter* const writer_;
777 const T* const stream_;
778 const intptr_t section_offset_;
779 const intptr_t start_offset_;
780 const char* const object_type_;
781 const char* const object_name_;
782
783 DISALLOW_COPY_AND_ASSIGN(TraceImageObjectScope);
784};
785
786class AssemblyImageWriter : public ImageWriter {
787 public:
788 AssemblyImageWriter(Thread* thread,
789 BaseWriteStream* stream,
790 const Trie<const char>* deobfuscation_trie = nullptr,
791 bool strip = false,
792 Elf* debug_elf = nullptr);
793 void Finalize();
794
795 private:
796 virtual void WriteBss(bool vm);
797 virtual void WriteROData(NonStreamingWriteStream* clustered_stream, bool vm);
798
799 virtual bool EnterSection(ProgramSection section,
800 bool vm,
801 intptr_t alignment,
802 intptr_t* alignment_padding = nullptr);
803 virtual void ExitSection(ProgramSection name, bool vm, intptr_t size);
804 virtual intptr_t WriteTargetWord(word value);
805 virtual intptr_t WriteBytes(const void* bytes, intptr_t size);
806 virtual intptr_t Align(intptr_t alignment,
807 intptr_t offset,
808 intptr_t position);
809 virtual intptr_t Relocation(intptr_t section_offset,
810 intptr_t source_label,
811 intptr_t source_offset,
812 intptr_t target_label,
813 intptr_t target_offset);
814 virtual intptr_t RelocatedAddress(intptr_t section_offset, intptr_t label) {
815 // Cannot calculate snapshot-relative addresses in assembly snapshots.
816 return WriteTargetWord(Image::kNoRelocatedAddress);
817 }
818 virtual void FrameUnwindPrologue();
819 virtual void FrameUnwindEpilogue();
820 virtual void AddCodeSymbol(const Code& code,
821 const char* symbol,
822 intptr_t offset);
823 virtual void AddDataSymbol(const char* symbol, intptr_t offset, size_t size);
824
825 BaseWriteStream* const assembly_stream_;
826 Dwarf* const assembly_dwarf_;
827 Elf* const debug_elf_;
828
829 // Used in Relocation to output "(.)" for relocations involving the current
830 // section position.
831 intptr_t current_section_label_ = 0;
832
833 // Used for creating local symbols for code and data objects in the
834 // debugging info, if separately written.
835 ZoneGrowableArray<Elf::SymbolData>* current_symbols_ = nullptr;
836
837 // Maps labels to the appropriate symbol names for relocations and DWARF
838 // output.
839 IntMap<const char*> label_to_symbol_name_;
840
841 DISALLOW_COPY_AND_ASSIGN(AssemblyImageWriter);
842};
843#endif
844
846 public:
847#if defined(DART_PRECOMPILER)
848 BlobImageWriter(Thread* thread,
849 NonStreamingWriteStream* vm_instructions,
850 NonStreamingWriteStream* isolate_instructions,
851 const Trie<const char>* deobfuscation_trie = nullptr,
852 Elf* debug_elf = nullptr,
853 Elf* elf = nullptr);
854#else
855 BlobImageWriter(Thread* thread,
856 NonStreamingWriteStream* vm_instructions,
857 NonStreamingWriteStream* isolate_instructions,
858 Elf* debug_elf = nullptr,
859 Elf* elf = nullptr);
860#endif
861
862 private:
863 virtual void WriteBss(bool vm);
864 virtual void WriteROData(NonStreamingWriteStream* clustered_stream, bool vm);
865
866 virtual bool EnterSection(ProgramSection section,
867 bool vm,
868 intptr_t alignment,
869 intptr_t* alignment_padding = nullptr);
870 virtual void ExitSection(ProgramSection name, bool vm, intptr_t size);
871 virtual intptr_t WriteTargetWord(word value);
872 virtual intptr_t WriteBytes(const void* bytes, intptr_t size);
873 virtual intptr_t Align(intptr_t alignment,
874 intptr_t offset,
875 intptr_t position);
876 // TODO(rmacnak): Generate .debug_frame / .eh_frame / .arm.exidx to
877 // provide unwinding information.
878 virtual void FrameUnwindPrologue() {}
879 virtual void FrameUnwindEpilogue() {}
880#if defined(DART_PRECOMPILER)
881 virtual intptr_t Relocation(intptr_t section_offset,
882 intptr_t source_label,
883 intptr_t source_offset,
884 intptr_t target_label,
885 intptr_t target_offset);
886 virtual intptr_t RelocatedAddress(intptr_t section_offset, intptr_t label) {
887 return ImageWriter::Relocation(section_offset,
888 Elf::Relocation::kSnapshotRelative, label);
889 }
890 virtual void AddCodeSymbol(const Code& code,
891 const char* symbol,
892 intptr_t offset);
893 virtual void AddDataSymbol(const char* symbol, intptr_t offset, size_t size);
894
895 // Set on section entrance to a new array containing the relocations for the
896 // current section.
897 ZoneGrowableArray<Elf::Relocation>* current_relocations_ = nullptr;
898 // Set on section entrance to a new array containing the local symbol data
899 // for the current section.
900 ZoneGrowableArray<Elf::SymbolData>* current_symbols_ = nullptr;
901#endif
902
903 NonStreamingWriteStream* const vm_instructions_;
904 NonStreamingWriteStream* const isolate_instructions_;
905 Elf* const elf_;
906 Elf* const debug_elf_;
907
908 // Set on section entrance to the stream that should be used by the writing
909 // methods.
910 NonStreamingWriteStream* current_section_stream_ = nullptr;
911
912 DISALLOW_COPY_AND_ASSIGN(BlobImageWriter);
913};
914
915} // namespace dart
916
917#endif // RUNTIME_VM_IMAGE_SNAPSHOT_H_
Align
int count
TArray< uint32_t > Key
static void encode(uint8_t output[16], const uint32_t input[4])
Definition SkMD5.cpp:240
#define ASSERT_NOTNULL(ptr)
Definition assert.h:323
static constexpr T decode(S value)
Definition bitfield.h:173
static constexpr S update(T value, S original)
Definition bitfield.h:190
static constexpr S encode(T value)
Definition bitfield.h:167
virtual void WriteBss(bool vm)
virtual bool EnterSection(ProgramSection section, bool vm, intptr_t alignment, intptr_t *alignment_padding=nullptr)
virtual void WriteROData(NonStreamingWriteStream *clustered_stream, bool vm)
virtual void ExitSection(ProgramSection name, bool vm, intptr_t size)
virtual void FrameUnwindPrologue()
virtual void FrameUnwindEpilogue()
virtual intptr_t WriteBytes(const void *bytes, intptr_t size)
virtual intptr_t WriteTargetWord(word value)
ObjectPtr GetObjectAt(uint32_t offset) const
InstructionsPtr GetInstructionsAt(uint32_t offset) const
ONLY_IN_PRECOMPILED(uword GetBareInstructionsEnd() const)
ApiErrorPtr VerifyAlignment() const
ONLY_IN_PRECOMPILED(uword GetBareInstructionsAt(uint32_t offset) const)
intptr_t GetTextObjectCount() const
virtual void FrameUnwindEpilogue()=0
static intptr_t SizeInSnapshot(ObjectPtr object)
bool IsROSpace() const
V8SnapshotProfileWriter * profile_writer_
const char *const instructions_type_
intptr_t WriteFixed(T value)
GrowableArray< ObjectData > objects_
static intptr_t SizeInSnapshot(const Object &object)
void TraceInstructions(const Instructions &instructions)
virtual intptr_t Align(intptr_t alignment, intptr_t offset, intptr_t position)=0
void Write(NonStreamingWriteStream *clustered_stream, bool vm)
GrowableArray< InstructionsData > instructions_
void SetProfileWriter(V8SnapshotProfileWriter *profile_writer)
void DumpInstructionStats()
static constexpr intptr_t kRODataAlignment
virtual void FrameUnwindPrologue()=0
const char *const padding_type_
static const char * TagObjectTypeAsReadOnly(Zone *zone, const char *type)
intptr_t AlignWithBreakInstructions(intptr_t alignment, intptr_t offset)
intptr_t text_size() const
void DumpInstructionsSizes()
virtual void ExitSection(ProgramSection name, bool vm, intptr_t size)=0
const char *const image_type_
static constexpr intptr_t kTextAlignment
virtual void WriteROData(NonStreamingWriteStream *clustered_stream, bool vm)
const char *const instructions_section_type_
virtual intptr_t WriteBytes(const void *bytes, intptr_t size)=0
static constexpr intptr_t kBssAlignment
static constexpr intptr_t kNumProgramSections
void GetTrampolineInfo(intptr_t *count, intptr_t *size) const
virtual void WriteBss(bool vm)=0
int32_t GetTextOffsetFor(InstructionsPtr instructions, CodePtr code)
const char * ObjectTypeForProfile(const Object &object) const
virtual intptr_t WriteTargetWord(word value)=0
uint32_t GetDataOffsetFor(ObjectPtr raw_object)
intptr_t data_size() const
void PrepareForSerialization(GrowableArray< ImageWriterCommand > *commands)
Thread *const thread_
virtual bool EnterSection(ProgramSection name, bool vm, intptr_t alignment, intptr_t *alignment_padding=nullptr)=0
const char *const trampoline_type_
uint32_t AddBytesToData(uint8_t *bytes, intptr_t length)
static const char * SectionSymbol(ProgramSection section, bool vm)
static uword GetMarkedTags(classid_t cid, intptr_t size, bool is_canonical=false)
friend class TraceImageObjectScope
void WriteText(bool vm)
uword object_size() const
uword * bss() const
bool contains(uword address) const
const uint8_t * build_id() const
friend class AssemblyImageWriter
Image(const uword raw_memory)
intptr_t build_id_length() const
friend class BitsContainer
void * object_start() const
bool compiled_to_elf() const
Image(const void *raw_memory)
uword instructions_relocated_address() const
static bool IsKeyEqual(Pair pair, Key key)
static Key KeyOf(Pair kv)
static uword Hash(Key key)
static Value ValueOf(Pair kv)
static ObjectPtr null()
Definition object.h:433
static constexpr bool IsAligned(T x, uintptr_t alignment, uintptr_t offset=0)
Definition utils.h:77
#define ASSERT(E)
glong glong end
static const uint8_t buffer[]
uint8_t value
const char * name
Definition fuchsia.cc:50
size_t length
static constexpr intptr_t kObjectStartAlignment
const char *const name
int32_t classid_t
Definition globals.h:524
uintptr_t uword
Definition globals.h:501
intptr_t word
Definition globals.h:500
const intptr_t cid
constexpr intptr_t kWordSize
Definition globals.h:509
DirectChainedHashMap< ObjectOffsetTrait > ObjectOffsetMap
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
#define T
Point offset
struct dart::ImageWriterCommand::@153::@155 insert_instruction_of_code
ImageWriterCommand(intptr_t expected_offset, uint8_t *trampoline_bytes, intptr_t trampoline_length)
struct dart::ImageWriterCommand::@153::@157 insert_padding
struct dart::ImageWriterCommand::@153::@156 insert_trampoline_bytes
ImageWriterCommand(intptr_t expected_offset, intptr_t padding_length)
ImageWriterCommand(intptr_t expected_offset, CodePtr code)
InstructionsData(InstructionsPtr insns, CodePtr code, intptr_t text_offset)
InstructionsData(uint8_t *trampoline_bytes, intptr_t trampoline_length, intptr_t text_offset)
ObjectData(uint8_t *buf, intptr_t length)
struct dart::ImageWriter::ObjectData::@162::@164 bytes
ObjectOffsetPair(ObjectPtr obj, int32_t off)