| // Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #ifndef RUNTIME_VM_DWARF_SO_WRITER_H_ |
| #define RUNTIME_VM_DWARF_SO_WRITER_H_ |
| |
| #include "platform/globals.h" |
| |
| #if defined(DART_PRECOMPILER) |
| |
| #include "vm/datastream.h" |
| #include "vm/dwarf.h" |
| #include "vm/so_writer.h" |
| |
| namespace dart { |
| |
| class DwarfSharedObjectStream : public DwarfWriteStream { |
| public: |
| DwarfSharedObjectStream(Zone* zone, NonStreamingWriteStream* stream) |
| : zone_(ASSERT_NOTNULL(zone)), |
| stream_(ASSERT_NOTNULL(stream)), |
| relocations_(new (zone) SharedObjectWriter::RelocationArray()) {} |
| |
| static constexpr intptr_t kInitialBufferSize = 64 * KB; |
| |
| const uint8_t* buffer() const { return stream_->buffer(); } |
| intptr_t bytes_written() const { return stream_->bytes_written(); } |
| intptr_t Position() const { return stream_->Position(); } |
| |
| void sleb128(intptr_t value) override { stream_->WriteSLEB128(value); } |
| void uleb128(uintptr_t value) override { stream_->WriteLEB128(value); } |
| void u1(uint8_t value) override { stream_->WriteByte(value); } |
| void u2(uint16_t value) override { stream_->WriteFixed(value); } |
| void u4(uint32_t value) override { stream_->WriteFixed(value); } |
| void u8(uint64_t value) override { stream_->WriteFixed(value); } |
| void string(const char* cstr) override { // NOLINT |
| // Unlike stream_->WriteString(), we want the null terminator written. |
| stream_->WriteBytes(cstr, strlen(cstr) + 1); |
| } |
| // The prefix is ignored for DwarfSharedObjectStreams. |
| void WritePrefixedLength(const char* unused, |
| std::function<void()> body) override { |
| const intptr_t fixup = stream_->Position(); |
| // We assume DWARF v2 currently, so all sizes are 32-bit. |
| u4(0); |
| // All sizes for DWARF sections measure the size of the section data _after_ |
| // the size value. |
| const intptr_t start = stream_->Position(); |
| body(); |
| const intptr_t end = stream_->Position(); |
| stream_->SetPosition(fixup); |
| u4(end - start); |
| stream_->SetPosition(end); |
| } |
| // Shorthand for when working directly with DwarfSharedObjectStreams. |
| void WritePrefixedLength(std::function<void()> body) { |
| WritePrefixedLength(nullptr, body); |
| } |
| |
| void OffsetFromSymbol(intptr_t label, |
| intptr_t offset, |
| size_t size = kAddressSize) override { |
| ASSERT(size > 0); |
| ASSERT(size <= static_cast<size_t>(kInt64Size)); |
| relocations_->Add({size, stream_->Position(), |
| SharedObjectWriter::Relocation::kSnapshotRelative, 0, |
| label, offset}); |
| const uint64_t placeholder = 0; // Resolved later. |
| stream_->WriteBytes(&placeholder, size); |
| } |
| void InitializeAbstractOrigins(intptr_t size) override { |
| abstract_origins_size_ = size; |
| abstract_origins_ = zone_->Alloc<uint32_t>(abstract_origins_size_); |
| } |
| void RegisterAbstractOrigin(intptr_t index) override { |
| ASSERT(abstract_origins_ != nullptr); |
| ASSERT(index < abstract_origins_size_); |
| abstract_origins_[index] = stream_->Position(); |
| } |
| void AbstractOrigin(intptr_t index) override { u4(abstract_origins_[index]); } |
| |
| // Generates the offset of the virtual address corresponding to the given |
| // symbol label from the current position in the output. That is, if |
| // X = the virtual address of the current position |
| // Y = the virtual address of the symbol |
| // then the value at the current position in the output is Y - X. |
| // |
| // If no size is provided, the size of the offset in the stream is |
| // the native word size. |
| void RelativeSymbolOffset(intptr_t label, size_t size = kAddressSize) { |
| relocations_->Add({size, stream_->Position(), |
| SharedObjectWriter::Relocation::kSelfRelative, 0, label, |
| 0}); |
| const uint64_t placeholder = 0; // Resolved later. |
| stream_->WriteBytes(&placeholder, size); |
| } |
| |
| intptr_t Align(intptr_t alignment, intptr_t offset = 0) { |
| return stream_->Align(alignment, offset); |
| } |
| |
| const SharedObjectWriter::RelocationArray* relocations() const { |
| return relocations_; |
| } |
| |
| protected: |
| Zone* const zone_; |
| NonStreamingWriteStream* const stream_; |
| SharedObjectWriter::RelocationArray* const relocations_ = nullptr; |
| uint32_t* abstract_origins_ = nullptr; |
| intptr_t abstract_origins_size_ = -1; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(DwarfSharedObjectStream); |
| }; |
| |
| } // namespace dart |
| |
| #endif // DART_PRECOMPILER |
| |
| #endif // RUNTIME_VM_DWARF_SO_WRITER_H_ |