Emit global variables as S_CONSTANT records for codeview debug info.

Summary:
This emits S_CONSTANT records for global variables.
Currently this emits records for the global variables already being tracked in the
LLVM IR metadata, which are just constant global variables; we'll also want S_CONSTANTs
for static data members and enums.

Related to https://bugs.llvm.org/show_bug.cgi?id=41615

Reviewers: rnk

Subscribers: aprantl, hiraditya, llvm-commits, thakis

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D61926

llvm-svn: 360948
This commit is contained in:
Amy Huang 2019-05-16 22:28:52 +00:00
parent 52877406d0
commit d9ffd45945
3 changed files with 133 additions and 31 deletions

View File

@ -41,6 +41,7 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h"
#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
#include "llvm/DebugInfo/CodeView/EnumTables.h"
@ -66,6 +67,7 @@
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
@ -2940,10 +2942,19 @@ void CodeViewDebug::collectGlobalVariableInfo() {
for (const MDNode *Node : CUs->operands()) {
const auto *CU = cast<DICompileUnit>(Node);
for (const auto *GVE : CU->getGlobalVariables()) {
const DIGlobalVariable *DIGV = GVE->getVariable();
const DIExpression *DIE = GVE->getExpression();
// Emit constant global variables in a global symbol section.
if (GlobalMap.count(GVE) == 0 && DIE->isConstant()) {
CVGlobalVariable CVGV = {DIGV, DIE};
GlobalVariables.emplace_back(std::move(CVGV));
}
const auto *GV = GlobalMap.lookup(GVE);
if (!GV || GV->isDeclarationForLinker())
continue;
const DIGlobalVariable *DIGV = GVE->getVariable();
DIScope *Scope = DIGV->getScope();
SmallVector<CVGlobalVariable, 1> *VariableList;
if (Scope && isa<DILocalScope>(Scope)) {
@ -2958,7 +2969,7 @@ void CodeViewDebug::collectGlobalVariableInfo() {
// Emit this global variable into a COMDAT section.
VariableList = &ComdatVariables;
else
// Emit this globla variable in a single global symbol section.
// Emit this global variable in a single global symbol section.
VariableList = &GlobalVariables;
CVGlobalVariable CVGV = {DIGV, GV};
VariableList->emplace_back(std::move(CVGV));
@ -2981,13 +2992,14 @@ void CodeViewDebug::emitDebugInfoForGlobals() {
// Second, emit each global that is in a comdat into its own .debug$S
// section along with its own symbol substream.
for (const CVGlobalVariable &CVGV : ComdatVariables) {
MCSymbol *GVSym = Asm->getSymbol(CVGV.GV);
const GlobalVariable *GV = CVGV.GVInfo.get<const GlobalVariable *>();
MCSymbol *GVSym = Asm->getSymbol(GV);
OS.AddComment("Symbol subsection for " +
Twine(GlobalValue::dropLLVMManglingEscape(CVGV.GV->getName())));
Twine(GlobalValue::dropLLVMManglingEscape(GV->getName())));
switchToDebugSectionForSymbol(GVSym);
MCSymbol *EndLabel = beginCVSubsection(DebugSubsectionKind::Symbols);
// FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions.
emitDebugInfoForGlobal(CVGV.DIGV, CVGV.GV, GVSym);
emitDebugInfoForGlobal(CVGV);
endCVSubsection(EndLabel);
}
}
@ -3007,31 +3019,57 @@ void CodeViewDebug::emitDebugInfoForRetainedTypes() {
// Emit each global variable in the specified array.
void CodeViewDebug::emitGlobalVariableList(ArrayRef<CVGlobalVariable> Globals) {
for (const CVGlobalVariable &CVGV : Globals) {
MCSymbol *GVSym = Asm->getSymbol(CVGV.GV);
// FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions.
emitDebugInfoForGlobal(CVGV.DIGV, CVGV.GV, GVSym);
emitDebugInfoForGlobal(CVGV);
}
}
void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV,
const GlobalVariable *GV,
MCSymbol *GVSym) {
// DataSym record, see SymbolRecord.h for more info. Thread local data
// happens to have the same format as global data.
SymbolKind DataSym = GV->isThreadLocal()
? (DIGV->isLocalToUnit() ? SymbolKind::S_LTHREAD32
: SymbolKind::S_GTHREAD32)
: (DIGV->isLocalToUnit() ? SymbolKind::S_LDATA32
: SymbolKind::S_GDATA32);
MCSymbol *DataEnd = beginSymbolRecord(DataSym);
OS.AddComment("Type");
OS.EmitIntValue(getCompleteTypeIndex(DIGV->getType()).getIndex(), 4);
OS.AddComment("DataOffset");
OS.EmitCOFFSecRel32(GVSym, /*Offset=*/0);
OS.AddComment("Segment");
OS.EmitCOFFSectionIndex(GVSym);
OS.AddComment("Name");
const unsigned LengthOfDataRecord = 12;
emitNullTerminatedSymbolName(OS, DIGV->getName(), LengthOfDataRecord);
endSymbolRecord(DataEnd);
void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) {
const DIGlobalVariable *DIGV = CVGV.DIGV;
if (const GlobalVariable *GV =
CVGV.GVInfo.dyn_cast<const GlobalVariable *>()) {
// DataSym record, see SymbolRecord.h for more info. Thread local data
// happens to have the same format as global data.
MCSymbol *GVSym = Asm->getSymbol(GV);
SymbolKind DataSym = GV->isThreadLocal()
? (DIGV->isLocalToUnit() ? SymbolKind::S_LTHREAD32
: SymbolKind::S_GTHREAD32)
: (DIGV->isLocalToUnit() ? SymbolKind::S_LDATA32
: SymbolKind::S_GDATA32);
MCSymbol *DataEnd = beginSymbolRecord(DataSym);
OS.AddComment("Type");
OS.EmitIntValue(getCompleteTypeIndex(DIGV->getType()).getIndex(), 4);
OS.AddComment("DataOffset");
OS.EmitCOFFSecRel32(GVSym, /*Offset=*/0);
OS.AddComment("Segment");
OS.EmitCOFFSectionIndex(GVSym);
OS.AddComment("Name");
const unsigned LengthOfDataRecord = 12;
emitNullTerminatedSymbolName(OS, DIGV->getName(), LengthOfDataRecord);
endSymbolRecord(DataEnd);
} else {
// FIXME: Currently this only emits the global variables in the IR metadata.
// This should also emit enums and static data members.
const DIExpression *DIE = CVGV.GVInfo.get<const DIExpression *>();
assert(DIE->isConstant() &&
"Global constant variables must contain a constant expression.");
uint64_t Val = DIE->getElement(1);
MCSymbol *SConstantEnd = beginSymbolRecord(SymbolKind::S_CONSTANT);
OS.AddComment("Type");
OS.EmitIntValue(getTypeIndex(DIGV->getType()).getIndex(), 4);
OS.AddComment("Value");
// Encoded integers shouldn't need more than 10 bytes.
uint8_t data[10];
BinaryStreamWriter Writer(data, llvm::support::endianness::little);
CodeViewRecordIO IO(Writer);
cantFail(IO.mapEncodedInteger(Val));
StringRef SRef((char *)data, Writer.getOffset());
OS.EmitBinaryData(SRef);
OS.AddComment("Name");
emitNullTerminatedSymbolName(OS, DIGV->getDisplayName());
endSymbolRecord(SConstantEnd);
}
}

View File

@ -17,6 +17,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/DbgEntityHistoryCalculator.h"
@ -100,7 +101,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
struct CVGlobalVariable {
const DIGlobalVariable *DIGV;
const GlobalVariable *GV;
PointerUnion<const GlobalVariable *, const DIExpression *> GVInfo;
};
struct InlineSite {
@ -313,8 +314,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
void emitDebugInfoForGlobals();
void emitGlobalVariableList(ArrayRef<CVGlobalVariable> Globals);
void emitDebugInfoForGlobal(const DIGlobalVariable *DIGV,
const GlobalVariable *GV, MCSymbol *GVSym);
void emitDebugInfoForGlobal(const CVGlobalVariable &CVGV);
/// 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

View File

@ -0,0 +1,64 @@
; 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:
; const int Test1 = 1;
; int main() {
; return Test1;
; }
; $ clang t.cpp -S -emit-llvm -g -gcodeview -o t.ll
; ASM-LABEL: .long 241 # Symbol subsection for globals
; ASM: .short {{.*-.*}} # Record length
; ASM: .short 4359 # Record kind: S_CONSTANT
; ASM-NEXT: .long 4099 # Type
; ASM-NEXT: .byte 0x01, 0x00 # Value
; ASM-NEXT: .asciz "Test1" # Name
; OBJ: CodeViewDebugInfo [
; OBJ: Section: .debug$S
; OBJ: Magic: 0x4
; OBJ: Subsection [
; OBJ: SubSectionType: Symbols (0xF1)
; OBJ: ConstantSym {
; OBJ-NEXT: Kind: S_CONSTANT (0x1107)
; OBJ-NEXT: Type: const int (0x1003)
; OBJ-NEXT: Value: 1
; OBJ-NEXT: Name: Test1
; OBJ-NEXT: }
; 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-msvc"
; Function Attrs: noinline norecurse nounwind optnone
define dso_local i32 @main() #0 !dbg !13 {
entry:
%retval = alloca i32, align 4
store i32 0, i32* %retval, align 4
ret i32 1, !dbg !16
}
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!9, !10, !11}
!llvm.ident = !{!12}
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (https://github.com/llvm/llvm-project.git 4a1902b6739e3087a03c0ac7ab85b640764e9335)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None)
!1 = !DIFile(filename: "<stdin>", directory: "C:\5Csrc\5Ctest", checksumkind: CSK_MD5, checksum: "0d5ef00bdd80bdb409a3deac9938f20d")
!2 = !{}
!3 = !{!4}
!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value))
!5 = distinct !DIGlobalVariable(name: "Test1", scope: !0, file: !6, line: 1, type: !7, isLocal: true, isDefinition: true)
!6 = !DIFile(filename: "t.cpp", directory: "C:\5Csrc\5Ctest", checksumkind: CSK_MD5, checksum: "0d5ef00bdd80bdb409a3deac9938f20d")
!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8)
!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!9 = !{i32 2, !"CodeView", i32 1}
!10 = !{i32 2, !"Debug Info Version", i32 3}
!11 = !{i32 1, !"wchar_size", i32 2}
!12 = !{!"clang version 9.0.0 (https://github.com/llvm/llvm-project.git 4a1902b6739e3087a03c0ac7ab85b640764e9335)"}
!13 = distinct !DISubprogram(name: "main", scope: !6, file: !6, line: 3, type: !14, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
!14 = !DISubroutineType(types: !15)
!15 = !{!8}
!16 = !DILocation(line: 4, scope: !13)