Skip to content

Commit 4b7ecac

Browse files
committed
[CodeGen][COFF] Always emit CodeView compiler info on Windows targets
MSVC always emits minimal CodeView metadata with compiler information, even when debug info is otherwise disabled. Other tools may rely on this metadata being present. For example, linkers use it to determine whether hotpatching is enabled for the object file.
1 parent 6955a7d commit 4b7ecac

File tree

13 files changed

+183
-34
lines changed

13 files changed

+183
-34
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,11 @@ CodeGenModule::CodeGenModule(ASTContext &C,
414414
CodeGenOpts.CoverageNotesFile.size() ||
415415
CodeGenOpts.CoverageDataFile.size())
416416
DebugInfo.reset(new CGDebugInfo(*this));
417+
else if (getTriple().isOSWindows())
418+
// On Windows targets, we want to emit compiler info even if debug info is
419+
// otherwise disabled. Use a temporary CGDebugInfo instance to emit only
420+
// basic compiler metadata.
421+
CGDebugInfo(*this);
417422

418423
Block.GlobalUniqueCount = 0;
419424

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// REQUIRES: x86-registered-target
2+
3+
// Check that CodeView compiler version is emitted even when debug info is otherwise disabled.
4+
5+
// RUN: %clang --target=i686-pc-windows-msvc -S -emit-llvm %s -o - | FileCheck --check-prefix=IR %s
6+
// IR: !llvm.dbg.cu = !{!0}
7+
// IR: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version {{.*}}", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, splitDebugInlining: false, nameTableKind: None)
8+
9+
// RUN: %clang --target=i686-pc-windows-msvc -c %s -o %t.o
10+
// RUN: llvm-readobj --codeview %t.o | FileCheck %s
11+
// CHECK: CodeViewDebugInfo [
12+
// CHECK-NEXT: Section: .debug$S (4)
13+
// CHECK-NEXT: Magic: 0x4
14+
// CHECK-NEXT: Subsection [
15+
// CHECK-NEXT: SubSectionType: Symbols (0xF1)
16+
// CHECK-NEXT: SubSectionSize: 0x40
17+
// CHECK-NEXT: ObjNameSym {
18+
// CHECK-NEXT: Kind: S_OBJNAME (0x1101)
19+
// CHECK-NEXT: Signature: 0x0
20+
// CHECK-NEXT: ObjectName:
21+
// CHECK-NEXT: }
22+
// CHECK-NEXT: Compile3Sym {
23+
// CHECK-NEXT: Kind: S_COMPILE3 (0x113C)
24+
// CHECK-NEXT: Language: Cpp (0x1)
25+
// CHECK-NEXT: Flags [ (0x0)
26+
// CHECK-NEXT: ]
27+
// CHECK-NEXT: Machine: Pentium3 (0x7)
28+
// CHECK-NEXT: FrontendVersion:
29+
// CHECK-NEXT: BackendVersion:
30+
// CHECK-NEXT: VersionName: clang version
31+
// CHECK-NEXT: }
32+
// CHECK-NEXT: ]
33+
// CHECK-NEXT: ]
34+
35+
int main() {
36+
return 0;
37+
}

clang/test/CodeGenCXX/debug-info-hotpatch-aarch64.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,9 @@
1111
// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH
1212
// HOTPATCH: S_COMPILE3 [size = [[#]]]
1313
// HOTPATCH: flags = hot patchable
14-
///
15-
/// Unfortunately we need /Z7, Clang does not systematically generate S_COMPILE3.
16-
///
14+
//
1715
// RUN: %clang_cl --target=aarch64-pc-windows-msvc /c -o %t.obj -- %s
18-
// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=NO-HOTPATCH
19-
// NO-HOTPATCH-NOT: flags = hot patchable
16+
// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH
2017

2118
int main() {
2219
return 0;

clang/test/CodeGenCXX/debug-info-hotpatch-arm.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,9 @@
1111
// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH
1212
// HOTPATCH: S_COMPILE3 [size = [[#]]]
1313
// HOTPATCH: flags = hot patchable
14-
///
15-
/// Unfortunately we need /Z7, Clang does not systematically generate S_COMPILE3.
16-
///
14+
//
1715
// RUN: %clang_cl --target=arm-pc-windows-msvc /c -o %t.obj -- %s
18-
// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=NO-HOTPATCH
19-
// NO-HOTPATCH-NOT: flags = hot patchable
16+
// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH
2017

2118
int main() {
2219
return 0;

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -560,11 +560,12 @@ bool AsmPrinter::doInitialization(Module &M) {
560560
}
561561

562562
if (MAI->doesSupportDebugInformation()) {
563-
bool EmitCodeView = M.getCodeViewFlag();
564-
if (EmitCodeView &&
565-
(TM.getTargetTriple().isOSWindows() || TM.getTargetTriple().isUEFI()))
563+
// On Windows targets, emit minimal CodeView compiler info even when debug
564+
// info is disabled.
565+
if ((TM.getTargetTriple().isOSWindows() || TM.getTargetTriple().isUEFI()) &&
566+
M.getNamedMetadata("llvm.dbg.cu"))
566567
Handlers.push_back(std::make_unique<CodeViewDebug>(this));
567-
if (!EmitCodeView || M.getDwarfVersion()) {
568+
if (M.getDwarfVersion() || !M.getCodeViewFlag()) {
568569
if (hasDebugInfo()) {
569570
DD = new DwarfDebug(this);
570571
Handlers.push_back(std::unique_ptr<DwarfDebug>(DD));

llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -613,19 +613,30 @@ static SourceLanguage MapDWLangToCVLang(unsigned DWLang) {
613613
void CodeViewDebug::beginModule(Module *M) {
614614
// If module doesn't have named metadata anchors or COFF debug section
615615
// is not available, skip any debug info related stuff.
616-
if (!Asm->hasDebugInfo() ||
617-
!Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) {
616+
if (!Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) {
618617
Asm = nullptr;
619618
return;
620619
}
621620

622621
TheCPU = mapArchToCVCPUType(M->getTargetTriple().getArch());
623622

624623
// Get the current source language.
625-
const MDNode *Node = *M->debug_compile_units_begin();
624+
const MDNode *Node;
625+
if (Asm->hasDebugInfo()) {
626+
Node = *M->debug_compile_units_begin();
627+
} else {
628+
// When emitting only compiler information, we may have only NoDebug CUs,
629+
// which would be skipped by debug_compile_units_begin.
630+
NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
631+
Node = *CUs->operands().begin();
632+
}
626633
const auto *CU = cast<DICompileUnit>(Node);
627634

628635
CurrentSourceLanguage = MapDWLangToCVLang(CU->getSourceLanguage());
636+
NoDebug =
637+
!M->getCodeViewFlag() || CU->getEmissionKind() == DICompileUnit::NoDebug;
638+
if (NoDebug)
639+
return;
629640

630641
collectGlobalVariableInfo();
631642

@@ -636,7 +647,7 @@ void CodeViewDebug::beginModule(Module *M) {
636647
}
637648

638649
void CodeViewDebug::endModule() {
639-
if (!Asm || !Asm->hasDebugInfo())
650+
if (!Asm)
640651
return;
641652

642653
// The COFF .debug$S section consists of several subsections, each starting
@@ -652,6 +663,8 @@ void CodeViewDebug::endModule() {
652663
emitObjName();
653664
emitCompilerInformation();
654665
endCVSubsection(CompilerInfo);
666+
if (NoDebug)
667+
return;
655668

656669
emitInlineeLinesSubsection();
657670

@@ -1440,6 +1453,9 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
14401453
}
14411454

14421455
void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) {
1456+
if (NoDebug)
1457+
return;
1458+
14431459
const TargetSubtargetInfo &TSI = MF->getSubtarget();
14441460
const TargetRegisterInfo *TRI = TSI.getRegisterInfo();
14451461
const MachineFrameInfo &MFI = MF->getFrameInfo();
@@ -3031,6 +3047,9 @@ void CodeViewDebug::collectLexicalBlockInfo(
30313047
}
30323048

30333049
void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) {
3050+
if (NoDebug)
3051+
return;
3052+
30343053
const Function &GV = MF->getFunction();
30353054
assert(FnDebugInfo.count(&GV));
30363055
assert(CurFn == FnDebugInfo[&GV].get());
@@ -3089,6 +3108,8 @@ static bool isUsableDebugLoc(DebugLoc DL) {
30893108

30903109
void CodeViewDebug::beginInstruction(const MachineInstr *MI) {
30913110
DebugHandlerBase::beginInstruction(MI);
3111+
if (NoDebug)
3112+
return;
30923113

30933114
// Ignore DBG_VALUE and DBG_LABEL locations and function prologue.
30943115
if (!Asm || !CurFn || MI->isDebugInstr() ||

llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
9898
/// The codeview CPU type used by the translation unit.
9999
codeview::CPUType TheCPU;
100100

101+
/// Whether to emit compiler information only.
102+
bool NoDebug = false;
103+
101104
static LocalVarDef createDefRangeMem(uint16_t CVRegister, int Offset);
102105

103106
/// Similar to DbgVariable in DwarfDebug, but not dwarf-specific.

llvm/test/DebugInfo/COFF/dwarf-headers.ll

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,33 @@
4343
; DWO-4: 0x00000000: Compile Unit: {{.*}} version = 0x0004, abbr_offset
4444
; DWO-4: 0x0000000b: DW_TAG_compile_unit
4545

46+
; Check that basic CodeView compiler info is emitted even when the DWARF debug format is used.
47+
; RUN: llc -dwarf-version=4 \
48+
; RUN: -filetype=obj -O0 -mtriple=x86_64-unknown-windows-msvc < %s \
49+
; RUN: | llvm-readobj --codeview - | FileCheck %s --check-prefix=CODEVIEW
50+
; CODEVIEW: CodeViewDebugInfo [
51+
; CODEVIEW-NEXT: Section: .debug$S (4)
52+
; CODEVIEW-NEXT: Magic: 0x4
53+
; CODEVIEW-NEXT: Subsection [
54+
; CODEVIEW-NEXT: SubSectionType: Symbols (0xF1)
55+
; CODEVIEW-NEXT: SubSectionSize: 0x90
56+
; CODEVIEW-NEXT: ObjNameSym {
57+
; CODEVIEW-NEXT: Kind: S_OBJNAME (0x1101)
58+
; CODEVIEW-NEXT: Signature: 0x0
59+
; CODEVIEW-NEXT: ObjectName:
60+
; CODEVIEW-NEXT: }
61+
; CODEVIEW-NEXT: Compile3Sym {
62+
; CODEVIEW-NEXT: Kind: S_COMPILE3 (0x113C)
63+
; CODEVIEW-NEXT: Language: Cpp (0x1)
64+
; CODEVIEW-NEXT: Flags [ (0x0)
65+
; CODEVIEW-NEXT: ]
66+
; CODEVIEW-NEXT: Machine: X64 (0xD0)
67+
; CODEVIEW-NEXT: FrontendVersion: 17.0.0.0
68+
; CODEVIEW-NEXT: BackendVersion:
69+
; CODEVIEW-NEXT: VersionName: clang version 17.0.0
70+
; CODEVIEW-NEXT: }
71+
; CODEVIEW-NEXT: ]
72+
; CODEVIEW-NEXT: ]
4673

4774
; ModuleID = 't.cpp'
4875
source_filename = "t.cpp"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; RUN: llc -filetype=obj -o - < %s | llvm-readobj --codeview - | FileCheck %s
2+
; Check that basic CodeView compiler info is emitted even when the CodeView flag is not set.
3+
4+
; CHECK-NOT: CodeViewTypes
5+
; CHECK: CodeViewDebugInfo [
6+
; CHECK-NEXT: Section: .debug$S (4)
7+
; CHECK-NEXT: Magic: 0x4
8+
; CHECK-NEXT: Subsection [
9+
; CHECK-NEXT: SubSectionType: Symbols (0xF1)
10+
; CHECK-NEXT: SubSectionSize: 0x2C
11+
; CHECK-NEXT: ObjNameSym {
12+
; CHECK-NEXT: Kind: S_OBJNAME (0x1101)
13+
; CHECK-NEXT: Signature: 0x0
14+
; CHECK-NEXT: ObjectName:
15+
; CHECK-NEXT: }
16+
; CHECK-NEXT: Compile3Sym {
17+
; CHECK-NEXT: Kind: S_COMPILE3 (0x113C)
18+
; CHECK-NEXT: Language: C (0x0)
19+
; CHECK-NEXT: Flags [ (0x0)
20+
; CHECK-NEXT: ]
21+
; CHECK-NEXT: Machine: X64 (0xD0)
22+
; CHECK-NEXT: FrontendVersion:
23+
; CHECK-NEXT: BackendVersion:
24+
; CHECK-NEXT: VersionName: clang
25+
; CHECK-NEXT: }
26+
; CHECK-NEXT: ]
27+
; CHECK-NEXT: ]
28+
29+
source_filename = "empty"
30+
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
31+
target triple = "x86_64-pc-windows-msvc19.0.24215"
32+
33+
!llvm.dbg.cu = !{!0}
34+
!llvm.module.flags = !{!2}
35+
36+
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "clang", emissionKind: NoDebug)
37+
!1 = !DIFile(filename: "empty", directory: "path/to")
38+
!2 = !{i32 2, !"Debug Info Version", i32 3}

llvm/test/DebugInfo/COFF/emission-kind-no-debug.ll

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
11
; RUN: llc -filetype=obj -o - < %s | llvm-readobj --codeview - | FileCheck %s
2-
; Check that debug info isn't emitted for CodeView with emissionKind NoDebug
2+
; Check that only basic compiler info is emitted for CodeView with emissionKind NoDebug
33

4-
; CHECK-NOT: CodeViewTypes
5-
; CHECK-NOT: CodeViewDebugInfo
4+
; CHECK-NOT: CodeViewTypes
5+
; CHECK: CodeViewDebugInfo [
6+
; CHECK-NEXT: Section: .debug$S (4)
7+
; CHECK-NEXT: Magic: 0x4
8+
; CHECK-NEXT: Subsection [
9+
; CHECK-NEXT: SubSectionType: Symbols (0xF1)
10+
; CHECK-NEXT: SubSectionSize: 0x2C
11+
; CHECK-NEXT: ObjNameSym {
12+
; CHECK-NEXT: Kind: S_OBJNAME (0x1101)
13+
; CHECK-NEXT: Signature: 0x0
14+
; CHECK-NEXT: ObjectName:
15+
; CHECK-NEXT: }
16+
; CHECK-NEXT: Compile3Sym {
17+
; CHECK-NEXT: Kind: S_COMPILE3 (0x113C)
18+
; CHECK-NEXT: Language: C (0x0)
19+
; CHECK-NEXT: Flags [ (0x0)
20+
; CHECK-NEXT: ]
21+
; CHECK-NEXT: Machine: X64 (0xD0)
22+
; CHECK-NEXT: FrontendVersion:
23+
; CHECK-NEXT: BackendVersion:
24+
; CHECK-NEXT: VersionName: clang
25+
; CHECK-NEXT: }
26+
; CHECK-NEXT: ]
27+
; CHECK-NEXT: ]
628

729
source_filename = "empty"
830
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"

0 commit comments

Comments
 (0)