Skip to content

Commit 0e2aaa5

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 0e2aaa5

18 files changed

+215
-52
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 6 additions & 1 deletion
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

@@ -1051,7 +1056,7 @@ void CodeGenModule::Release() {
10511056
"StrictVTablePointersRequirement",
10521057
llvm::MDNode::get(VMContext, Ops));
10531058
}
1054-
if (getModuleDebugInfo())
1059+
if (getModuleDebugInfo() || getTriple().isOSWindows())
10551060
// We support a single version in the linked module. The LLVM
10561061
// parser will drop debug info with a different version number
10571062
// (and warn about it, too).
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:
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;

clang/test/Frontend/ast-main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: env SDKROOT="/" %clang -emit-llvm -S -o %t1.ll -x c - < %s
1+
// RUN: env SDKROOT="/" %clang -emit-llvm -S -o - -x c - < %s | grep -v DIFile > %t1.ll
22
// RUN: env SDKROOT="/" %clang -emit-ast -o %t.ast %s
3-
// RUN: env SDKROOT="/" %clang -emit-llvm -S -o %t2.ll -x ast - < %t.ast
3+
// RUN: env SDKROOT="/" %clang -emit-llvm -S -o - -x ast - < %t.ast | grep -v DIFile > %t2.ll
44
// RUN: diff %t1.ll %t2.ll
55

66
int main(void) {

clang/test/Frontend/ast-main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: env SDKROOT="/" %clang -Wno-error=return-type -emit-llvm -S -o %t1.ll -x c++ - < %s
1+
// RUN: env SDKROOT="/" %clang -Wno-error=return-type -emit-llvm -S -o - -x c++ - < %s | grep -v DIFile > %t1.ll
22
// RUN: env SDKROOT="/" %clang -Wno-error=return-type -fno-delayed-template-parsing -emit-ast -o %t.ast %s
3-
// RUN: env SDKROOT="/" %clang -Wno-error=return-type -emit-llvm -S -o %t2.ll -x ast - < %t.ast
3+
// RUN: env SDKROOT="/" %clang -Wno-error=return-type -emit-llvm -S -o - -x ast - < %t.ast | grep -v DIFile > %t2.ll
44
// RUN: diff %t1.ll %t2.ll
55

66
// http://llvm.org/bugs/show_bug.cgi?id=15377

clang/test/Frontend/ir-support.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44
// We strip differing '.file' directives before comparing.
55

66
// Reference output:
7-
// RUN: %clang_cc1 -S -o - %s | grep -v '\.file' > %t.s
7+
// RUN: %clang_cc1 -triple=x86_64-windows -S -o - %s | grep -v '\.file' > %t.s
88

99
// LLVM bitcode:
10-
// RUN: %clang_cc1 -emit-llvm-bc -o %t.bc %s
11-
// RUN: %clang_cc1 -S -o - %t.bc | grep -v '\.file' > %t.bc.s
10+
// RUN: %clang_cc1 -triple=x86_64-windows -emit-llvm-bc -o %t.bc %s
11+
// RUN: %clang_cc1 -triple=x86_64-windows -S -o - %t.bc | grep -v '\.file' > %t.bc.s
1212
// RUN: diff %t.s %t.bc.s
1313

1414
// LLVM IR source code:
15-
// RUN: %clang_cc1 -emit-llvm -o %t.ll %s
16-
// RUN: %clang_cc1 -S -o - %t.ll | grep -v '\.file' > %t.ll.s
15+
// RUN: %clang_cc1 -triple=x86_64-windows -emit-llvm -o %t.ll %s
16+
// RUN: %clang_cc1 -triple=x86_64-windows -S -o - %t.ll | grep -v '\.file' > %t.ll.s
1717
// RUN: diff %t.s %t.ll.s
1818

1919
int f(void) { return 0; }

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,11 @@ bool AsmPrinter::doInitialization(Module &M) {
561561

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

llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ static CPUType mapArchToCVCPUType(Triple::ArchType Type) {
125125
return CPUType::ARM64;
126126
case Triple::ArchType::mipsel:
127127
return CPUType::MIPS;
128+
case Triple::ArchType::UnknownArch:
129+
return CPUType::Unknown;
128130
default:
129131
report_fatal_error("target architecture doesn't map to a CodeView CPUType");
130132
}
@@ -611,21 +613,33 @@ static SourceLanguage MapDWLangToCVLang(unsigned DWLang) {
611613
}
612614

613615
void CodeViewDebug::beginModule(Module *M) {
614-
// If module doesn't have named metadata anchors or COFF debug section
615-
// is not available, skip any debug info related stuff.
616-
if (!Asm->hasDebugInfo() ||
617-
!Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) {
616+
// If COFF debug section is not available, skip any debug info related stuff.
617+
if (!Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) {
618618
Asm = nullptr;
619619
return;
620620
}
621621

622+
CompilerInfoAsm = Asm;
622623
TheCPU = mapArchToCVCPUType(M->getTargetTriple().getArch());
623624

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

628637
CurrentSourceLanguage = MapDWLangToCVLang(CU->getSourceLanguage());
638+
if (!M->getCodeViewFlag() ||
639+
CU->getEmissionKind() == DICompileUnit::NoDebug) {
640+
Asm = nullptr;
641+
return;
642+
}
629643

630644
collectGlobalVariableInfo();
631645

@@ -636,7 +650,7 @@ void CodeViewDebug::beginModule(Module *M) {
636650
}
637651

638652
void CodeViewDebug::endModule() {
639-
if (!Asm || !Asm->hasDebugInfo())
653+
if (!CompilerInfoAsm)
640654
return;
641655

642656
// The COFF .debug$S section consists of several subsections, each starting
@@ -652,6 +666,8 @@ void CodeViewDebug::endModule() {
652666
emitObjName();
653667
emitCompilerInformation();
654668
endCVSubsection(CompilerInfo);
669+
if (!Asm)
670+
return;
655671

656672
emitInlineeLinesSubsection();
657673

@@ -788,7 +804,7 @@ void CodeViewDebug::emitTypeGlobalHashes() {
788804
void CodeViewDebug::emitObjName() {
789805
MCSymbol *CompilerEnd = beginSymbolRecord(SymbolKind::S_OBJNAME);
790806

791-
StringRef PathRef(Asm->TM.Options.ObjectFilenameForDebug);
807+
StringRef PathRef(CompilerInfoAsm->TM.Options.ObjectFilenameForDebug);
792808
llvm::SmallString<256> PathStore(PathRef);
793809

794810
if (PathRef.empty() || PathRef == "-") {
@@ -846,7 +862,7 @@ void CodeViewDebug::emitCompilerInformation() {
846862
}
847863
using ArchType = llvm::Triple::ArchType;
848864
ArchType Arch = MMI->getModule()->getTargetTriple().getArch();
849-
if (Asm->TM.Options.Hotpatch || Arch == ArchType::thumb ||
865+
if (CompilerInfoAsm->TM.Options.Hotpatch || Arch == ArchType::thumb ||
850866
Arch == ArchType::aarch64) {
851867
Flags |= static_cast<uint32_t>(CompileSym3Flags::HotPatch);
852868
}
@@ -1015,7 +1031,7 @@ void CodeViewDebug::switchToDebugSectionForSymbol(const MCSymbol *GVSym) {
10151031
const MCSymbol *KeySym = GVSec ? GVSec->getCOMDATSymbol() : nullptr;
10161032

10171033
MCSectionCOFF *DebugSec = cast<MCSectionCOFF>(
1018-
Asm->getObjFileLowering().getCOFFDebugSymbolsSection());
1034+
CompilerInfoAsm->getObjFileLowering().getCOFFDebugSymbolsSection());
10191035
DebugSec = OS.getContext().getAssociativeCOFFSection(DebugSec, KeySym);
10201036

10211037
OS.switchSection(DebugSec);

llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h

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

101+
/// The AsmPrinter used for emitting compiler metadata. When only compiler
102+
/// info is being emitted, DebugHandlerBase::Asm may be null.
103+
AsmPrinter *CompilerInfoAsm = nullptr;
104+
101105
static LocalVarDef createDefRangeMem(uint16_t CVRegister, int Offset);
102106

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

0 commit comments

Comments
 (0)