Skip to content

Commit 6f83a5f

Browse files
sstricklcommit-bot@chromium.org
authored andcommitted
[vm/aot] Add a GNU build ID to direct-to-ELF snapshots.
For proper crashpad integration, we need to generate a build ID, as the build ID generated by crashpad if there is not one will be a simple XOR of the first text page, which rarely changes for Dart snapshots. Assembly snapshots already have a build ID included by the assembler, so we currently only do this for ELF snapshots. Currently the build ID is a 128-bit hash value that is four separate 32-bit hash values concatenated together. Those hash values come from the contents of the VM and isolate .text and .rodata sections. This change also contains work to separate out the concepts of sections and segments in the ELF builder. Now, consecutive allocated sections with the same write and execute flags are combined into a single PT_LOAD segment when possible, which reduces the padding needed to ensure that segments start on page boundaries in ELF snapshots. Bug: #42020 Change-Id: I42a837dae665a3902d881b8d151b49ede87d6c67 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-linux-release-simarm_x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/150625 Commit-Queue: Tess Strickland <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent 2e939f2 commit 6f83a5f

File tree

11 files changed

+872
-500
lines changed

11 files changed

+872
-500
lines changed

pkg/native_stack_traces/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 0.3.7
4+
5+
- Added buildId accessor for retrieving GNU build IDs from DWARF files that
6+
include them.
7+
38
## 0.3.6
49

510
- Adjusts RegExp for stack trace header line to be more flexible in what it

pkg/native_stack_traces/lib/src/constants.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
// The section name in which the build ID is stored as a note.
6+
const String buildIdSectionName = ".note.gnu.build-id";
7+
// The type of a build ID note.
8+
const int buildIdNoteType = 3;
9+
// The name of a build ID note.
10+
const String buildIdNoteName = "GNU";
11+
512
// The dynamic symbol name for the VM instructions section.
613
const String vmSymbolName = "_kDartVmSnapshotInstructions";
714

pkg/native_stack_traces/lib/src/dwarf.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,18 @@ class Dwarf {
12141214
vmStartAddress, isolateStartAddress);
12151215
}
12161216

1217+
/// The build ID for the debugging information.
1218+
///
1219+
/// Returns null if there is no build ID information recorded.
1220+
String get buildId {
1221+
final sections = _elf.namedSections(constants.buildIdSectionName);
1222+
if (sections.isEmpty) return null;
1223+
final Note note = sections.single;
1224+
if (note.type != constants.buildIdNoteType) return null;
1225+
if (note.name != constants.buildIdNoteName) return null;
1226+
return note.description.map((i) => i.toRadixString(16)).join();
1227+
}
1228+
12171229
/// The call information for the given virtual address. There may be
12181230
/// multiple [CallInfo] objects returned for a single virtual address when
12191231
/// code has been inlined.

pkg/native_stack_traces/lib/src/elf.dart

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ class ProgramHeaderEntry {
322322
..writeln(paddedHex(paddr, wordSize))
323323
..write('Size in file: ')
324324
..writeln(filesz)
325-
..write('Size in memory')
325+
..write('Size in memory: ')
326326
..writeln(memsz)
327327
..write('Alignment: 0x')
328328
..write(paddedHex(align, wordSize));
@@ -421,6 +421,7 @@ class SectionHeaderEntry {
421421
static const _SHT_STRTAB = 3;
422422
static const _SHT_HASH = 5;
423423
static const _SHT_DYNAMIC = 6;
424+
static const _SHT_NOTE = 7;
424425
static const _SHT_NOBITS = 8;
425426
static const _SHT_DYNSYM = 11;
426427

@@ -437,6 +438,7 @@ class SectionHeaderEntry {
437438
_SHT_STRTAB: "SHT_STRTAB",
438439
_SHT_HASH: "SHT_HASH",
439440
_SHT_DYNAMIC: "SHT_DYNAMIC",
441+
_SHT_NOTE: "SHT_NOTE",
440442
_SHT_NOBITS: "SHT_NOBITS",
441443
_SHT_DYNSYM: "SHT_DYNSYM",
442444
};
@@ -545,6 +547,8 @@ class Section {
545547
return SymbolTable.fromReader(reader, entry);
546548
case SectionHeaderEntry._SHT_DYNSYM:
547549
return SymbolTable.fromReader(reader, entry);
550+
case SectionHeaderEntry._SHT_NOTE:
551+
return Note.fromReader(reader, entry);
548552
default:
549553
return Section._(entry);
550554
}
@@ -574,6 +578,55 @@ class Section {
574578
}
575579
}
576580

581+
/// A section that contains a single note.
582+
class Note extends Section {
583+
final int type;
584+
final String name;
585+
final Uint8List description;
586+
587+
Note._(entry, this.type, this.name, this.description) : super._(entry);
588+
589+
static Note fromReader(Reader originalReader, SectionHeaderEntry entry) {
590+
final reader = originalReader.refocusedCopy(entry.offset, entry.size);
591+
final nameLength = reader.readBytes(4);
592+
final descriptionLength = reader.readBytes(4);
593+
final type = reader.readBytes(4);
594+
final nameEnd = reader.offset + nameLength;
595+
final name = reader.readNullTerminatedString();
596+
assert(reader.offset == nameEnd);
597+
assert(reader.length - reader.offset == descriptionLength);
598+
final descriptionStart = reader.offset;
599+
final descriptionEnd = descriptionStart + descriptionLength;
600+
final description =
601+
Uint8List.sublistView(reader.bdata, descriptionStart, descriptionEnd);
602+
return Note._(entry, type, name, description);
603+
}
604+
605+
void writeToStringBuffer(StringBuffer buffer) {
606+
buffer
607+
..write('Section "')
608+
..write(headerEntry.name)
609+
..writeln('" is a note:');
610+
buffer
611+
..write(' Type: ')
612+
..writeln(type);
613+
buffer
614+
..write(' Name: "')
615+
..write(name)
616+
..writeln('"');
617+
buffer
618+
..write(' Description: ')
619+
..writeln(description);
620+
}
621+
622+
@override
623+
String toString() {
624+
final buffer = StringBuffer();
625+
writeToStringBuffer(buffer);
626+
return buffer.toString();
627+
}
628+
}
629+
577630
/// A map from table offsets to strings, used to store names of ELF objects.
578631
class StringTable extends Section {
579632
final _entries;

pkg/native_stack_traces/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
name: native_stack_traces
22
description: Utilities for working with non-symbolic stack traces.
3-
version: 0.3.6
3+
version: 0.3.7
44

55
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/native_stack_traces
66

77
environment:
8-
sdk: '>=2.7.1 <3.0.0'
8+
sdk: '>=2.8 <3.0.0'
99

1010
executables:
1111
decode:

runtime/include/dart_api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3524,17 +3524,20 @@ typedef void (*Dart_StreamingWriteCallback)(void* callback_data,
35243524
// Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual
35253525
// symbol names in the objects are given by the '...AsmSymbol' definitions.
35263526
#if defined(__APPLE__)
3527+
#define kSnapshotBuildIdCSymbol "kDartSnapshotBuildId"
35273528
#define kVmSnapshotDataCSymbol "kDartVmSnapshotData"
35283529
#define kVmSnapshotInstructionsCSymbol "kDartVmSnapshotInstructions"
35293530
#define kIsolateSnapshotDataCSymbol "kDartIsolateSnapshotData"
35303531
#define kIsolateSnapshotInstructionsCSymbol "kDartIsolateSnapshotInstructions"
35313532
#else
3533+
#define kSnapshotBuildIdCSymbol "_kDartSnapshotBuildId"
35323534
#define kVmSnapshotDataCSymbol "_kDartVmSnapshotData"
35333535
#define kVmSnapshotInstructionsCSymbol "_kDartVmSnapshotInstructions"
35343536
#define kIsolateSnapshotDataCSymbol "_kDartIsolateSnapshotData"
35353537
#define kIsolateSnapshotInstructionsCSymbol "_kDartIsolateSnapshotInstructions"
35363538
#endif
35373539

3540+
#define kSnapshotBuildIdAsmSymbol "_kDartSnapshotBuildId"
35383541
#define kVmSnapshotDataAsmSymbol "_kDartVmSnapshotData"
35393542
#define kVmSnapshotInstructionsAsmSymbol "_kDartVmSnapshotInstructions"
35403543
#define kIsolateSnapshotDataAsmSymbol "_kDartIsolateSnapshotData"

runtime/platform/elf.h

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ struct ElfHeader {
3636
};
3737

3838
enum class ProgramHeaderType : uint32_t {
39+
PT_NULL = 0,
3940
PT_LOAD = 1,
4041
PT_DYNAMIC = 2,
42+
PT_NOTE = 4,
4143
PT_PHDR = 6,
4244
};
4345

@@ -63,10 +65,22 @@ struct ProgramHeader {
6365
#endif
6466
};
6567

68+
enum class SectionHeaderType : uint32_t {
69+
SHT_NULL = 0,
70+
SHT_PROGBITS = 1,
71+
SHT_SYMTAB = 2,
72+
SHT_STRTAB = 3,
73+
SHT_HASH = 5,
74+
SHT_NOTE = 7,
75+
SHT_NOBITS = 8,
76+
SHT_DYNAMIC = 6,
77+
SHT_DYNSYM = 11,
78+
};
79+
6680
struct SectionHeader {
6781
#if defined(TARGET_ARCH_IS_32_BIT)
6882
uint32_t name;
69-
uint32_t type;
83+
SectionHeaderType type;
7084
uint32_t flags;
7185
uint32_t memory_offset;
7286
uint32_t file_offset;
@@ -77,7 +91,7 @@ struct SectionHeader {
7791
uint32_t entry_size;
7892
#else
7993
uint32_t name;
80-
uint32_t type;
94+
SectionHeaderType type;
8195
uint64_t flags;
8296
uint64_t memory_offset;
8397
uint64_t file_offset;
@@ -107,6 +121,36 @@ struct Symbol {
107121
#endif
108122
};
109123

124+
enum class DynamicEntryType : uint32_t {
125+
DT_NULL = 0,
126+
DT_HASH = 4,
127+
DT_STRTAB = 5,
128+
DT_SYMTAB = 6,
129+
DT_STRSZ = 10,
130+
DT_SYMENT = 11,
131+
};
132+
133+
struct DynamicEntry {
134+
#if defined(TARGET_ARCH_IS_32_BIT)
135+
uint32_t tag;
136+
uint32_t value;
137+
#else
138+
uint64_t tag;
139+
uint64_t value;
140+
#endif
141+
};
142+
143+
enum class NoteType : uint32_t {
144+
NT_GNU_BUILD_ID = 3,
145+
};
146+
147+
struct Note {
148+
uint32_t name_size;
149+
uint32_t description_size;
150+
NoteType type;
151+
uint8_t data[];
152+
};
153+
110154
#pragma pack(pop)
111155

112156
static constexpr intptr_t ELFCLASS32 = 1;
@@ -134,15 +178,6 @@ static const intptr_t PF_X = 1;
134178
static const intptr_t PF_W = 2;
135179
static const intptr_t PF_R = 4;
136180

137-
static const intptr_t SHT_NULL = 0;
138-
static const intptr_t SHT_PROGBITS = 1;
139-
static const intptr_t SHT_SYMTAB = 2;
140-
static const intptr_t SHT_STRTAB = 3;
141-
static const intptr_t SHT_HASH = 5;
142-
static const intptr_t SHT_NOBITS = 8;
143-
static const intptr_t SHT_DYNAMIC = 6;
144-
static const intptr_t SHT_DYNSYM = 11;
145-
146181
static const intptr_t SHF_WRITE = 0x1;
147182
static const intptr_t SHF_ALLOC = 0x2;
148183
static const intptr_t SHF_EXECINSTR = 0x4;
@@ -151,24 +186,14 @@ static const intptr_t SHN_UNDEF = 0;
151186

152187
static const intptr_t STN_UNDEF = 0;
153188

154-
static const intptr_t PT_NULL = 0;
155-
static const intptr_t PT_LOAD = 1;
156-
static const intptr_t PT_DYNAMIC = 2;
157-
static const intptr_t PT_PHDR = 6;
158-
159189
static const intptr_t STB_LOCAL = 0;
160190
static const intptr_t STB_GLOBAL = 1;
161191

162192
static const intptr_t STT_OBJECT = 1; // I.e., data.
163193
static const intptr_t STT_FUNC = 2;
164194
static const intptr_t STT_SECTION = 3;
165195

166-
static const intptr_t DT_NULL = 0;
167-
static const intptr_t DT_HASH = 4;
168-
static const intptr_t DT_STRTAB = 5;
169-
static const intptr_t DT_SYMTAB = 6;
170-
static const intptr_t DT_STRSZ = 10;
171-
static const intptr_t DT_SYMENT = 11;
196+
static constexpr const char* ELF_NOTE_GNU = "GNU";
172197

173198
} // namespace elf
174199
} // namespace dart

0 commit comments

Comments
 (0)