mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-03-07 11:59:09 +00:00
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:
parent
52877406d0
commit
d9ffd45945
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
64
test/DebugInfo/COFF/global-constants.ll
Normal file
64
test/DebugInfo/COFF/global-constants.ll
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user