Reland "[vm] Mark snapshots that were compiled directly to ELF.

Since the virtual addresses in ELF snapshots are the same as in
separately saved debugging information, print the virtual address in
non-symbolic frames again when running from a snapshot compiled directly
to ELF."

Storing the relocated address as an extra field in the Image header,
which requires increasing the Image header size on 64-bit platforms,
means Image pages cannot be used reliably as HeapPages as objects no
longer start after kMaxObjectAlignment bytes.

Instead, we return to an older design that just uses the lowest bit
in the BSS offset to store whether the instructions in an Image were
compiled directly to ELF.

Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-precomp-linux-release-simarm_x64-try,vm-precomp-ffi-qemu-linux-release-arm-try
Change-Id: I3819b0dc2719d69f5e8764ca8be8c6ae7171a7bc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/146560
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
This commit is contained in:
Tess Strickland 2020-05-11 08:41:17 +00:00 committed by commit-bot@chromium.org
parent 9e14e7da2a
commit a6d06b59ec
11 changed files with 223 additions and 62 deletions

View file

@ -1,5 +1,10 @@
# Changelog
## 0.3.5
- Use virtual addresses in non-symbolic stack frames as a fallback if we cannot
retrieve an appropriate offset from the instructions section otherwise.
## 0.3.4
- Decoded Dart calls are now never considered internal, only VM stub calls.

View file

@ -66,7 +66,8 @@ const _symbolOffsetREString = r'(?<symbol>' +
r')\+(?<offset>(?:0x)?[\da-f]+)';
final _symbolOffsetRE = RegExp(_symbolOffsetREString);
final _traceLineRE = RegExp(
r' #(\d{2}) abs (?<address>[\da-f]+)(?: virt ([\da-f]+))? (?<rest>.*)$');
r' #(\d{2}) abs (?<absolute>[\da-f]+)(?: virt (?<virtual>[\da-f]+))? '
r'(?<rest>.*)$');
/// Parses strings of the format <static symbol>+<integer offset>, where
/// <static symbol> is one of the static symbols used for Dart instruction
@ -115,10 +116,19 @@ PCOffset _retrievePCOffset(StackTraceHeader header, RegExpMatch match) {
// If we're parsing the absolute address, we can only convert it into
// a PCOffset if we saw the instructions line of the stack trace header.
if (header != null) {
final addressString = match.namedGroup('address');
final addressString = match.namedGroup('absolute');
final address = int.tryParse(addressString, radix: 16);
return header.offsetOf(address);
}
// If all other cases failed, check for a virtual address. Until this package
// depends on a version of Dart which only prints virtual addresses when the
// virtual addresses in the snapshot are the same as in separately saved
// debugging information, the other methods should be tried first.
final virtualString = match.namedGroup('virtual');
if (virtualString != null) {
final address = int.tryParse(virtualString, radix: 16);
return PCOffset(address, InstructionsSection.none);
}
return null;
}

View file

@ -1106,7 +1106,7 @@ class StubCallInfo extends CallInfo {
}
/// The instructions section in which a program counter address is located.
enum InstructionsSection { vm, isolate }
enum InstructionsSection { none, vm, isolate }
/// A program counter address viewed as an offset into the appropriate
/// instructions section of a Dart snapshot.
@ -1239,6 +1239,9 @@ class Dwarf {
/// The virtual address in this DWARF information for the given [PCOffset].
int virtualAddressOf(PCOffset pcOffset) {
switch (pcOffset.section) {
case InstructionsSection.none:
// This address is already virtualized, so we don't need to change it.
return pcOffset.offset;
case InstructionsSection.vm:
return pcOffset.offset + vmStartAddress;
case InstructionsSection.isolate:

View file

@ -1,6 +1,6 @@
name: native_stack_traces
description: Utilities for working with non-symbolic stack traces.
version: 0.3.4
version: 0.3.5
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/native_stack_traces

View file

@ -106,8 +106,9 @@ main(List<String> args) async {
// For DWARF stack traces, we can't guarantee that the stack traces are
// textually equal on all platforms, but if we retrieve the PC offsets
// out of the stack trace, those should be equal.
Expect.deepEquals(
collectPCOffsets(dwarfTrace1), collectPCOffsets(dwarfTrace2));
final tracePCOffsets1 = collectPCOffsets(dwarfTrace1);
final tracePCOffsets2 = collectPCOffsets(dwarfTrace2);
Expect.deepEquals(tracePCOffsets1, tracePCOffsets2);
// Check that translating the DWARF stack trace (without internal frames)
// matches the symbolic stack trace.
@ -132,6 +133,17 @@ main(List<String> args) async {
Expect.isTrue(originalStackFrames.length > 0);
Expect.deepEquals(translatedStackFrames, originalStackFrames);
// Since we compiled directly to ELF, there should be 'virt' markers in the
// stack traces. Make sure the address following the marker matches the
// relocated address calculated from the PCOffset for each frame.
final virtTrace1 = explicitVirtualAddresses(dwarfTrace1);
final virtTrace2 = explicitVirtualAddresses(dwarfTrace2);
Expect.deepEquals(
virtTrace1, tracePCOffsets1.map((o) => o.virtualAddressIn(dwarf)));
Expect.deepEquals(
virtTrace2, tracePCOffsets2.map((o) => o.virtualAddressIn(dwarf)));
});
}
@ -140,3 +152,14 @@ final _symbolicFrameRE = RegExp(r'^#\d+\s+');
Iterable<String> onlySymbolicFrameLines(Iterable<String> lines) {
return lines.where((line) => _symbolicFrameRE.hasMatch(line));
}
final _virtRE = RegExp(r'virt ([a-f\d]+)');
Iterable<int> explicitVirtualAddresses(Iterable<String> lines) sync* {
for (final line in lines) {
final match = _virtRE.firstMatch(line);
if (match != null) {
yield int.parse(match.group(1), radix: 16);
}
}
}

View file

@ -6565,9 +6565,9 @@ Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback,
&vm_image_writer, &isolate_image_writer);
writer.WriteFullSnapshot();
elf->AddROData("_kDartVmSnapshotData", vm_snapshot_data_buffer,
elf->AddROData(kVmSnapshotDataAsmSymbol, vm_snapshot_data_buffer,
writer.VmIsolateSnapshotSize());
elf->AddROData("_kDartIsolateSnapshotData", isolate_snapshot_data_buffer,
elf->AddROData(kIsolateSnapshotDataAsmSymbol, isolate_snapshot_data_buffer,
writer.IsolateSnapshotSize());
if (elf_dwarf != nullptr) {

View file

@ -7,6 +7,7 @@
#include "platform/elf.h"
#include "vm/cpu.h"
#include "vm/hash_map.h"
#include "vm/image_snapshot.h"
#include "vm/thread.h"
#include "vm/zone_text_buffer.h"
@ -640,6 +641,21 @@ Elf::Elf(Zone* zone, StreamingWriteStream* stream)
AddSection(shstrtab_, ".shstrtab");
}
// The VM segment comes after the program header segment and BSS segments,
// both of which are a single page.
static constexpr uword kVmSnapshotOffset = 2 * Elf::kPageSize;
// Find the relocated base of the loaded ELF snapshot. Returns 0 if there is
// no loaded ELF snapshot.
uword Elf::SnapshotRelocatedBaseAddress(uword vm_start) {
ASSERT(vm_start > kVmSnapshotOffset);
const Image vm_instructions_image(reinterpret_cast<const void*>(vm_start));
if (!vm_instructions_image.compiled_to_elf()) return 0;
return vm_start - kVmSnapshotOffset;
}
void Elf::AddSection(Section* section, const char* name) {
ASSERT(section_table_file_size_ < 0);
ASSERT(!shstrtab_->HasBeenFinalized());
@ -736,6 +752,9 @@ intptr_t Elf::AddBSSData(const char* name, intptr_t size) {
ProgramBits* const image =
new (zone_) ProgramBits(true, false, true, bytes, size);
static_assert(Image::kBssAlignment <= kPageSize,
"ELF .bss section is not aligned as expected by Image class");
ASSERT_EQUAL(image->alignment, kPageSize);
AddSection(image, ".bss");
return AddSectionSymbol(image, name, size);
@ -779,6 +798,8 @@ void Elf::Finalize() {
FinalizeProgramTable();
ComputeFileOffsets();
ASSERT(VerifySegmentOrder());
// Finally, write the ELF file contents.
WriteHeader();
WriteProgramTable();
@ -844,6 +865,63 @@ void Elf::ComputeFileOffsets() {
file_offset += section_table_file_size_;
}
bool Elf::VerifySegmentOrder() {
// We can only verify the segment order after FinalizeProgramTable(), since
// we assume that all segments have been added, including the two program
// table segments.
ASSERT(program_table_file_size_ > 0);
// Find the names and symbols for the .bss and .text segments.
auto const bss_section_name = shstrtab_->Lookup(".bss");
// For separate debugging information for assembly snapshots, no .bss section
// is added. However, we're only interested in strict segment orders when
// generating ELF snapshots, so only continue when there's a .bss section.
if (bss_section_name == -1) return true;
auto const text_section_name = shstrtab_->Lookup(".text");
ASSERT(text_section_name != -1);
auto const bss_symbol_name = dynstrtab_->Lookup("_kDartBSSData");
auto const vm_symbol_name =
dynstrtab_->Lookup(kVmSnapshotInstructionsAsmSymbol);
auto const isolate_symbol_name =
dynstrtab_->Lookup(kIsolateSnapshotInstructionsAsmSymbol);
ASSERT(bss_symbol_name != -1);
ASSERT(vm_symbol_name != -1);
ASSERT(isolate_symbol_name != -1);
auto const bss_symbol = dynsym_->FindSymbolWithNameIndex(bss_symbol_name);
auto const vm_symbol = dynsym_->FindSymbolWithNameIndex(vm_symbol_name);
auto const isolate_symbol =
dynsym_->FindSymbolWithNameIndex(isolate_symbol_name);
ASSERT(bss_symbol != nullptr);
ASSERT(vm_symbol != nullptr);
ASSERT(isolate_symbol != nullptr);
// Check that the first non-program table segments are in the expected order.
auto const bss_segment = segments_[2];
ASSERT_EQUAL(bss_segment->segment_type, elf::PT_LOAD);
ASSERT_EQUAL(bss_segment->section_name(), bss_section_name);
ASSERT_EQUAL(bss_segment->memory_offset(), bss_symbol->offset);
ASSERT_EQUAL(bss_segment->MemorySize(), bss_symbol->size);
auto const vm_segment = segments_[3];
ASSERT_EQUAL(vm_segment->segment_type, elf::PT_LOAD);
ASSERT_EQUAL(vm_segment->section_name(), text_section_name);
ASSERT_EQUAL(vm_segment->memory_offset(), vm_symbol->offset);
ASSERT_EQUAL(vm_segment->MemorySize(), vm_symbol->size);
auto const isolate_segment = segments_[4];
ASSERT_EQUAL(isolate_segment->segment_type, elf::PT_LOAD);
ASSERT_EQUAL(isolate_segment->section_name(), text_section_name);
ASSERT_EQUAL(isolate_segment->memory_offset(), isolate_symbol->offset);
ASSERT_EQUAL(isolate_segment->MemorySize(), isolate_symbol->size);
// Also make sure that the memory offset of the VM segment is as expected.
ASSERT_EQUAL(bss_segment->memory_offset(), kPageSize);
ASSERT(bss_segment->MemorySize() <= kPageSize);
ASSERT_EQUAL(vm_segment->memory_offset(), kVmSnapshotOffset);
return true;
}
void Elf::WriteHeader() {
#if defined(TARGET_ARCH_IS_32_BIT)
uint8_t size = elf::ELFCLASS32;

View file

@ -26,6 +26,12 @@ class Elf : public ZoneAllocated {
static const intptr_t kPageSize = 4096;
// Used by the non-symbolic stack frame printer to calculate the relocated
// base address of the loaded ELF snapshot given the start of the VM
// instructions. Only works for ELF snapshots written by Dart, not those
// compiled from assembly.
static uword SnapshotRelocatedBaseAddress(uword vm_start);
intptr_t NextMemoryOffset() const { return memory_offset_; }
intptr_t NextSectionIndex() const { return sections_.length(); }
intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size);
@ -78,6 +84,8 @@ class Elf : public ZoneAllocated {
void FinalizeProgramTable();
void ComputeFileOffsets();
bool VerifySegmentOrder();
void WriteHeader();
void WriteSectionTable();
void WriteProgramTable();

View file

@ -416,9 +416,8 @@ void ImageWriter::WriteROData(WriteStream* stream) {
intptr_t section_start = stream->Position();
stream->WriteWord(next_data_offset_); // Data length.
COMPILE_ASSERT(kMaxObjectAlignment >= kObjectAlignment);
// Zero values for other image header fields.
stream->Align(kMaxObjectAlignment);
ASSERT(stream->Position() - section_start == Image::kHeaderSize);
// Heap page objects start here.
@ -640,33 +639,35 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
// Start snapshot at page boundary.
ASSERT(VirtualMemory::PageSize() >= kMaxObjectAlignment);
ASSERT(VirtualMemory::PageSize() >= Image::kBssAlignment);
Align(VirtualMemory::PageSize());
assembly_stream_.Print("%s:\n", instructions_symbol);
intptr_t text_offset = 0;
// This head also provides the gap to make the instructions snapshot
// look like a OldPage.
const intptr_t image_size = Utils::RoundUp(
next_text_offset_, compiler::target::ObjectAlignment::kObjectAlignment);
WriteWordLiteralText(image_size);
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
WriteWordLiteralText(0); // No relocations.
text_offset += WriteWordLiteralText(0); // No relocations.
#endif
intptr_t header_words = Image::kHeaderSize / sizeof(compiler::target::uword);
for (intptr_t i = Image::kHeaderFields; i < header_words; i++) {
WriteWordLiteralText(0);
}
text_offset += Align(kMaxObjectAlignment, text_offset);
ASSERT_EQUAL(text_offset, Image::kHeaderSize);
// Only valid if bare_instruction_payloads is true.
const V8SnapshotProfileWriter::ObjectId instructions_section_id(
offset_space_, bare_instruction_payloads ? Image::kHeaderSize : -1);
V8SnapshotProfileWriter::ObjectId instructions_section_id(offset_space_, -1);
if (bare_instruction_payloads) {
const intptr_t section_size = image_size - Image::kHeaderSize;
const intptr_t instructions_section_start = text_offset;
const intptr_t section_size = image_size - instructions_section_start;
// Add the RawInstructionsSection header.
const compiler::target::uword marked_tags =
ObjectLayout::OldBit::encode(true) |
@ -675,15 +676,15 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
ObjectLayout::NewBit::encode(false) |
ObjectLayout::SizeTag::encode(AdjustObjectSizeForTarget(section_size)) |
ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
WriteWordLiteralText(marked_tags);
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_ - Image::kHeaderSize -
compiler::target::InstructionsSection::HeaderSize();
WriteWordLiteralText(instructions_length);
next_text_offset_ - (text_offset + compiler::target::kWordSize);
text_offset += WriteWordLiteralText(instructions_length);
if (profile_writer_ != nullptr) {
instructions_section_id = {offset_space_, instructions_section_start};
const intptr_t non_instruction_bytes =
compiler::target::InstructionsSection::HeaderSize();
profile_writer_->SetObjectTypeAndName(instructions_section_id,
@ -695,23 +696,18 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
}
}
const intptr_t section_headers_size =
Image::kHeaderSize +
(bare_instruction_payloads
? compiler::target::InstructionsSection::HeaderSize()
: 0);
const intptr_t instructions_start = text_offset;
FrameUnwindPrologue();
PcDescriptors& descriptors = PcDescriptors::Handle(zone);
SnapshotTextObjectNamer namer(zone);
intptr_t text_offset = 0;
ASSERT(offset_space_ != V8SnapshotProfileWriter::kSnapshot);
for (intptr_t i = 0; i < instructions_.length(); i++) {
auto& data = instructions_[i];
const bool is_trampoline = data.trampoline_bytes != nullptr;
ASSERT((data.text_offset_ - instructions_[0].text_offset_) == text_offset);
ASSERT_EQUAL(data.text_offset_, text_offset);
intptr_t dwarf_index = i;
#if defined(DART_PRECOMPILER)
@ -723,21 +719,19 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
const auto object_name = namer.SnapshotNameFor(dwarf_index, data);
if (profile_writer_ != nullptr) {
const auto object_offset = section_headers_size + text_offset;
const V8SnapshotProfileWriter::ObjectId object_id(offset_space_,
object_offset);
const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
auto const type = is_trampoline ? trampoline_type_ : instructions_type_;
const intptr_t size = is_trampoline ? data.trampoline_length
: SizeInSnapshot(data.insns_->raw());
profile_writer_->SetObjectTypeAndName(object_id, type, object_name);
profile_writer_->AttributeBytesTo(object_id, size);
profile_writer_->SetObjectTypeAndName(id, type, object_name);
profile_writer_->AttributeBytesTo(id, size);
// If the object is wrapped in an InstructionSection, then add an
// element reference.
if (bare_instruction_payloads) {
const intptr_t element_offset = text_offset - instructions_start;
profile_writer_->AttributeReferenceTo(
instructions_section_id,
{object_id, V8SnapshotProfileWriter::Reference::kElement,
text_offset});
{id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
}
}
@ -799,8 +793,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
#if defined(DART_PRECOMPILER)
if (debug_dwarf_ != nullptr) {
auto const payload_offset = section_headers_size + text_offset;
debug_dwarf_->AddCode(code, object_name, payload_offset);
debug_dwarf_->AddCode(code, object_name, text_offset);
}
#endif
// 2. Write a label at the entry point.
@ -837,14 +830,14 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
if ((cursor - payload_start) == next_reloc_offset) {
assembly_stream_.Print("%s %s - (.) + %" Pd "\n", kLiteralPrefix,
bss_symbol, /*addend=*/data);
text_offset += compiler::target::kWordSize;
next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1;
} else {
WriteWordLiteralText(data);
text_offset += WriteWordLiteralText(data);
}
}
assert(next_reloc_offset != (possible_relocations_end - payload_start));
WriteByteSequence(possible_relocations_end, payload_end);
text_offset += payload_size;
text_offset += WriteByteSequence(possible_relocations_end, payload_end);
#else
text_offset += WriteByteSequence(payload_start, payload_end);
#endif
@ -862,9 +855,8 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
compiler::target::ObjectAlignment::kObjectAlignment) -
unaligned_size;
while (alignment_size > 0) {
WriteWordLiteralText(kBreakInstructionFiller);
text_offset += WriteWordLiteralText(kBreakInstructionFiller);
alignment_size -= sizeof(compiler::target::uword);
text_offset += sizeof(compiler::target::uword);
}
ASSERT(kWordSize != compiler::target::kWordSize ||
@ -881,7 +873,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
text_offset +=
Align(compiler::target::ObjectAlignment::kObjectAlignment, text_offset);
ASSERT_EQUAL(section_headers_size + text_offset, image_size);
ASSERT_EQUAL(text_offset, image_size);
FrameUnwindEpilogue();
@ -902,15 +894,16 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
// Since we don't want to add the actual contents of the segment in the
// separate debugging information, we pass nullptr for the bytes, which
// creates an appropriate NOBITS section instead of PROGBITS.
auto const debug_segment_base2 =
debug_dwarf_->elf()->AddText(instructions_symbol, /*bytes=*/nullptr,
section_headers_size + text_offset);
auto const debug_segment_base2 = debug_dwarf_->elf()->AddText(
instructions_symbol, /*bytes=*/nullptr, text_offset);
// Double-check that no other ELF sections were added in the middle of
// 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.
assembly_stream_.Align(Image::kBssAlignment);
assembly_stream_.Print("%s:\n", bss_symbol);
// Currently we only put one symbol in the data section, the address of
@ -929,7 +922,7 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
#endif
const char* data_symbol =
vm ? "_kDartVmSnapshotData" : "_kDartIsolateSnapshotData";
vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
assembly_stream_.Print(".globl %s\n", data_symbol);
Align(kMaxObjectAlignment);
assembly_stream_.Print("%s:\n", data_symbol);
@ -1101,16 +1094,16 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
next_text_offset_, compiler::target::ObjectAlignment::kObjectAlignment);
instructions_blob_stream_.WriteTargetWord(image_size);
#if defined(DART_PRECOMPILER)
instructions_blob_stream_.WriteTargetWord(
elf_ != nullptr ? bss_base_ - segment_base : 0);
// Store the offset of the BSS section from the instructions section here.
// The lowest bit is set to indicate we compiled directly to ELF.
const word bss_offset = bss_base_ - segment_base;
ASSERT_EQUAL(Utils::RoundDown(bss_offset, Image::kBssAlignment), bss_offset);
instructions_blob_stream_.WriteTargetWord(bss_offset | 0x1);
#else
instructions_blob_stream_.WriteTargetWord(0); // No relocations.
#endif
const intptr_t header_words =
Image::kHeaderSize / sizeof(compiler::target::uword);
for (intptr_t i = Image::kHeaderFields; i < header_words; i++) {
instructions_blob_stream_.WriteTargetWord(0);
}
instructions_blob_stream_.Align(kMaxObjectAlignment);
ASSERT_EQUAL(instructions_blob_stream_.Position(), Image::kHeaderSize);
// Only valid when bare_instructions_payloads is true.
const V8SnapshotProfileWriter::ObjectId instructions_section_id(

View file

@ -9,6 +9,7 @@
#include <utility>
#include "platform/assert.h"
#include "platform/utils.h"
#include "vm/allocation.h"
#include "vm/compiler/runtime_api.h"
#include "vm/datastream.h"
@ -45,17 +46,41 @@ class Image : ValueObject {
return snapshot_size - kHeaderSize;
}
uword bss_offset() const {
return *(reinterpret_cast<const uword*>(raw_memory_) + 1);
// 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);
}
static constexpr intptr_t kHeaderFields = 2;
static constexpr intptr_t kHeaderSize = kMaxObjectAlignment;
COMPILE_ASSERT((kHeaderFields * compiler::target::kWordSize) <= kHeaderSize);
// 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;
}
private:
static constexpr intptr_t kHeaderFields = 2;
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");
// Determines how many bits we have for encoding any extra information in
// the BSS offset.
static constexpr intptr_t kBssAlignment = compiler::target::kWordSize;
const void* raw_memory_; // The symbol kInstructionsSnapshot.
// For access to private constants.
friend class AssemblyImageWriter;
friend class BlobImageWriter;
friend class ImageWriter;
friend class Elf;
DISALLOW_COPY_AND_ASSIGN(Image);
};
@ -375,13 +400,14 @@ class AssemblyImageWriter : public ImageWriter {
const char* kLiteralPrefix = ".long";
#endif
void WriteWordLiteralText(compiler::target::uword value) {
intptr_t WriteWordLiteralText(compiler::target::uword value) {
// Padding is helpful for comparing the .S with --disassemble.
#if defined(TARGET_ARCH_IS_64_BIT)
assembly_stream_.Print(".quad 0x%0.16" Px "\n", value);
#else
assembly_stream_.Print(".long 0x%0.8" Px "\n", value);
#endif
return compiler::target::kWordSize;
}
StreamingWriteStream assembly_stream_;

View file

@ -27,6 +27,7 @@
#include "vm/debugger.h"
#include "vm/deopt_instructions.h"
#include "vm/double_conversion.h"
#include "vm/elf.h"
#include "vm/exceptions.h"
#include "vm/growable_array.h"
#include "vm/hash.h"
@ -23589,17 +23590,31 @@ StackTracePtr StackTrace::New(const Array& code_array,
}
#if defined(DART_PRECOMPILED_RUNTIME)
// Prints the best representation(s) for the call address.
static void PrintNonSymbolicStackFrameBody(ZoneTextBuffer* buffer,
uword call_addr,
uword isolate_instructions,
uword vm_instructions) {
const word vm_offset = call_addr - vm_instructions;
const word isolate_offset = call_addr - isolate_instructions;
// If the VM instructions image was compiled directly to ELF, we can determine
// the base address of the snapshot shared object from the section start.
const uword snapshot_base =
Elf::SnapshotRelocatedBaseAddress(vm_instructions);
// Pick the closest instructions section start before the call address.
if (vm_offset > 0 && (isolate_offset < 0 || vm_offset < isolate_offset)) {
if (snapshot_base != 0) {
const uword relocated_section = vm_instructions - snapshot_base;
buffer->Printf(" virt %" Pp "", relocated_section + vm_offset);
}
buffer->Printf(" %s+0x%" Px "", kVmSnapshotInstructionsAsmSymbol,
vm_offset);
} else if (isolate_offset > 0) {
if (snapshot_base != 0) {
const uword relocated_section = isolate_instructions - snapshot_base;
buffer->Printf(" virt %" Pp "", relocated_section + isolate_offset);
}
buffer->Printf(" %s+0x%" Px "", kIsolateSnapshotInstructionsAsmSymbol,
isolate_offset);
} else {