diff options
Diffstat (limited to 'lib/CodeGen/AsmPrinter/CodeViewDebug.cpp')
-rw-r--r-- | lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 539 |
1 files changed, 347 insertions, 192 deletions
diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index a81d56e9618b..1d0a003dc50a 100644 --- a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeViewDebug.h" +#include "DwarfExpression.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -19,9 +20,9 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/Triple.h" @@ -34,9 +35,14 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetLoweringObjectFile.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Config/llvm-config.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" @@ -61,17 +67,15 @@ #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/SMLoc.h" -#include "llvm/Target/TargetFrameLowering.h" -#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Target/TargetSubtargetInfo.h" #include <algorithm> #include <cassert> #include <cctype> @@ -86,6 +90,9 @@ using namespace llvm; using namespace llvm::codeview; +static cl::opt<bool> EmitDebugGlobalHashes("emit-codeview-ghash-section", + cl::ReallyHidden, cl::init(false)); + CodeViewDebug::CodeViewDebug(AsmPrinter *AP) : DebugHandlerBase(AP), OS(*Asm->OutStreamer), TypeTable(Allocator) { // If module doesn't have named metadata anchors or COFF debug section @@ -153,12 +160,19 @@ StringRef CodeViewDebug::getFullFilepath(const DIFile *File) { } unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) { + StringRef FullPath = getFullFilepath(F); unsigned NextId = FileIdMap.size() + 1; - auto Insertion = FileIdMap.insert(std::make_pair(F, NextId)); + auto Insertion = FileIdMap.insert(std::make_pair(FullPath, NextId)); if (Insertion.second) { // We have to compute the full filepath and emit a .cv_file directive. - StringRef FullPath = getFullFilepath(F); - bool Success = OS.EmitCVFileDirective(NextId, FullPath); + std::string Checksum = fromHex(F->getChecksum()); + void *CKMem = OS.getContext().allocate(Checksum.size(), 1); + memcpy(CKMem, Checksum.data(), Checksum.size()); + ArrayRef<uint8_t> ChecksumAsBytes(reinterpret_cast<const uint8_t *>(CKMem), + Checksum.size()); + DIFile::ChecksumKind ChecksumKind = F->getChecksumKind(); + bool Success = OS.EmitCVFileDirective(NextId, FullPath, ChecksumAsBytes, + static_cast<unsigned>(ChecksumKind)); (void)Success; assert(Success && ".cv_file directive failed"); } @@ -270,7 +284,7 @@ TypeIndex CodeViewDebug::getScopeIndex(const DIScope *Scope) { // Build the fully qualified name of the scope. std::string ScopeName = getFullyQualifiedName(Scope); StringIdRecord SID(TypeIndex(), ScopeName); - auto TI = TypeTable.writeKnownType(SID); + auto TI = TypeTable.writeLeafType(SID); return recordTypeIndexForDINode(Scope, TI); } @@ -295,12 +309,12 @@ TypeIndex CodeViewDebug::getFuncIdForSubprogram(const DISubprogram *SP) { TypeIndex ClassType = getTypeIndex(Class); MemberFuncIdRecord MFuncId(ClassType, getMemberFunctionType(SP, Class), DisplayName); - TI = TypeTable.writeKnownType(MFuncId); + TI = TypeTable.writeLeafType(MFuncId); } else { // Otherwise, this must be a free function. TypeIndex ParentScope = getScopeIndex(Scope); FuncIdRecord FuncId(ParentScope, getTypeIndex(SP->getType()), DisplayName); - TI = TypeTable.writeKnownType(FuncId); + TI = TypeTable.writeLeafType(FuncId); } return recordTypeIndexForDINode(SP, TI); @@ -324,8 +338,9 @@ TypeIndex CodeViewDebug::getMemberFunctionType(const DISubprogram *SP, // function type, as the complete class type is likely to reference this // member function type. TypeLoweringScope S(*this); - TypeIndex TI = - lowerTypeMemberFunction(SP->getType(), Class, SP->getThisAdjustment()); + const bool IsStaticMethod = (SP->getFlags() & DINode::FlagStaticMember) != 0; + TypeIndex TI = lowerTypeMemberFunction( + SP->getType(), Class, SP->getThisAdjustment(), IsStaticMethod); return recordTypeIndexForDINode(SP, TI, Class); } @@ -476,10 +491,13 @@ void CodeViewDebug::endModule() { OS.AddComment("String table"); OS.EmitCVStringTableDirective(); - // Emit type information last, so that any types we translate while emitting - // function info are included. + // Emit type information and hashes last, so that any types we translate while + // emitting function info are included. emitTypeInformation(); + if (EmitDebugGlobalHashes) + emitTypeGlobalHashes(); + clear(); } @@ -496,11 +514,6 @@ static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S) { } void CodeViewDebug::emitTypeInformation() { - // Do nothing if we have no debug info or if no non-trivial types were emitted - // to TypeTable during codegen. - NamedMDNode *CU_Nodes = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); - if (!CU_Nodes) - return; if (TypeTable.empty()) return; @@ -545,7 +558,39 @@ void CodeViewDebug::emitTypeInformation() { } } -namespace { +void CodeViewDebug::emitTypeGlobalHashes() { + if (TypeTable.empty()) + return; + + // Start the .debug$H section with the version and hash algorithm, currently + // hardcoded to version 0, SHA1. + OS.SwitchSection(Asm->getObjFileLowering().getCOFFGlobalTypeHashesSection()); + + OS.EmitValueToAlignment(4); + OS.AddComment("Magic"); + OS.EmitIntValue(COFF::DEBUG_HASHES_SECTION_MAGIC, 4); + OS.AddComment("Section Version"); + OS.EmitIntValue(0, 2); + OS.AddComment("Hash Algorithm"); + OS.EmitIntValue(uint16_t(GlobalTypeHashAlg::SHA1), 2); + + TypeIndex TI(TypeIndex::FirstNonSimpleIndex); + for (const auto &GHR : TypeTable.hashes()) { + if (OS.isVerboseAsm()) { + // Emit an EOL-comment describing which TypeIndex this hash corresponds + // to, as well as the stringified SHA1 hash. + SmallString<32> Comment; + raw_svector_ostream CommentOS(Comment); + CommentOS << formatv("{0:X+} [{1}]", TI.getIndex(), GHR); + OS.AddComment(Comment); + ++TI; + } + assert(GHR.Hash.size() % 20 == 0); + StringRef S(reinterpret_cast<const char *>(GHR.Hash.data()), + GHR.Hash.size()); + OS.EmitBinaryData(S); + } +} static SourceLanguage MapDWLangToCVLang(unsigned DWLang) { switch (DWLang) { @@ -572,6 +617,8 @@ static SourceLanguage MapDWLangToCVLang(unsigned DWLang) { return SourceLanguage::Cobol; case dwarf::DW_LANG_Java: return SourceLanguage::Java; + case dwarf::DW_LANG_D: + return SourceLanguage::D; 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, @@ -580,9 +627,11 @@ static SourceLanguage MapDWLangToCVLang(unsigned DWLang) { } } +namespace { struct Version { int Part[4]; }; +} // end anonymous namespace // Takes a StringRef like "clang 4.0.0.0 (other nonsense 123)" and parses out // the version number. @@ -605,20 +654,19 @@ static Version parseVersion(StringRef Name) { 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"); + case Triple::ArchType::x86: + return CPUType::Pentium3; + case Triple::ArchType::x86_64: + return CPUType::X64; + case Triple::ArchType::thumb: + return CPUType::Thumb; + case Triple::ArchType::aarch64: + return CPUType::ARM64; + default: + report_fatal_error("target architecture doesn't map to a CodeView CPUType"); } } -} // end anonymous namespace - void CodeViewDebug::emitCompilerInformation() { MCContext &Context = MMI->getContext(); MCSymbol *CompilerBegin = Context.createTempSymbol(), @@ -678,8 +726,10 @@ void CodeViewDebug::emitInlineeLinesSubsection() { OS.AddComment("Inlinee lines subsection"); MCSymbol *InlineEnd = beginCVSubsection(DebugSubsectionKind::InlineeLines); - // We don't provide any extra file info. - // FIXME: Find out if debuggers use this info. + // We emit the checksum info for files. This is used by debuggers to + // determine if a pdb matches the source before loading it. Visual Studio, + // for instance, will display a warning that the breakpoints are not valid if + // the pdb does not match the source. OS.AddComment("Inlinee lines signature"); OS.EmitIntValue(unsigned(InlineeLinesSignature::Normal), 4); @@ -692,13 +742,10 @@ void CodeViewDebug::emitInlineeLinesSubsection() { OS.AddComment("Inlined function " + SP->getName() + " starts at " + SP->getFilename() + Twine(':') + Twine(SP->getLine())); OS.AddBlankLine(); - // The filechecksum table uses 8 byte entries for now, and file ids start at - // 1. - unsigned FileOffset = (FileId - 1) * 8; OS.AddComment("Type index of inlined function"); OS.EmitIntValue(InlineeIdx.getIndex(), 4); OS.AddComment("Offset into filechecksum table"); - OS.EmitIntValue(FileOffset, 4); + OS.EmitCVFileChecksumOffsetDirective(FileId); OS.AddComment("Starting line number"); OS.EmitIntValue(SP->getLine(), 4); } @@ -799,6 +846,10 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, if (FuncName.empty()) FuncName = GlobalValue::dropLLVMManglingEscape(GV->getName()); + // Emit FPO data, but only on 32-bit x86. No other platforms use it. + if (Triple(MMI->getModule()->getTargetTriple()).getArch() == Triple::x86) + OS.EmitCVFPOData(Fn); + // Emit a symbol subsection, required by VS2012+ to find function boundaries. OS.AddComment("Symbol subsection for " + Twine(FuncName)); MCSymbol *SymbolsEnd = beginCVSubsection(DebugSubsectionKind::Symbols); @@ -858,6 +909,30 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, emitInlinedCallSite(FI, InlinedAt, I->second); } + for (auto Annot : FI.Annotations) { + MCSymbol *Label = Annot.first; + MDTuple *Strs = cast<MDTuple>(Annot.second); + MCSymbol *AnnotBegin = MMI->getContext().createTempSymbol(), + *AnnotEnd = MMI->getContext().createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(AnnotEnd, AnnotBegin, 2); + OS.EmitLabel(AnnotBegin); + OS.AddComment("Record kind: S_ANNOTATION"); + OS.EmitIntValue(SymbolKind::S_ANNOTATION, 2); + OS.EmitCOFFSecRel32(Label, /*Offset=*/0); + // FIXME: Make sure we don't overflow the max record size. + OS.EmitCOFFSectionIndex(Label); + OS.EmitIntValue(Strs->getNumOperands(), 2); + for (Metadata *MD : Strs->operands()) { + // MDStrings are null terminated, so we can do EmitBytes and get the + // nice .asciz directive. + StringRef Str = cast<MDString>(MD)->getString(); + assert(Str.data()[Str.size()] == '\0' && "non-nullterminated MDString"); + OS.EmitBytes(StringRef(Str.data(), Str.size() + 1)); + } + OS.EmitLabel(AnnotEnd); + } + if (SP != nullptr) emitDebugInfoForUDTs(LocalUDTs); @@ -947,13 +1022,110 @@ void CodeViewDebug::collectVariableInfoFromMFTable( } } +static bool canUseReferenceType(const DbgVariableLocation &Loc) { + return !Loc.LoadChain.empty() && Loc.LoadChain.back() == 0; +} + +static bool needsReferenceType(const DbgVariableLocation &Loc) { + return Loc.LoadChain.size() == 2 && Loc.LoadChain.back() == 0; +} + +void CodeViewDebug::calculateRanges( + LocalVariable &Var, const DbgValueHistoryMap::InstrRanges &Ranges) { + const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo(); + + // Calculate the definition ranges. + for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { + const InsnRange &Range = *I; + const MachineInstr *DVInst = Range.first; + assert(DVInst->isDebugValue() && "Invalid History entry"); + // FIXME: Find a way to represent constant variables, since they are + // relatively common. + Optional<DbgVariableLocation> Location = + DbgVariableLocation::extractFromMachineInstruction(*DVInst); + if (!Location) + continue; + + // CodeView can only express variables in register and variables in memory + // at a constant offset from a register. However, for variables passed + // indirectly by pointer, it is common for that pointer to be spilled to a + // stack location. For the special case of one offseted load followed by a + // zero offset load (a pointer spilled to the stack), we change the type of + // the local variable from a value type to a reference type. This tricks the + // debugger into doing the load for us. + if (Var.UseReferenceType) { + // We're using a reference type. Drop the last zero offset load. + if (canUseReferenceType(*Location)) + Location->LoadChain.pop_back(); + else + continue; + } else if (needsReferenceType(*Location)) { + // This location can't be expressed without switching to a reference type. + // Start over using that. + Var.UseReferenceType = true; + Var.DefRanges.clear(); + calculateRanges(Var, Ranges); + return; + } + + // We can only handle a register or an offseted load of a register. + if (Location->Register == 0 || Location->LoadChain.size() > 1) + continue; + { + LocalVarDefRange DR; + DR.CVRegister = TRI->getCodeViewRegNum(Location->Register); + DR.InMemory = !Location->LoadChain.empty(); + DR.DataOffset = + !Location->LoadChain.empty() ? Location->LoadChain.back() : 0; + if (Location->FragmentInfo) { + DR.IsSubfield = true; + DR.StructOffset = Location->FragmentInfo->OffsetInBits / 8; + } else { + DR.IsSubfield = false; + DR.StructOffset = 0; + } + + if (Var.DefRanges.empty() || + Var.DefRanges.back().isDifferentLocation(DR)) { + Var.DefRanges.emplace_back(std::move(DR)); + } + } + + // Compute the label range. + const MCSymbol *Begin = getLabelBeforeInsn(Range.first); + const MCSymbol *End = getLabelAfterInsn(Range.second); + if (!End) { + // 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); + const DIExpression *DIExpr = DVInst->getDebugExpression(); + while (J != E && + !fragmentsOverlap(DIExpr, J->first->getDebugExpression())) + ++J; + if (J != E) + End = getLabelBeforeInsn(J->first); + else + End = Asm->getFunctionEnd(); + } + + // If the last range end is our begin, just extend the last range. + // Otherwise make a new range. + SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &R = + Var.DefRanges.back().Ranges; + if (!R.empty() && R.back().second == Begin) + R.back().second = End; + else + R.emplace_back(Begin, End); + + // FIXME: Do more range combining. + } +} + void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { DenseSet<InlinedVariable> Processed; // Grab the variable info that was squirreled away in the MMI side-table. collectVariableInfoFromMFTable(Processed); - const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo(); - for (const auto &I : DbgValues) { InlinedVariable IV = I.first; if (Processed.count(IV)) @@ -976,87 +1148,15 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { LocalVariable Var; Var.DIVar = DIVar; - // Calculate the definition ranges. - for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - const InsnRange &Range = *I; - const MachineInstr *DVInst = Range.first; - assert(DVInst->isDebugValue() && "Invalid History entry"); - const DIExpression *DIExpr = DVInst->getDebugExpression(); - bool IsSubfield = false; - unsigned StructOffset = 0; - - // Handle fragments. - auto Fragment = DIExpr->getFragmentInfo(); - if (Fragment) { - IsSubfield = true; - StructOffset = Fragment->OffsetInBits / 8; - } else if (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. - // FIXME: Find a way to represent constant variables, since they are - // relatively common. - unsigned Reg = - DVInst->getOperand(0).isReg() ? DVInst->getOperand(0).getReg() : 0; - if (Reg == 0) - continue; - - // Handle the two cases we can handle: indirect in memory and in register. - unsigned CVReg = TRI->getCodeViewRegNum(Reg); - bool InMemory = DVInst->getOperand(1).isImm(); - int Offset = InMemory ? DVInst->getOperand(1).getImm() : 0; - { - 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(DR)) { - Var.DefRanges.emplace_back(std::move(DR)); - } - } - - // Compute the label range. - const MCSymbol *Begin = getLabelBeforeInsn(Range.first); - const MCSymbol *End = getLabelAfterInsn(Range.second); - if (!End) { - // 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(); - } - - // If the last range end is our begin, just extend the last range. - // Otherwise make a new range. - SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &Ranges = - Var.DefRanges.back().Ranges; - if (!Ranges.empty() && Ranges.back().second == Begin) - Ranges.back().second = End; - else - Ranges.emplace_back(Begin, End); - - // FIXME: Do more range combining. - } - + calculateRanges(Var, Ranges); recordLocalVariable(std::move(Var), InlinedAt); } } void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { - const Function *GV = MF->getFunction(); - assert(FnDebugInfo.count(GV) == false); - CurFn = &FnDebugInfo[GV]; + const Function &GV = MF->getFunction(); + assert(FnDebugInfo.count(&GV) == false); + CurFn = &FnDebugInfo[&GV]; CurFn->FuncId = NextFuncId++; CurFn->Begin = Asm->getFunctionBegin(); @@ -1087,10 +1187,40 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { } } -void CodeViewDebug::addToUDTs(const DIType *Ty, TypeIndex TI) { +static bool shouldEmitUdt(const DIType *T) { + if (!T) + return false; + + // MSVC does not emit UDTs for typedefs that are scoped to classes. + if (T->getTag() == dwarf::DW_TAG_typedef) { + if (DIScope *Scope = T->getScope().resolve()) { + switch (Scope->getTag()) { + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_union_type: + return false; + } + } + } + + while (true) { + if (!T || T->isForwardDecl()) + return false; + + const DIDerivedType *DT = dyn_cast<DIDerivedType>(T); + if (!DT) + return true; + T = DT->getBaseType().resolve(); + } + return true; +} + +void CodeViewDebug::addToUDTs(const DIType *Ty) { // Don't record empty UDTs. if (Ty->getName().empty()) return; + if (!shouldEmitUdt(Ty)) + return; SmallVector<StringRef, 5> QualifiedNameComponents; const DISubprogram *ClosestSubprogram = getQualifiedNameComponents( @@ -1099,10 +1229,11 @@ void CodeViewDebug::addToUDTs(const DIType *Ty, TypeIndex TI) { std::string FullyQualifiedName = getQualifiedName(QualifiedNameComponents, getPrettyScopeName(Ty)); - if (ClosestSubprogram == nullptr) - GlobalUDTs.emplace_back(std::move(FullyQualifiedName), TI); - else if (ClosestSubprogram == CurrentSubprogram) - LocalUDTs.emplace_back(std::move(FullyQualifiedName), TI); + if (ClosestSubprogram == nullptr) { + GlobalUDTs.emplace_back(std::move(FullyQualifiedName), Ty); + } else if (ClosestSubprogram == CurrentSubprogram) { + LocalUDTs.emplace_back(std::move(FullyQualifiedName), Ty); + } // TODO: What if the ClosestSubprogram is neither null or the current // subprogram? Currently, the UDT just gets dropped on the floor. @@ -1139,7 +1270,8 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) { // The member function type of a member function pointer has no // ThisAdjustment. return lowerTypeMemberFunction(cast<DISubroutineType>(Ty), ClassTy, - /*ThisAdjustment=*/0); + /*ThisAdjustment=*/0, + /*IsStaticMethod=*/false); } return lowerTypeFunction(cast<DISubroutineType>(Ty)); case dwarf::DW_TAG_enumeration_type: @@ -1160,7 +1292,7 @@ TypeIndex CodeViewDebug::lowerTypeAlias(const DIDerivedType *Ty) { TypeIndex UnderlyingTypeIndex = getTypeIndex(UnderlyingTypeRef); StringRef TypeName = Ty->getName(); - addToUDTs(Ty, UnderlyingTypeIndex); + addToUDTs(Ty); if (UnderlyingTypeIndex == TypeIndex(SimpleTypeKind::Int32Long) && TypeName == "HRESULT") @@ -1193,11 +1325,12 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) { "codeview doesn't support subranges with lower bounds"); int64_t Count = Subrange->getCount(); - // Variable Length Array (VLA) has Count equal to '-1'. - // Replace with Count '1', assume it is the minimum VLA length. - // FIXME: Make front-end support VLA subrange and emit LF_DIMVARLU. + // Forward declarations of arrays without a size and VLAs use a count of -1. + // Emit a count of zero in these cases to match what MSVC does for arrays + // without a size. MSVC doesn't support VLAs, so it's not clear what we + // should do for them even if we could distinguish them. if (Count == -1) - Count = 1; + Count = 0; // Update the element size and element type index for subsequent subranges. ElementSize *= Count; @@ -1209,7 +1342,7 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) { StringRef Name = (i == 0) ? Ty->getName() : ""; ArrayRecord AR(ElementTypeIndex, IndexType, ArraySize, Name); - ElementTypeIndex = TypeTable.writeKnownType(AR); + ElementTypeIndex = TypeTable.writeLeafType(AR); } return ElementTypeIndex; @@ -1342,7 +1475,7 @@ TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) { // do. PointerOptions PO = PointerOptions::None; PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8); - return TypeTable.writeKnownType(PR); + return TypeTable.writeLeafType(PR); } static PointerToMemberRepresentation @@ -1393,7 +1526,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.writeKnownType(PR); + return TypeTable.writeLeafType(PR); } /// Given a DWARF calling convention, get the CodeView equivalent. If we don't @@ -1432,7 +1565,7 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) { } TypeIndex ModifiedTI = getTypeIndex(BaseTy); ModifierRecord MR(ModifiedTI, Mods); - return TypeTable.writeKnownType(MR); + return TypeTable.writeLeafType(MR); } TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) { @@ -1449,18 +1582,19 @@ TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) { } ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices); - TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec); + TypeIndex ArgListIndex = TypeTable.writeLeafType(ArgListRec); CallingConvention CC = dwarfCCToCodeView(Ty->getCC()); ProcedureRecord Procedure(ReturnTypeIndex, CC, FunctionOptions::None, ArgTypeIndices.size(), ArgListIndex); - return TypeTable.writeKnownType(Procedure); + return TypeTable.writeLeafType(Procedure); } TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty, const DIType *ClassTy, - int ThisAdjustment) { + int ThisAdjustment, + bool IsStaticMethod) { // Lower the containing class type. TypeIndex ClassType = getTypeIndex(ClassTy); @@ -1475,26 +1609,22 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty, ReturnTypeIndex = ReturnAndArgTypesRef.front(); ArgTypeIndices = ReturnAndArgTypesRef.drop_front(); } - TypeIndex ThisTypeIndex = TypeIndex::Void(); - if (!ArgTypeIndices.empty()) { + TypeIndex ThisTypeIndex; + if (!IsStaticMethod && !ArgTypeIndices.empty()) { ThisTypeIndex = ArgTypeIndices.front(); ArgTypeIndices = ArgTypeIndices.drop_front(); } ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices); - TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec); + TypeIndex ArgListIndex = TypeTable.writeLeafType(ArgListRec); CallingConvention CC = dwarfCCToCodeView(Ty->getCC()); - // TODO: Need to use the correct values for: - // FunctionOptions - // ThisPointerAdjustment. + // TODO: Need to use the correct values for FunctionOptions. MemberFunctionRecord MFR(ReturnTypeIndex, ClassType, ThisTypeIndex, CC, FunctionOptions::None, ArgTypeIndices.size(), ArgListIndex, ThisAdjustment); - TypeIndex TI = TypeTable.writeKnownType(MFR); - - return TI; + return TypeTable.writeLeafType(MFR); } TypeIndex CodeViewDebug::lowerTypeVFTableShape(const DIDerivedType *Ty) { @@ -1503,7 +1633,7 @@ TypeIndex CodeViewDebug::lowerTypeVFTableShape(const DIDerivedType *Ty) { SmallVector<VFTableSlotKind, 4> Slots(VSlotCount, VFTableSlotKind::Near); VFTableShapeRecord VFTSR(Slots); - return TypeTable.writeKnownType(VFTSR); + return TypeTable.writeLeafType(VFTSR); } static MemberAccess translateAccessFlags(unsigned RecordTag, unsigned Flags) { @@ -1530,6 +1660,9 @@ static MethodOptions translateMethodOptionFlags(const DISubprogram *SP) { static MethodKind translateMethodKindFlags(const DISubprogram *SP, bool Introduced) { + if (SP->getFlags() & DINode::FlagStaticMember) + return MethodKind::Static; + switch (SP->getVirtuality()) { case dwarf::DW_VIRTUALITY_none: break; @@ -1542,8 +1675,6 @@ static MethodKind translateMethodKindFlags(const DISubprogram *SP, llvm_unreachable("unhandled virtuality case"); } - // FIXME: Get Clang to mark DISubprogram as static and do something with it. - return MethodKind::Vanilla; } @@ -1593,9 +1724,8 @@ TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) { if (Ty->isForwardDecl()) { CO |= ClassOptions::ForwardReference; } else { - FieldListRecordBuilder FLRB(TypeTable); - - FLRB.begin(); + ContinuationRecordBuilder ContinuationBuilder; + ContinuationBuilder.begin(ContinuationRecordKind::FieldList); for (const DINode *Element : Ty->getElements()) { // We assume that the frontend provides all members in source declaration // order, which is what MSVC does. @@ -1603,18 +1733,18 @@ TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) { EnumeratorRecord ER(MemberAccess::Public, APSInt::getUnsigned(Enumerator->getValue()), Enumerator->getName()); - FLRB.writeMemberType(ER); + ContinuationBuilder.writeMemberType(ER); EnumeratorCount++; } } - FTI = FLRB.end(true); + FTI = TypeTable.insertRecord(ContinuationBuilder); } std::string FullName = getFullyQualifiedName(Ty); EnumRecord ER(EnumeratorCount, CO, FTI, FullName, Ty->getIdentifier(), getTypeIndex(Ty->getBaseType())); - return TypeTable.writeKnownType(ER); + return TypeTable.writeLeafType(ER); } //===----------------------------------------------------------------------===// @@ -1643,7 +1773,7 @@ struct llvm::ClassInfo { TypeIndex VShapeTI; - std::vector<const DICompositeType *> NestedClasses; + std::vector<const DIType *> NestedTypes; }; void CodeViewDebug::clear() { @@ -1694,12 +1824,14 @@ ClassInfo CodeViewDebug::collectClassInfo(const DICompositeType *Ty) { } 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_typedef) { + Info.NestedTypes.push_back(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. } } else if (auto *Composite = dyn_cast<DICompositeType>(Element)) { - Info.NestedClasses.push_back(Composite); + Info.NestedTypes.push_back(Composite); } // Skip other unrecognized kinds of elements. } @@ -1715,7 +1847,7 @@ TypeIndex CodeViewDebug::lowerTypeClass(const DICompositeType *Ty) { std::string FullName = getFullyQualifiedName(Ty); ClassRecord CR(Kind, 0, CO, TypeIndex(), TypeIndex(), TypeIndex(), 0, FullName, Ty->getIdentifier()); - TypeIndex FwdDeclTI = TypeTable.writeKnownType(CR); + TypeIndex FwdDeclTI = TypeTable.writeLeafType(CR); if (!Ty->isForwardDecl()) DeferredCompleteTypes.push_back(Ty); return FwdDeclTI; @@ -1741,16 +1873,17 @@ TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) { ClassRecord CR(Kind, FieldCount, CO, FieldTI, TypeIndex(), VShapeTI, SizeInBytes, FullName, Ty->getIdentifier()); - TypeIndex ClassTI = TypeTable.writeKnownType(CR); + TypeIndex ClassTI = TypeTable.writeLeafType(CR); if (const auto *File = Ty->getFile()) { StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(File)); - TypeIndex SIDI = TypeTable.writeKnownType(SIDR); + TypeIndex SIDI = TypeTable.writeLeafType(SIDR); + UdtSourceLineRecord USLR(ClassTI, SIDI, Ty->getLine()); - TypeTable.writeKnownType(USLR); + TypeTable.writeLeafType(USLR); } - addToUDTs(Ty, ClassTI); + addToUDTs(Ty); return ClassTI; } @@ -1760,7 +1893,7 @@ TypeIndex CodeViewDebug::lowerTypeUnion(const DICompositeType *Ty) { ClassOptions::ForwardReference | getCommonClassOptions(Ty); std::string FullName = getFullyQualifiedName(Ty); UnionRecord UR(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier()); - TypeIndex FwdDeclTI = TypeTable.writeKnownType(UR); + TypeIndex FwdDeclTI = TypeTable.writeLeafType(UR); if (!Ty->isForwardDecl()) DeferredCompleteTypes.push_back(Ty); return FwdDeclTI; @@ -1782,14 +1915,15 @@ TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) { UnionRecord UR(FieldCount, CO, FieldTI, SizeInBytes, FullName, Ty->getIdentifier()); - TypeIndex UnionTI = TypeTable.writeKnownType(UR); + TypeIndex UnionTI = TypeTable.writeLeafType(UR); StringIdRecord SIR(TypeIndex(0x0), getFullFilepath(Ty->getFile())); - TypeIndex SIRI = TypeTable.writeKnownType(SIR); + TypeIndex SIRI = TypeTable.writeLeafType(SIR); + UdtSourceLineRecord USLR(UnionTI, SIRI, Ty->getLine()); - TypeTable.writeKnownType(USLR); + TypeTable.writeLeafType(USLR); - addToUDTs(Ty, UnionTI); + addToUDTs(Ty); return UnionTI; } @@ -1802,8 +1936,8 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { // list record. unsigned MemberCount = 0; ClassInfo Info = collectClassInfo(Ty); - FieldListRecordBuilder FLBR(TypeTable); - FLBR.begin(); + ContinuationRecordBuilder ContinuationBuilder; + ContinuationBuilder.begin(ContinuationRecordKind::FieldList); // Create base classes. for (const DIDerivedType *I : Info.Inheritance) { @@ -1821,14 +1955,14 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { getTypeIndex(I->getBaseType()), getVBPTypeIndex(), VBPtrOffset, VBTableIndex); - FLBR.writeMemberType(VBCR); + ContinuationBuilder.writeMemberType(VBCR); } else { assert(I->getOffsetInBits() % 8 == 0 && "bases must be on byte boundaries"); BaseClassRecord BCR(translateAccessFlags(Ty->getTag(), I->getFlags()), getTypeIndex(I->getBaseType()), I->getOffsetInBits() / 8); - FLBR.writeMemberType(BCR); + ContinuationBuilder.writeMemberType(BCR); } } @@ -1842,7 +1976,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { if (Member->isStaticMember()) { StaticDataMemberRecord SDMR(Access, MemberBaseType, MemberName); - FLBR.writeMemberType(SDMR); + ContinuationBuilder.writeMemberType(SDMR); MemberCount++; continue; } @@ -1851,7 +1985,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { if ((Member->getFlags() & DINode::FlagArtificial) && Member->getName().startswith("_vptr$")) { VFPtrRecord VFPR(getTypeIndex(Member->getBaseType())); - FLBR.writeMemberType(VFPR); + ContinuationBuilder.writeMemberType(VFPR); MemberCount++; continue; } @@ -1868,12 +2002,12 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { StartBitOffset -= MemberOffsetInBits; BitFieldRecord BFR(MemberBaseType, Member->getSizeInBits(), StartBitOffset); - MemberBaseType = TypeTable.writeKnownType(BFR); + MemberBaseType = TypeTable.writeLeafType(BFR); } uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8; DataMemberRecord DMR(Access, MemberBaseType, MemberOffsetInBytes, MemberName); - FLBR.writeMemberType(DMR); + ContinuationBuilder.writeMemberType(DMR); MemberCount++; } @@ -1898,40 +2032,42 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { } assert(!Methods.empty() && "Empty methods map entry"); if (Methods.size() == 1) - FLBR.writeMemberType(Methods[0]); + ContinuationBuilder.writeMemberType(Methods[0]); else { + // FIXME: Make this use its own ContinuationBuilder so that + // MethodOverloadList can be split correctly. MethodOverloadListRecord MOLR(Methods); - TypeIndex MethodList = TypeTable.writeKnownType(MOLR); + TypeIndex MethodList = TypeTable.writeLeafType(MOLR); + OverloadedMethodRecord OMR(Methods.size(), MethodList, Name); - FLBR.writeMemberType(OMR); + ContinuationBuilder.writeMemberType(OMR); } } // Create nested classes. - for (const DICompositeType *Nested : Info.NestedClasses) { + for (const DIType *Nested : Info.NestedTypes) { NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName()); - FLBR.writeMemberType(R); + ContinuationBuilder.writeMemberType(R); MemberCount++; } - TypeIndex FieldTI = FLBR.end(true); + TypeIndex FieldTI = TypeTable.insertRecord(ContinuationBuilder); return std::make_tuple(FieldTI, Info.VShapeTI, MemberCount, - !Info.NestedClasses.empty()); + !Info.NestedTypes.empty()); } TypeIndex CodeViewDebug::getVBPTypeIndex() { if (!VBPType.getIndex()) { // Make a 'const int *' type. ModifierRecord MR(TypeIndex::Int32(), ModifierOptions::Const); - TypeIndex ModifiedTI = TypeTable.writeKnownType(MR); + TypeIndex ModifiedTI = TypeTable.writeLeafType(MR); PointerKind PK = getPointerSizeInBytes() == 8 ? PointerKind::Near64 : PointerKind::Near32; PointerMode PM = PointerMode::Pointer; PointerOptions PO = PointerOptions::None; PointerRecord PR(ModifiedTI, PK, PM, PO, getPointerSizeInBytes()); - - VBPType = TypeTable.writeKnownType(PR); + VBPType = TypeTable.writeLeafType(PR); } return VBPType; @@ -1957,6 +2093,16 @@ TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef, DITypeRef ClassTyRef) { return recordTypeIndexForDINode(Ty, TI, ClassTy); } +TypeIndex CodeViewDebug::getTypeIndexForReferenceTo(DITypeRef TypeRef) { + DIType *Ty = TypeRef.resolve(); + PointerRecord PR(getTypeIndex(Ty), + getPointerSizeInBytes() == 8 ? PointerKind::Near64 + : PointerKind::Near32, + PointerMode::LValueReference, PointerOptions::None, + Ty->getSizeInBits() / 8); + return TypeTable.writeLeafType(PR); +} + TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { const DIType *Ty = TypeRef.resolve(); @@ -2064,7 +2210,9 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) { Flags |= LocalSymFlags::IsOptimizedOut; OS.AddComment("TypeIndex"); - TypeIndex TI = getCompleteTypeIndex(Var.DIVar->getType()); + TypeIndex TI = Var.UseReferenceType + ? getTypeIndexForReferenceTo(Var.DIVar->getType()) + : getCompleteTypeIndex(Var.DIVar->getType()); OS.EmitIntValue(TI.getIndex(), 4); OS.AddComment("Flags"); OS.EmitIntValue(static_cast<uint16_t>(Flags), 2); @@ -2125,19 +2273,21 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) { } void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) { - const Function *GV = MF->getFunction(); - assert(FnDebugInfo.count(GV)); - assert(CurFn == &FnDebugInfo[GV]); + const Function &GV = MF->getFunction(); + assert(FnDebugInfo.count(&GV)); + assert(CurFn == &FnDebugInfo[&GV]); - collectVariableInfo(GV->getSubprogram()); + collectVariableInfo(GV.getSubprogram()); // Don't emit anything if we don't have any line tables. if (!CurFn->HaveLineInfo) { - FnDebugInfo.erase(GV); + FnDebugInfo.erase(&GV); CurFn = nullptr; return; } + CurFn->Annotations = MF->getCodeViewAnnotations(); + CurFn->End = Asm->getFunctionEnd(); CurFn = nullptr; @@ -2156,6 +2306,8 @@ void CodeViewDebug::beginInstruction(const MachineInstr *MI) { DebugLoc DL = MI->getDebugLoc(); if (!DL && MI->getParent() != PrevInstBB) { for (const auto &NextMI : *MI->getParent()) { + if (NextMI.isDebugValue()) + continue; DL = NextMI.getDebugLoc(); if (DL) break; @@ -2187,8 +2339,11 @@ void CodeViewDebug::endCVSubsection(MCSymbol *EndLabel) { } void CodeViewDebug::emitDebugInfoForUDTs( - ArrayRef<std::pair<std::string, TypeIndex>> UDTs) { - for (const std::pair<std::string, codeview::TypeIndex> &UDT : UDTs) { + ArrayRef<std::pair<std::string, const DIType *>> UDTs) { + for (const auto &UDT : UDTs) { + const DIType *T = UDT.second; + assert(shouldEmitUdt(T)); + MCSymbol *UDTRecordBegin = MMI->getContext().createTempSymbol(), *UDTRecordEnd = MMI->getContext().createTempSymbol(); OS.AddComment("Record length"); @@ -2199,7 +2354,7 @@ void CodeViewDebug::emitDebugInfoForUDTs( OS.EmitIntValue(unsigned(SymbolKind::S_UDT), 2); OS.AddComment("Type"); - OS.EmitIntValue(UDT.second.getIndex(), 4); + OS.EmitIntValue(getCompleteTypeIndex(T).getIndex(), 4); emitNullTerminatedSymbolName(OS, UDT.first); OS.EmitLabel(UDTRecordEnd); |