[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.

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
Change-Id: Ie531953da7edd024cea02c0571e1e1dd7d7427eb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/145840
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
This commit is contained in:
Tess Strickland 2020-05-04 09:19:23 +00:00 committed by commit-bot@chromium.org
parent 645f3acca7
commit 250b84987d
8 changed files with 65 additions and 10 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

@ -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

@ -408,6 +408,9 @@ void ImageWriter::WriteROData(WriteStream* stream) {
intptr_t section_start = stream->Position();
stream->WriteWord(next_data_offset_); // Data length.
for (intptr_t i = 1; i < Image::kHeaderFields; i++) {
stream->WriteWord(0); // Zero values for other image header fields.
}
COMPILE_ASSERT(kMaxObjectAlignment >= kObjectAlignment);
stream->Align(kMaxObjectAlignment);
@ -648,6 +651,8 @@ void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
WriteWordLiteralText(0); // No relocations.
#endif
WriteWordLiteralText(0); // Not compiling directly to ELF.
intptr_t header_words = Image::kHeaderSize / sizeof(compiler::target::uword);
for (intptr_t i = Image::kHeaderFields; i < header_words; i++) {
WriteWordLiteralText(0);
@ -921,7 +926,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);
@ -1095,8 +1100,11 @@ void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
#if defined(DART_PRECOMPILER)
instructions_blob_stream_.WriteTargetWord(
elf_ != nullptr ? bss_base_ - segment_base : 0);
// Store the virtual address of the instructions section here.
instructions_blob_stream_.WriteTargetWord(segment_base);
#else
instructions_blob_stream_.WriteTargetWord(0); // No relocations.
instructions_blob_stream_.WriteTargetWord(0); // Not an ELF snapshot.
#endif
const intptr_t header_words =
Image::kHeaderSize / sizeof(compiler::target::uword);

View file

@ -45,13 +45,23 @@ class Image : ValueObject {
return snapshot_size - kHeaderSize;
}
// The following method only has meaning for instructions images.
uword bss_offset() const {
return *(reinterpret_cast<const uword*>(raw_memory_) + 1);
}
static constexpr intptr_t kHeaderFields = 2;
static constexpr intptr_t kHeaderSize = kMaxObjectAlignment;
COMPILE_ASSERT((kHeaderFields * compiler::target::kWordSize) <= kHeaderSize);
// For instructions images that were compiled directly to ELF, returns the
// virtual address of the instructions section, otherwise returns 0.
uword virtual_address() const {
return *(reinterpret_cast<const uword*>(raw_memory_) + 2);
}
static constexpr intptr_t kHeaderFields = 3;
static constexpr intptr_t kUnalignedHeaderSize =
kHeaderFields * compiler::target::kWordSize;
// Can't use Utils::RoundUp because of ASSERT() in Utils::RoundDown.
static constexpr intptr_t kHeaderSize =
(kUnalignedHeaderSize + kMaxObjectAlignment - 1) & -kMaxObjectAlignment;
private:
const void* raw_memory_; // The symbol kInstructionsSnapshot.

View file

@ -23480,6 +23480,7 @@ 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,
@ -23488,9 +23489,27 @@ static void PrintNonSymbolicStackFrameBody(ZoneTextBuffer* buffer,
const word isolate_offset = call_addr - isolate_instructions;
// Pick the closest instructions section start before the call address.
if (vm_offset > 0 && (isolate_offset < 0 || vm_offset < isolate_offset)) {
// If this VM image was compiled directly to ELF, then print the virtual
// address of the call address, since the virtual addresses will match
// those in any separately saved debugging information.
const Image vm_instructions_image(
reinterpret_cast<const uword*>(vm_instructions));
const uword virtual_base = vm_instructions_image.virtual_address();
if (virtual_base != 0) {
buffer->Printf(" virt %" Pp "", virtual_base + vm_offset);
}
buffer->Printf(" %s+0x%" Px "", kVmSnapshotInstructionsAsmSymbol,
vm_offset);
} else if (isolate_offset > 0) {
// If this isolate image was compiled directly to ELF, then print the
// virtual address of the call address, since the virtual addresses will
// match those in any separately saved debugging information.
const Image isolate_instructions_image(
reinterpret_cast<const uword*>(isolate_instructions));
const uword virtual_base = isolate_instructions_image.virtual_address();
if (virtual_base != 0) {
buffer->Printf(" virt %" Pp "", virtual_base + isolate_offset);
}
buffer->Printf(" %s+0x%" Px "", kIsolateSnapshotInstructionsAsmSymbol,
isolate_offset);
} else {