mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:44:27 +00:00
[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:
parent
645f3acca7
commit
250b84987d
8 changed files with 65 additions and 10 deletions
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue