blob: 9e15cd7a75674c5798e245f4b9d47bfa2a36b3c1 [file] [edit]
// Copyright (c) 2026, 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_DEBUG_INFO_STREAM_H_
#define RUNTIME_VM_DEBUG_INFO_STREAM_H_
#include "platform/globals.h"
#if defined(DART_PRECOMPILER)
#include "vm/datastream.h"
#include "vm/debug_info.h"
#include "vm/so_writer.h"
namespace dart {
class DebugInfoStream : public DebugInfoWriteStream {
public:
DebugInfoStream(Zone* zone, NonStreamingWriteStream* stream)
: zone_(ASSERT_NOTNULL(zone)),
stream_(ASSERT_NOTNULL(stream)),
relocations_(new (zone) SharedObjectWriter::RelocationArray()) {}
static constexpr intptr_t kInitialBufferSize = 64 * KB;
uint8_t* buffer() { return stream_->buffer(); }
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 SetPosition(intptr_t value) { stream_->SetPosition(value); }
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 bytes(const void* addr, intptr_t len) { stream_->WriteBytes(addr, len); }
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 binary debug-info streams.
void WritePrefixedLength(const char* unused,
std::function<void()> body) override {
const intptr_t fixup = stream_->Position();
// DWARF v2 sizes and CodeView subsection sizes are both 32-bit here.
u4(0);
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 DebugInfoStreams.
void WritePrefixedLength(std::function<void()> body) {
WritePrefixedLength(nullptr, body);
}
void WritePrefixedLengthU16(std::function<void()> body) {
const intptr_t fixup = stream_->Position();
u2(0);
const intptr_t start = stream_->Position();
body();
const intptr_t end = stream_->Position();
const intptr_t length = end - start;
ASSERT(length <= kMaxUint16);
stream_->SetPosition(fixup);
u2(static_cast<uint16_t>(length));
stream_->SetPosition(end);
}
uint8_t LoadU1(intptr_t offset) const {
ASSERT(offset >= 0);
ASSERT(offset < bytes_written());
return stream_->buffer()[offset];
}
void StoreU1(intptr_t offset, uint8_t value) {
ASSERT(offset >= 0);
ASSERT(offset < bytes_written());
stream_->buffer()[offset] = value;
}
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,
uint8_t fill_byte = 0) {
return stream_->Align(alignment, offset, fill_byte);
}
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(DebugInfoStream);
};
} // namespace dart
#endif // DART_PRECOMPILER
#endif // RUNTIME_VM_DEBUG_INFO_STREAM_H_