diff options
Diffstat (limited to 'contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp')
-rw-r--r-- | contrib/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 692 |
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"); |