summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp')
-rw-r--r--contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp692
1 files changed, 454 insertions, 238 deletions
diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index ebf80de..8344051 100644
--- a/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -13,17 +13,20 @@
#include "CodeViewDebug.h"
#include "llvm/ADT/TinyPtrVector.h"
-#include "llvm/DebugInfo/CodeView/ByteStream.h"
+#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeDumper.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/DebugInfo/MSF/StreamReader.h"
#include "llvm/IR/Constants.h"
+#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCSectionCOFF.h"
#include "llvm/MC/MCSymbol.h"
@@ -35,9 +38,11 @@
using namespace llvm;
using namespace llvm::codeview;
+using namespace llvm::msf;
CodeViewDebug::CodeViewDebug(AsmPrinter *AP)
- : DebugHandlerBase(AP), OS(*Asm->OutStreamer), CurFn(nullptr) {
+ : DebugHandlerBase(AP), OS(*Asm->OutStreamer), Allocator(),
+ TypeTable(Allocator), CurFn(nullptr) {
// If module doesn't have named metadata anchors or COFF debug section
// is not available, skip any debug info related stuff.
if (!MMI->getModule()->getNamedMetadata("llvm.dbg.cu") ||
@@ -108,8 +113,9 @@ unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) {
if (Insertion.second) {
// We have to compute the full filepath and emit a .cv_file directive.
StringRef FullPath = getFullFilepath(F);
- NextId = OS.EmitCVFileDirective(NextId, FullPath);
- assert(NextId == FileIdMap.size() && ".cv_file directive failed");
+ bool Success = OS.EmitCVFileDirective(NextId, FullPath);
+ (void)Success;
+ assert(Success && ".cv_file directive failed");
}
return Insertion.first->second;
}
@@ -120,7 +126,16 @@ CodeViewDebug::getInlineSite(const DILocation *InlinedAt,
auto SiteInsertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()});
InlineSite *Site = &SiteInsertion.first->second;
if (SiteInsertion.second) {
+ unsigned ParentFuncId = CurFn->FuncId;
+ if (const DILocation *OuterIA = InlinedAt->getInlinedAt())
+ ParentFuncId =
+ getInlineSite(OuterIA, InlinedAt->getScope()->getSubprogram())
+ .SiteFuncId;
+
Site->SiteFuncId = NextFuncId++;
+ OS.EmitCVInlineSiteIdDirective(
+ Site->SiteFuncId, ParentFuncId, maybeRecordFile(InlinedAt->getFile()),
+ InlinedAt->getLine(), InlinedAt->getColumn(), SMLoc());
Site->Inlinee = Inlinee;
InlinedSubprograms.insert(Inlinee);
getFuncIdForSubprogram(Inlinee);
@@ -208,8 +223,8 @@ TypeIndex CodeViewDebug::getScopeIndex(const DIScope *Scope) {
// Build the fully qualified name of the scope.
std::string ScopeName = getFullyQualifiedName(Scope);
- TypeIndex TI =
- TypeTable.writeStringId(StringIdRecord(TypeIndex(), ScopeName));
+ StringIdRecord SID(TypeIndex(), ScopeName);
+ auto TI = TypeTable.writeKnownType(SID);
return recordTypeIndexForDINode(Scope, TI);
}
@@ -234,12 +249,12 @@ TypeIndex CodeViewDebug::getFuncIdForSubprogram(const DISubprogram *SP) {
TypeIndex ClassType = getTypeIndex(Class);
MemberFuncIdRecord MFuncId(ClassType, getMemberFunctionType(SP, Class),
DisplayName);
- TI = TypeTable.writeMemberFuncId(MFuncId);
+ TI = TypeTable.writeKnownType(MFuncId);
} else {
// Otherwise, this must be a free function.
TypeIndex ParentScope = getScopeIndex(Scope);
FuncIdRecord FuncId(ParentScope, getTypeIndex(SP->getType()), DisplayName);
- TI = TypeTable.writeFuncId(FuncId);
+ TI = TypeTable.writeKnownType(FuncId);
}
return recordTypeIndexForDINode(SP, TI);
@@ -353,8 +368,8 @@ void CodeViewDebug::maybeRecordLocation(const DebugLoc &DL,
}
OS.EmitCVLocDirective(FuncId, FileId, DL.getLine(), DL.getCol(),
- /*PrologueEnd=*/false,
- /*IsStmt=*/false, DL->getFilename());
+ /*PrologueEnd=*/false, /*IsStmt=*/false,
+ DL->getFilename(), SMLoc());
}
void CodeViewDebug::emitCodeViewMagicVersion() {
@@ -377,6 +392,11 @@ void CodeViewDebug::endModule() {
// Use the generic .debug$S section, and make a subsection for all the inlined
// subprograms.
switchToDebugSectionForSymbol(nullptr);
+
+ MCSymbol *CompilerInfo = beginCVSubsection(ModuleSubstreamKind::Symbols);
+ emitCompilerInformation();
+ endCVSubsection(CompilerInfo);
+
emitInlineeLinesSubsection();
// Emit per-function debug information.
@@ -418,10 +438,13 @@ void CodeViewDebug::endModule() {
}
static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S) {
- // Microsoft's linker seems to have trouble with symbol names longer than
- // 0xffd8 bytes.
- S = S.substr(0, 0xffd8);
- SmallString<32> NullTerminatedString(S);
+ // The maximum CV record length is 0xFF00. Most of the strings we emit appear
+ // after a fixed length portion of the record. The fixed length portion should
+ // always be less than 0xF00 (3840) bytes, so truncate the string so that the
+ // overall record size is less than the maximum allowed.
+ unsigned MaxFixedRecordLength = 0xF00;
+ SmallString<32> NullTerminatedString(
+ S.take_front(MaxRecordLength - MaxFixedRecordLength - 1));
NullTerminatedString.push_back('\0');
OS.EmitBytes(NullTerminatedString);
}
@@ -446,48 +469,175 @@ void CodeViewDebug::emitTypeInformation() {
CommentPrefix += ' ';
}
- CVTypeDumper CVTD(nullptr, /*PrintRecordBytes=*/false);
- TypeTable.ForEachRecord(
- [&](TypeIndex Index, StringRef Record) {
- if (OS.isVerboseAsm()) {
- // Emit a block comment describing the type record for readability.
- SmallString<512> CommentBlock;
- raw_svector_ostream CommentOS(CommentBlock);
- ScopedPrinter SP(CommentOS);
- SP.setPrefix(CommentPrefix);
- CVTD.setPrinter(&SP);
- Error E = CVTD.dump({Record.bytes_begin(), Record.bytes_end()});
- if (E) {
- logAllUnhandledErrors(std::move(E), errs(), "error: ");
- llvm_unreachable("produced malformed type record");
- }
- // emitRawComment will insert its own tab and comment string before
- // the first line, so strip off our first one. It also prints its own
- // newline.
- OS.emitRawComment(
- CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
- } else {
+ TypeDatabase TypeDB;
+ CVTypeDumper CVTD(TypeDB);
+ TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef<uint8_t> Record) {
+ if (OS.isVerboseAsm()) {
+ // Emit a block comment describing the type record for readability.
+ SmallString<512> CommentBlock;
+ raw_svector_ostream CommentOS(CommentBlock);
+ ScopedPrinter SP(CommentOS);
+ SP.setPrefix(CommentPrefix);
+ TypeDumpVisitor TDV(TypeDB, &SP, false);
+ Error E = CVTD.dump(Record, TDV);
+ if (E) {
+ logAllUnhandledErrors(std::move(E), errs(), "error: ");
+ llvm_unreachable("produced malformed type record");
+ }
+ // emitRawComment will insert its own tab and comment string before
+ // the first line, so strip off our first one. It also prints its own
+ // newline.
+ OS.emitRawComment(
+ CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
+ } else {
#ifndef NDEBUG
- // Assert that the type data is valid even if we aren't dumping
- // comments. The MSVC linker doesn't do much type record validation,
- // so the first link of an invalid type record can succeed while
- // subsequent links will fail with LNK1285.
- ByteStream<> Stream({Record.bytes_begin(), Record.bytes_end()});
- CVTypeArray Types;
- StreamReader Reader(Stream);
- Error E = Reader.readArray(Types, Reader.getLength());
- if (!E) {
- TypeVisitorCallbacks C;
- E = CVTypeVisitor(C).visitTypeStream(Types);
- }
- if (E) {
- logAllUnhandledErrors(std::move(E), errs(), "error: ");
- llvm_unreachable("produced malformed type record");
- }
+ // Assert that the type data is valid even if we aren't dumping
+ // comments. The MSVC linker doesn't do much type record validation,
+ // so the first link of an invalid type record can succeed while
+ // subsequent links will fail with LNK1285.
+ ByteStream Stream(Record);
+ CVTypeArray Types;
+ StreamReader Reader(Stream);
+ Error E = Reader.readArray(Types, Reader.getLength());
+ if (!E) {
+ TypeVisitorCallbacks C;
+ E = CVTypeVisitor(C).visitTypeStream(Types);
+ }
+ if (E) {
+ logAllUnhandledErrors(std::move(E), errs(), "error: ");
+ llvm_unreachable("produced malformed type record");
+ }
#endif
- }
- OS.EmitBinaryData(Record);
- });
+ }
+ StringRef S(reinterpret_cast<const char *>(Record.data()), Record.size());
+ OS.EmitBinaryData(S);
+ });
+}
+
+namespace {
+
+static SourceLanguage MapDWLangToCVLang(unsigned DWLang) {
+ switch (DWLang) {
+ case dwarf::DW_LANG_C:
+ case dwarf::DW_LANG_C89:
+ case dwarf::DW_LANG_C99:
+ case dwarf::DW_LANG_C11:
+ case dwarf::DW_LANG_ObjC:
+ return SourceLanguage::C;
+ case dwarf::DW_LANG_C_plus_plus:
+ case dwarf::DW_LANG_C_plus_plus_03:
+ case dwarf::DW_LANG_C_plus_plus_11:
+ case dwarf::DW_LANG_C_plus_plus_14:
+ return SourceLanguage::Cpp;
+ case dwarf::DW_LANG_Fortran77:
+ case dwarf::DW_LANG_Fortran90:
+ case dwarf::DW_LANG_Fortran03:
+ case dwarf::DW_LANG_Fortran08:
+ return SourceLanguage::Fortran;
+ case dwarf::DW_LANG_Pascal83:
+ return SourceLanguage::Pascal;
+ case dwarf::DW_LANG_Cobol74:
+ case dwarf::DW_LANG_Cobol85:
+ return SourceLanguage::Cobol;
+ case dwarf::DW_LANG_Java:
+ return SourceLanguage::Java;
+ default:
+ // There's no CodeView representation for this language, and CV doesn't
+ // have an "unknown" option for the language field, so we'll use MASM,
+ // as it's very low level.
+ return SourceLanguage::Masm;
+ }
+}
+
+struct Version {
+ int Part[4];
+};
+
+// Takes a StringRef like "clang 4.0.0.0 (other nonsense 123)" and parses out
+// the version number.
+static Version parseVersion(StringRef Name) {
+ Version V = {{0}};
+ int N = 0;
+ for (const char C : Name) {
+ if (isdigit(C)) {
+ V.Part[N] *= 10;
+ V.Part[N] += C - '0';
+ } else if (C == '.') {
+ ++N;
+ if (N >= 4)
+ return V;
+ } else if (N > 0)
+ return V;
+ }
+ return V;
+}
+
+static CPUType mapArchToCVCPUType(Triple::ArchType Type) {
+ switch (Type) {
+ case Triple::ArchType::x86:
+ return CPUType::Pentium3;
+ case Triple::ArchType::x86_64:
+ return CPUType::X64;
+ case Triple::ArchType::thumb:
+ return CPUType::Thumb;
+ default:
+ report_fatal_error("target architecture doesn't map to a CodeView "
+ "CPUType");
+ }
+}
+
+} // anonymous namespace
+
+void CodeViewDebug::emitCompilerInformation() {
+ MCContext &Context = MMI->getContext();
+ MCSymbol *CompilerBegin = Context.createTempSymbol(),
+ *CompilerEnd = Context.createTempSymbol();
+ OS.AddComment("Record length");
+ OS.emitAbsoluteSymbolDiff(CompilerEnd, CompilerBegin, 2);
+ OS.EmitLabel(CompilerBegin);
+ OS.AddComment("Record kind: S_COMPILE3");
+ OS.EmitIntValue(SymbolKind::S_COMPILE3, 2);
+ uint32_t Flags = 0;
+
+ NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
+ const MDNode *Node = *CUs->operands().begin();
+ const auto *CU = cast<DICompileUnit>(Node);
+
+ // The low byte of the flags indicates the source language.
+ Flags = MapDWLangToCVLang(CU->getSourceLanguage());
+ // TODO: Figure out which other flags need to be set.
+
+ OS.AddComment("Flags and language");
+ OS.EmitIntValue(Flags, 4);
+
+ OS.AddComment("CPUType");
+ CPUType CPU =
+ mapArchToCVCPUType(Triple(MMI->getModule()->getTargetTriple()).getArch());
+ OS.EmitIntValue(static_cast<uint64_t>(CPU), 2);
+
+ StringRef CompilerVersion = CU->getProducer();
+ Version FrontVer = parseVersion(CompilerVersion);
+ OS.AddComment("Frontend version");
+ for (int N = 0; N < 4; ++N)
+ OS.EmitIntValue(FrontVer.Part[N], 2);
+
+ // Some Microsoft tools, like Binscope, expect a backend version number of at
+ // least 8.something, so we'll coerce the LLVM version into a form that
+ // guarantees it'll be big enough without really lying about the version.
+ int Major = 1000 * LLVM_VERSION_MAJOR +
+ 10 * LLVM_VERSION_MINOR +
+ LLVM_VERSION_PATCH;
+ // Clamp it for builds that use unusually large version numbers.
+ Major = std::min<int>(Major, std::numeric_limits<uint16_t>::max());
+ Version BackVer = {{ Major, 0, 0, 0 }};
+ OS.AddComment("Backend version");
+ for (int N = 0; N < 4; ++N)
+ OS.EmitIntValue(BackVer.Part[N], 2);
+
+ OS.AddComment("Null-terminated compiler version string");
+ emitNullTerminatedSymbolName(OS, CompilerVersion);
+
+ OS.EmitLabel(CompilerEnd);
}
void CodeViewDebug::emitInlineeLinesSubsection() {
@@ -525,17 +675,6 @@ void CodeViewDebug::emitInlineeLinesSubsection() {
endCVSubsection(InlineEnd);
}
-void CodeViewDebug::collectInlineSiteChildren(
- SmallVectorImpl<unsigned> &Children, const FunctionInfo &FI,
- const InlineSite &Site) {
- for (const DILocation *ChildSiteLoc : Site.ChildSites) {
- auto I = FI.InlineSites.find(ChildSiteLoc);
- const InlineSite &ChildSite = I->second;
- Children.push_back(ChildSite.SiteFuncId);
- collectInlineSiteChildren(Children, FI, ChildSite);
- }
-}
-
void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI,
const DILocation *InlinedAt,
const InlineSite &Site) {
@@ -561,11 +700,9 @@ void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI,
unsigned FileId = maybeRecordFile(Site.Inlinee->getFile());
unsigned StartLineNum = Site.Inlinee->getLine();
- SmallVector<unsigned, 3> SecondaryFuncIds;
- collectInlineSiteChildren(SecondaryFuncIds, FI, Site);
OS.EmitCVInlineLinetableDirective(Site.SiteFuncId, FileId, StartLineNum,
- FI.Begin, FI.End, SecondaryFuncIds);
+ FI.Begin, FI.End);
OS.EmitLabel(InlineEnd);
@@ -641,13 +778,13 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
OS.emitAbsoluteSymbolDiff(ProcRecordEnd, ProcRecordBegin, 2);
OS.EmitLabel(ProcRecordBegin);
- if (GV->hasLocalLinkage()) {
- OS.AddComment("Record kind: S_LPROC32_ID");
- OS.EmitIntValue(unsigned(SymbolKind::S_LPROC32_ID), 2);
- } else {
- OS.AddComment("Record kind: S_GPROC32_ID");
- OS.EmitIntValue(unsigned(SymbolKind::S_GPROC32_ID), 2);
- }
+ if (GV->hasLocalLinkage()) {
+ OS.AddComment("Record kind: S_LPROC32_ID");
+ OS.EmitIntValue(unsigned(SymbolKind::S_LPROC32_ID), 2);
+ } else {
+ OS.AddComment("Record kind: S_GPROC32_ID");
+ OS.EmitIntValue(unsigned(SymbolKind::S_GPROC32_ID), 2);
+ }
// These fields are filled in by tools like CVPACK which run after the fact.
OS.AddComment("PtrParent");
@@ -667,7 +804,7 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
OS.AddComment("Function type index");
OS.EmitIntValue(getFuncIdForSubprogram(GV->getSubprogram()).getIndex(), 4);
OS.AddComment("Function section relative address");
- OS.EmitCOFFSecRel32(Fn);
+ OS.EmitCOFFSecRel32(Fn, /*Offset=*/0);
OS.AddComment("Function section index");
OS.EmitCOFFSectionIndex(Fn);
OS.AddComment("Flags");
@@ -711,29 +848,33 @@ CodeViewDebug::createDefRangeMem(uint16_t CVRegister, int Offset) {
DR.InMemory = -1;
DR.DataOffset = Offset;
assert(DR.DataOffset == Offset && "truncation");
+ DR.IsSubfield = 0;
DR.StructOffset = 0;
DR.CVRegister = CVRegister;
return DR;
}
CodeViewDebug::LocalVarDefRange
-CodeViewDebug::createDefRangeReg(uint16_t CVRegister) {
+CodeViewDebug::createDefRangeGeneral(uint16_t CVRegister, bool InMemory,
+ int Offset, bool IsSubfield,
+ uint16_t StructOffset) {
LocalVarDefRange DR;
- DR.InMemory = 0;
- DR.DataOffset = 0;
- DR.StructOffset = 0;
+ DR.InMemory = InMemory;
+ DR.DataOffset = Offset;
+ DR.IsSubfield = IsSubfield;
+ DR.StructOffset = StructOffset;
DR.CVRegister = CVRegister;
return DR;
}
-void CodeViewDebug::collectVariableInfoFromMMITable(
+void CodeViewDebug::collectVariableInfoFromMFTable(
DenseSet<InlinedVariable> &Processed) {
- const TargetSubtargetInfo &TSI = Asm->MF->getSubtarget();
+ const MachineFunction &MF = *Asm->MF;
+ const TargetSubtargetInfo &TSI = MF.getSubtarget();
const TargetFrameLowering *TFI = TSI.getFrameLowering();
const TargetRegisterInfo *TRI = TSI.getRegisterInfo();
- for (const MachineModuleInfo::VariableDbgInfo &VI :
- MMI->getVariableDbgInfo()) {
+ for (const MachineFunction::VariableDbgInfo &VI : MF.getVariableDbgInfo()) {
if (!VI.Var)
continue;
assert(VI.Var->isValidLocationForIntrinsic(VI.Loc) &&
@@ -770,7 +911,7 @@ void CodeViewDebug::collectVariableInfoFromMMITable(
void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
DenseSet<InlinedVariable> Processed;
// Grab the variable info that was squirreled away in the MMI side-table.
- collectVariableInfoFromMMITable(Processed);
+ collectVariableInfoFromMFTable(Processed);
const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo();
@@ -802,10 +943,17 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
const MachineInstr *DVInst = Range.first;
assert(DVInst->isDebugValue() && "Invalid History entry");
const DIExpression *DIExpr = DVInst->getDebugExpression();
-
- // Bail if there is a complex DWARF expression for now.
- if (DIExpr && DIExpr->getNumElements() > 0)
- continue;
+ bool IsSubfield = false;
+ unsigned StructOffset = 0;
+
+ // Handle fragments.
+ auto Fragment = DIExpr->getFragmentInfo();
+ if (DIExpr && Fragment) {
+ IsSubfield = true;
+ StructOffset = Fragment->OffsetInBits / 8;
+ } else if (DIExpr && DIExpr->getNumElements() > 0) {
+ continue; // Ignore unrecognized exprs.
+ }
// Bail if operand 0 is not a valid register. This means the variable is a
// simple constant, or is described by a complex expression.
@@ -817,19 +965,20 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
continue;
// Handle the two cases we can handle: indirect in memory and in register.
- bool IsIndirect = DVInst->getOperand(1).isImm();
- unsigned CVReg = TRI->getCodeViewRegNum(DVInst->getOperand(0).getReg());
+ unsigned CVReg = TRI->getCodeViewRegNum(Reg);
+ bool InMemory = DVInst->getOperand(1).isImm();
+ int Offset = InMemory ? DVInst->getOperand(1).getImm() : 0;
{
- LocalVarDefRange DefRange;
- if (IsIndirect) {
- int64_t Offset = DVInst->getOperand(1).getImm();
- DefRange = createDefRangeMem(CVReg, Offset);
- } else {
- DefRange = createDefRangeReg(CVReg);
- }
+ LocalVarDefRange DR;
+ DR.CVRegister = CVReg;
+ DR.InMemory = InMemory;
+ DR.DataOffset = Offset;
+ DR.IsSubfield = IsSubfield;
+ DR.StructOffset = StructOffset;
+
if (Var.DefRanges.empty() ||
- Var.DefRanges.back().isDifferentLocation(DefRange)) {
- Var.DefRanges.emplace_back(std::move(DefRange));
+ Var.DefRanges.back().isDifferentLocation(DR)) {
+ Var.DefRanges.emplace_back(std::move(DR));
}
}
@@ -837,8 +986,14 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
const MCSymbol *End = getLabelAfterInsn(Range.second);
if (!End) {
- if (std::next(I) != E)
- End = getLabelBeforeInsn(std::next(I)->first);
+ // This range is valid until the next overlapping bitpiece. In the
+ // common case, ranges will not be bitpieces, so they will overlap.
+ auto J = std::next(I);
+ while (J != E &&
+ !fragmentsOverlap(DIExpr, J->first->getDebugExpression()))
+ ++J;
+ if (J != E)
+ End = getLabelBeforeInsn(J->first);
else
End = Asm->getFunctionEnd();
}
@@ -873,6 +1028,8 @@ void CodeViewDebug::beginFunction(const MachineFunction *MF) {
CurFn->FuncId = NextFuncId++;
CurFn->Begin = Asm->getFunctionBegin();
+ OS.EmitCVFuncIdDirective(CurFn->FuncId);
+
// Find the end of the function prolog. First known non-DBG_VALUE and
// non-frame setup location marks the beginning of the function body.
// FIXME: is there a simpler a way to do this? Can we just search
@@ -933,6 +1090,9 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) {
case dwarf::DW_TAG_base_type:
return lowerTypeBasic(cast<DIBasicType>(Ty));
case dwarf::DW_TAG_pointer_type:
+ if (cast<DIDerivedType>(Ty)->getName() == "__vtbl_ptr_type")
+ return lowerTypeVFTableShape(cast<DIDerivedType>(Ty));
+ LLVM_FALLTHROUGH;
case dwarf::DW_TAG_reference_type:
case dwarf::DW_TAG_rvalue_reference_type:
return lowerTypePointer(cast<DIDerivedType>(Ty));
@@ -940,6 +1100,7 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) {
return lowerTypeMemberPointer(cast<DIDerivedType>(Ty));
case dwarf::DW_TAG_const_type:
case dwarf::DW_TAG_volatile_type:
+ // TODO: add support for DW_TAG_atomic_type here
return lowerTypeModifier(cast<DIDerivedType>(Ty));
case dwarf::DW_TAG_subroutine_type:
if (ClassTy) {
@@ -989,20 +1150,25 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
uint64_t ElementSize = getBaseTypeSize(ElementTypeRef) / 8;
- bool UndefinedSubrange = false;
- // FIXME:
- // There is a bug in the front-end where an array of a structure, which was
- // declared as incomplete structure first, ends up not getting a size assigned
- // to it. (PR28303)
+ // We want to assert that the element type multiplied by the array lengths
+ // match the size of the overall array. However, if we don't have complete
+ // type information for the base type, we can't make this assertion. This
+ // happens if limited debug info is enabled in this case:
+ // struct VTableOptzn { VTableOptzn(); virtual ~VTableOptzn(); };
+ // VTableOptzn array[3];
+ // The DICompositeType of VTableOptzn will have size zero, and the array will
+ // have size 3 * sizeof(void*), and we should avoid asserting.
+ //
+ // There is a related bug in the front-end where an array of a structure,
+ // which was declared as incomplete structure first, ends up not getting a
+ // size assigned to it. (PR28303)
// Example:
// struct A(*p)[3];
// struct A { int f; } a[3];
- //
- // This needs to be fixed in the front-end, but in the meantime we don't want
- // to trigger an assertion because of this.
- if (Ty->getSizeInBits() == 0) {
- UndefinedSubrange = true;
+ bool PartiallyIncomplete = false;
+ if (Ty->getSizeInBits() == 0 || ElementSize == 0) {
+ PartiallyIncomplete = true;
}
// Add subranges to array type.
@@ -1021,18 +1187,24 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
// FIXME: Make front-end support VLA subrange and emit LF_DIMVARLU.
if (Count == -1) {
Count = 1;
- UndefinedSubrange = true;
+ PartiallyIncomplete = true;
}
- StringRef Name = (i == 0) ? Ty->getName() : "";
// Update the element size and element type index for subsequent subranges.
ElementSize *= Count;
- ElementTypeIndex = TypeTable.writeArray(
- ArrayRecord(ElementTypeIndex, IndexType, ElementSize, Name));
+
+ // If this is the outermost array, use the size from the array. It will be
+ // more accurate if PartiallyIncomplete is true.
+ uint64_t ArraySize =
+ (i == 0 && ElementSize == 0) ? Ty->getSizeInBits() / 8 : ElementSize;
+
+ StringRef Name = (i == 0) ? Ty->getName() : "";
+ ArrayRecord AR(ElementTypeIndex, IndexType, ArraySize, Name);
+ ElementTypeIndex = TypeTable.writeKnownType(AR);
}
- (void)UndefinedSubrange;
- assert(UndefinedSubrange || ElementSize == (Ty->getSizeInBits() / 8));
+ (void)PartiallyIncomplete;
+ assert(PartiallyIncomplete || ElementSize == (Ty->getSizeInBits() / 8));
return ElementTypeIndex;
}
@@ -1080,20 +1252,20 @@ TypeIndex CodeViewDebug::lowerTypeBasic(const DIBasicType *Ty) {
break;
case dwarf::DW_ATE_signed:
switch (ByteSize) {
- case 1: STK = SimpleTypeKind::SByte; break;
- case 2: STK = SimpleTypeKind::Int16Short; break;
- case 4: STK = SimpleTypeKind::Int32; break;
- case 8: STK = SimpleTypeKind::Int64Quad; break;
- case 16: STK = SimpleTypeKind::Int128Oct; break;
+ case 1: STK = SimpleTypeKind::SignedCharacter; break;
+ case 2: STK = SimpleTypeKind::Int16Short; break;
+ case 4: STK = SimpleTypeKind::Int32; break;
+ case 8: STK = SimpleTypeKind::Int64Quad; break;
+ case 16: STK = SimpleTypeKind::Int128Oct; break;
}
break;
case dwarf::DW_ATE_unsigned:
switch (ByteSize) {
- case 1: STK = SimpleTypeKind::Byte; break;
- case 2: STK = SimpleTypeKind::UInt16Short; break;
- case 4: STK = SimpleTypeKind::UInt32; break;
- case 8: STK = SimpleTypeKind::UInt64Quad; break;
- case 16: STK = SimpleTypeKind::UInt128Oct; break;
+ case 1: STK = SimpleTypeKind::UnsignedCharacter; break;
+ case 2: STK = SimpleTypeKind::UInt16Short; break;
+ case 4: STK = SimpleTypeKind::UInt32; break;
+ case 8: STK = SimpleTypeKind::UInt64Quad; break;
+ case 16: STK = SimpleTypeKind::UInt128Oct; break;
}
break;
case dwarf::DW_ATE_UTF:
@@ -1133,13 +1305,6 @@ TypeIndex CodeViewDebug::lowerTypeBasic(const DIBasicType *Ty) {
TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) {
TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType());
- // While processing the type being pointed to it is possible we already
- // created this pointer type. If so, we check here and return the existing
- // pointer type.
- auto I = TypeIndices.find({Ty, nullptr});
- if (I != TypeIndices.end())
- return I->second;
-
// Pointers to simple types can use SimpleTypeMode, rather than having a
// dedicated pointer type record.
if (PointeeTI.isSimple() &&
@@ -1171,7 +1336,7 @@ TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) {
// do.
PointerOptions PO = PointerOptions::None;
PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8);
- return TypeTable.writePointer(PR);
+ return TypeTable.writeKnownType(PR);
}
static PointerToMemberRepresentation
@@ -1222,7 +1387,7 @@ TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty) {
MemberPointerInfo MPI(
ClassTI, translatePtrToMemberRep(SizeInBytes, IsPMF, Ty->getFlags()));
PointerRecord PR(PointeeTI, PK, PM, PO, SizeInBytes, MPI);
- return TypeTable.writePointer(PR);
+ return TypeTable.writeKnownType(PR);
}
/// Given a DWARF calling convention, get the CodeView equivalent. If we don't
@@ -1244,7 +1409,7 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) {
bool IsModifier = true;
const DIType *BaseTy = Ty;
while (IsModifier && BaseTy) {
- // FIXME: Need to add DWARF tag for __unaligned.
+ // FIXME: Need to add DWARF tags for __unaligned and _Atomic
switch (BaseTy->getTag()) {
case dwarf::DW_TAG_const_type:
Mods |= ModifierOptions::Const;
@@ -1260,16 +1425,8 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) {
BaseTy = cast<DIDerivedType>(BaseTy)->getBaseType().resolve();
}
TypeIndex ModifiedTI = getTypeIndex(BaseTy);
-
- // While processing the type being pointed to, it is possible we already
- // created this modifier type. If so, we check here and return the existing
- // modifier type.
- auto I = TypeIndices.find({Ty, nullptr});
- if (I != TypeIndices.end())
- return I->second;
-
ModifierRecord MR(ModifiedTI, Mods);
- return TypeTable.writeModifier(MR);
+ return TypeTable.writeKnownType(MR);
}
TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
@@ -1286,13 +1443,13 @@ TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
}
ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices);
- TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec);
+ TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec);
CallingConvention CC = dwarfCCToCodeView(Ty->getCC());
ProcedureRecord Procedure(ReturnTypeIndex, CC, FunctionOptions::None,
ArgTypeIndices.size(), ArgListIndex);
- return TypeTable.writeProcedure(Procedure);
+ return TypeTable.writeKnownType(Procedure);
}
TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
@@ -1319,20 +1476,29 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
}
ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices);
- TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec);
+ TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec);
CallingConvention CC = dwarfCCToCodeView(Ty->getCC());
// TODO: Need to use the correct values for:
// FunctionOptions
// ThisPointerAdjustment.
- TypeIndex TI = TypeTable.writeMemberFunction(MemberFunctionRecord(
- ReturnTypeIndex, ClassType, ThisTypeIndex, CC, FunctionOptions::None,
- ArgTypeIndices.size(), ArgListIndex, ThisAdjustment));
+ MemberFunctionRecord MFR(ReturnTypeIndex, ClassType, ThisTypeIndex, CC,
+ FunctionOptions::None, ArgTypeIndices.size(),
+ ArgListIndex, ThisAdjustment);
+ TypeIndex TI = TypeTable.writeKnownType(MFR);
return TI;
}
+TypeIndex CodeViewDebug::lowerTypeVFTableShape(const DIDerivedType *Ty) {
+ unsigned VSlotCount = Ty->getSizeInBits() / (8 * Asm->MAI->getPointerSize());
+ SmallVector<VFTableSlotKind, 4> Slots(VSlotCount, VFTableSlotKind::Near);
+
+ VFTableShapeRecord VFTSR(Slots);
+ return TypeTable.writeKnownType(VFTSR);
+}
+
static MemberAccess translateAccessFlags(unsigned RecordTag, unsigned Flags) {
switch (Flags & DINode::FlagAccessibility) {
case DINode::FlagPrivate: return MemberAccess::Private;
@@ -1420,25 +1586,28 @@ TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) {
if (Ty->isForwardDecl()) {
CO |= ClassOptions::ForwardReference;
} else {
- FieldListRecordBuilder Fields;
+ FieldListRecordBuilder FLRB(TypeTable);
+
+ FLRB.begin();
for (const DINode *Element : Ty->getElements()) {
// We assume that the frontend provides all members in source declaration
// order, which is what MSVC does.
if (auto *Enumerator = dyn_cast_or_null<DIEnumerator>(Element)) {
- Fields.writeEnumerator(EnumeratorRecord(
- MemberAccess::Public, APSInt::getUnsigned(Enumerator->getValue()),
- Enumerator->getName()));
+ EnumeratorRecord ER(MemberAccess::Public,
+ APSInt::getUnsigned(Enumerator->getValue()),
+ Enumerator->getName());
+ FLRB.writeMemberType(ER);
EnumeratorCount++;
}
}
- FTI = TypeTable.writeFieldList(Fields);
+ FTI = FLRB.end();
}
std::string FullName = getFullyQualifiedName(Ty);
- return TypeTable.writeEnum(EnumRecord(EnumeratorCount, CO, FTI, FullName,
- Ty->getIdentifier(),
- getTypeIndex(Ty->getBaseType())));
+ EnumRecord ER(EnumeratorCount, CO, FTI, FullName, Ty->getIdentifier(),
+ getTypeIndex(Ty->getBaseType()));
+ return TypeTable.writeKnownType(ER);
}
//===----------------------------------------------------------------------===//
@@ -1465,6 +1634,8 @@ struct llvm::ClassInfo {
// Direct overloaded methods gathered by name.
MethodsMap Methods;
+ TypeIndex VShapeTI;
+
std::vector<const DICompositeType *> NestedClasses;
};
@@ -1513,11 +1684,13 @@ ClassInfo CodeViewDebug::collectClassInfo(const DICompositeType *Ty) {
collectMemberInfo(Info, DDTy);
} else if (DDTy->getTag() == dwarf::DW_TAG_inheritance) {
Info.Inheritance.push_back(DDTy);
+ } else if (DDTy->getTag() == dwarf::DW_TAG_pointer_type &&
+ DDTy->getName() == "__vtbl_ptr_type") {
+ Info.VShapeTI = getTypeIndex(DDTy);
} else if (DDTy->getTag() == dwarf::DW_TAG_friend) {
// Ignore friend members. It appears that MSVC emitted info about
// friends in the past, but modern versions do not.
}
- // FIXME: Get Clang to emit function virtual table here and handle it.
} else if (auto *Composite = dyn_cast<DICompositeType>(Element)) {
Info.NestedClasses.push_back(Composite);
}
@@ -1533,9 +1706,9 @@ TypeIndex CodeViewDebug::lowerTypeClass(const DICompositeType *Ty) {
ClassOptions CO =
ClassOptions::ForwardReference | getCommonClassOptions(Ty);
std::string FullName = getFullyQualifiedName(Ty);
- TypeIndex FwdDeclTI = TypeTable.writeClass(ClassRecord(
- Kind, 0, CO, HfaKind::None, WindowsRTClassKind::None, TypeIndex(),
- TypeIndex(), TypeIndex(), 0, FullName, Ty->getIdentifier()));
+ ClassRecord CR(Kind, 0, CO, TypeIndex(), TypeIndex(), TypeIndex(), 0,
+ FullName, Ty->getIdentifier());
+ TypeIndex FwdDeclTI = TypeTable.writeKnownType(CR);
if (!Ty->isForwardDecl())
DeferredCompleteTypes.push_back(Ty);
return FwdDeclTI;
@@ -1559,14 +1732,14 @@ TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) {
uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
- TypeIndex ClassTI = TypeTable.writeClass(ClassRecord(
- Kind, FieldCount, CO, HfaKind::None, WindowsRTClassKind::None, FieldTI,
- TypeIndex(), VShapeTI, SizeInBytes, FullName, Ty->getIdentifier()));
+ ClassRecord CR(Kind, FieldCount, CO, FieldTI, TypeIndex(), VShapeTI,
+ SizeInBytes, FullName, Ty->getIdentifier());
+ TypeIndex ClassTI = TypeTable.writeKnownType(CR);
- TypeTable.writeUdtSourceLine(UdtSourceLineRecord(
- ClassTI, TypeTable.writeStringId(StringIdRecord(
- TypeIndex(0x0), getFullFilepath(Ty->getFile()))),
- Ty->getLine()));
+ StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
+ TypeIndex SIDI = TypeTable.writeKnownType(SIDR);
+ UdtSourceLineRecord USLR(ClassTI, SIDI, Ty->getLine());
+ TypeTable.writeKnownType(USLR);
addToUDTs(Ty, ClassTI);
@@ -1577,9 +1750,8 @@ TypeIndex CodeViewDebug::lowerTypeUnion(const DICompositeType *Ty) {
ClassOptions CO =
ClassOptions::ForwardReference | getCommonClassOptions(Ty);
std::string FullName = getFullyQualifiedName(Ty);
- TypeIndex FwdDeclTI =
- TypeTable.writeUnion(UnionRecord(0, CO, HfaKind::None, TypeIndex(), 0,
- FullName, Ty->getIdentifier()));
+ UnionRecord UR(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier());
+ TypeIndex FwdDeclTI = TypeTable.writeKnownType(UR);
if (!Ty->isForwardDecl())
DeferredCompleteTypes.push_back(Ty);
return FwdDeclTI;
@@ -1599,14 +1771,14 @@ TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) {
uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
std::string FullName = getFullyQualifiedName(Ty);
- TypeIndex UnionTI = TypeTable.writeUnion(
- UnionRecord(FieldCount, CO, HfaKind::None, FieldTI, SizeInBytes, FullName,
- Ty->getIdentifier()));
+ UnionRecord UR(FieldCount, CO, FieldTI, SizeInBytes, FullName,
+ Ty->getIdentifier());
+ TypeIndex UnionTI = TypeTable.writeKnownType(UR);
- TypeTable.writeUdtSourceLine(UdtSourceLineRecord(
- UnionTI, TypeTable.writeStringId(StringIdRecord(
- TypeIndex(0x0), getFullFilepath(Ty->getFile()))),
- Ty->getLine()));
+ StringIdRecord SIR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
+ TypeIndex SIRI = TypeTable.writeKnownType(SIR);
+ UdtSourceLineRecord USLR(UnionTI, SIRI, Ty->getLine());
+ TypeTable.writeKnownType(USLR);
addToUDTs(Ty, UnionTI);
@@ -1621,7 +1793,8 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
// list record.
unsigned MemberCount = 0;
ClassInfo Info = collectClassInfo(Ty);
- FieldListRecordBuilder Fields;
+ FieldListRecordBuilder FLBR(TypeTable);
+ FLBR.begin();
// Create base classes.
for (const DIDerivedType *I : Info.Inheritance) {
@@ -1631,16 +1804,22 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
unsigned VBPtrOffset = 0;
// FIXME: Despite the accessor name, the offset is really in bytes.
unsigned VBTableIndex = I->getOffsetInBits() / 4;
- Fields.writeVirtualBaseClass(VirtualBaseClassRecord(
- translateAccessFlags(Ty->getTag(), I->getFlags()),
+ auto RecordKind = (I->getFlags() & DINode::FlagIndirectVirtualBase) == DINode::FlagIndirectVirtualBase
+ ? TypeRecordKind::IndirectVirtualBaseClass
+ : TypeRecordKind::VirtualBaseClass;
+ VirtualBaseClassRecord VBCR(
+ RecordKind, translateAccessFlags(Ty->getTag(), I->getFlags()),
getTypeIndex(I->getBaseType()), getVBPTypeIndex(), VBPtrOffset,
- VBTableIndex));
+ VBTableIndex);
+
+ FLBR.writeMemberType(VBCR);
} else {
assert(I->getOffsetInBits() % 8 == 0 &&
"bases must be on byte boundaries");
- Fields.writeBaseClass(BaseClassRecord(
- translateAccessFlags(Ty->getTag(), I->getFlags()),
- getTypeIndex(I->getBaseType()), I->getOffsetInBits() / 8));
+ BaseClassRecord BCR(translateAccessFlags(Ty->getTag(), I->getFlags()),
+ getTypeIndex(I->getBaseType()),
+ I->getOffsetInBits() / 8);
+ FLBR.writeMemberType(BCR);
}
}
@@ -1653,8 +1832,17 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
translateAccessFlags(Ty->getTag(), Member->getFlags());
if (Member->isStaticMember()) {
- Fields.writeStaticDataMember(
- StaticDataMemberRecord(Access, MemberBaseType, MemberName));
+ StaticDataMemberRecord SDMR(Access, MemberBaseType, MemberName);
+ FLBR.writeMemberType(SDMR);
+ MemberCount++;
+ continue;
+ }
+
+ // Virtual function pointer member.
+ if ((Member->getFlags() & DINode::FlagArtificial) &&
+ Member->getName().startswith("_vptr$")) {
+ VFPtrRecord VFPR(getTypeIndex(Member->getBaseType()));
+ FLBR.writeMemberType(VFPR);
MemberCount++;
continue;
}
@@ -1669,12 +1857,14 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
MemberOffsetInBits = CI->getZExtValue() + MemberInfo.BaseOffset;
}
StartBitOffset -= MemberOffsetInBits;
- MemberBaseType = TypeTable.writeBitField(BitFieldRecord(
- MemberBaseType, Member->getSizeInBits(), StartBitOffset));
+ BitFieldRecord BFR(MemberBaseType, Member->getSizeInBits(),
+ StartBitOffset);
+ MemberBaseType = TypeTable.writeKnownType(BFR);
}
uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8;
- Fields.writeDataMember(DataMemberRecord(Access, MemberBaseType,
- MemberOffsetInBytes, MemberName));
+ DataMemberRecord DMR(Access, MemberBaseType, MemberOffsetInBytes,
+ MemberName);
+ FLBR.writeMemberType(DMR);
MemberCount++;
}
@@ -1691,33 +1881,32 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
if (Introduced)
VFTableOffset = SP->getVirtualIndex() * getPointerSizeInBytes();
- Methods.push_back(
- OneMethodRecord(MethodType, translateMethodKindFlags(SP, Introduced),
- translateMethodOptionFlags(SP),
- translateAccessFlags(Ty->getTag(), SP->getFlags()),
- VFTableOffset, Name));
+ Methods.push_back(OneMethodRecord(
+ MethodType, translateAccessFlags(Ty->getTag(), SP->getFlags()),
+ translateMethodKindFlags(SP, Introduced),
+ translateMethodOptionFlags(SP), VFTableOffset, Name));
MemberCount++;
}
assert(Methods.size() > 0 && "Empty methods map entry");
if (Methods.size() == 1)
- Fields.writeOneMethod(Methods[0]);
+ FLBR.writeMemberType(Methods[0]);
else {
- TypeIndex MethodList =
- TypeTable.writeMethodOverloadList(MethodOverloadListRecord(Methods));
- Fields.writeOverloadedMethod(
- OverloadedMethodRecord(Methods.size(), MethodList, Name));
+ MethodOverloadListRecord MOLR(Methods);
+ TypeIndex MethodList = TypeTable.writeKnownType(MOLR);
+ OverloadedMethodRecord OMR(Methods.size(), MethodList, Name);
+ FLBR.writeMemberType(OMR);
}
}
// Create nested classes.
for (const DICompositeType *Nested : Info.NestedClasses) {
NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName());
- Fields.writeNestedType(R);
+ FLBR.writeMemberType(R);
MemberCount++;
}
- TypeIndex FieldTI = TypeTable.writeFieldList(Fields);
- return std::make_tuple(FieldTI, TypeIndex(), MemberCount,
+ TypeIndex FieldTI = FLBR.end();
+ return std::make_tuple(FieldTI, Info.VShapeTI, MemberCount,
!Info.NestedClasses.empty());
}
@@ -1725,7 +1914,7 @@ TypeIndex CodeViewDebug::getVBPTypeIndex() {
if (!VBPType.getIndex()) {
// Make a 'const int *' type.
ModifierRecord MR(TypeIndex::Int32(), ModifierOptions::Const);
- TypeIndex ModifiedTI = TypeTable.writeModifier(MR);
+ TypeIndex ModifiedTI = TypeTable.writeKnownType(MR);
PointerKind PK = getPointerSizeInBytes() == 8 ? PointerKind::Near64
: PointerKind::Near32;
@@ -1733,7 +1922,7 @@ TypeIndex CodeViewDebug::getVBPTypeIndex() {
PointerOptions PO = PointerOptions::None;
PointerRecord PR(ModifiedTI, PK, PM, PO, getPointerSizeInBytes());
- VBPType = TypeTable.writePointer(PR);
+ VBPType = TypeTable.writeKnownType(PR);
}
return VBPType;
@@ -1880,30 +2069,47 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
SmallString<20> BytePrefix;
for (const LocalVarDefRange &DefRange : Var.DefRanges) {
BytePrefix.clear();
- // FIXME: Handle bitpieces.
- if (DefRange.StructOffset != 0)
- continue;
-
if (DefRange.InMemory) {
- DefRangeRegisterRelSym Sym(DefRange.CVRegister, 0, DefRange.DataOffset, 0,
- 0, 0, ArrayRef<LocalVariableAddrGap>());
+ uint16_t RegRelFlags = 0;
+ if (DefRange.IsSubfield) {
+ RegRelFlags = DefRangeRegisterRelSym::IsSubfieldFlag |
+ (DefRange.StructOffset
+ << DefRangeRegisterRelSym::OffsetInParentShift);
+ }
+ DefRangeRegisterRelSym Sym(S_DEFRANGE_REGISTER_REL);
+ Sym.Hdr.Register = DefRange.CVRegister;
+ Sym.Hdr.Flags = RegRelFlags;
+ Sym.Hdr.BasePointerOffset = DefRange.DataOffset;
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL);
BytePrefix +=
StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
BytePrefix +=
- StringRef(reinterpret_cast<const char *>(&Sym.Header),
- sizeof(Sym.Header) - sizeof(LocalVariableAddrRange));
+ StringRef(reinterpret_cast<const char *>(&Sym.Hdr), sizeof(Sym.Hdr));
} else {
assert(DefRange.DataOffset == 0 && "unexpected offset into register");
- // Unclear what matters here.
- DefRangeRegisterSym Sym(DefRange.CVRegister, 0, 0, 0, 0,
- ArrayRef<LocalVariableAddrGap>());
- ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER);
- BytePrefix +=
- StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
- BytePrefix +=
- StringRef(reinterpret_cast<const char *>(&Sym.Header),
- sizeof(Sym.Header) - sizeof(LocalVariableAddrRange));
+ if (DefRange.IsSubfield) {
+ // Unclear what matters here.
+ DefRangeSubfieldRegisterSym Sym(S_DEFRANGE_SUBFIELD_REGISTER);
+ Sym.Hdr.Register = DefRange.CVRegister;
+ Sym.Hdr.MayHaveNoName = 0;
+ Sym.Hdr.OffsetInParent = DefRange.StructOffset;
+
+ ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_SUBFIELD_REGISTER);
+ BytePrefix += StringRef(reinterpret_cast<const char *>(&SymKind),
+ sizeof(SymKind));
+ BytePrefix += StringRef(reinterpret_cast<const char *>(&Sym.Hdr),
+ sizeof(Sym.Hdr));
+ } else {
+ // Unclear what matters here.
+ DefRangeRegisterSym Sym(S_DEFRANGE_REGISTER);
+ Sym.Hdr.Register = DefRange.CVRegister;
+ Sym.Hdr.MayHaveNoName = 0;
+ ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER);
+ BytePrefix += StringRef(reinterpret_cast<const char *>(&SymKind),
+ sizeof(SymKind));
+ BytePrefix += StringRef(reinterpret_cast<const char *>(&Sym.Hdr),
+ sizeof(Sym.Hdr));
+ }
}
OS.EmitCVDefRangeDirective(DefRange.Ranges, BytePrefix);
}
@@ -1983,6 +2189,15 @@ void CodeViewDebug::emitDebugInfoForUDTs(
}
void CodeViewDebug::emitDebugInfoForGlobals() {
+ DenseMap<const DIGlobalVariableExpression *, const GlobalVariable *>
+ GlobalMap;
+ for (const GlobalVariable &GV : MMI->getModule()->globals()) {
+ SmallVector<DIGlobalVariableExpression *, 1> GVEs;
+ GV.getDebugInfo(GVEs);
+ for (const auto *GVE : GVEs)
+ GlobalMap[GVE] = &GV;
+ }
+
NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
for (const MDNode *Node : CUs->operands()) {
const auto *CU = cast<DICompileUnit>(Node);
@@ -1992,31 +2207,32 @@ void CodeViewDebug::emitDebugInfoForGlobals() {
// 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_or_null<GlobalVariable>(G->getVariable())) {
+ for (const auto *GVE : CU->getGlobalVariables()) {
+ if (const auto *GV = GlobalMap.lookup(GVE))
if (!GV->hasComdat() && !GV->isDeclarationForLinker()) {
if (!EndLabel) {
OS.AddComment("Symbol subsection for globals");
EndLabel = beginCVSubsection(ModuleSubstreamKind::Symbols);
}
- emitDebugInfoForGlobal(G, Asm->getSymbol(GV));
+ // FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions.
+ emitDebugInfoForGlobal(GVE->getVariable(), GV, 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_or_null<GlobalVariable>(G->getVariable())) {
+ for (const auto *GVE : CU->getGlobalVariables()) {
+ if (const auto *GV = GlobalMap.lookup(GVE)) {
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);
+ // FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions.
+ emitDebugInfoForGlobal(GVE->getVariable(), GV, GVSym);
endCVSubsection(EndLabel);
}
}
@@ -2037,6 +2253,7 @@ void CodeViewDebug::emitDebugInfoForRetainedTypes() {
}
void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV,
+ const GlobalVariable *GV,
MCSymbol *GVSym) {
// DataSym record, see SymbolRecord.h for more info.
// FIXME: Thread local data, etc
@@ -2045,7 +2262,6 @@ void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV,
OS.AddComment("Record length");
OS.emitAbsoluteSymbolDiff(DataEnd, DataBegin, 2);
OS.EmitLabel(DataBegin);
- const auto *GV = cast<GlobalVariable>(DIGV->getVariable());
if (DIGV->isLocalToUnit()) {
if (GV->isThreadLocal()) {
OS.AddComment("Record kind: S_LTHREAD32");
@@ -2066,7 +2282,7 @@ void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV,
OS.AddComment("Type");
OS.EmitIntValue(getCompleteTypeIndex(DIGV->getType()).getIndex(), 4);
OS.AddComment("DataOffset");
- OS.EmitCOFFSecRel32(GVSym);
+ OS.EmitCOFFSecRel32(GVSym, /*Offset=*/0);
OS.AddComment("Segment");
OS.EmitCOFFSectionIndex(GVSym);
OS.AddComment("Name");
OpenPOWER on IntegriCloud