diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:01:25 +0000 |
commit | d8e91e46262bc44006913e6796843909f1ac7bcd (patch) | |
tree | 7d0c143d9b38190e0fa0180805389da22cd834c5 /lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | |
parent | b7eb8e35e481a74962664b63dfb09483b200209a (diff) |
Notes
Diffstat (limited to 'lib/CodeGen/AsmPrinter/CodeViewDebug.cpp')
-rw-r--r-- | lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 850 |
1 files changed, 537 insertions, 313 deletions
diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 8c5c5478d01a..8cabad4ad312 100644 --- a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -31,6 +31,7 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/LexicalScopes.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfo.h" @@ -43,6 +44,7 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/EnumTables.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" @@ -72,6 +74,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Path.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Target/TargetLoweringObjectFile.h" @@ -90,8 +93,20 @@ using namespace llvm; using namespace llvm::codeview; -static cl::opt<bool> EmitDebugGlobalHashes("emit-codeview-ghash-section", - cl::ReallyHidden, cl::init(false)); +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; + case Triple::ArchType::aarch64: + return CPUType::ARM64; + default: + report_fatal_error("target architecture doesn't map to a CodeView CPUType"); + } +} CodeViewDebug::CodeViewDebug(AsmPrinter *AP) : DebugHandlerBase(AP), OS(*Asm->OutStreamer), TypeTable(Allocator) { @@ -100,11 +115,21 @@ CodeViewDebug::CodeViewDebug(AsmPrinter *AP) if (!MMI->getModule()->getNamedMetadata("llvm.dbg.cu") || !AP->getObjFileLowering().getCOFFDebugSymbolsSection()) { Asm = nullptr; + MMI->setDebugInfoAvailability(false); return; } - // Tell MMI that we have debug info. MMI->setDebugInfoAvailability(true); + + TheCPU = + mapArchToCVCPUType(Triple(MMI->getModule()->getTargetTriple()).getArch()); + + collectGlobalVariableInfo(); + + // Check if we should emit type record hashes. + ConstantInt *GH = mdconst::extract_or_null<ConstantInt>( + MMI->getModule()->getModuleFlag("CodeViewGHash")); + EmitDebugGlobalHashes = GH && !GH->isZero(); } StringRef CodeViewDebug::getFullFilepath(const DIFile *File) { @@ -116,7 +141,9 @@ StringRef CodeViewDebug::getFullFilepath(const DIFile *File) { // If this is a Unix-style path, just use it as is. Don't try to canonicalize // it textually because one of the path components could be a symlink. - if (!Dir.empty() && Dir[0] == '/') { + if (Dir.startswith("/") || Filename.startswith("/")) { + if (llvm::sys::path::is_absolute(Filename, llvm::sys::path::Style::posix)) + return Filename; Filepath = Dir; if (Dir.back() != '/') Filepath += '/'; @@ -337,6 +364,36 @@ TypeIndex CodeViewDebug::getFuncIdForSubprogram(const DISubprogram *SP) { return recordTypeIndexForDINode(SP, TI); } +static bool isTrivial(const DICompositeType *DCTy) { + return ((DCTy->getFlags() & DINode::FlagTrivial) == DINode::FlagTrivial); +} + +static FunctionOptions +getFunctionOptions(const DISubroutineType *Ty, + const DICompositeType *ClassTy = nullptr, + StringRef SPName = StringRef("")) { + FunctionOptions FO = FunctionOptions::None; + const DIType *ReturnTy = nullptr; + if (auto TypeArray = Ty->getTypeArray()) { + if (TypeArray.size()) + ReturnTy = TypeArray[0].resolve(); + } + + if (auto *ReturnDCTy = dyn_cast_or_null<DICompositeType>(ReturnTy)) { + if (!isTrivial(ReturnDCTy)) + FO |= FunctionOptions::CxxReturnUdt; + } + + // DISubroutineType is unnamed. Use DISubprogram's i.e. SPName in comparison. + if (ClassTy && !isTrivial(ClassTy) && SPName == ClassTy->getName()) { + FO |= FunctionOptions::Constructor; + + // TODO: put the FunctionOptions::ConstructorWithVirtualBases flag. + + } + return FO; +} + TypeIndex CodeViewDebug::getMemberFunctionType(const DISubprogram *SP, const DICompositeType *Class) { // Always use the method declaration as the key for the function type. The @@ -356,8 +413,10 @@ TypeIndex CodeViewDebug::getMemberFunctionType(const DISubprogram *SP, // member function type. TypeLoweringScope S(*this); const bool IsStaticMethod = (SP->getFlags() & DINode::FlagStaticMember) != 0; + + FunctionOptions FO = getFunctionOptions(SP->getType(), Class, SP->getName()); TypeIndex TI = lowerTypeMemberFunction( - SP->getType(), Class, SP->getThisAdjustment(), IsStaticMethod); + SP->getType(), Class, SP->getThisAdjustment(), IsStaticMethod, FO); return recordTypeIndexForDINode(SP, TI, Class); } @@ -508,6 +567,11 @@ void CodeViewDebug::endModule() { OS.AddComment("String table"); OS.EmitCVStringTableDirective(); + // Emit S_BUILDINFO, which points to LF_BUILDINFO. Put this in its own symbol + // subsection in the generic .debug$S section at the end. There is no + // particular reason for this ordering other than to match MSVC. + emitBuildInfo(); + // Emit type information and hashes last, so that any types we translate while // emitting function info are included. emitTypeInformation(); @@ -669,30 +733,8 @@ static Version parseVersion(StringRef Name) { 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; - case Triple::ArchType::aarch64: - return CPUType::ARM64; - default: - report_fatal_error("target architecture doesn't map to a CodeView CPUType"); - } -} - 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); + MCSymbol *CompilerEnd = beginSymbolRecord(SymbolKind::S_COMPILE3); uint32_t Flags = 0; NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); @@ -707,9 +749,7 @@ void CodeViewDebug::emitCompilerInformation() { OS.EmitIntValue(Flags, 4); OS.AddComment("CPUType"); - CPUType CPU = - mapArchToCVCPUType(Triple(MMI->getModule()->getTargetTriple()).getArch()); - OS.EmitIntValue(static_cast<uint64_t>(CPU), 2); + OS.EmitIntValue(static_cast<uint64_t>(TheCPU), 2); StringRef CompilerVersion = CU->getProducer(); Version FrontVer = parseVersion(CompilerVersion); @@ -733,7 +773,48 @@ void CodeViewDebug::emitCompilerInformation() { OS.AddComment("Null-terminated compiler version string"); emitNullTerminatedSymbolName(OS, CompilerVersion); - OS.EmitLabel(CompilerEnd); + endSymbolRecord(CompilerEnd); +} + +static TypeIndex getStringIdTypeIdx(GlobalTypeTableBuilder &TypeTable, + StringRef S) { + StringIdRecord SIR(TypeIndex(0x0), S); + return TypeTable.writeLeafType(SIR); +} + +void CodeViewDebug::emitBuildInfo() { + // First, make LF_BUILDINFO. It's a sequence of strings with various bits of + // build info. The known prefix is: + // - Absolute path of current directory + // - Compiler path + // - Main source file path, relative to CWD or absolute + // - Type server PDB file + // - Canonical compiler command line + // If frontend and backend compilation are separated (think llc or LTO), it's + // not clear if the compiler path should refer to the executable for the + // frontend or the backend. Leave it blank for now. + TypeIndex BuildInfoArgs[BuildInfoRecord::MaxArgs] = {}; + NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); + const MDNode *Node = *CUs->operands().begin(); // FIXME: Multiple CUs. + const auto *CU = cast<DICompileUnit>(Node); + const DIFile *MainSourceFile = CU->getFile(); + BuildInfoArgs[BuildInfoRecord::CurrentDirectory] = + getStringIdTypeIdx(TypeTable, MainSourceFile->getDirectory()); + BuildInfoArgs[BuildInfoRecord::SourceFile] = + getStringIdTypeIdx(TypeTable, MainSourceFile->getFilename()); + // FIXME: Path to compiler and command line. PDB is intentionally blank unless + // we implement /Zi type servers. + BuildInfoRecord BIR(BuildInfoArgs); + TypeIndex BuildInfoIndex = TypeTable.writeLeafType(BIR); + + // Make a new .debug$S subsection for the S_BUILDINFO record, which points + // from the module symbols into the type stream. + MCSymbol *BISubsecEnd = beginCVSubsection(DebugSubsectionKind::Symbols); + MCSymbol *BIEnd = beginSymbolRecord(SymbolKind::S_BUILDINFO); + OS.AddComment("LF_BUILDINFO index"); + OS.EmitIntValue(BuildInfoIndex.getIndex(), 4); + endSymbolRecord(BIEnd); + endCVSubsection(BISubsecEnd); } void CodeViewDebug::emitInlineeLinesSubsection() { @@ -773,18 +854,11 @@ void CodeViewDebug::emitInlineeLinesSubsection() { void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt, const InlineSite &Site) { - MCSymbol *InlineBegin = MMI->getContext().createTempSymbol(), - *InlineEnd = MMI->getContext().createTempSymbol(); - assert(TypeIndices.count({Site.Inlinee, nullptr})); TypeIndex InlineeIdx = TypeIndices[{Site.Inlinee, nullptr}]; // SymbolRecord - OS.AddComment("Record length"); - OS.emitAbsoluteSymbolDiff(InlineEnd, InlineBegin, 2); // RecordLength - OS.EmitLabel(InlineBegin); - OS.AddComment("Record kind: S_INLINESITE"); - OS.EmitIntValue(SymbolKind::S_INLINESITE, 2); // RecordKind + MCSymbol *InlineEnd = beginSymbolRecord(SymbolKind::S_INLINESITE); OS.AddComment("PtrParent"); OS.EmitIntValue(0, 4); @@ -799,9 +873,9 @@ void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI, OS.EmitCVInlineLinetableDirective(Site.SiteFuncId, FileId, StartLineNum, FI.Begin, FI.End); - OS.EmitLabel(InlineEnd); + endSymbolRecord(InlineEnd); - emitLocalVariableList(Site.InlinedLocals); + emitLocalVariableList(FI, Site.InlinedLocals); // Recurse on child inlined call sites before closing the scope. for (const DILocation *ChildSite : Site.ChildSites) { @@ -812,10 +886,7 @@ void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI, } // Close the scope. - OS.AddComment("Record length"); - OS.EmitIntValue(2, 2); // RecordLength - OS.AddComment("Record kind: S_INLINESITE_END"); - OS.EmitIntValue(SymbolKind::S_INLINESITE_END, 2); // RecordKind + emitEndSymbolRecord(SymbolKind::S_INLINESITE_END); } void CodeViewDebug::switchToDebugSectionForSymbol(const MCSymbol *GVSym) { @@ -850,13 +921,7 @@ void CodeViewDebug::emitDebugInfoForThunk(const Function *GV, MCSymbol *SymbolsEnd = beginCVSubsection(DebugSubsectionKind::Symbols); // Emit S_THUNK32 - MCSymbol *ThunkRecordBegin = MMI->getContext().createTempSymbol(), - *ThunkRecordEnd = MMI->getContext().createTempSymbol(); - OS.AddComment("Record length"); - OS.emitAbsoluteSymbolDiff(ThunkRecordEnd, ThunkRecordBegin, 2); - OS.EmitLabel(ThunkRecordBegin); - OS.AddComment("Record kind: S_THUNK32"); - OS.EmitIntValue(unsigned(SymbolKind::S_THUNK32), 2); + MCSymbol *ThunkRecordEnd = beginSymbolRecord(SymbolKind::S_THUNK32); OS.AddComment("PtrParent"); OS.EmitIntValue(0, 4); OS.AddComment("PtrEnd"); @@ -874,17 +939,13 @@ void CodeViewDebug::emitDebugInfoForThunk(const Function *GV, OS.AddComment("Function name"); emitNullTerminatedSymbolName(OS, FuncName); // Additional fields specific to the thunk ordinal would go here. - OS.EmitLabel(ThunkRecordEnd); + endSymbolRecord(ThunkRecordEnd); // Local variables/inlined routines are purposely omitted here. The point of // marking this as a thunk is so Visual Studio will NOT stop in this routine. // Emit S_PROC_ID_END - const unsigned RecordLengthForSymbolEnd = 2; - OS.AddComment("Record length"); - OS.EmitIntValue(RecordLengthForSymbolEnd, 2); - OS.AddComment("Record kind: S_PROC_ID_END"); - OS.EmitIntValue(unsigned(SymbolKind::S_PROC_ID_END), 2); + emitEndSymbolRecord(SymbolKind::S_PROC_ID_END); endCVSubsection(SymbolsEnd); } @@ -927,19 +988,9 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, OS.AddComment("Symbol subsection for " + Twine(FuncName)); MCSymbol *SymbolsEnd = beginCVSubsection(DebugSubsectionKind::Symbols); { - MCSymbol *ProcRecordBegin = MMI->getContext().createTempSymbol(), - *ProcRecordEnd = MMI->getContext().createTempSymbol(); - OS.AddComment("Record length"); - 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); - } + SymbolKind ProcKind = GV->hasLocalLinkage() ? SymbolKind::S_LPROC32_ID + : SymbolKind::S_GPROC32_ID; + MCSymbol *ProcRecordEnd = beginSymbolRecord(ProcKind); // These fields are filled in by tools like CVPACK which run after the fact. OS.AddComment("PtrParent"); @@ -968,9 +1019,28 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, OS.AddComment("Function name"); // Truncate the name so we won't overflow the record length field. emitNullTerminatedSymbolName(OS, FuncName); - OS.EmitLabel(ProcRecordEnd); + endSymbolRecord(ProcRecordEnd); - emitLocalVariableList(FI.Locals); + MCSymbol *FrameProcEnd = beginSymbolRecord(SymbolKind::S_FRAMEPROC); + // Subtract out the CSR size since MSVC excludes that and we include it. + OS.AddComment("FrameSize"); + OS.EmitIntValue(FI.FrameSize - FI.CSRSize, 4); + OS.AddComment("Padding"); + OS.EmitIntValue(0, 4); + OS.AddComment("Offset of padding"); + OS.EmitIntValue(0, 4); + OS.AddComment("Bytes of callee saved registers"); + OS.EmitIntValue(FI.CSRSize, 4); + OS.AddComment("Exception handler offset"); + OS.EmitIntValue(0, 4); + OS.AddComment("Exception handler section"); + OS.EmitIntValue(0, 2); + OS.AddComment("Flags (defines frame register)"); + OS.EmitIntValue(uint32_t(FI.FrameProcOpts), 4); + endSymbolRecord(FrameProcEnd); + + emitLocalVariableList(FI, FI.Locals); + emitGlobalVariableList(FI.Globals); emitLexicalBlockList(FI.ChildBlocks, FI); // Emit inlined call site information. Only emit functions inlined directly @@ -986,13 +1056,7 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, 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); + MCSymbol *AnnotEnd = beginSymbolRecord(SymbolKind::S_ANNOTATION); OS.EmitCOFFSecRel32(Label, /*Offset=*/0); // FIXME: Make sure we don't overflow the max record size. OS.EmitCOFFSectionIndex(Label); @@ -1004,17 +1068,14 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, assert(Str.data()[Str.size()] == '\0' && "non-nullterminated MDString"); OS.EmitBytes(StringRef(Str.data(), Str.size() + 1)); } - OS.EmitLabel(AnnotEnd); + endSymbolRecord(AnnotEnd); } if (SP != nullptr) emitDebugInfoForUDTs(LocalUDTs); // We're done with this function. - OS.AddComment("Record length"); - OS.EmitIntValue(0x0002, 2); - OS.AddComment("Record kind: S_PROC_ID_END"); - OS.EmitIntValue(unsigned(SymbolKind::S_PROC_ID_END), 2); + emitEndSymbolRecord(SymbolKind::S_PROC_ID_END); } endCVSubsection(SymbolsEnd); @@ -1034,21 +1095,8 @@ CodeViewDebug::createDefRangeMem(uint16_t CVRegister, int Offset) { return DR; } -CodeViewDebug::LocalVarDefRange -CodeViewDebug::createDefRangeGeneral(uint16_t CVRegister, bool InMemory, - int Offset, bool IsSubfield, - uint16_t StructOffset) { - LocalVarDefRange DR; - DR.InMemory = InMemory; - DR.DataOffset = Offset; - DR.IsSubfield = IsSubfield; - DR.StructOffset = StructOffset; - DR.CVRegister = CVRegister; - return DR; -} - void CodeViewDebug::collectVariableInfoFromMFTable( - DenseSet<InlinedVariable> &Processed) { + DenseSet<InlinedEntity> &Processed) { const MachineFunction &MF = *Asm->MF; const TargetSubtargetInfo &TSI = MF.getSubtarget(); const TargetFrameLowering *TFI = TSI.getFrameLowering(); @@ -1060,7 +1108,7 @@ void CodeViewDebug::collectVariableInfoFromMFTable( assert(VI.Var->isValidLocationForIntrinsic(VI.Loc) && "Expected inlined-at fields to agree"); - Processed.insert(InlinedVariable(VI.Var, VI.Loc->getInlinedAt())); + Processed.insert(InlinedEntity(VI.Var, VI.Loc->getInlinedAt())); LexicalScope *Scope = LScopes.findLexicalScope(VI.Loc); // If variable scope is not found then skip this variable. @@ -1196,15 +1244,15 @@ void CodeViewDebug::calculateRanges( } void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { - DenseSet<InlinedVariable> Processed; + DenseSet<InlinedEntity> Processed; // Grab the variable info that was squirreled away in the MMI side-table. collectVariableInfoFromMFTable(Processed); for (const auto &I : DbgValues) { - InlinedVariable IV = I.first; + InlinedEntity IV = I.first; if (Processed.count(IV)) continue; - const DILocalVariable *DIVar = IV.first; + const DILocalVariable *DIVar = cast<DILocalVariable>(IV.first); const DILocation *InlinedAt = IV.second; // Instruction ranges, specifying where IV is accessible. @@ -1228,6 +1276,9 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { } void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { + const TargetSubtargetInfo &TSI = MF->getSubtarget(); + const TargetRegisterInfo *TRI = TSI.getRegisterInfo(); + const MachineFrameInfo &MFI = MF->getFrameInfo(); const Function &GV = MF->getFunction(); auto Insertion = FnDebugInfo.insert({&GV, llvm::make_unique<FunctionInfo>()}); assert(Insertion.second && "function already has info"); @@ -1235,6 +1286,66 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) { CurFn->FuncId = NextFuncId++; CurFn->Begin = Asm->getFunctionBegin(); + // The S_FRAMEPROC record reports the stack size, and how many bytes of + // callee-saved registers were used. For targets that don't use a PUSH + // instruction (AArch64), this will be zero. + CurFn->CSRSize = MFI.getCVBytesOfCalleeSavedRegisters(); + CurFn->FrameSize = MFI.getStackSize(); + CurFn->OffsetAdjustment = MFI.getOffsetAdjustment(); + CurFn->HasStackRealignment = TRI->needsStackRealignment(*MF); + + // For this function S_FRAMEPROC record, figure out which codeview register + // will be the frame pointer. + CurFn->EncodedParamFramePtrReg = EncodedFramePtrReg::None; // None. + CurFn->EncodedLocalFramePtrReg = EncodedFramePtrReg::None; // None. + if (CurFn->FrameSize > 0) { + if (!TSI.getFrameLowering()->hasFP(*MF)) { + CurFn->EncodedLocalFramePtrReg = EncodedFramePtrReg::StackPtr; + CurFn->EncodedParamFramePtrReg = EncodedFramePtrReg::StackPtr; + } else { + // If there is an FP, parameters are always relative to it. + CurFn->EncodedParamFramePtrReg = EncodedFramePtrReg::FramePtr; + if (CurFn->HasStackRealignment) { + // If the stack needs realignment, locals are relative to SP or VFRAME. + CurFn->EncodedLocalFramePtrReg = EncodedFramePtrReg::StackPtr; + } else { + // Otherwise, locals are relative to EBP, and we probably have VLAs or + // other stack adjustments. + CurFn->EncodedLocalFramePtrReg = EncodedFramePtrReg::FramePtr; + } + } + } + + // Compute other frame procedure options. + FrameProcedureOptions FPO = FrameProcedureOptions::None; + if (MFI.hasVarSizedObjects()) + FPO |= FrameProcedureOptions::HasAlloca; + if (MF->exposesReturnsTwice()) + FPO |= FrameProcedureOptions::HasSetJmp; + // FIXME: Set HasLongJmp if we ever track that info. + if (MF->hasInlineAsm()) + FPO |= FrameProcedureOptions::HasInlineAssembly; + if (GV.hasPersonalityFn()) { + if (isAsynchronousEHPersonality( + classifyEHPersonality(GV.getPersonalityFn()))) + FPO |= FrameProcedureOptions::HasStructuredExceptionHandling; + else + FPO |= FrameProcedureOptions::HasExceptionHandling; + } + if (GV.hasFnAttribute(Attribute::InlineHint)) + FPO |= FrameProcedureOptions::MarkedInline; + if (GV.hasFnAttribute(Attribute::Naked)) + FPO |= FrameProcedureOptions::Naked; + if (MFI.hasStackProtectorIndex()) + FPO |= FrameProcedureOptions::SecurityChecks; + FPO |= FrameProcedureOptions(uint32_t(CurFn->EncodedLocalFramePtrReg) << 14U); + FPO |= FrameProcedureOptions(uint32_t(CurFn->EncodedParamFramePtrReg) << 16U); + if (Asm->TM.getOptLevel() != CodeGenOpt::None && !GV.optForSize() && + !GV.hasFnAttribute(Attribute::OptimizeNone)) + FPO |= FrameProcedureOptions::OptimizedForSpeed; + // FIXME: Set GuardCfg when it is implemented. + CurFn->FrameProcOpts = FPO; + OS.EmitCVFuncIdDirective(CurFn->FuncId); // Find the end of the function prolog. First known non-DBG_VALUE and @@ -1358,6 +1469,8 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) { case dwarf::DW_TAG_union_type: return lowerTypeUnion(cast<DICompositeType>(Ty)); case dwarf::DW_TAG_unspecified_type: + if (Ty->getName() == "decltype(nullptr)") + return TypeIndex::NullptrT(); return TypeIndex::None(); default: // Use the null type index. @@ -1552,6 +1665,9 @@ TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty, break; } + if (Ty->isObjectPointer()) + PO |= PointerOptions::Const; + PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8); return TypeTable.writeLeafType(PR); } @@ -1702,49 +1818,54 @@ TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) { CallingConvention CC = dwarfCCToCodeView(Ty->getCC()); - ProcedureRecord Procedure(ReturnTypeIndex, CC, FunctionOptions::None, - ArgTypeIndices.size(), ArgListIndex); + FunctionOptions FO = getFunctionOptions(Ty); + ProcedureRecord Procedure(ReturnTypeIndex, CC, FO, ArgTypeIndices.size(), + ArgListIndex); return TypeTable.writeLeafType(Procedure); } TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty, const DIType *ClassTy, int ThisAdjustment, - bool IsStaticMethod) { + bool IsStaticMethod, + FunctionOptions FO) { // Lower the containing class type. TypeIndex ClassType = getTypeIndex(ClassTy); - SmallVector<TypeIndex, 8> ReturnAndArgTypeIndices; - for (DITypeRef ArgTypeRef : Ty->getTypeArray()) - ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgTypeRef)); + DITypeRefArray ReturnAndArgs = Ty->getTypeArray(); - // MSVC uses type none for variadic argument. - if (ReturnAndArgTypeIndices.size() > 1 && - ReturnAndArgTypeIndices.back() == TypeIndex::Void()) { - ReturnAndArgTypeIndices.back() = TypeIndex::None(); - } - TypeIndex ReturnTypeIndex = TypeIndex::Void(); - ArrayRef<TypeIndex> ArgTypeIndices = None; - if (!ReturnAndArgTypeIndices.empty()) { - auto ReturnAndArgTypesRef = makeArrayRef(ReturnAndArgTypeIndices); - ReturnTypeIndex = ReturnAndArgTypesRef.front(); - ArgTypeIndices = ReturnAndArgTypesRef.drop_front(); - } + unsigned Index = 0; + SmallVector<TypeIndex, 8> ArgTypeIndices; + TypeIndex ReturnTypeIndex = getTypeIndex(ReturnAndArgs[Index++]); + + // If the first argument is a pointer type and this isn't a static method, + // treat it as the special 'this' parameter, which is encoded separately from + // the arguments. TypeIndex ThisTypeIndex; - if (!IsStaticMethod && !ArgTypeIndices.empty()) { - ThisTypeIndex = ArgTypeIndices.front(); - ArgTypeIndices = ArgTypeIndices.drop_front(); + if (!IsStaticMethod && ReturnAndArgs.size() > Index) { + if (const DIDerivedType *PtrTy = + dyn_cast_or_null<DIDerivedType>(ReturnAndArgs[Index].resolve())) { + if (PtrTy->getTag() == dwarf::DW_TAG_pointer_type) { + ThisTypeIndex = getTypeIndexForThisPtr(PtrTy, Ty); + Index++; + } + } } + while (Index < ReturnAndArgs.size()) + ArgTypeIndices.push_back(getTypeIndex(ReturnAndArgs[Index++])); + + // MSVC uses type none for variadic argument. + if (!ArgTypeIndices.empty() && ArgTypeIndices.back() == TypeIndex::Void()) + ArgTypeIndices.back() = TypeIndex::None(); + ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices); TypeIndex ArgListIndex = TypeTable.writeLeafType(ArgListRec); CallingConvention CC = dwarfCCToCodeView(Ty->getCC()); - // TODO: Need to use the correct values for FunctionOptions. - MemberFunctionRecord MFR(ReturnTypeIndex, ClassType, ThisTypeIndex, CC, - FunctionOptions::None, ArgTypeIndices.size(), - ArgListIndex, ThisAdjustment); + MemberFunctionRecord MFR(ReturnTypeIndex, ClassType, ThisTypeIndex, CC, FO, + ArgTypeIndices.size(), ArgListIndex, ThisAdjustment); return TypeTable.writeLeafType(MFR); } @@ -1825,12 +1946,20 @@ static ClassOptions getCommonClassOptions(const DICompositeType *Ty) { if (ImmediateScope && isa<DICompositeType>(ImmediateScope)) CO |= ClassOptions::Nested; - // Put the Scoped flag on function-local types. - for (const DIScope *Scope = ImmediateScope; Scope != nullptr; - Scope = Scope->getScope().resolve()) { - if (isa<DISubprogram>(Scope)) { + // Put the Scoped flag on function-local types. MSVC puts this flag for enum + // type only when it has an immediate function scope. Clang never puts enums + // inside DILexicalBlock scopes. Enum types, as generated by clang, are + // always in function, class, or file scopes. + if (Ty->getTag() == dwarf::DW_TAG_enumeration_type) { + if (ImmediateScope && isa<DISubprogram>(ImmediateScope)) CO |= ClassOptions::Scoped; - break; + } else { + for (const DIScope *Scope = ImmediateScope; Scope != nullptr; + Scope = Scope->getScope().resolve()) { + if (isa<DISubprogram>(Scope)) { + CO |= ClassOptions::Scoped; + break; + } } } @@ -1930,6 +2059,7 @@ void CodeViewDebug::clear() { GlobalUDTs.clear(); TypeIndices.clear(); CompleteTypeIndices.clear(); + ScopeGlobals.clear(); } void CodeViewDebug::collectMemberInfo(ClassInfo &Info, @@ -2275,6 +2405,32 @@ TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef, DITypeRef ClassTyRef) { return recordTypeIndexForDINode(Ty, TI, ClassTy); } +codeview::TypeIndex +CodeViewDebug::getTypeIndexForThisPtr(const DIDerivedType *PtrTy, + const DISubroutineType *SubroutineTy) { + assert(PtrTy->getTag() == dwarf::DW_TAG_pointer_type && + "this type must be a pointer type"); + + PointerOptions Options = PointerOptions::None; + if (SubroutineTy->getFlags() & DINode::DIFlags::FlagLValueReference) + Options = PointerOptions::LValueRefThisPointer; + else if (SubroutineTy->getFlags() & DINode::DIFlags::FlagRValueReference) + Options = PointerOptions::RValueRefThisPointer; + + // Check if we've already translated this type. If there is no ref qualifier + // on the function then we look up this pointer type with no associated class + // so that the TypeIndex for the this pointer can be shared with the type + // index for other pointers to this class type. If there is a ref qualifier + // then we lookup the pointer using the subroutine as the parent type. + auto I = TypeIndices.find({PtrTy, SubroutineTy}); + if (I != TypeIndices.end()) + return I->second; + + TypeLoweringScope S(*this); + TypeIndex TI = lowerTypePointer(PtrTy, Options); + return recordTypeIndexForDINode(PtrTy, TI, SubroutineTy); +} + TypeIndex CodeViewDebug::getTypeIndexForReferenceTo(DITypeRef TypeRef) { DIType *Ty = TypeRef.resolve(); PointerRecord PR(getTypeIndex(Ty), @@ -2292,6 +2448,14 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { if (!Ty) return TypeIndex::Void(); + // Look through typedefs when getting the complete type index. Call + // getTypeIndex on the typdef to ensure that any UDTs are accumulated and are + // emitted only once. + if (Ty->getTag() == dwarf::DW_TAG_typedef) + (void)getTypeIndex(Ty); + while (Ty->getTag() == dwarf::DW_TAG_typedef) + Ty = cast<DIDerivedType>(Ty)->getBaseType().resolve(); + // If this is a non-record type, the complete type index is the same as the // normal type index. Just call getTypeIndex. switch (Ty->getTag()) { @@ -2360,35 +2524,40 @@ void CodeViewDebug::emitDeferredCompleteTypes() { } } -void CodeViewDebug::emitLocalVariableList(ArrayRef<LocalVariable> Locals) { +void CodeViewDebug::emitLocalVariableList(const FunctionInfo &FI, + ArrayRef<LocalVariable> Locals) { // Get the sorted list of parameters and emit them first. SmallVector<const LocalVariable *, 6> Params; for (const LocalVariable &L : Locals) if (L.DIVar->isParameter()) Params.push_back(&L); - llvm::sort(Params.begin(), Params.end(), - [](const LocalVariable *L, const LocalVariable *R) { - return L->DIVar->getArg() < R->DIVar->getArg(); - }); + llvm::sort(Params, [](const LocalVariable *L, const LocalVariable *R) { + return L->DIVar->getArg() < R->DIVar->getArg(); + }); for (const LocalVariable *L : Params) - emitLocalVariable(*L); + emitLocalVariable(FI, *L); // Next emit all non-parameters in the order that we found them. for (const LocalVariable &L : Locals) if (!L.DIVar->isParameter()) - emitLocalVariable(L); + emitLocalVariable(FI, L); } -void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) { - // LocalSym record, see SymbolRecord.h for more info. - MCSymbol *LocalBegin = MMI->getContext().createTempSymbol(), - *LocalEnd = MMI->getContext().createTempSymbol(); - OS.AddComment("Record length"); - OS.emitAbsoluteSymbolDiff(LocalEnd, LocalBegin, 2); - OS.EmitLabel(LocalBegin); +/// Only call this on endian-specific types like ulittle16_t and little32_t, or +/// structs composed of them. +template <typename T> +static void copyBytesForDefRange(SmallString<20> &BytePrefix, + SymbolKind SymKind, const T &DefRangeHeader) { + BytePrefix.resize(2 + sizeof(T)); + ulittle16_t SymKindLE = ulittle16_t(SymKind); + memcpy(&BytePrefix[0], &SymKindLE, 2); + memcpy(&BytePrefix[2], &DefRangeHeader, sizeof(T)); +} - OS.AddComment("Record kind: S_LOCAL"); - OS.EmitIntValue(unsigned(SymbolKind::S_LOCAL), 2); +void CodeViewDebug::emitLocalVariable(const FunctionInfo &FI, + const LocalVariable &Var) { + // LocalSym record, see SymbolRecord.h for more info. + MCSymbol *LocalEnd = beginSymbolRecord(SymbolKind::S_LOCAL); LocalSymFlags Flags = LocalSymFlags::None; if (Var.DIVar->isParameter()) @@ -2405,7 +2574,7 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) { OS.EmitIntValue(static_cast<uint16_t>(Flags), 2); // Truncate the name so we won't overflow the record length field. emitNullTerminatedSymbolName(OS, Var.DIVar->getName()); - OS.EmitLabel(LocalEnd); + endSymbolRecord(LocalEnd); // Calculate the on disk prefix of the appropriate def range record. The // records and on disk formats are described in SymbolRecords.h. BytePrefix @@ -2414,45 +2583,53 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) { for (const LocalVarDefRange &DefRange : Var.DefRanges) { BytePrefix.clear(); if (DefRange.InMemory) { - uint16_t RegRelFlags = 0; - if (DefRange.IsSubfield) { - RegRelFlags = DefRangeRegisterRelSym::IsSubfieldFlag | - (DefRange.StructOffset - << DefRangeRegisterRelSym::OffsetInParentShift); + int Offset = DefRange.DataOffset; + unsigned Reg = DefRange.CVRegister; + + // 32-bit x86 call sequences often use PUSH instructions, which disrupt + // ESP-relative offsets. Use the virtual frame pointer, VFRAME or $T0, + // instead. In frames without stack realignment, $T0 will be the CFA. + if (RegisterId(Reg) == RegisterId::ESP) { + Reg = unsigned(RegisterId::VFRAME); + Offset += FI.OffsetAdjustment; + } + + // If we can use the chosen frame pointer for the frame and this isn't a + // sliced aggregate, use the smaller S_DEFRANGE_FRAMEPOINTER_REL record. + // Otherwise, use S_DEFRANGE_REGISTER_REL. + EncodedFramePtrReg EncFP = encodeFramePtrReg(RegisterId(Reg), TheCPU); + if (!DefRange.IsSubfield && EncFP != EncodedFramePtrReg::None && + (bool(Flags & LocalSymFlags::IsParameter) + ? (EncFP == FI.EncodedParamFramePtrReg) + : (EncFP == FI.EncodedLocalFramePtrReg))) { + little32_t FPOffset = little32_t(Offset); + copyBytesForDefRange(BytePrefix, S_DEFRANGE_FRAMEPOINTER_REL, FPOffset); + } else { + uint16_t RegRelFlags = 0; + if (DefRange.IsSubfield) { + RegRelFlags = DefRangeRegisterRelSym::IsSubfieldFlag | + (DefRange.StructOffset + << DefRangeRegisterRelSym::OffsetInParentShift); + } + DefRangeRegisterRelSym::Header DRHdr; + DRHdr.Register = Reg; + DRHdr.Flags = RegRelFlags; + DRHdr.BasePointerOffset = Offset; + copyBytesForDefRange(BytePrefix, S_DEFRANGE_REGISTER_REL, DRHdr); } - 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.Hdr), sizeof(Sym.Hdr)); } else { assert(DefRange.DataOffset == 0 && "unexpected offset into register"); 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)); + DefRangeSubfieldRegisterSym::Header DRHdr; + DRHdr.Register = DefRange.CVRegister; + DRHdr.MayHaveNoName = 0; + DRHdr.OffsetInParent = DefRange.StructOffset; + copyBytesForDefRange(BytePrefix, S_DEFRANGE_SUBFIELD_REGISTER, DRHdr); } 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)); + DefRangeRegisterSym::Header DRHdr; + DRHdr.Register = DefRange.CVRegister; + DRHdr.MayHaveNoName = 0; + copyBytesForDefRange(BytePrefix, S_DEFRANGE_REGISTER, DRHdr); } } OS.EmitCVDefRangeDirective(DefRange.Ranges, BytePrefix); @@ -2469,15 +2646,7 @@ void CodeViewDebug::emitLexicalBlockList(ArrayRef<LexicalBlock *> Blocks, /// lexical block scope. void CodeViewDebug::emitLexicalBlock(const LexicalBlock &Block, const FunctionInfo& FI) { - MCSymbol *RecordBegin = MMI->getContext().createTempSymbol(), - *RecordEnd = MMI->getContext().createTempSymbol(); - - // Lexical block symbol record. - OS.AddComment("Record length"); - OS.emitAbsoluteSymbolDiff(RecordEnd, RecordBegin, 2); // Record Length - OS.EmitLabel(RecordBegin); - OS.AddComment("Record kind: S_BLOCK32"); - OS.EmitIntValue(SymbolKind::S_BLOCK32, 2); // Record Kind + MCSymbol *RecordEnd = beginSymbolRecord(SymbolKind::S_BLOCK32); OS.AddComment("PtrParent"); OS.EmitIntValue(0, 4); // PtrParent OS.AddComment("PtrEnd"); @@ -2490,19 +2659,17 @@ void CodeViewDebug::emitLexicalBlock(const LexicalBlock &Block, OS.EmitCOFFSectionIndex(FI.Begin); // Func Symbol OS.AddComment("Lexical block name"); emitNullTerminatedSymbolName(OS, Block.Name); // Name - OS.EmitLabel(RecordEnd); + endSymbolRecord(RecordEnd); // Emit variables local to this lexical block. - emitLocalVariableList(Block.Locals); + emitLocalVariableList(FI, Block.Locals); + emitGlobalVariableList(Block.Globals); // Emit lexical blocks contained within this block. emitLexicalBlockList(Block.Children, FI); // Close the lexical block scope. - OS.AddComment("Record length"); - OS.EmitIntValue(2, 2); // Record Length - OS.AddComment("Record kind: S_END"); - OS.EmitIntValue(SymbolKind::S_END, 2); // Record Kind + emitEndSymbolRecord(SymbolKind::S_END); } /// Convenience routine for collecting lexical block information for a list @@ -2510,9 +2677,10 @@ void CodeViewDebug::emitLexicalBlock(const LexicalBlock &Block, void CodeViewDebug::collectLexicalBlockInfo( SmallVectorImpl<LexicalScope *> &Scopes, SmallVectorImpl<LexicalBlock *> &Blocks, - SmallVectorImpl<LocalVariable> &Locals) { + SmallVectorImpl<LocalVariable> &Locals, + SmallVectorImpl<CVGlobalVariable> &Globals) { for (LexicalScope *Scope : Scopes) - collectLexicalBlockInfo(*Scope, Blocks, Locals); + collectLexicalBlockInfo(*Scope, Blocks, Locals, Globals); } /// Populate the lexical blocks and local variable lists of the parent with @@ -2520,45 +2688,58 @@ void CodeViewDebug::collectLexicalBlockInfo( void CodeViewDebug::collectLexicalBlockInfo( LexicalScope &Scope, SmallVectorImpl<LexicalBlock *> &ParentBlocks, - SmallVectorImpl<LocalVariable> &ParentLocals) { + SmallVectorImpl<LocalVariable> &ParentLocals, + SmallVectorImpl<CVGlobalVariable> &ParentGlobals) { if (Scope.isAbstractScope()) return; - auto LocalsIter = ScopeVariables.find(&Scope); - if (LocalsIter == ScopeVariables.end()) { - // This scope does not contain variables and can be eliminated. - collectLexicalBlockInfo(Scope.getChildren(), ParentBlocks, ParentLocals); - return; - } - SmallVectorImpl<LocalVariable> &Locals = LocalsIter->second; - + // Gather information about the lexical scope including local variables, + // global variables, and address ranges. + bool IgnoreScope = false; + auto LI = ScopeVariables.find(&Scope); + SmallVectorImpl<LocalVariable> *Locals = + LI != ScopeVariables.end() ? &LI->second : nullptr; + auto GI = ScopeGlobals.find(Scope.getScopeNode()); + SmallVectorImpl<CVGlobalVariable> *Globals = + GI != ScopeGlobals.end() ? GI->second.get() : nullptr; const DILexicalBlock *DILB = dyn_cast<DILexicalBlock>(Scope.getScopeNode()); - if (!DILB) { - // This scope is not a lexical block and can be eliminated, but keep any - // local variables it contains. - ParentLocals.append(Locals.begin(), Locals.end()); - collectLexicalBlockInfo(Scope.getChildren(), ParentBlocks, ParentLocals); - return; - } - const SmallVectorImpl<InsnRange> &Ranges = Scope.getRanges(); - if (Ranges.size() != 1 || !getLabelAfterInsn(Ranges.front().second)) { - // This lexical block scope has too many address ranges to represent in the - // current CodeView format or does not have a valid address range. - // Eliminate this lexical scope and promote any locals it contains to the - // parent scope. - // - // For lexical scopes with multiple address ranges you may be tempted to - // construct a single range covering every instruction where the block is - // live and everything in between. Unfortunately, Visual Studio only - // displays variables from the first matching lexical block scope. If the - // first lexical block contains exception handling code or cold code which - // is moved to the bottom of the routine creating a single range covering - // nearly the entire routine, then it will hide all other lexical blocks - // and the variables they contain. - // - ParentLocals.append(Locals.begin(), Locals.end()); - collectLexicalBlockInfo(Scope.getChildren(), ParentBlocks, ParentLocals); + + // Ignore lexical scopes which do not contain variables. + if (!Locals && !Globals) + IgnoreScope = true; + + // Ignore lexical scopes which are not lexical blocks. + if (!DILB) + IgnoreScope = true; + + // Ignore scopes which have too many address ranges to represent in the + // current CodeView format or do not have a valid address range. + // + // For lexical scopes with multiple address ranges you may be tempted to + // construct a single range covering every instruction where the block is + // live and everything in between. Unfortunately, Visual Studio only + // displays variables from the first matching lexical block scope. If the + // first lexical block contains exception handling code or cold code which + // is moved to the bottom of the routine creating a single range covering + // nearly the entire routine, then it will hide all other lexical blocks + // and the variables they contain. + if (Ranges.size() != 1 || !getLabelAfterInsn(Ranges.front().second)) + IgnoreScope = true; + + if (IgnoreScope) { + // This scope can be safely ignored and eliminating it will reduce the + // size of the debug information. Be sure to collect any variable and scope + // information from the this scope or any of its children and collapse them + // into the parent scope. + if (Locals) + ParentLocals.append(Locals->begin(), Locals->end()); + if (Globals) + ParentGlobals.append(Globals->begin(), Globals->end()); + collectLexicalBlockInfo(Scope.getChildren(), + ParentBlocks, + ParentLocals, + ParentGlobals); return; } @@ -2569,8 +2750,8 @@ void CodeViewDebug::collectLexicalBlockInfo( if (!BlockInsertion.second) return; - // Create a lexical block containing the local variables and collect the - // the lexical block information for the children. + // Create a lexical block containing the variables and collect the the + // lexical block information for the children. const InsnRange &Range = Ranges.front(); assert(Range.first && Range.second); LexicalBlock &Block = BlockInsertion.first->second; @@ -2579,9 +2760,15 @@ void CodeViewDebug::collectLexicalBlockInfo( assert(Block.Begin && "missing label for scope begin"); assert(Block.End && "missing label for scope end"); Block.Name = DILB->getName(); - Block.Locals = std::move(Locals); + if (Locals) + Block.Locals = std::move(*Locals); + if (Globals) + Block.Globals = std::move(*Globals); ParentBlocks.push_back(&Block); - collectLexicalBlockInfo(Scope.getChildren(), Block.Children, Block.Locals); + collectLexicalBlockInfo(Scope.getChildren(), + Block.Children, + Block.Locals, + Block.Globals); } void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) { @@ -2593,7 +2780,10 @@ void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) { // Build the lexical block structure to emit for this routine. if (LexicalScope *CFS = LScopes.getCurrentFunctionScope()) - collectLexicalBlockInfo(*CFS, CurFn->ChildBlocks, CurFn->Locals); + collectLexicalBlockInfo(*CFS, + CurFn->ChildBlocks, + CurFn->Locals, + CurFn->Globals); // Clear the scope and variable information from the map which will not be // valid after we have finished processing this routine. This also prepares @@ -2660,30 +2850,57 @@ void CodeViewDebug::endCVSubsection(MCSymbol *EndLabel) { OS.EmitValueToAlignment(4); } +static StringRef getSymbolName(SymbolKind SymKind) { + for (const EnumEntry<SymbolKind> &EE : getSymbolTypeNames()) + if (EE.Value == SymKind) + return EE.Name; + return ""; +} + +MCSymbol *CodeViewDebug::beginSymbolRecord(SymbolKind SymKind) { + MCSymbol *BeginLabel = MMI->getContext().createTempSymbol(), + *EndLabel = MMI->getContext().createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(EndLabel, BeginLabel, 2); + OS.EmitLabel(BeginLabel); + if (OS.isVerboseAsm()) + OS.AddComment("Record kind: " + getSymbolName(SymKind)); + OS.EmitIntValue(unsigned(SymKind), 2); + return EndLabel; +} + +void CodeViewDebug::endSymbolRecord(MCSymbol *SymEnd) { + // MSVC does not pad out symbol records to four bytes, but LLVM does to avoid + // an extra copy of every symbol record in LLD. This increases object file + // size by less than 1% in the clang build, and is compatible with the Visual + // C++ linker. + OS.EmitValueToAlignment(4); + OS.EmitLabel(SymEnd); +} + +void CodeViewDebug::emitEndSymbolRecord(SymbolKind EndKind) { + OS.AddComment("Record length"); + OS.EmitIntValue(2, 2); + if (OS.isVerboseAsm()) + OS.AddComment("Record kind: " + getSymbolName(EndKind)); + OS.EmitIntValue(unsigned(EndKind), 2); // Record Kind +} + void CodeViewDebug::emitDebugInfoForUDTs( 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"); - OS.emitAbsoluteSymbolDiff(UDTRecordEnd, UDTRecordBegin, 2); - OS.EmitLabel(UDTRecordBegin); - - OS.AddComment("Record kind: S_UDT"); - OS.EmitIntValue(unsigned(SymbolKind::S_UDT), 2); - + MCSymbol *UDTRecordEnd = beginSymbolRecord(SymbolKind::S_UDT); OS.AddComment("Type"); OS.EmitIntValue(getCompleteTypeIndex(T).getIndex(), 4); - emitNullTerminatedSymbolName(OS, UDT.first); - OS.EmitLabel(UDTRecordEnd); + endSymbolRecord(UDTRecordEnd); } } -void CodeViewDebug::emitDebugInfoForGlobals() { +void CodeViewDebug::collectGlobalVariableInfo() { DenseMap<const DIGlobalVariableExpression *, const GlobalVariable *> GlobalMap; for (const GlobalVariable &GV : MMI->getModule()->globals()) { @@ -2696,42 +2913,56 @@ void CodeViewDebug::emitDebugInfoForGlobals() { NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); for (const MDNode *Node : CUs->operands()) { const auto *CU = cast<DICompileUnit>(Node); - - // First, emit all globals that are not in a comdat in a single symbol - // substream. MSVC doesn't like it if the substream is empty, so only open - // it if we have at least one global to emit. - switchToDebugSectionForSymbol(nullptr); - MCSymbol *EndLabel = nullptr; 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(DebugSubsectionKind::Symbols); - } - // FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions. - emitDebugInfoForGlobal(GVE->getVariable(), GV, Asm->getSymbol(GV)); - } + const auto *GV = GlobalMap.lookup(GVE); + if (!GV || GV->isDeclarationForLinker()) + continue; + const DIGlobalVariable *DIGV = GVE->getVariable(); + DIScope *Scope = DIGV->getScope(); + SmallVector<CVGlobalVariable, 1> *VariableList; + if (Scope && isa<DILocalScope>(Scope)) { + // Locate a global variable list for this scope, creating one if + // necessary. + auto Insertion = ScopeGlobals.insert( + {Scope, std::unique_ptr<GlobalVariableList>()}); + if (Insertion.second) + Insertion.first->second = llvm::make_unique<GlobalVariableList>(); + VariableList = Insertion.first->second.get(); + } else if (GV->hasComdat()) + // Emit this global variable into a COMDAT section. + VariableList = &ComdatVariables; + else + // Emit this globla variable in a single global symbol section. + VariableList = &GlobalVariables; + CVGlobalVariable CVGV = {DIGV, GV}; + VariableList->emplace_back(std::move(CVGV)); } - 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 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::dropLLVMManglingEscape(GV->getName()))); - switchToDebugSectionForSymbol(GVSym); - EndLabel = beginCVSubsection(DebugSubsectionKind::Symbols); - // FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions. - emitDebugInfoForGlobal(GVE->getVariable(), GV, GVSym); - endCVSubsection(EndLabel); - } - } - } +void CodeViewDebug::emitDebugInfoForGlobals() { + // First, emit all globals that are not in a comdat in a single symbol + // substream. MSVC doesn't like it if the substream is empty, so only open + // it if we have at least one global to emit. + switchToDebugSectionForSymbol(nullptr); + if (!GlobalVariables.empty()) { + OS.AddComment("Symbol subsection for globals"); + MCSymbol *EndLabel = beginCVSubsection(DebugSubsectionKind::Symbols); + emitGlobalVariableList(GlobalVariables); + 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 CVGlobalVariable &CVGV : ComdatVariables) { + MCSymbol *GVSym = Asm->getSymbol(CVGV.GV); + OS.AddComment("Symbol subsection for " + + Twine(GlobalValue::dropLLVMManglingEscape(CVGV.GV->getName()))); + switchToDebugSectionForSymbol(GVSym); + MCSymbol *EndLabel = beginCVSubsection(DebugSubsectionKind::Symbols); + // FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions. + emitDebugInfoForGlobal(CVGV.DIGV, CVGV.GV, GVSym); + endCVSubsection(EndLabel); } } @@ -2747,34 +2978,26 @@ void CodeViewDebug::emitDebugInfoForRetainedTypes() { } } +// Emit each global variable in the specified array. +void CodeViewDebug::emitGlobalVariableList(ArrayRef<CVGlobalVariable> Globals) { + for (const CVGlobalVariable &CVGV : Globals) { + MCSymbol *GVSym = Asm->getSymbol(CVGV.GV); + // FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions. + emitDebugInfoForGlobal(CVGV.DIGV, CVGV.GV, GVSym); + } +} + void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV, const GlobalVariable *GV, MCSymbol *GVSym) { - // DataSym record, see SymbolRecord.h for more info. - // FIXME: Thread local data, etc - MCSymbol *DataBegin = MMI->getContext().createTempSymbol(), - *DataEnd = MMI->getContext().createTempSymbol(); - const unsigned FixedLengthOfThisRecord = 12; - OS.AddComment("Record length"); - OS.emitAbsoluteSymbolDiff(DataEnd, DataBegin, 2); - OS.EmitLabel(DataBegin); - if (DIGV->isLocalToUnit()) { - if (GV->isThreadLocal()) { - OS.AddComment("Record kind: S_LTHREAD32"); - OS.EmitIntValue(unsigned(SymbolKind::S_LTHREAD32), 2); - } else { - OS.AddComment("Record kind: S_LDATA32"); - OS.EmitIntValue(unsigned(SymbolKind::S_LDATA32), 2); - } - } else { - if (GV->isThreadLocal()) { - OS.AddComment("Record kind: S_GTHREAD32"); - OS.EmitIntValue(unsigned(SymbolKind::S_GTHREAD32), 2); - } else { - OS.AddComment("Record kind: S_GDATA32"); - OS.EmitIntValue(unsigned(SymbolKind::S_GDATA32), 2); - } - } + // DataSym record, see SymbolRecord.h for more info. Thread local data + // happens to have the same format as global data. + SymbolKind DataSym = GV->isThreadLocal() + ? (DIGV->isLocalToUnit() ? SymbolKind::S_LTHREAD32 + : SymbolKind::S_GTHREAD32) + : (DIGV->isLocalToUnit() ? SymbolKind::S_LDATA32 + : SymbolKind::S_GDATA32); + MCSymbol *DataEnd = beginSymbolRecord(DataSym); OS.AddComment("Type"); OS.EmitIntValue(getCompleteTypeIndex(DIGV->getType()).getIndex(), 4); OS.AddComment("DataOffset"); @@ -2782,6 +3005,7 @@ void CodeViewDebug::emitDebugInfoForGlobal(const DIGlobalVariable *DIGV, OS.AddComment("Segment"); OS.EmitCOFFSectionIndex(GVSym); OS.AddComment("Name"); - emitNullTerminatedSymbolName(OS, DIGV->getName(), FixedLengthOfThisRecord); - OS.EmitLabel(DataEnd); + const unsigned LengthOfDataRecord = 12; + emitNullTerminatedSymbolName(OS, DIGV->getName(), LengthOfDataRecord); + endSymbolRecord(DataEnd); } |