forked from OSchip/llvm-project
Re-land "[codeview] Emit information about global variables"
This reverts commit r271962 and reinstantes r271957. MSVC's linker doesn't appear to like it if you have an empty symbol substream, so only open a symbol substream if we're going to emit something about globals into it. Makes check-asan pass. llvm-svn: 271965
This commit is contained in:
parent
4ece163c92
commit
6f3406df67
|
@ -232,7 +232,7 @@ void CodeViewDebug::emitCodeViewMagicVersion() {
|
|||
}
|
||||
|
||||
void CodeViewDebug::endModule() {
|
||||
if (FnDebugInfo.empty())
|
||||
if (!Asm || !MMI->hasDebugInfo())
|
||||
return;
|
||||
|
||||
assert(Asm != nullptr);
|
||||
|
@ -242,13 +242,18 @@ void CodeViewDebug::endModule() {
|
|||
// of the payload followed by the payload itself. The subsections are 4-byte
|
||||
// aligned.
|
||||
|
||||
// Make a subsection for all the inlined subprograms.
|
||||
// Use the generic .debug$S section, and make a subsection for all the inlined
|
||||
// subprograms.
|
||||
switchToDebugSectionForSymbol(nullptr);
|
||||
emitInlineeLinesSubsection();
|
||||
|
||||
// Emit per-function debug information.
|
||||
for (auto &P : FnDebugInfo)
|
||||
emitDebugInfoForFunction(P.first, P.second);
|
||||
|
||||
// Emit global variable debug information.
|
||||
emitDebugInfoForGlobals();
|
||||
|
||||
// Switch back to the generic .debug$S section after potentially processing
|
||||
// comdat symbol sections.
|
||||
switchToDebugSectionForSymbol(nullptr);
|
||||
|
@ -326,17 +331,9 @@ void CodeViewDebug::emitInlineeLinesSubsection() {
|
|||
if (InlinedSubprograms.empty())
|
||||
return;
|
||||
|
||||
// Use the generic .debug$S section.
|
||||
switchToDebugSectionForSymbol(nullptr);
|
||||
|
||||
MCSymbol *InlineBegin = MMI->getContext().createTempSymbol(),
|
||||
*InlineEnd = MMI->getContext().createTempSymbol();
|
||||
|
||||
OS.AddComment("Inlinee lines subsection");
|
||||
OS.EmitIntValue(unsigned(ModuleSubstreamKind::InlineeLines), 4);
|
||||
OS.AddComment("Subsection size");
|
||||
OS.emitAbsoluteSymbolDiff(InlineEnd, InlineBegin, 4);
|
||||
OS.EmitLabel(InlineBegin);
|
||||
MCSymbol *InlineEnd = beginCVSubsection(ModuleSubstreamKind::InlineeLines);
|
||||
|
||||
// We don't provide any extra file info.
|
||||
// FIXME: Find out if debuggers use this info.
|
||||
|
@ -363,7 +360,7 @@ void CodeViewDebug::emitInlineeLinesSubsection() {
|
|||
OS.EmitIntValue(SP->getLine(), 4);
|
||||
}
|
||||
|
||||
OS.EmitLabel(InlineEnd);
|
||||
endCVSubsection(InlineEnd);
|
||||
}
|
||||
|
||||
void CodeViewDebug::collectInlineSiteChildren(
|
||||
|
@ -467,13 +464,8 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
|
|||
FuncName = GlobalValue::getRealLinkageName(GV->getName());
|
||||
|
||||
// Emit a symbol subsection, required by VS2012+ to find function boundaries.
|
||||
MCSymbol *SymbolsBegin = MMI->getContext().createTempSymbol(),
|
||||
*SymbolsEnd = MMI->getContext().createTempSymbol();
|
||||
OS.AddComment("Symbol subsection for " + Twine(FuncName));
|
||||
OS.EmitIntValue(unsigned(ModuleSubstreamKind::Symbols), 4);
|
||||
OS.AddComment("Subsection size");
|
||||
OS.emitAbsoluteSymbolDiff(SymbolsEnd, SymbolsBegin, 4);
|
||||
OS.EmitLabel(SymbolsBegin);
|
||||
MCSymbol *SymbolsEnd = beginCVSubsection(ModuleSubstreamKind::Symbols);
|
||||
{
|
||||
MCSymbol *ProcRecordBegin = MMI->getContext().createTempSymbol(),
|
||||
*ProcRecordEnd = MMI->getContext().createTempSymbol();
|
||||
|
@ -532,9 +524,7 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
|
|||
OS.AddComment("Record kind: S_PROC_ID_END");
|
||||
OS.EmitIntValue(unsigned(SymbolKind::S_PROC_ID_END), 2);
|
||||
}
|
||||
OS.EmitLabel(SymbolsEnd);
|
||||
// Every subsection must be aligned to a 4-byte boundary.
|
||||
OS.EmitValueToAlignment(4);
|
||||
endCVSubsection(SymbolsEnd);
|
||||
|
||||
// We have an assembler directive that takes care of the whole line table.
|
||||
OS.EmitCVLinetableDirective(FI.FuncId, Fn, FI.End);
|
||||
|
@ -1272,3 +1262,82 @@ void CodeViewDebug::beginInstruction(const MachineInstr *MI) {
|
|||
return;
|
||||
maybeRecordLocation(DL, Asm->MF);
|
||||
}
|
||||
|
||||
MCSymbol *CodeViewDebug::beginCVSubsection(ModuleSubstreamKind Kind) {
|
||||
MCSymbol *BeginLabel = MMI->getContext().createTempSymbol(),
|
||||
*EndLabel = MMI->getContext().createTempSymbol();
|
||||
OS.EmitIntValue(unsigned(Kind), 4);
|
||||
OS.AddComment("Subsection size");
|
||||
OS.emitAbsoluteSymbolDiff(EndLabel, BeginLabel, 4);
|
||||
OS.EmitLabel(BeginLabel);
|
||||
return EndLabel;
|
||||
}
|
||||
|
||||
void CodeViewDebug::endCVSubsection(MCSymbol *EndLabel) {
|
||||
OS.EmitLabel(EndLabel);
|
||||
// Every subsection must be aligned to a 4-byte boundary.
|
||||
OS.EmitValueToAlignment(4);
|
||||
}
|
||||
|
||||
void CodeViewDebug::emitDebugInfoForGlobals() {
|
||||
NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
|
||||
for (const MDNode *Node : CUs->operands()) {
|
||||
const auto *CU = cast<DICompileUnit>(Node);
|
||||
|
||||
// First, emit all globals that are not in a comdat in a single symbol
|
||||
// substream. MSVC doesn't like it if the substream is empty, so only open
|
||||
// it if we have at least one global to emit.
|
||||
switchToDebugSectionForSymbol(nullptr);
|
||||
MCSymbol *EndLabel = nullptr;
|
||||
for (const DIGlobalVariable *G : CU->getGlobalVariables()) {
|
||||
if (const auto *GV = dyn_cast<GlobalVariable>(G->getVariable()))
|
||||
if (!GV->hasComdat()) {
|
||||
if (!EndLabel) {
|
||||
OS.AddComment("Symbol subsection for globals");
|
||||
EndLabel = beginCVSubsection(ModuleSubstreamKind::Symbols);
|
||||
}
|
||||
emitDebugInfoForGlobal(G, Asm->getSymbol(GV));
|
||||
}
|
||||
}
|
||||
if (EndLabel)
|
||||
endCVSubsection(EndLabel);
|
||||
|
||||
// Second, emit each global that is in a comdat into its own .debug$S
|
||||
// section along with its own symbol substream.
|
||||
for (const DIGlobalVariable *G : CU->getGlobalVariables()) {
|
||||
if (const auto *GV = dyn_cast<GlobalVariable>(G->getVariable())) {
|
||||
if (GV->hasComdat()) {
|
||||
MCSymbol *GVSym = Asm->getSymbol(GV);
|
||||
OS.AddComment("Symbol subsection for " +
|
||||
Twine(GlobalValue::getRealLinkageName(GV->getName())));
|
||||
switchToDebugSectionForSymbol(GVSym);
|
||||
EndLabel = beginCVSubsection(ModuleSubstreamKind::Symbols);
|
||||
emitDebugInfoForGlobal(G, GVSym);
|
||||
endCVSubsection(EndLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV,
|
||||
MCSymbol *GVSym) {
|
||||
// DataSym record, see SymbolRecord.h for more info.
|
||||
// FIXME: Thread local data, etc
|
||||
MCSymbol *DataBegin = MMI->getContext().createTempSymbol(),
|
||||
*DataEnd = MMI->getContext().createTempSymbol();
|
||||
OS.AddComment("Record length");
|
||||
OS.emitAbsoluteSymbolDiff(DataEnd, DataBegin, 2);
|
||||
OS.EmitLabel(DataBegin);
|
||||
OS.AddComment("Record kind: S_GDATA32");
|
||||
OS.EmitIntValue(unsigned(SymbolKind::S_GDATA32), 2);
|
||||
OS.AddComment("Type");
|
||||
OS.EmitIntValue(getCompleteTypeIndex(DIGV->getType()).getIndex(), 4);
|
||||
OS.AddComment("DataOffset");
|
||||
OS.EmitCOFFSecRel32(GVSym);
|
||||
OS.AddComment("Segment");
|
||||
OS.EmitCOFFSectionIndex(GVSym);
|
||||
OS.AddComment("Name");
|
||||
emitNullTerminatedSymbolName(OS, DIGV->getName());
|
||||
OS.EmitLabel(DataEnd);
|
||||
}
|
||||
|
|
|
@ -169,6 +169,17 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
|
|||
|
||||
void emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI);
|
||||
|
||||
void emitDebugInfoForGlobals();
|
||||
|
||||
void emitDebugInfoForGlobal(const DIGlobalVariable *DIGV, MCSymbol *GVSym);
|
||||
|
||||
/// Opens a subsection of the given kind in a .debug$S codeview section.
|
||||
/// Returns an end label for use with endCVSubsection when the subsection is
|
||||
/// finished.
|
||||
MCSymbol *beginCVSubsection(codeview::ModuleSubstreamKind Kind);
|
||||
|
||||
void endCVSubsection(MCSymbol *EndLabel);
|
||||
|
||||
void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt,
|
||||
const InlineSite &Site);
|
||||
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
; RUN: llc < %s | FileCheck %s --check-prefix=ASM
|
||||
; RUN: llc < %s -filetype=obj | llvm-readobj - -codeview | FileCheck %s --check-prefix=OBJ
|
||||
|
||||
; C++ source to regenerate:
|
||||
; $ cat t.cpp
|
||||
; int first;
|
||||
; template <typename T> struct A { static const int comdat = 3; };
|
||||
; const int *middle = &A<void>::comdat;
|
||||
; int last;
|
||||
; $ clang t.cpp -S -emit-llvm -g -gcodeview -o t.ll
|
||||
|
||||
; ASM: .section .debug$S,"dr"
|
||||
; ASM: .p2align 2
|
||||
; ASM: .long 4 # Debug section magic
|
||||
|
||||
; ASM: .short {{.*-.*}} # Record length
|
||||
; ASM: .short 4365 # Record kind: S_GDATA32
|
||||
; ASM: .long 116 # Type
|
||||
; ASM: .secrel32 "?first@@3HA" # DataOffset
|
||||
; ASM: .secidx "?first@@3HA" # Segment
|
||||
; ASM: .asciz "first" # Name
|
||||
|
||||
; ASM: .short {{.*-.*}} # Record length
|
||||
; ASM: .short 4365 # Record kind: S_GDATA32
|
||||
; ASM: .long 4097 # Type
|
||||
; ASM: .secrel32 "?middle@@3PEBHEB" # DataOffset
|
||||
; ASM: .secidx "?middle@@3PEBHEB" # Segment
|
||||
; ASM: .asciz "middle" # Name
|
||||
|
||||
; ASM: .short {{.*-.*}} # Record length
|
||||
; ASM: .short 4365 # Record kind: S_GDATA32
|
||||
; ASM: .long 116 # Type
|
||||
; ASM: .secrel32 "?last@@3HA" # DataOffset
|
||||
; ASM: .secidx "?last@@3HA" # Segment
|
||||
; ASM: .asciz "last" # Name
|
||||
|
||||
; ASM: .section .debug$S,"dr",associative,"?comdat@?$A@X@@2HB"
|
||||
; ASM: .p2align 2
|
||||
; ASM: .long 4 # Debug section magic
|
||||
|
||||
; ASM: .short {{.*-.*}} # Record length
|
||||
; ASM: .short 4365 # Record kind: S_GDATA32
|
||||
; ASM: .long 4096 # Type
|
||||
; ASM: .secrel32 "?comdat@?$A@X@@2HB" # DataOffset
|
||||
; ASM: .secidx "?comdat@?$A@X@@2HB" # Segment
|
||||
; ASM: .asciz "comdat" # Name
|
||||
|
||||
; OBJ: CodeViewTypes [
|
||||
; OBJ: Section: .debug$T
|
||||
; OBJ: Magic: 0x4
|
||||
; OBJ: Modifier (0x1000) {
|
||||
; OBJ: TypeLeafKind: LF_MODIFIER (0x1001)
|
||||
; OBJ: ModifiedType: int (0x74)
|
||||
; OBJ: Modifiers [ (0x1)
|
||||
; OBJ: Const (0x1)
|
||||
; OBJ: ]
|
||||
; OBJ: }
|
||||
; OBJ: Pointer (0x1001) {
|
||||
; OBJ: TypeLeafKind: LF_POINTER (0x1002)
|
||||
; OBJ: PointeeType: const int (0x1000)
|
||||
; OBJ: PointerAttributes: 0x1000C
|
||||
; OBJ: PtrType: Near64 (0xC)
|
||||
; OBJ: PtrMode: Pointer (0x0)
|
||||
; OBJ: IsFlat: 0
|
||||
; OBJ: IsConst: 0
|
||||
; OBJ: IsVolatile: 0
|
||||
; OBJ: IsUnaligned: 0
|
||||
; OBJ: }
|
||||
; OBJ: ]
|
||||
|
||||
; OBJ: CodeViewDebugInfo [
|
||||
; OBJ: Section: .debug$S
|
||||
; OBJ: Magic: 0x4
|
||||
; OBJ: Subsection [
|
||||
; OBJ: SubSectionType: Symbols (0xF1)
|
||||
; OBJ: DataSym {
|
||||
; OBJ: DataOffset: ?first@@3HA+0x0
|
||||
; OBJ: Type: int (0x74)
|
||||
; OBJ: DisplayName: first
|
||||
; OBJ: LinkageName: ?first@@3HA
|
||||
; OBJ: }
|
||||
; OBJ: DataSym {
|
||||
; OBJ: DataOffset: ?middle@@3PEBHEB+0x0
|
||||
; OBJ: Type: const int* (0x1001)
|
||||
; OBJ: DisplayName: middle
|
||||
; OBJ: LinkageName: ?middle@@3PEBHEB
|
||||
; OBJ: }
|
||||
; OBJ: DataSym {
|
||||
; OBJ: DataOffset: ?last@@3HA+0x0
|
||||
; OBJ: Type: int (0x74)
|
||||
; OBJ: DisplayName: last
|
||||
; OBJ: LinkageName: ?last@@3HA
|
||||
; OBJ: }
|
||||
; OBJ: ]
|
||||
; OBJ: ]
|
||||
; OBJ: CodeViewDebugInfo [
|
||||
; OBJ: Section: .debug$S (6)
|
||||
; OBJ: Magic: 0x4
|
||||
; OBJ: Subsection [
|
||||
; OBJ: SubSectionType: Symbols (0xF1)
|
||||
; OBJ: SubSectionSize: 0x15
|
||||
; OBJ: DataSym {
|
||||
; OBJ: DataOffset: ?comdat@?$A@X@@2HB+0x0
|
||||
; OBJ: Type: const int (0x1000)
|
||||
; OBJ: DisplayName: comdat
|
||||
; OBJ: LinkageName: ?comdat@?$A@X@@2HB
|
||||
; OBJ: }
|
||||
; OBJ: ]
|
||||
; OBJ: ]
|
||||
|
||||
; ModuleID = 't.cpp'
|
||||
source_filename = "t.cpp"
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc19.0.23918"
|
||||
|
||||
$"\01?comdat@?$A@X@@2HB" = comdat any
|
||||
|
||||
@"\01?first@@3HA" = global i32 0, align 4
|
||||
@"\01?comdat@?$A@X@@2HB" = linkonce_odr constant i32 3, comdat, align 4
|
||||
@"\01?middle@@3PEBHEB" = global i32* @"\01?comdat@?$A@X@@2HB", align 8
|
||||
@"\01?last@@3HA" = global i32 0, align 4
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!16, !17, !18}
|
||||
!llvm.ident = !{!19}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 271937)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3)
|
||||
!1 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvm\5Cbuild")
|
||||
!2 = !{}
|
||||
!3 = !{!4, !6, !13, !15}
|
||||
!4 = distinct !DIGlobalVariable(name: "first", linkageName: "\01?first@@3HA", scope: !0, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, variable: i32* @"\01?first@@3HA")
|
||||
!5 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
|
||||
!6 = distinct !DIGlobalVariable(name: "comdat", linkageName: "\01?comdat@?$A@X@@2HB", scope: !0, file: !1, line: 2, type: !7, isLocal: false, isDefinition: true, variable: i32* @"\01?comdat@?$A@X@@2HB", declaration: !8)
|
||||
!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !5)
|
||||
!8 = !DIDerivedType(tag: DW_TAG_member, name: "comdat", scope: !9, file: !1, line: 2, baseType: !7, flags: DIFlagStaticMember, extraData: i32 3)
|
||||
!9 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A<void>", file: !1, line: 2, size: 8, align: 8, elements: !10, templateParams: !11)
|
||||
!10 = !{!8}
|
||||
!11 = !{!12}
|
||||
!12 = !DITemplateTypeParameter(name: "T", type: null)
|
||||
!13 = distinct !DIGlobalVariable(name: "middle", linkageName: "\01?middle@@3PEBHEB", scope: !0, file: !1, line: 3, type: !14, isLocal: false, isDefinition: true, variable: i32** @"\01?middle@@3PEBHEB")
|
||||
!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64, align: 64)
|
||||
!15 = distinct !DIGlobalVariable(name: "last", linkageName: "\01?last@@3HA", scope: !0, file: !1, line: 4, type: !5, isLocal: false, isDefinition: true, variable: i32* @"\01?last@@3HA")
|
||||
!16 = !{i32 2, !"CodeView", i32 1}
|
||||
!17 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!18 = !{i32 1, !"PIC Level", i32 2}
|
||||
!19 = !{!"clang version 3.9.0 (trunk 271937)"}
|
Loading…
Reference in New Issue