[vm] Add build ID to non-symbolic stack traces.

Since we've run out of room for more fields in the Image object header
on 64-bit architectures, the serializer instead creates an ImageHeader
object for precompiled snapshots that is placed at the start of text
segments. The new ImageHeader object contains the following information:

* The offset of the BSS segment from the text segment, previously
  stored in the Image object header.

* The relocated address of the text segment in the dynamic shared
  object. Due to restrictions when generating assembly snapshots, this
  field is only set for ELF snapshots, and so it can also be used to
  detect whether a snapshot was compiled to assembly or ELF.

* The offset of the build ID description field from the text segment.

* The length of the build ID description field.

We replace the BSS offset in the Image object header with the offset of
the ImageHeader object within the text segment, so that we can detect
when a given Image has an ImageHeader object available.

There are no methods available on ImageHeader objects, but instead the
Image itself controls access to the information. In particular, the
relocated address method either returns the relocated address
information from the ImageHeader object or from the initialized BSS
depending on the type of snapshot, so the caller need not do this work.
Also, instead of returning the raw offset to the BSS section and having
the caller turn that into an appropriate pointer, the method for
accessing the BSS segment now returns a pointer to the segment.

Bug: https://github.com/dart-lang/sdk/issues/43274
Cq-Include-Trybots: luci.dart.try:vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-precomp-android-release-arm_x64-try
Change-Id: I15eae4ad0a088260b127f3d07da79374215b7f56
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/163207
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
Tess Strickland
2020-09-22 17:14:44 +00:00
committed by commit-bot@chromium.org
parent 2b1105d2fe
commit d5649fc9f6
22 changed files with 778 additions and 274 deletions
+3 -1
View File
@@ -1257,7 +1257,9 @@ class Dwarf {
final note = sections.single as Note;
if (note.type != constants.buildIdNoteType) return null;
if (note.name != constants.buildIdNoteName) return null;
return note.description.map((i) => i.toRadixString(16)).join();
return note.description
.map((i) => i.toRadixString(16).padLeft(2, '0'))
.join();
}
/// The call information for the given virtual address. There may be
-13
View File
@@ -476,7 +476,6 @@ bool LoadedElf::ReadSections() {
".bss does not have enough space.");
vm_bss_ = reinterpret_cast<uword*>(base_->start() + header.memory_offset);
isolate_bss_ = vm_bss_ + BSS::kVmEntryCount;
// We set applicable BSS entries in ResolveSymbols().
}
}
@@ -504,22 +503,10 @@ bool LoadedElf::ResolveSymbols(const uint8_t** vm_data,
output = vm_data;
} else if (strcmp(name, kVmSnapshotInstructionsAsmSymbol) == 0) {
output = vm_instrs;
if (output != nullptr) {
// Store the value of the symbol in the VM BSS, as it contains the
// address of the VM instructions section relative to the DSO base.
BSS::InitializeBSSEntry(BSS::Relocation::InstructionsRelocatedAddress,
sym.value, vm_bss_);
}
} else if (strcmp(name, kIsolateSnapshotDataAsmSymbol) == 0) {
output = isolate_data;
} else if (strcmp(name, kIsolateSnapshotInstructionsAsmSymbol) == 0) {
output = isolate_instrs;
if (output != nullptr) {
// Store the value of the symbol in the isolate BSS, as it contains the
// address of the isolate instructions section relative to the DSO base.
BSS::InitializeBSSEntry(BSS::Relocation::InstructionsRelocatedAddress,
sym.value, isolate_bss_);
}
}
if (output != nullptr) {
@@ -113,7 +113,15 @@ main(List<String> args) async {
// Check that translating the DWARF stack trace (without internal frames)
// matches the symbolic stack trace.
final dwarf = Dwarf.fromFile(scriptDwarfDebugInfo)!;
assert(dwarf != null);
// Check that build IDs match for traces.
final buildId1 = buildId(dwarfTrace1);
Expect.isFalse(buildId1.isEmpty);
Expect.equals(dwarf.buildId!, buildId1);
final buildId2 = buildId(dwarfTrace2);
Expect.isFalse(buildId2.isEmpty);
Expect.equals(dwarf.buildId!, buildId2);
final translatedDwarfTrace1 = await Stream.fromIterable(dwarfTrace1)
.transform(DwarfStackTraceDecoder(dwarf))
.toList();
@@ -178,6 +186,17 @@ main(List<String> args) async {
});
}
final _buildIdRE = RegExp(r"build_id: '([a-f\d]+)'");
String buildId(Iterable<String> lines) {
for (final line in lines) {
final match = _buildIdRE.firstMatch(line);
if (match != null) {
return match.group(1)!;
}
}
return '';
}
final _symbolicFrameRE = RegExp(r'^#\d+\s+');
Iterable<String> onlySymbolicFrameLines(Iterable<String> lines) {
@@ -113,7 +113,17 @@ main(List<String> args) async {
// Check that translating the DWARF stack trace (without internal frames)
// matches the symbolic stack trace.
final dwarf = Dwarf.fromFile(scriptDwarfDebugInfo);
assert(dwarf != null);
Expect.isNotNull(dwarf);
// Check that build IDs match for traces.
Expect.isNotNull(dwarf.buildId);
final buildId1 = buildId(dwarfTrace1);
Expect.isFalse(buildId1.isEmpty);
Expect.equals(dwarf.buildId, buildId1);
final buildId2 = buildId(dwarfTrace2);
Expect.isFalse(buildId2.isEmpty);
Expect.equals(dwarf.buildId, buildId2);
final translatedDwarfTrace1 = await Stream.fromIterable(dwarfTrace1)
.transform(DwarfStackTraceDecoder(dwarf))
.toList();
@@ -178,6 +188,17 @@ main(List<String> args) async {
});
}
final _buildIdRE = RegExp(r"build_id: '([a-f\d]+)'");
String buildId(Iterable<String> lines) {
for (final line in lines) {
final match = _buildIdRE.firstMatch(line);
if (match != null) {
return match.group(1);
}
}
return '';
}
final _symbolicFrameRE = RegExp(r'^#\d+\s+');
Iterable<String> onlySymbolicFrameLines(Iterable<String> lines) {
+2 -2
View File
@@ -31,8 +31,8 @@ void BSS::Initialize(Thread* current, uword* bss_start, bool vm) {
auto const instructions = reinterpret_cast<uword>(
current->isolate_group()->source()->snapshot_instructions);
uword dso_base;
// For non-natively loaded snapshots, this is instead initialized in
// LoadedElf::ResolveSymbols().
// Needed for assembly snapshots. For ELF snapshots, we set up the relocated
// address information directly in the text segment ImageHeader.
if (NativeSymbolResolver::LookupSharedObject(instructions, &dso_base)) {
InitializeBSSEntry(Relocation::InstructionsRelocatedAddress,
instructions - dso_base, bss_start);
+2 -1
View File
@@ -91,7 +91,8 @@ typedef uint16_t ClassIdTagType;
V(FutureOr) \
V(UserTag) \
V(TransferableTypedData) \
V(WeakSerializationReference)
V(WeakSerializationReference) \
V(ImageHeader)
#define CLASS_LIST_ARRAYS(V) \
V(Array) \
+4 -12
View File
@@ -7217,12 +7217,8 @@ ApiErrorPtr FullSnapshotReader::ReadVMSnapshot() {
// Initialize entries in the VM portion of the BSS segment.
ASSERT(Snapshot::IncludesCode(kind_));
Image image(instructions_image_);
if (image.bss_offset() != 0) {
// The const cast is safe because we're translating from the start of the
// instructions (read-only) to the start of the BSS (read-write).
uword* const bss_start = const_cast<uword*>(reinterpret_cast<const uword*>(
instructions_image_ + image.bss_offset()));
BSS::Initialize(thread_, bss_start, /*vm=*/true);
if (auto const bss = image.bss()) {
BSS::Initialize(thread_, bss, /*vm=*/true);
}
#endif // defined(DART_PRECOMPILED_RUNTIME)
@@ -7353,12 +7349,8 @@ void FullSnapshotReader::InitializeBSS() {
// Initialize entries in the isolate portion of the BSS segment.
ASSERT(Snapshot::IncludesCode(kind_));
Image image(instructions_image_);
if (image.bss_offset() != 0) {
// The const cast is safe because we're translating from the start of the
// instructions (read-only) to the start of the BSS (read-write).
uword* const bss_start = const_cast<uword*>(reinterpret_cast<const uword*>(
instructions_image_ + image.bss_offset()));
BSS::Initialize(thread_, bss_start, /*vm=*/false);
if (auto const bss = image.bss()) {
BSS::Initialize(thread_, bss, /*vm=*/false);
}
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
+8
View File
@@ -800,6 +800,10 @@ word ForwardingCorpse::FakeInstance::InstanceSize() {
return 0;
}
word ImageHeader::InstanceSize() {
return RoundedAllocationSize(UnroundedSize());
}
word Instance::NextFieldOffset() {
return TranslateOffsetInWords(dart::Instance::NextFieldOffset());
}
@@ -808,6 +812,10 @@ word Pointer::NextFieldOffset() {
return TranslateOffsetInWords(dart::Pointer::NextFieldOffset());
}
word ImageHeader::NextFieldOffset() {
return -kWordSize;
}
word WeakSerializationReference::NextFieldOffset() {
return -kWordSize;
}
+7
View File
@@ -1179,6 +1179,13 @@ class Code : public AllStatic {
static word NextFieldOffset();
};
class ImageHeader : public AllStatic {
public:
static word UnroundedSize();
static word InstanceSize();
static word NextFieldOffset();
};
class WeakSerializationReference : public AllStatic {
public:
static word InstanceSize();
@@ -454,6 +454,7 @@ static constexpr dart::compiler::target::word FutureOr_InstanceSize = 8;
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
16;
static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -966,6 +967,7 @@ static constexpr dart::compiler::target::word FutureOr_InstanceSize = 16;
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
32;
static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -1469,6 +1471,7 @@ static constexpr dart::compiler::target::word FutureOr_InstanceSize = 8;
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
16;
static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -1982,6 +1985,7 @@ static constexpr dart::compiler::target::word FutureOr_InstanceSize = 16;
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
32;
static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -2484,6 +2488,7 @@ static constexpr dart::compiler::target::word FutureOr_InstanceSize = 8;
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
16;
static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -2990,6 +2995,7 @@ static constexpr dart::compiler::target::word FutureOr_InstanceSize = 16;
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
32;
static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -3487,6 +3493,7 @@ static constexpr dart::compiler::target::word FutureOr_InstanceSize = 8;
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
16;
static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -3994,6 +4001,7 @@ static constexpr dart::compiler::target::word FutureOr_InstanceSize = 16;
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
32;
static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -4542,6 +4550,8 @@ static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8;
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 16;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
20;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word
@@ -5105,6 +5115,8 @@ static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
40;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
@@ -5673,6 +5685,8 @@ static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
40;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
@@ -6229,6 +6243,8 @@ static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8;
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 16;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 24;
static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
20;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word
@@ -6785,6 +6801,8 @@ static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
40;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
@@ -7346,6 +7364,8 @@ static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
40;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
@@ -306,6 +306,7 @@
SIZEOF(FutureOr, InstanceSize, FutureOrLayout) \
SIZEOF(GrowableObjectArray, InstanceSize, GrowableObjectArrayLayout) \
SIZEOF(ICData, InstanceSize, ICDataLayout) \
SIZEOF(ImageHeader, UnroundedSize, ImageHeaderLayout) \
SIZEOF(Instance, InstanceSize, InstanceLayout) \
SIZEOF(Instructions, InstanceSize, InstructionsLayout) \
SIZEOF(Instructions, UnalignedHeaderSize, InstructionsLayout) \
+95 -17
View File
@@ -127,7 +127,7 @@ class Section : public ZoneAllocated {
FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
// Each section belongs to at most one PT_LOAD segment.
const Segment* load_segment = nullptr;
Segment* load_segment = nullptr;
virtual intptr_t MemorySize() const = 0;
@@ -234,6 +234,9 @@ class Segment : public ZoneAllocated {
// a memory offset since we use it to determine the segment memory offset.
ASSERT(initial_section->IsAllocated());
ASSERT(initial_section->memory_offset_is_set());
// Make sure the memory offset chosen for the initial section is consistent
// with the alignment for the segment.
ASSERT(Utils::IsAligned(initial_section->memory_offset(), Alignment(type)));
sections_.Add(initial_section);
if (type == elf::ProgramHeaderType::PT_LOAD) {
ASSERT(initial_section->load_segment == nullptr);
@@ -245,6 +248,7 @@ class Segment : public ZoneAllocated {
static intptr_t Alignment(elf::ProgramHeaderType segment_type) {
switch (segment_type) {
case elf::ProgramHeaderType::PT_PHDR:
case elf::ProgramHeaderType::PT_DYNAMIC:
return compiler::target::kWordSize;
case elf::ProgramHeaderType::PT_NOTE:
@@ -319,6 +323,30 @@ class Segment : public ZoneAllocated {
return true;
}
void Replace(Section* old_section, Section* new_section) {
ASSERT(old_section->load_segment == this);
// All these must be true for replacement to be safe.
ASSERT_EQUAL(static_cast<uint32_t>(old_section->type),
static_cast<uint32_t>(new_section->type));
ASSERT_EQUAL(old_section->MemorySize(), new_section->MemorySize());
ASSERT_EQUAL(old_section->IsExecutable(), new_section->IsExecutable());
ASSERT_EQUAL(old_section->IsWritable(), new_section->IsWritable());
ASSERT(old_section->memory_offset_is_set());
ASSERT(!new_section->memory_offset_is_set());
for (intptr_t i = 0; i < sections_.length(); i++) {
auto const section = sections_[i];
if (section != old_section) {
continue;
}
new_section->set_memory_offset(old_section->memory_offset());
sections_[i] = new_section;
new_section->load_segment = this;
old_section->load_segment = nullptr;
return;
}
UNREACHABLE();
}
intptr_t FileOffset() const { return sections_[0]->file_offset(); }
intptr_t FileSize() const {
@@ -792,6 +820,7 @@ class NoteSegment : public Segment {
}
};
// We assume that the final program table fits in a single page of memory.
static const intptr_t kProgramTableSegmentSize = Elf::kPageSize;
// Here, both VM and isolate will be compiled into a single snapshot.
@@ -834,9 +863,20 @@ Elf::Elf(Zone* zone, StreamingWriteStream* stream, Type type, Dwarf* dwarf)
auto const start_segment =
new (zone_) ProgramTableLoadSegment(zone_, kProgramTableSegmentSize);
segments_.Add(start_segment);
// Note that the BSS segment must be the first user-defined segment because
// We allocate an initial build ID of all zeroes, since we need the build ID
// memory offset during ImageHeader creation (see BlobImageWriter::WriteText).
// We replace it with the real build ID during finalization. (We add this
// prior to BSS because we make the BuildID section writable also, so they are
// placed in the same segment before any non-writable ones, and if we add it
// after, then in separate debugging information, it'll go into a separate
// segment because the BSS section for debugging info is NOBITS.)
build_id_ = GenerateBuildId();
AddSection(build_id_, kBuildIdNoteName, kSnapshotBuildIdAsmSymbol);
// Note that the BSS segment must be in the first user-defined segment because
// it cannot be placed in between any two non-writable segments, due to a bug
// in Jelly Bean's ELF loader. See also Elf::WriteProgramTable().
// in Jelly Bean's ELF loader. (For this reason, the program table segments
// generated during finalization are marked as writable.) See also
// Elf::WriteProgramTable().
//
// We add it in all cases, even to the separate debugging information ELF,
// to ensure that relocated addresses are consistent between ELF snapshots
@@ -844,8 +884,14 @@ Elf::Elf(Zone* zone, StreamingWriteStream* stream, Type type, Dwarf* dwarf)
AddSection(bss_, ".bss", kSnapshotBssAsmSymbol);
}
intptr_t Elf::NextMemoryOffset() const {
return Utils::RoundUp(LastLoadSegment()->MemoryEnd(), Elf::kPageSize);
intptr_t Elf::NextMemoryOffset(intptr_t alignment) const {
// Without more information, we won't know whether we might create a new
// segment or put the section into the current one. Thus, for now, only allow
// the offset to be queried ahead of time if it matches the load segment
// alignment.
auto const type = elf::ProgramHeaderType::PT_LOAD;
ASSERT_EQUAL(alignment, Segment::Alignment(type));
return Utils::RoundUp(LastLoadSegment()->MemoryEnd(), alignment);
}
uword Elf::BssStart(bool vm) const {
@@ -870,8 +916,10 @@ intptr_t Elf::AddSection(Section* section,
// We can't add this section to the last load segment, so create a new one.
// The new segment starts at the next aligned address.
auto const type = elf::ProgramHeaderType::PT_LOAD;
intptr_t alignment =
Utils::Maximum(section->alignment, Segment::Alignment(type));
auto const start_address =
Utils::RoundUp(last_load->MemoryEnd(), Segment::Alignment(type));
Utils::RoundUp(last_load->MemoryEnd(), alignment);
section->set_memory_offset(start_address);
auto const segment = new (zone_) Segment(zone_, section, type);
segments_.Add(segment);
@@ -882,13 +930,31 @@ intptr_t Elf::AddSection(Section* section,
return section->memory_offset();
}
void Elf::ReplaceSection(Section* old_section, Section* new_section) {
ASSERT(section_table_file_size_ < 0);
ASSERT(old_section->index_is_set());
ASSERT(!new_section->index_is_set());
ASSERT_EQUAL(new_section->IsAllocated(), old_section->IsAllocated());
new_section->set_name(old_section->name());
new_section->set_index(old_section->index());
sections_[old_section->index()] = new_section;
if (!old_section->IsAllocated()) {
return;
}
ASSERT(program_table_file_size_ < 0);
ASSERT(old_section->load_segment != nullptr);
old_section->load_segment->Replace(old_section, new_section);
}
intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
// When making a separate debugging info file for assembly, we don't have
// the binary text segment contents.
ASSERT(type_ == Type::DebugInfo || bytes != nullptr);
auto const image = new (zone_)
BitsContainer(type_, /*executable=*/true,
/*writable=*/false, size, bytes, Elf::kPageSize);
auto const image = new (zone_) BitsContainer(type_, /*executable=*/true,
/*writable=*/false, size, bytes,
ImageWriter::kTextAlignment);
return AddSection(image, ".text", name);
}
@@ -904,14 +970,14 @@ Section* Elf::CreateBSS(Zone* zone, Type type, intptr_t size) {
memset(bytes, 0, size);
}
return new (zone) BitsContainer(type, /*executable=*/false, /*writable=*/true,
kBssSize, bytes, Image::kBssAlignment);
kBssSize, bytes, ImageWriter::kBssAlignment);
}
intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
ASSERT(bytes != nullptr);
auto const image = new (zone_)
BitsContainer(type_, /*executable=*/false,
/*writable=*/false, size, bytes, kMaxObjectAlignment);
auto const image = new (zone_) BitsContainer(type_, /*executable=*/false,
/*writable=*/false, size, bytes,
ImageWriter::kRODataAlignment);
return AddSection(image, ".rodata", name);
}
@@ -1189,11 +1255,11 @@ void Elf::Finalize() {
// without changing how we add the .text and .rodata sections (since we
// determine memory offsets for those sections when we add them, and the
// text sections must have the memory offsets to do BSS relocations).
if (auto const build_id = GenerateBuildId()) {
AddSection(build_id, ".note.gnu.build-id", kSnapshotBuildIdAsmSymbol);
if (auto const new_build_id = GenerateBuildId()) {
ReplaceSection(build_id_, new_build_id);
// Add a PT_NOTE segment for the build ID.
segments_.Add(new (zone_) NoteSegment(zone_, build_id));
segments_.Add(new (zone_) NoteSegment(zone_, new_build_id));
}
// Adding the dynamic symbol table and associated sections.
@@ -1291,6 +1357,13 @@ static uint32_t HashBitsContainer(const BitsContainer* bits) {
return FinalizeHash(hash, 32);
}
uword Elf::BuildIdStart(intptr_t* size) {
ASSERT(size != nullptr);
ASSERT(build_id_ != nullptr);
*size = kBuildIdDescriptionLength;
return build_id_->memory_offset() + kBuildIdDescriptionOffset;
}
Section* Elf::GenerateBuildId() {
uint8_t* notes_buffer = nullptr;
WriteStream stream(&notes_buffer, ZoneReallocate, kBuildIdSize);
@@ -1319,9 +1392,14 @@ Section* Elf::GenerateBuildId() {
}
ASSERT_EQUAL(stream.bytes_written() - description_start,
kBuildIdDescriptionLength);
ASSERT_EQUAL(stream.bytes_written(), kBuildIdSize);
// While the build ID section does not need to be writable, it and the
// BSS section are allocated segments at the same time. Having the same flags
// ensures they will be combined in the same segment and not unnecessarily
// aligned into a new page.
return new (zone_) BitsContainer(
elf::SectionHeaderType::SHT_NOTE, /*allocate=*/true, /*executable=*/false,
/*writable=*/false, stream.bytes_written(), notes_buffer, kNoteAlignment);
/*writable=*/true, stream.bytes_written(), notes_buffer, kNoteAlignment);
}
void Elf::FinalizeProgramTable() {
+17 -4
View File
@@ -35,7 +35,7 @@ class Elf : public ZoneAllocated {
Type type,
Dwarf* dwarf = nullptr);
static const intptr_t kPageSize = 4096;
static constexpr intptr_t kPageSize = 4096;
bool IsStripped() const { return dwarf_ == nullptr; }
@@ -44,13 +44,13 @@ class Elf : public ZoneAllocated {
Dwarf* dwarf() { return dwarf_; }
uword BssStart(bool vm) const;
uword BuildIdStart(intptr_t* size);
// What the next memory offset for a kPageSize-aligned section would be.
// What the next memory offset for an appropriately aligned section would be.
//
// Only used by BlobImageWriter::WriteText() to determine the memory offset
// for the text section before it is added.
intptr_t NextMemoryOffset() const;
intptr_t AddNoBits(const char* name, const uint8_t* bytes, intptr_t size);
intptr_t NextMemoryOffset(intptr_t alignment) const;
intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size);
intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size);
void AddDebug(const char* name, const uint8_t* bytes, intptr_t size);
@@ -58,6 +58,8 @@ class Elf : public ZoneAllocated {
void Finalize();
private:
static constexpr const char* kBuildIdNoteName = ".note.gnu.build-id";
static Section* CreateBSS(Zone* zone, Type type, intptr_t size);
// Adds the section and also creates a PT_LOAD segment for the section if it
@@ -71,6 +73,11 @@ class Elf : public ZoneAllocated {
intptr_t AddSection(Section* section,
const char* name,
const char* symbol_name = nullptr);
// Replaces [old_section] with [new_section] in all appropriate places. If the
// section is allocated, the memory size of the section must be the same as
// the original to ensure any already-calculated memory offsets are unchanged.
void ReplaceSection(Section* old_section, Section* new_section);
void AddStaticSymbol(const char* name,
intptr_t info,
intptr_t section_index,
@@ -118,6 +125,12 @@ class Elf : public ZoneAllocated {
StringTable* strtab_ = nullptr;
SymbolTable* symtab_ = nullptr;
// We always create a GNU build ID for all Elf files. In order to create
// the appropriate offset to it in an ImageHeader object, we create an
// initial build ID section as a placeholder and then replace that section
// during finalization once we have the information to calculate the real one.
Section* build_id_;
GrowableArray<Section*> sections_;
GrowableArray<Segment*> segments_;
intptr_t memory_offset_;
+381 -163
View File
@@ -6,6 +6,7 @@
#include "include/dart_api.h"
#include "platform/assert.h"
#include "vm/bss_relocs.h"
#include "vm/class_id.h"
#include "vm/compiler/runtime_api.h"
#include "vm/dwarf.h"
@@ -36,10 +37,84 @@ DEFINE_FLAG(bool,
DEFINE_FLAG(charp,
print_instructions_sizes_to,
NULL,
nullptr,
"Print sizes of all instruction objects to the given file");
#endif
const ImageHeaderLayout* Image::ExtraInfo(const uword raw_memory,
const uword size) {
#if defined(DART_PRECOMPILED_RUNTIME)
auto const raw_value = FieldValue(raw_memory, HeaderField::ImageHeaderOffset);
if (raw_value != kNoImageHeader) {
ASSERT(raw_value >= kHeaderSize);
ASSERT(raw_value <= size - ImageHeader::InstanceSize());
return reinterpret_cast<const ImageHeaderLayout*>(raw_memory + raw_value);
}
#endif
return nullptr;
}
uword* Image::bss() const {
#if defined(DART_PRECOMPILED_RUNTIME)
ASSERT(extra_info_ != nullptr);
// There should always be a non-zero BSS offset.
ASSERT(extra_info_->bss_offset_ != 0);
// Returning a non-const uword* is safe because we're translating from
// the start of the instructions (read-only) to the start of the BSS
// (read-write).
return reinterpret_cast<uword*>(raw_memory_ + extra_info_->bss_offset_);
#else
return nullptr;
#endif
}
uword Image::instructions_relocated_address() const {
#if defined(DART_PRECOMPILED_RUNTIME)
ASSERT(extra_info_ != nullptr);
// For assembly snapshots, we need to retrieve this from the initialized BSS.
const uword address =
compiled_to_elf() ? extra_info_->instructions_relocated_address_
: bss()[BSS::RelocationIndex(
BSS::Relocation::InstructionsRelocatedAddress)];
ASSERT(address != kNoRelocatedAddress);
return address;
#else
return kNoRelocatedAddress;
#endif
}
const uint8_t* Image::build_id() const {
#if defined(DART_PRECOMPILED_RUNTIME)
ASSERT(extra_info_ != nullptr);
if (extra_info_->build_id_offset_ != kNoBuildId) {
return reinterpret_cast<const uint8_t*>(raw_memory_ +
extra_info_->build_id_offset_);
}
#endif
return nullptr;
}
intptr_t Image::build_id_length() const {
#if defined(DART_PRECOMPILED_RUNTIME)
ASSERT(extra_info_ != nullptr);
return extra_info_->build_id_length_;
#else
return 0;
#endif
}
bool Image::compiled_to_elf() const {
#if defined(DART_PRECOMPILED_RUNTIME)
ASSERT(extra_info_ != nullptr);
// Since assembly snapshots can't set up this field correctly (instead,
// it's initialized in BSS at snapshot load time), we use it to detect
// direct-to-ELF snapshots.
return extra_info_->instructions_relocated_address_ != kNoRelocatedAddress;
#else
return false;
#endif
}
intptr_t ObjectOffsetTrait::Hashcode(Key key) {
ObjectPtr obj = key;
ASSERT(!obj->IsSmi());
@@ -88,6 +163,8 @@ ImageWriter::ImageWriter(Thread* t)
next_text_offset_(0),
objects_(),
instructions_(),
image_type_(TagObjectTypeAsReadOnly(t->zone(), "Image")),
image_header_type_(TagObjectTypeAsReadOnly(t->zone(), "ImageHeader")),
instructions_section_type_(
TagObjectTypeAsReadOnly(t->zone(), "InstructionsSection")),
instructions_type_(TagObjectTypeAsReadOnly(t->zone(), "Instructions")),
@@ -412,33 +489,36 @@ void ImageWriter::Write(WriteStream* clustered_stream, bool vm) {
data.obj_ = &Object::Handle(zone, data.raw_obj_);
}
// Append the direct-mapped RO data objects after the clustered snapshot.
// We need to do this before WriteText because WriteText currently adds the
// finalized contents of the clustered_stream as data sections.
offset_space_ = vm ? V8SnapshotProfileWriter::kVmData
: V8SnapshotProfileWriter::kIsolateData;
WriteROData(clustered_stream);
// Needs to happen before WriteText, as we add information about the
// BSSsection in the text section as an initial ImageHeader object.
WriteBss(vm);
offset_space_ = vm ? V8SnapshotProfileWriter::kVmText
: V8SnapshotProfileWriter::kIsolateText;
// Needs to happen after WriteROData, because all image writers currently
// add the clustered data information to their output in WriteText().
WriteText(clustered_stream, vm);
WriteText(vm);
// Append the direct-mapped RO data objects after the clustered snapshot
// and then for ELF and assembly outputs, add appropriate sections with
// that combined data.
offset_space_ = vm ? V8SnapshotProfileWriter::kVmData
: V8SnapshotProfileWriter::kIsolateData;
WriteROData(clustered_stream, vm);
}
void ImageWriter::WriteROData(WriteStream* stream) {
void ImageWriter::WriteROData(WriteStream* stream, bool vm) {
#if defined(DART_PRECOMPILER)
const intptr_t start_position = stream->Position();
#endif
stream->Align(kMaxObjectAlignment);
stream->Align(ImageWriter::kRODataAlignment);
// Heap page starts here.
intptr_t section_start = stream->Position();
stream->WriteWord(next_data_offset_); // Data length.
// Zero values for other image header fields.
stream->Align(kMaxObjectAlignment);
stream->WriteWord(0); // No ImageHeader object in data sections.
// Zero values for the rest of the Image object header bytes.
stream->Align(Image::kHeaderSize);
ASSERT(stream->Position() - section_start == Image::kHeaderSize);
#if defined(DART_PRECOMPILER)
if (profile_writer_ != nullptr) {
@@ -751,7 +831,60 @@ const char* SnapshotTextObjectNamer::SnapshotNameFor(
return SnapshotNameFor(index, *data.code_);
}
void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
#if defined(DART_PRECOMPILER)
static const char* const kVmSnapshotBssAsmSymbol = "_kDartVmSnapshotBss";
static const char* const kIsolateSnapshotBssAsmSymbol =
"_kDartIsolateSnapshotBss";
#endif
void AssemblyImageWriter::WriteBss(bool vm) {
#if defined(DART_PRECOMPILER)
auto const bss_symbol =
vm ? kVmSnapshotBssAsmSymbol : kIsolateSnapshotBssAsmSymbol;
assembly_stream_.Print(".bss\n");
// Align the BSS contents as expected by the Image class.
Align(ImageWriter::kBssAlignment);
assembly_stream_.Print("%s:\n", bss_symbol);
auto const entry_count = vm ? BSS::kVmEntryCount : BSS::kIsolateEntryCount;
for (intptr_t i = 0; i < entry_count; i++) {
WriteWordLiteralText(0);
}
#endif
}
void AssemblyImageWriter::WriteROData(WriteStream* clustered_stream, bool vm) {
ImageWriter::WriteROData(clustered_stream, vm);
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \
defined(TARGET_OS_FUCHSIA)
assembly_stream_.Print(".section .rodata\n");
#elif defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
assembly_stream_.Print(".const\n");
#else
UNIMPLEMENTED();
#endif
const char* data_symbol =
vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
assembly_stream_.Print(".globl %s\n", data_symbol);
Align(ImageWriter::kRODataAlignment);
assembly_stream_.Print("%s:\n", data_symbol);
const uword buffer = reinterpret_cast<uword>(clustered_stream->buffer());
const intptr_t length = clustered_stream->bytes_written();
WriteByteSequence(buffer, buffer + length);
#if defined(DART_PRECOMPILER)
if (debug_elf_ != nullptr) {
// Add a NoBits section for the ROData as well.
debug_elf_->AddROData(data_symbol, clustered_stream->buffer(), length);
}
#endif // defined(DART_PRECOMPILER)
#endif // !defined(DART_PRECOMPILED_RUNTIME)
}
void AssemblyImageWriter::WriteText(bool vm) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
@@ -760,26 +893,26 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const bool bare_instruction_payloads =
FLAG_precompiled_mode && FLAG_use_bare_instructions;
#if defined(DART_PRECOMPILER)
const char* bss_symbol =
vm ? "_kDartVmSnapshotBss" : "_kDartIsolateSnapshotBss";
intptr_t debug_segment_base = 0;
if (debug_elf_ != nullptr) {
debug_segment_base = debug_elf_->NextMemoryOffset();
}
#endif
const char* instructions_symbol = vm ? kVmSnapshotInstructionsAsmSymbol
: kIsolateSnapshotInstructionsAsmSymbol;
assembly_stream_.Print(".text\n");
assembly_stream_.Print(".globl %s\n", instructions_symbol);
// Start snapshot at page boundary.
ASSERT(VirtualMemory::PageSize() >= kMaxObjectAlignment);
ASSERT(VirtualMemory::PageSize() >= Image::kBssAlignment);
Align(VirtualMemory::PageSize());
ASSERT(ImageWriter::kTextAlignment >= VirtualMemory::PageSize());
Align(ImageWriter::kTextAlignment);
assembly_stream_.Print("%s:\n", instructions_symbol);
#if defined(DART_PRECOMPILER)
auto const bss_symbol =
vm ? kVmSnapshotBssAsmSymbol : kIsolateSnapshotBssAsmSymbol;
intptr_t debug_segment_base = 0;
if (debug_elf_ != nullptr) {
debug_segment_base =
debug_elf_->NextMemoryOffset(ImageWriter::kTextAlignment);
}
#endif
intptr_t text_offset = 0;
#if defined(DART_PRECOMPILER)
// Parent used for later profile objects. Starts off as the Image. When
@@ -793,64 +926,113 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const intptr_t image_size = Utils::RoundUp(
next_text_offset_, compiler::target::ObjectAlignment::kObjectAlignment);
text_offset += WriteWordLiteralText(image_size);
#if defined(DART_PRECOMPILER)
assembly_stream_.Print("%s %s - %s\n", kLiteralPrefix, bss_symbol,
instructions_symbol);
text_offset += compiler::target::kWordSize;
#else
text_offset += WriteWordLiteralText(0); // No relocations.
#endif
text_offset += Align(kMaxObjectAlignment, text_offset);
ASSERT_EQUAL(text_offset, Image::kHeaderSize);
#if defined(DART_PRECOMPILER)
if (profile_writer_ != nullptr) {
profile_writer_->SetObjectTypeAndName(parent_id, "Image",
instructions_symbol);
// Assign post-instruction padding to the Image, unless we're writing bare
// instruction payloads, in which case we'll assign it to the
// InstructionsSection object.
const intptr_t padding =
bare_instruction_payloads ? 0 : image_size - next_text_offset_;
profile_writer_->AttributeBytesTo(parent_id, Image::kHeaderSize + padding);
profile_writer_->AddRoot(parent_id);
if (FLAG_precompiled_mode) {
// Output the offset to the ImageHeader object from the start of the image.
text_offset += WriteWordLiteralText(Image::kHeaderSize);
} else {
text_offset += WriteWordLiteralText(Image::kNoImageHeader);
}
#endif
// Zero values for the rest of the Image object header bytes.
text_offset += Align(Image::kHeaderSize, text_offset);
ASSERT_EQUAL(text_offset, Image::kHeaderSize);
if (bare_instruction_payloads) {
#if defined(DART_PRECOMPILER)
if (FLAG_precompiled_mode) {
if (profile_writer_ != nullptr) {
profile_writer_->SetObjectTypeAndName(parent_id, image_type_,
instructions_symbol);
// Assign post-instruction padding to the Image, unless we're writing bare
// instruction payloads, in which case we'll assign it to the
// InstructionsSection object.
const intptr_t padding =
bare_instruction_payloads ? 0 : image_size - next_text_offset_;
profile_writer_->AttributeBytesTo(parent_id,
Image::kHeaderSize + padding);
profile_writer_->AddRoot(parent_id);
}
// Write the ImageHeader object, starting with the header.
const intptr_t image_header_size =
compiler::target::ImageHeader::InstanceSize();
if (profile_writer_ != nullptr) {
const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
profile_writer_->SetObjectTypeAndName(id, image_header_type_,
instructions_symbol);
const intptr_t padding = image_size - next_text_offset_;
profile_writer_->AttributeBytesTo(
id, compiler::target::InstructionsSection::HeaderSize() + padding);
profile_writer_->AttributeBytesTo(id, image_header_size);
const intptr_t element_offset = id.second - parent_id.second;
profile_writer_->AttributeReferenceTo(
parent_id,
{id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
// Later objects will have the InstructionsSection as a parent.
parent_id = id;
}
#endif
const intptr_t section_size = image_size - text_offset;
// Add the RawInstructionsSection header.
const compiler::target::uword marked_tags =
ObjectLayout::OldBit::encode(true) |
ObjectLayout::OldAndNotMarkedBit::encode(false) |
ObjectLayout::OldAndNotRememberedBit::encode(true) |
ObjectLayout::NewBit::encode(false) |
ObjectLayout::SizeTag::encode(AdjustObjectSizeForTarget(section_size)) |
ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
ObjectLayout::SizeTag::encode(
AdjustObjectSizeForTarget(image_header_size)) |
ObjectLayout::ClassIdTag::encode(kImageHeaderCid);
text_offset += WriteWordLiteralText(marked_tags);
// Calculated using next_text_offset_, which doesn't include post-payload
// padding to object alignment.
const intptr_t instructions_length =
next_text_offset_ - (text_offset + compiler::target::kWordSize);
text_offset += WriteWordLiteralText(instructions_length);
// An ImageHeader has four fields:
// 1) The BSS offset from this section.
assembly_stream_.Print("%s %s - %s\n", kLiteralPrefix, bss_symbol,
instructions_symbol);
text_offset += compiler::target::kWordSize;
// 2) The relocated address of the instructions.
//
// For assembly snapshots, we can't generate assembly to get the absolute
// address of the text section, as using the section symbol gives us a
// relative offset from the section start, which is 0. Instead, depend on
// the BSS initialization to retrieve this for us at runtime. As a side
// effect, this field also doubles as a way to detect whether we compiled to
// assembly or directly to ELF.
text_offset += WriteWordLiteralText(Image::kNoRelocatedAddress);
// TODO(dartbug.com/43274): Change once we generate consistent build IDs
// between assembly snapshots and their debugging information.
// 3) The GNU build ID offset from this section.
text_offset += WriteWordLiteralText(Image::kNoBuildId);
// 4) The GNU build ID length.
text_offset += WriteWordLiteralText(0);
text_offset +=
Align(compiler::target::ObjectAlignment::kObjectAlignment, text_offset);
ASSERT_EQUAL(text_offset, Image::kHeaderSize + image_header_size);
if (bare_instruction_payloads) {
if (profile_writer_ != nullptr) {
const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
instructions_symbol);
const intptr_t padding = image_size - next_text_offset_;
profile_writer_->AttributeBytesTo(
id, compiler::target::InstructionsSection::HeaderSize() + padding);
const intptr_t element_offset = id.second - parent_id.second;
profile_writer_->AttributeReferenceTo(
parent_id,
{id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
// Later objects will have the InstructionsSection as a parent.
parent_id = id;
}
const intptr_t section_size = image_size - text_offset;
// Add the RawInstructionsSection header.
const compiler::target::uword marked_tags =
ObjectLayout::OldBit::encode(true) |
ObjectLayout::OldAndNotMarkedBit::encode(false) |
ObjectLayout::OldAndNotRememberedBit::encode(true) |
ObjectLayout::NewBit::encode(false) |
ObjectLayout::SizeTag::encode(
AdjustObjectSizeForTarget(section_size)) |
ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
text_offset += WriteWordLiteralText(marked_tags);
// Calculated using next_text_offset_, which doesn't include post-payload
// padding to object alignment.
const intptr_t instructions_length =
next_text_offset_ - (text_offset + compiler::target::kWordSize);
text_offset += WriteWordLiteralText(instructions_length);
}
}
#endif
FrameUnwindPrologue();
@@ -932,7 +1114,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
text_offset += sizeof(compiler::target::uword);
WriteWordLiteralText(insns.raw_ptr()->size_and_flags_);
text_offset += sizeof(compiler::target::uword);
#else // defined(IS_SIMARM_X64)
#else // defined(IS_SIMARM_X64)
uword object_start = reinterpret_cast<uword>(insns.raw_ptr());
WriteWordLiteralText(marked_tags);
object_start += sizeof(uword);
@@ -1053,41 +1235,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
// writing the text section.
ASSERT(debug_segment_base2 == debug_segment_base);
}
assembly_stream_.Print(".bss\n");
// Align the BSS contents as expected by the Image class.
Align(Image::kBssAlignment);
assembly_stream_.Print("%s:\n", bss_symbol);
auto const entry_count = vm ? BSS::kVmEntryCount : BSS::kIsolateEntryCount;
for (intptr_t i = 0; i < entry_count; i++) {
WriteWordLiteralText(0);
}
#endif
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \
defined(TARGET_OS_FUCHSIA)
assembly_stream_.Print(".section .rodata\n");
#elif defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
assembly_stream_.Print(".const\n");
#else
UNIMPLEMENTED();
#endif
const char* data_symbol =
vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
assembly_stream_.Print(".globl %s\n", data_symbol);
Align(kMaxObjectAlignment);
assembly_stream_.Print("%s:\n", data_symbol);
const uword buffer = reinterpret_cast<uword>(clustered_stream->buffer());
const intptr_t length = clustered_stream->bytes_written();
WriteByteSequence(buffer, buffer + length);
#if defined(DART_PRECOMPILER)
if (debug_elf_ != nullptr) {
// Add a NoBits section for the ROData as well.
debug_elf_->AddROData(data_symbol, clustered_stream->buffer(), length);
}
#endif // defined(DART_PRECOMPILER)
#endif // !defined(DART_PRECOMPILED_RUNTIME)
}
@@ -1220,7 +1368,35 @@ intptr_t BlobImageWriter::WriteByteSequence(uword start, uword end) {
return size;
}
void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
void BlobImageWriter::WriteBss(bool vm) {
#if defined(DART_PRECOMPILER)
// We don't actually write a BSS segment, it's created as part of the
// Elf constructor, but make sure it has an non-zero start.
ASSERT(elf_->BssStart(vm) != 0);
#endif
}
void BlobImageWriter::WriteROData(WriteStream* clustered_stream, bool vm) {
ImageWriter::WriteROData(clustered_stream, vm);
#if defined(DART_PRECOMPILER)
auto const data_symbol =
vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
if (elf_ != nullptr) {
elf_->AddROData(data_symbol, clustered_stream->buffer(),
clustered_stream->bytes_written());
}
if (debug_elf_ != nullptr) {
// To keep memory addresses consistent, we create elf::SHT_NOBITS sections
// in the debugging information. We still pass along the buffers because
// we'll need the buffer bytes at generation time to calculate the build ID
// so it'll match the one in the snapshot.
debug_elf_->AddROData(data_symbol, clustered_stream->buffer(),
clustered_stream->bytes_written());
}
#endif
}
void BlobImageWriter::WriteText(bool vm) {
const bool bare_instruction_payloads =
FLAG_precompiled_mode && FLAG_use_bare_instructions;
auto const zone = Thread::Current()->zone();
@@ -1230,11 +1406,12 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
: kIsolateSnapshotInstructionsAsmSymbol;
intptr_t segment_base = 0;
if (elf_ != nullptr) {
segment_base = elf_->NextMemoryOffset();
segment_base = elf_->NextMemoryOffset(ImageWriter::kTextAlignment);
}
intptr_t debug_segment_base = 0;
if (debug_elf_ != nullptr) {
debug_segment_base = debug_elf_->NextMemoryOffset();
debug_segment_base =
debug_elf_->NextMemoryOffset(ImageWriter::kTextAlignment);
// If we're also generating an ELF snapshot, we want the virtual addresses
// in it and the separately saved DWARF information to match.
ASSERT(elf_ == nullptr || segment_base == debug_segment_base);
@@ -1254,71 +1431,120 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const intptr_t image_size = Utils::RoundUp(
next_text_offset_, compiler::target::ObjectAlignment::kObjectAlignment);
instructions_blob_stream_.WriteTargetWord(image_size);
#if defined(DART_PRECOMPILER)
// Store the offset of the BSS section from the instructions section here.
// If not compiling to ELF (and thus no BSS segment), write 0.
const word bss_offset =
elf_ != nullptr ? elf_->BssStart(vm) - segment_base : 0;
ASSERT_EQUAL(Utils::RoundDown(bss_offset, Image::kBssAlignment), bss_offset);
// Set the lowest bit if we are compiling to ELF.
const word compiled_to_elf = elf_ != nullptr ? 0x1 : 0x0;
instructions_blob_stream_.WriteTargetWord(bss_offset | compiled_to_elf);
#else
instructions_blob_stream_.WriteTargetWord(0); // No relocations.
#endif
instructions_blob_stream_.Align(kMaxObjectAlignment);
if (FLAG_precompiled_mode) {
// Output the offset to the ImageHeader object from the start of the image.
instructions_blob_stream_.WriteTargetWord(Image::kHeaderSize);
} else {
instructions_blob_stream_.WriteTargetWord(0); // No ImageHeader object.
}
// Zero values for the rest of the Image object header bytes.
instructions_blob_stream_.Align(Image::kHeaderSize);
ASSERT_EQUAL(instructions_blob_stream_.Position(), Image::kHeaderSize);
text_offset += Image::kHeaderSize;
#if defined(DART_PRECOMPILER)
if (profile_writer_ != nullptr) {
profile_writer_->SetObjectTypeAndName(parent_id, "Image",
instructions_symbol);
// Assign post-instruction padding to the Image, unless we're writing bare
// instruction payloads, in which case we'll assign it to the
// InstructionsSection object.
const intptr_t padding =
bare_instruction_payloads ? 0 : image_size - next_text_offset_;
profile_writer_->AttributeBytesTo(parent_id, Image::kHeaderSize + padding);
profile_writer_->AddRoot(parent_id);
}
#endif
if (bare_instruction_payloads) {
#if defined(DART_PRECOMPILER)
if (FLAG_precompiled_mode) {
if (profile_writer_ != nullptr) {
profile_writer_->SetObjectTypeAndName(parent_id, image_type_,
instructions_symbol);
// Assign post-instruction padding to the Image, unless we're writing bare
// instruction payloads, in which case we'll assign it to the
// InstructionsSection object.
const intptr_t padding =
bare_instruction_payloads ? 0 : image_size - next_text_offset_;
profile_writer_->AttributeBytesTo(parent_id,
Image::kHeaderSize + padding);
profile_writer_->AddRoot(parent_id);
}
// Write the ImageHeader object, starting with the header.
const intptr_t image_header_size =
compiler::target::ImageHeader::InstanceSize();
if (profile_writer_ != nullptr) {
const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
profile_writer_->SetObjectTypeAndName(id, image_header_type_,
instructions_symbol);
const intptr_t padding = image_size - next_text_offset_;
profile_writer_->AttributeBytesTo(
id, compiler::target::InstructionsSection::HeaderSize() + padding);
profile_writer_->AttributeBytesTo(id, image_header_size);
const intptr_t element_offset = id.second - parent_id.second;
profile_writer_->AttributeReferenceTo(
parent_id,
{id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
// Later objects will have the InstructionsSection as a parent.
parent_id = id;
}
#endif
const intptr_t section_size = image_size - Image::kHeaderSize;
// Add the RawInstructionsSection header.
const compiler::target::uword marked_tags =
ObjectLayout::OldBit::encode(true) |
ObjectLayout::OldAndNotMarkedBit::encode(false) |
ObjectLayout::OldAndNotRememberedBit::encode(true) |
ObjectLayout::NewBit::encode(false) |
ObjectLayout::SizeTag::encode(AdjustObjectSizeForTarget(section_size)) |
ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
ObjectLayout::SizeTag::encode(
AdjustObjectSizeForTarget(image_header_size)) |
ObjectLayout::ClassIdTag::encode(kImageHeaderCid);
instructions_blob_stream_.WriteTargetWord(marked_tags);
// Uses next_text_offset_ to avoid any post-payload padding.
const intptr_t instructions_length =
next_text_offset_ - Image::kHeaderSize -
compiler::target::InstructionsSection::HeaderSize();
instructions_blob_stream_.WriteTargetWord(instructions_length);
ASSERT(elf_ != nullptr);
// An ImageHeader has four fields:
// 1) The BSS offset from this section.
const word bss_offset = elf_->BssStart(vm) - segment_base;
ASSERT(bss_offset != Image::kNoBssSection);
instructions_blob_stream_.WriteTargetWord(bss_offset);
// 2) The relocated address of the instructions.
//
// Since we set this to a non-zero value for ELF snapshots, we also use this
// to detect compiled-to-ELF snapshots.
ASSERT(segment_base != Image::kNoRelocatedAddress);
instructions_blob_stream_.WriteTargetWord(segment_base);
// 3) The GNU build ID offset from this section.
intptr_t build_id_length = 0;
const word build_id_offset =
elf_->BuildIdStart(&build_id_length) - segment_base;
ASSERT(build_id_offset != Image::kNoBuildId);
instructions_blob_stream_.WriteTargetWord(build_id_offset);
// 4) The GNU build ID length.
ASSERT(build_id_length != 0);
instructions_blob_stream_.WriteTargetWord(build_id_length);
instructions_blob_stream_.Align(
compiler::target::ObjectAlignment::kObjectAlignment);
ASSERT_EQUAL(instructions_blob_stream_.Position() - text_offset,
compiler::target::InstructionsSection::HeaderSize());
text_offset += compiler::target::InstructionsSection::HeaderSize();
image_header_size);
text_offset += image_header_size;
if (bare_instruction_payloads) {
if (profile_writer_ != nullptr) {
const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
instructions_symbol);
const intptr_t padding = image_size - next_text_offset_;
profile_writer_->AttributeBytesTo(
id, compiler::target::InstructionsSection::HeaderSize() + padding);
const intptr_t element_offset = id.second - parent_id.second;
profile_writer_->AttributeReferenceTo(
parent_id,
{id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
// Later objects will have the InstructionsSection as a parent.
parent_id = id;
}
const intptr_t section_size = image_size - text_offset;
// Add the RawInstructionsSection header.
const compiler::target::uword marked_tags =
ObjectLayout::OldBit::encode(true) |
ObjectLayout::OldAndNotMarkedBit::encode(false) |
ObjectLayout::OldAndNotRememberedBit::encode(true) |
ObjectLayout::NewBit::encode(false) |
ObjectLayout::SizeTag::encode(
AdjustObjectSizeForTarget(section_size)) |
ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
instructions_blob_stream_.WriteTargetWord(marked_tags);
// Uses next_text_offset_ to avoid any post-payload padding.
const intptr_t instructions_length =
next_text_offset_ - text_offset -
compiler::target::InstructionsSection::HeaderSize();
instructions_blob_stream_.WriteTargetWord(instructions_length);
ASSERT_EQUAL(instructions_blob_stream_.Position() - text_offset,
compiler::target::InstructionsSection::HeaderSize());
text_offset += compiler::target::InstructionsSection::HeaderSize();
}
}
#endif
ASSERT_EQUAL(text_offset, instructions_blob_stream_.Position());
@@ -1403,7 +1629,7 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
instructions_blob_stream_.Align(alignment);
const intptr_t end_offset = instructions_blob_stream_.bytes_written();
text_offset += (end_offset - start_offset);
#else // defined(IS_SIMARM_X64)
#else // defined(IS_SIMARM_X64)
// Only payload is output in AOT snapshots.
const uword header_size =
bare_instruction_payloads
@@ -1447,6 +1673,7 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
PcDescriptors::Iterator iterator(
descriptors, /*kind_mask=*/PcDescriptorsLayout::kBSSRelocation);
const intptr_t bss_offset = elf_->BssStart(vm) - segment_base;
while (iterator.MoveNext()) {
const intptr_t reloc_offset = iterator.PcOffset();
@@ -1488,17 +1715,12 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
ASSERT_EQUAL(text_offset, instructions_blob_stream_.bytes_written());
ASSERT_EQUAL(text_offset, image_size);
#ifdef DART_PRECOMPILER
auto const data_symbol =
vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
#if defined(DART_PRECOMPILER)
if (elf_ != nullptr) {
auto const segment_base2 =
elf_->AddText(instructions_symbol, instructions_blob_stream_.buffer(),
instructions_blob_stream_.bytes_written());
ASSERT_EQUAL(segment_base2, segment_base);
// Write the .rodata section here like the AssemblyImageWriter.
elf_->AddROData(data_symbol, clustered_stream->buffer(),
clustered_stream->bytes_written());
}
if (debug_elf_ != nullptr) {
// To keep memory addresses consistent, we create elf::SHT_NOBITS sections
@@ -1509,8 +1731,6 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
instructions_symbol, instructions_blob_stream_.buffer(),
instructions_blob_stream_.bytes_written());
ASSERT_EQUAL(debug_segment_base2, debug_segment_base);
debug_elf_->AddROData(data_symbol, clustered_stream->buffer(),
clustered_stream->bytes_written());
}
#endif
}
@@ -1518,10 +1738,8 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
ImageReader::ImageReader(const uint8_t* data_image,
const uint8_t* instructions_image)
: data_image_(data_image), instructions_image_(instructions_image) {
ASSERT(data_image != NULL);
ASSERT(instructions_image != NULL);
}
: data_image_(ASSERT_NOTNULL(data_image)),
instructions_image_(ASSERT_NOTNULL(instructions_image)) {}
ApiErrorPtr ImageReader::VerifyAlignment() const {
if (!Utils::IsAligned(data_image_, kObjectAlignment) ||
+120 -38
View File
@@ -13,6 +13,7 @@
#include "vm/allocation.h"
#include "vm/compiler/runtime_api.h"
#include "vm/datastream.h"
#include "vm/elf.h"
#include "vm/globals.h"
#include "vm/growable_array.h"
#include "vm/hash_map.h"
@@ -26,65 +27,117 @@ namespace dart {
// Forward declarations.
class Code;
class Dwarf;
class Elf;
class Instructions;
class Object;
class Image : ValueObject {
public:
explicit Image(const void* raw_memory) : raw_memory_(raw_memory) {
explicit Image(const void* raw_memory)
: Image(reinterpret_cast<uword>(raw_memory)) {}
explicit Image(const uword raw_memory)
: raw_memory_(raw_memory),
snapshot_size_(FieldValue(raw_memory, HeaderField::ImageSize)),
extra_info_(ExtraInfo(raw_memory_, snapshot_size_)) {
ASSERT(Utils::IsAligned(raw_memory, kMaxObjectAlignment));
}
// Even though an Image is read-only memory, we must return a void* here.
// All objects in an Image are pre-marked, though, so the GC will not attempt
// to change the returned memory.
void* object_start() const {
return reinterpret_cast<void*>(reinterpret_cast<uword>(raw_memory_) +
kHeaderSize);
return reinterpret_cast<void*>(raw_memory_ + kHeaderSize);
}
uword object_size() const {
uword snapshot_size = *reinterpret_cast<const uword*>(raw_memory_);
return snapshot_size - kHeaderSize;
}
uword object_size() const { return snapshot_size_ - kHeaderSize; }
bool contains(uword address) const {
uword start = reinterpret_cast<uword>(object_start());
return address >= start && (address - start < object_size());
}
// Returns the offset of the BSS section from this image. Only has meaning for
// instructions images.
word bss_offset() const {
auto const raw_value = *(reinterpret_cast<const word*>(raw_memory_) + 1);
return Utils::RoundDown(raw_value, kBssAlignment);
}
// Returns the address of the BSS section, or nullptr if one is not available.
// Only has meaning for instructions images from precompiled snapshots.
uword* bss() const;
// Returns true if the image was compiled directly to ELF. Only has meaning
// for instructions images.
bool compiled_to_elf() const {
auto const raw_value = *(reinterpret_cast<const word*>(raw_memory_) + 1);
return (raw_value & 0x1) == 0x1;
}
// Returns the relocated address of the isolate's instructions, or 0 if
// one is not available. Only has meaning for instructions images from
// precompiled snapshots.
uword instructions_relocated_address() const;
// Returns the GNU build ID, or nullptr if not available. See
// build_id_length() for the length of the returned buffer. Only has meaning
// for instructions images from precompiled snapshots.
const uint8_t* build_id() const;
// Returns the length of the GNU build ID returned by build_id(). Only has
// meaning for instructions images from precompiled snapshots.
intptr_t build_id_length() const;
// Returns whether this instructions section was compiled to ELF. Only has
// meaning for instructions images from precompiled snapshots.
bool compiled_to_elf() const;
private:
static constexpr intptr_t kHeaderFields = 2;
// Word-sized fields in an Image object header.
enum class HeaderField : intptr_t {
// The size of the image (total of header and payload).
ImageSize,
// The offset of the ImageHeader object in the image. Note this offset
// is from the start of the _image_, _not_ from its payload start, so we
// can detect images without ImageHeaders by a 0 value here.
ImageHeaderOffset,
// If adding more fields, updating kHeaderFields below. (However, more
// fields _can't_ be added on 64-bit architectures, see the restrictions
// on kHeaderSize below.)
};
// Number of fields described by the HeaderField enum.
static constexpr intptr_t kHeaderFields =
static_cast<intptr_t>(HeaderField::ImageHeaderOffset) + 1;
static uword FieldValue(uword raw_memory, HeaderField field) {
return reinterpret_cast<const uword*>(
raw_memory)[static_cast<intptr_t>(field)];
}
// Constants used to denote special values for the offsets in the Image
// object header and the fields of the ImageHeader object.
static constexpr intptr_t kNoImageHeader = 0;
static constexpr intptr_t kNoBssSection = 0;
static constexpr intptr_t kNoRelocatedAddress = 0;
static constexpr intptr_t kNoBuildId = 0;
// The size of the Image object header.
//
// Note: Image::kHeaderSize is _not_ an architecture-dependent constant,
// and so there is no compiler::target::Image::kHeaderSize.
static constexpr intptr_t kHeaderSize = kMaxObjectAlignment;
// Explicitly double-checking kHeaderSize is never changed. Increasing the
// Image header size would mean objects would not start at a place expected
// by parts of the VM (like the GC) that use Image pages as HeapPages.
static_assert(kHeaderSize == kMaxObjectAlignment,
"Image page cannot be used as HeapPage");
// Make sure that the number of fields in the Image header fit both on the
// host and target architectures.
static_assert(kHeaderFields * kWordSize <= kHeaderSize,
"Too many fields in Image header for host architecture");
static_assert(kHeaderFields * compiler::target::kWordSize <= kHeaderSize,
"Too many fields in Image header for target architecture");
// Determines how many bits we have for encoding any extra information in
// the BSS offset.
static constexpr intptr_t kBssAlignment = compiler::target::kWordSize;
// We don't use a handle or the tagged pointer because this object cannot be
// moved in memory by the GC.
static const ImageHeaderLayout* ExtraInfo(const uword raw_memory,
const uword size);
const void* raw_memory_; // The symbol kInstructionsSnapshot.
// Most internal uses would cast this to uword, so just store it as such.
const uword raw_memory_;
const intptr_t snapshot_size_;
const ImageHeaderLayout* const extra_info_;
// For access to private constants.
friend class AssemblyImageWriter;
friend class BlobImageWriter;
friend class ImageWriter;
friend class Elf;
DISALLOW_COPY_AND_ASSIGN(Image);
};
@@ -178,12 +231,35 @@ class ImageWriter : public ValueObject {
explicit ImageWriter(Thread* thread);
virtual ~ImageWriter() {}
// Alignment constants used in writing ELF or assembly snapshots.
// BSS sections contain word-sized data.
static constexpr intptr_t kBssAlignment = compiler::target::kWordSize;
// ROData sections contain objects wrapped in an Image object.
static constexpr intptr_t kRODataAlignment = kMaxObjectAlignment;
// Text sections contain objects (even in bare instructions mode) wrapped
// in an Image object, and for now we also align them to the same page
// size assumed by Elf objects.
static_assert(Elf::kPageSize >= kMaxObjectAlignment,
"Page alignment must be consistent with max object alignment");
static constexpr intptr_t kTextAlignment = Elf::kPageSize;
void ResetOffsets() {
next_data_offset_ = Image::kHeaderSize;
next_text_offset_ = Image::kHeaderSize;
if (FLAG_use_bare_instructions && FLAG_precompiled_mode) {
next_text_offset_ += compiler::target::InstructionsSection::HeaderSize();
#if defined(DART_PRECOMPILER)
if (FLAG_precompiled_mode) {
// We reserve space for the initial ImageHeader object. It is manually
// serialized since it involves offsets to other parts of the snapshot.
next_text_offset_ += compiler::target::ImageHeader::InstanceSize();
if (FLAG_use_bare_instructions) {
// For bare instructions mode, we wrap all the instruction payloads
// in a single InstructionsSection object.
next_text_offset_ +=
compiler::target::InstructionsSection::HeaderSize();
}
}
#endif
objects_.Clear();
instructions_.Clear();
}
@@ -254,8 +330,9 @@ class ImageWriter : public ValueObject {
static const char* TagObjectTypeAsReadOnly(Zone* zone, const char* type);
protected:
void WriteROData(WriteStream* stream);
virtual void WriteText(WriteStream* clustered_stream, bool vm) = 0;
virtual void WriteBss(bool vm) = 0;
virtual void WriteROData(WriteStream* clustered_stream, bool vm);
virtual void WriteText(bool vm) = 0;
void DumpInstructionStats();
void DumpInstructionsSizes();
@@ -309,6 +386,8 @@ class ImageWriter : public ValueObject {
V8SnapshotProfileWriter::IdSpace offset_space_ =
V8SnapshotProfileWriter::kSnapshot;
V8SnapshotProfileWriter* profile_writer_ = nullptr;
const char* const image_type_;
const char* const image_header_type_;
const char* const instructions_section_type_;
const char* const instructions_type_;
const char* const trampoline_type_;
@@ -337,14 +416,13 @@ class TraceImageObjectScope {
stream_(ASSERT_NOTNULL(stream)),
section_offset_(section_offset),
start_offset_(stream_->Position() - section_offset),
object_(object) {}
object_type_(writer->ObjectTypeForProfile(object)) {}
~TraceImageObjectScope() {
if (writer_->profile_writer_ == nullptr) return;
ASSERT(writer_->IsROSpace());
writer_->profile_writer_->SetObjectTypeAndName(
{writer_->offset_space_, start_offset_},
writer_->ObjectTypeForProfile(object_), nullptr);
{writer_->offset_space_, start_offset_}, object_type_, nullptr);
writer_->profile_writer_->AttributeBytesTo(
{writer_->offset_space_, start_offset_},
stream_->Position() - section_offset_ - start_offset_);
@@ -355,7 +433,7 @@ class TraceImageObjectScope {
const T* const stream_;
const intptr_t section_offset_;
const intptr_t start_offset_;
const Object& object_;
const char* const object_type_;
};
class SnapshotTextObjectNamer {
@@ -391,9 +469,11 @@ class AssemblyImageWriter : public ImageWriter {
Elf* debug_elf = nullptr);
void Finalize();
virtual void WriteText(WriteStream* clustered_stream, bool vm);
private:
virtual void WriteBss(bool vm);
virtual void WriteROData(WriteStream* clustered_stream, bool vm);
virtual void WriteText(bool vm);
void FrameUnwindPrologue();
void FrameUnwindEpilogue();
intptr_t WriteByteSequence(uword start, uword end);
@@ -431,13 +511,15 @@ class BlobImageWriter : public ImageWriter {
Elf* debug_elf = nullptr,
Elf* elf = nullptr);
virtual void WriteText(WriteStream* clustered_stream, bool vm);
intptr_t InstructionsBlobSize() const {
return instructions_blob_stream_.bytes_written();
}
private:
virtual void WriteBss(bool vm);
virtual void WriteROData(WriteStream* clustered_stream, bool vm);
virtual void WriteText(bool vm);
intptr_t WriteByteSequence(uword start, uword end);
WriteStream instructions_blob_stream_;
+26 -21
View File
@@ -16051,6 +16051,10 @@ ICDataPtr ICData::Clone(const ICData& from) {
}
#endif
const char* ImageHeader::ToCString() const {
return "ImageHeader";
}
const char* WeakSerializationReference::ToCString() const {
#if defined(DART_PRECOMPILED_RUNTIME)
return Symbols::OptimizedOut().ToCString();
@@ -24400,8 +24404,7 @@ StackTracePtr StackTrace::New(const Array& code_array,
static void PrintNonSymbolicStackFrameBody(BaseTextBuffer* buffer,
uword call_addr,
uword isolate_instructions,
uword vm_instructions,
uword isolate_relocated_address) {
uword vm_instructions) {
const Image vm_image(reinterpret_cast<const void*>(vm_instructions));
const Image isolate_image(
reinterpret_cast<const void*>(isolate_instructions));
@@ -24412,7 +24415,9 @@ static void PrintNonSymbolicStackFrameBody(BaseTextBuffer* buffer,
// Only print the relocated address of the call when we know the saved
// debugging information (if any) will have the same relocated address.
if (isolate_image.compiled_to_elf()) {
buffer->Printf(" virt %" Pp "", isolate_relocated_address + offset);
const uword relocated_section_start =
isolate_image.instructions_relocated_address();
buffer->Printf(" virt %" Pp "", relocated_section_start + offset);
}
buffer->Printf(" %s+0x%" Px "", symbol_name, offset);
} else if (vm_image.contains(call_addr)) {
@@ -24484,16 +24489,6 @@ static void PrintSymbolicStackFrame(Zone* zone,
PrintSymbolicStackFrameBody(buffer, function_name, url, line, column);
}
// Find the relocated base of the given instructions section.
uword InstructionsRelocatedAddress(uword instructions_start) {
Image image(reinterpret_cast<const uint8_t*>(instructions_start));
auto const bss_start =
reinterpret_cast<const uword*>(instructions_start + image.bss_offset());
auto const index =
BSS::RelocationIndex(BSS::Relocation::InstructionsRelocatedAddress);
return bss_start[index];
}
const char* StackTrace::ToCString() const {
auto const T = Thread::Current();
auto const zone = T->zone();
@@ -24512,11 +24507,15 @@ const char* StackTrace::ToCString() const {
T->isolate_group()->source()->snapshot_instructions);
auto const vm_instructions = reinterpret_cast<uword>(
Dart::vm_isolate()->group()->source()->snapshot_instructions);
auto const vm_relocated_address =
InstructionsRelocatedAddress(vm_instructions);
auto const isolate_relocated_address =
InstructionsRelocatedAddress(isolate_instructions);
if (FLAG_dwarf_stack_traces_mode) {
const Image isolate_instructions_image(
reinterpret_cast<const void*>(isolate_instructions));
const Image vm_instructions_image(
reinterpret_cast<const void*>(vm_instructions));
auto const isolate_relocated_address =
isolate_instructions_image.instructions_relocated_address();
auto const vm_relocated_address =
vm_instructions_image.instructions_relocated_address();
// The Dart standard requires the output of StackTrace.toString to include
// all pending activations with precise source locations (i.e., to expand
// inlined frames and provide line and column numbers).
@@ -24530,6 +24529,14 @@ const char* StackTrace::ToCString() const {
OSThread* thread = OSThread::Current();
buffer.Printf("pid: %" Pd ", tid: %" Pd ", name %s\n", OS::ProcessId(),
OSThread::ThreadIdToIntPtr(thread->id()), thread->name());
if (auto const build_id = isolate_instructions_image.build_id()) {
const intptr_t length = isolate_instructions_image.build_id_length();
buffer.Printf("build_id: '");
for (intptr_t i = 0; i < length; i++) {
buffer.Printf("%02.2x", build_id[i]);
}
buffer.Printf("'\n");
}
// Print the dso_base of the VM and isolate_instructions. We print both here
// as the VM and isolate may be loaded from different snapshot images.
buffer.Printf("isolate_dso_base: %" Px "",
@@ -24591,8 +24598,7 @@ const char* StackTrace::ToCString() const {
// prints call addresses instead of return addresses.
buffer.Printf(" #%02" Pd " abs %" Pp "", frame_index, call_addr);
PrintNonSymbolicStackFrameBody(
&buffer, call_addr, isolate_instructions, vm_instructions,
isolate_relocated_address);
&buffer, call_addr, isolate_instructions, vm_instructions);
frame_index++;
continue;
} else if (function.IsNull()) {
@@ -24601,8 +24607,7 @@ const char* StackTrace::ToCString() const {
// non-symbolic stack traces.
PrintSymbolicStackFrameIndex(&buffer, frame_index);
PrintNonSymbolicStackFrameBody(
&buffer, call_addr, isolate_instructions, vm_instructions,
isolate_relocated_address);
&buffer, call_addr, isolate_instructions, vm_instructions);
frame_index++;
continue;
}
+20
View File
@@ -5959,6 +5959,26 @@ class ExceptionHandlers : public Object {
friend class Object;
};
// An ImageHeader contains extra information about serialized AOT snapshots.
//
// To avoid changing the embedder to return more information about an AOT
// snapshot and possibly disturbing existing clients of that interface, we
// serialize a single ImageHeader object at the start of any text segments.
class ImageHeader : public Object {
public:
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(ImageHeaderLayout));
}
// There are no public methods for the ImageHeader contents, because
// all access to the contents is handled by methods on the Image class.
private:
// Note there are no New() methods for ImageHeaders. Unstead, the serializer
// writes the ImageHeaderLayout object manually at the start of the text
// segment in precompiled snapshots.
FINAL_HEAP_OBJECT_IMPLEMENTATION(ImageHeader, Object);
};
// A WeakSerializationReference (WSR) denotes a type of weak reference to a
// target object. In particular, objects that can only be reached from roots via
// WSR edges during serialization of AOT snapshots should not be serialized. Of
+4
View File
@@ -684,6 +684,10 @@ void InstructionsSection::PrintJSONImpl(JSONStream* stream, bool ref) const {
Object::PrintJSONImpl(stream, ref);
}
void ImageHeader::PrintJSONImpl(JSONStream* stream, bool ref) const {
Object::PrintJSONImpl(stream, ref);
}
void WeakSerializationReference::PrintJSONImpl(JSONStream* stream,
bool ref) const {
JSONObject jsobj(stream);
+5
View File
@@ -223,6 +223,10 @@ intptr_t ObjectLayout::HeapSizeFromClass(uint32_t tags) const {
instance_size = element->HeapSize();
break;
}
case kImageHeaderCid: {
instance_size = ImageHeader::InstanceSize();
break;
}
case kWeakSerializationReferenceCid: {
instance_size = WeakSerializationReference::InstanceSize();
break;
@@ -564,6 +568,7 @@ NULL_VISITOR(Bool)
NULL_VISITOR(Capability)
NULL_VISITOR(SendPort)
NULL_VISITOR(TransferableTypedData)
NULL_VISITOR(ImageHeader)
REGULAR_VISITOR(Pointer)
NULL_VISITOR(DynamicLibrary)
VARIABLE_NULL_VISITOR(Instructions, Instructions::Size(raw_obj))
+19
View File
@@ -1404,6 +1404,25 @@ class KernelProgramInfoLayout : public ObjectLayout {
}
};
class ImageHeaderLayout : public ObjectLayout {
RAW_HEAP_OBJECT_IMPLEMENTATION(ImageHeader);
VISIT_NOTHING();
// The offset of the corresponding BSS section from this text section.
uword bss_offset_;
// The relocated address of this text section in the shared object. Properly
// filled for ELF snapshots, always 0 in assembly snapshots. (For the latter,
// we instead get the value during BSS initialization and store it there.)
uword instructions_relocated_address_;
// The offset of the GNU build ID section description field from this text
// section.
uword build_id_offset_;
// The length of the GNU build ID section description field.
uword build_id_length_;
friend class Image;
};
class WeakSerializationReferenceLayout : public ObjectLayout {
RAW_HEAP_OBJECT_IMPLEMENTATION(WeakSerializationReference);
+1
View File
@@ -582,6 +582,7 @@ MESSAGE_SNAPSHOT_UNREACHABLE(MonomorphicSmiableCall);
MESSAGE_SNAPSHOT_UNREACHABLE(UnwindError);
MESSAGE_SNAPSHOT_UNREACHABLE(FutureOr);
MESSAGE_SNAPSHOT_UNREACHABLE(WeakSerializationReference);
MESSAGE_SNAPSHOT_UNREACHABLE(ImageHeader);
MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary);
MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference);
+1
View File
@@ -242,6 +242,7 @@ DEFINE_TAGGED_POINTER(Script, Object)
DEFINE_TAGGED_POINTER(Library, Object)
DEFINE_TAGGED_POINTER(Namespace, Object)
DEFINE_TAGGED_POINTER(KernelProgramInfo, Object)
DEFINE_TAGGED_POINTER(ImageHeader, Object)
DEFINE_TAGGED_POINTER(WeakSerializationReference, Object)
DEFINE_TAGGED_POINTER(Code, Object)
DEFINE_TAGGED_POINTER(Bytecode, Object)