Skip to content

Commit 6196695

Browse files
aganeatstellar
authored andcommitted
[CodeView] Align type records on 4-bytes when emitting PDBs
When emitting PDBs, the TypeStreamMerger class is used to merge .debug$T records from the input .OBJ files into the output .PDB stream. Records in .OBJs are not required to be aligned on 4-bytes, and "The Netwide Assembler 2.14" generates non-aligned records. When compiling with -DLLVM_ENABLE_ASSERTIONS=ON, an assert was triggered in MergingTypeTableBuilder when non-ghash merging was used. With ghash merging there was no assert. As a result, LLD could potentially generate a non-aligned TPI stream. We now align records on 4-bytes when record indices are remapped, in TypeStreamMerger::remapIndices(). Differential Revision: https://reviews.llvm.org/D75081 (cherry picked from commit a732529)
1 parent cc6e51a commit 6196695

File tree

5 files changed

+83
-6
lines changed

5 files changed

+83
-6
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# RUN: yaml2obj < %s > %t.obj
2+
# RUN: yaml2obj %p/Inputs/generic.yaml > %t2.obj
3+
4+
# RUN: lld-link /out:%t.exe /debug /entry:main %t.obj %t2.obj /nodefaultlib
5+
# RUN: llvm-pdbutil dump --types --type-data %t.pdb | FileCheck %s
6+
# RUN: lld-link /out:%t.exe /debug:ghash /entry:main %t.obj %t2.obj /nodefaultlib
7+
# RUN: llvm-pdbutil dump --types --type-data %t.pdb | FileCheck %s
8+
9+
# CHECK: 0000: 12000810 03000000 00000000 00000000 0000F2F1
10+
11+
--- !COFF
12+
header:
13+
Machine: IMAGE_FILE_MACHINE_AMD64
14+
Characteristics: []
15+
sections:
16+
- Name: '.debug$T'
17+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
18+
Alignment: 1
19+
# It is important to keep the 'SectionData' since the .OBJ is reconstructed from it,
20+
# and that triggers an alignement bug in the output .PDB.
21+
SectionData: '040000001000081003000000000000000000000000000600011200000000'
22+
Types:
23+
- Kind: LF_PROCEDURE
24+
Procedure:
25+
ReturnType: 3
26+
CallConv: NearC
27+
Options: [ None ]
28+
ParameterCount: 0
29+
ArgumentList: 0
30+
- Kind: LF_ARGLIST
31+
ArgList:
32+
ArgIndices: [ ]
33+
symbols:
34+
- Name: '.debug$T'
35+
Value: 0
36+
SectionNumber: 1
37+
SimpleType: IMAGE_SYM_TYPE_NULL
38+
ComplexType: IMAGE_SYM_DTYPE_NULL
39+
StorageClass: IMAGE_SYM_CLASS_STATIC
40+
SectionDefinition:
41+
Length: 30
42+
NumberOfRelocations: 0
43+
NumberOfLinenumbers: 0
44+
CheckSum: 0
45+
Number: 0
46+
...

llvm/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ class GlobalTypeTableBuilder : public TypeCollection {
7171
template <typename CreateFunc>
7272
TypeIndex insertRecordAs(GloballyHashedType Hash, size_t RecordSize,
7373
CreateFunc Create) {
74+
assert(RecordSize < UINT32_MAX && "Record too big");
75+
assert(RecordSize % 4 == 0 &&
76+
"RecordSize is not a multiple of 4 bytes which will cause "
77+
"misalignment in the output TPI stream!");
78+
7479
auto Result = HashedRecords.try_emplace(Hash, nextTypeIndex());
7580

7681
if (LLVM_UNLIKELY(Result.second /*inserted*/ ||

llvm/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc,
9090
TypeIndex MergingTypeTableBuilder::insertRecordAs(hash_code Hash,
9191
ArrayRef<uint8_t> &Record) {
9292
assert(Record.size() < UINT32_MAX && "Record too big");
93-
assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
93+
assert(Record.size() % 4 == 0 &&
94+
"The type record size is not a multiple of 4 bytes which will cause "
95+
"misalignment in the output TPI stream!");
9496

9597
LocallyHashedType WeakHash{Hash, Record};
9698
auto Result = HashedRecords.try_emplace(WeakHash, nextTypeIndex());

llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,16 +360,18 @@ Error TypeStreamMerger::remapType(const CVType &Type) {
360360
[this, Type](MutableArrayRef<uint8_t> Storage) -> ArrayRef<uint8_t> {
361361
return remapIndices(Type, Storage);
362362
};
363+
unsigned AlignedSize = alignTo(Type.RecordData.size(), 4);
364+
363365
if (LLVM_LIKELY(UseGlobalHashes)) {
364366
GlobalTypeTableBuilder &Dest =
365367
isIdRecord(Type.kind()) ? *DestGlobalIdStream : *DestGlobalTypeStream;
366368
GloballyHashedType H = GlobalHashes[CurIndex.toArrayIndex()];
367-
DestIdx = Dest.insertRecordAs(H, Type.RecordData.size(), DoSerialize);
369+
DestIdx = Dest.insertRecordAs(H, AlignedSize, DoSerialize);
368370
} else {
369371
MergingTypeTableBuilder &Dest =
370372
isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream;
371373

372-
RemapStorage.resize(Type.RecordData.size());
374+
RemapStorage.resize(AlignedSize);
373375
ArrayRef<uint8_t> Result = DoSerialize(RemapStorage);
374376
if (!Result.empty())
375377
DestIdx = Dest.insertRecordBytes(Result);
@@ -386,9 +388,15 @@ Error TypeStreamMerger::remapType(const CVType &Type) {
386388
ArrayRef<uint8_t>
387389
TypeStreamMerger::remapIndices(const CVType &OriginalType,
388390
MutableArrayRef<uint8_t> Storage) {
391+
unsigned Align = OriginalType.RecordData.size() & 3;
392+
unsigned AlignedSize = alignTo(OriginalType.RecordData.size(), 4);
393+
assert(Storage.size() == AlignedSize &&
394+
"The storage buffer size is not a multiple of 4 bytes which will "
395+
"cause misalignment in the output TPI stream!");
396+
389397
SmallVector<TiReference, 4> Refs;
390398
discoverTypeIndices(OriginalType.RecordData, Refs);
391-
if (Refs.empty())
399+
if (Refs.empty() && Align == 0)
392400
return OriginalType.RecordData;
393401

394402
::memcpy(Storage.data(), OriginalType.RecordData.data(),
@@ -408,6 +416,16 @@ TypeStreamMerger::remapIndices(const CVType &OriginalType,
408416
return {};
409417
}
410418
}
419+
420+
if (Align > 0) {
421+
RecordPrefix *StorageHeader =
422+
reinterpret_cast<RecordPrefix *>(Storage.data());
423+
StorageHeader->RecordLen += 4 - Align;
424+
425+
DestContent = Storage.data() + OriginalType.RecordData.size();
426+
for (; Align < 4; ++Align)
427+
*DestContent++ = LF_PAD4 - Align;
428+
}
411429
return Storage;
412430
}
413431

llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) {
4444
void TpiStreamBuilder::addTypeRecord(ArrayRef<uint8_t> Record,
4545
Optional<uint32_t> Hash) {
4646
// If we just crossed an 8KB threshold, add a type index offset.
47+
assert(((Record.size() & 3) == 0) &&
48+
"The type record's size is not a multiple of 4 bytes which will "
49+
"cause misalignment in the output TPI stream!");
4750
size_t NewSize = TypeRecordBytes + Record.size();
4851
constexpr size_t EightKB = 8 * 1024;
4952
if (NewSize / EightKB > TypeRecordBytes / EightKB || TypeRecords.empty()) {
@@ -153,8 +156,11 @@ Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
153156
return EC;
154157

155158
for (auto Rec : TypeRecords) {
156-
assert(!Rec.empty()); // An empty record will not write anything, but it
157-
// would shift all offsets from here on.
159+
assert(!Rec.empty() && "Attempting to write an empty type record shifts "
160+
"all offsets in the TPI stream!");
161+
assert(((Rec.size() & 3) == 0) &&
162+
"The type record's size is not a multiple of 4 bytes which will "
163+
"cause misalignment in the output TPI stream!");
158164
if (auto EC = Writer.writeBytes(Rec))
159165
return EC;
160166
}

0 commit comments

Comments
 (0)