//===- llvm/CodeGen/DwarfDebug.cpp - Dwarf Debug Framework ----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains support for writing dwarf debug info into asm files. // //===----------------------------------------------------------------------===// #include "DwarfDebug.h" #include "ByteStreamer.h" #include "DIEHash.h" #include "DwarfCompileUnit.h" #include "DwarfExpression.h" #include "DwarfUnit.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" #include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/MachineLocation.h" #include "llvm/MC/SectionKind.h" #include "llvm/Pass.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include #include #include #include using namespace llvm; #define DEBUG_TYPE "dwarfdebug" STATISTIC(NumCSParams, "Number of dbg call site params created"); static cl::opt UseDwarfRangesBaseAddressSpecifier( "use-dwarf-ranges-base-address-specifier", cl::Hidden, cl::desc("Use base address specifiers in debug_ranges"), cl::init(false)); static cl::opt GenerateARangeSection("generate-arange-section", cl::Hidden, cl::desc("Generate dwarf aranges"), cl::init(false)); static cl::opt GenerateDwarfTypeUnits("generate-type-units", cl::Hidden, cl::desc("Generate DWARF4 type units."), cl::init(false)); static cl::opt SplitDwarfCrossCuReferences( "split-dwarf-cross-cu-references", cl::Hidden, cl::desc("Enable cross-cu references in DWO files"), cl::init(false)); enum DefaultOnOff { Default, Enable, Disable }; static cl::opt UnknownLocations( "use-unknown-locations", cl::Hidden, cl::desc("Make an absence of debug location information explicit."), cl::values(clEnumVal(Default, "At top of block or after label"), clEnumVal(Enable, "In all cases"), clEnumVal(Disable, "Never")), cl::init(Default)); static cl::opt AccelTables( "accel-tables", cl::Hidden, cl::desc("Output dwarf accelerator tables."), cl::values(clEnumValN(AccelTableKind::Default, "Default", "Default for platform"), clEnumValN(AccelTableKind::None, "Disable", "Disabled."), clEnumValN(AccelTableKind::Apple, "Apple", "Apple"), clEnumValN(AccelTableKind::Dwarf, "Dwarf", "DWARF")), cl::init(AccelTableKind::Default)); static cl::opt DwarfInlinedStrings("dwarf-inlined-strings", cl::Hidden, cl::desc("Use inlined strings rather than string section."), cl::values(clEnumVal(Default, "Default for platform"), clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")), cl::init(Default)); static cl::opt NoDwarfRangesSection("no-dwarf-ranges-section", cl::Hidden, cl::desc("Disable emission .debug_ranges section."), cl::init(false)); static cl::opt DwarfSectionsAsReferences( "dwarf-sections-as-references", cl::Hidden, cl::desc("Use sections+offset as references rather than labels."), cl::values(clEnumVal(Default, "Default for platform"), clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")), cl::init(Default)); static cl::opt UseGNUDebugMacro("use-gnu-debug-macro", cl::Hidden, cl::desc("Emit the GNU .debug_macro format with DWARF <5"), cl::init(false)); static cl::opt DwarfOpConvert( "dwarf-op-convert", cl::Hidden, cl::desc("Enable use of the DWARFv5 DW_OP_convert operator"), cl::values(clEnumVal(Default, "Default for platform"), clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")), cl::init(Default)); enum LinkageNameOption { DefaultLinkageNames, AllLinkageNames, AbstractLinkageNames }; static cl::opt DwarfLinkageNames("dwarf-linkage-names", cl::Hidden, cl::desc("Which DWARF linkage-name attributes to emit."), cl::values(clEnumValN(DefaultLinkageNames, "Default", "Default for platform"), clEnumValN(AllLinkageNames, "All", "All"), clEnumValN(AbstractLinkageNames, "Abstract", "Abstract subprograms")), cl::init(DefaultLinkageNames)); static cl::opt MinimizeAddrInV5Option( "minimize-addr-in-v5", cl::Hidden, cl::desc("Always use DW_AT_ranges in DWARFv5 whenever it could allow more " "address pool entry sharing to reduce relocations/object size"), cl::values(clEnumValN(DwarfDebug::MinimizeAddrInV5::Default, "Default", "Default address minimization strategy"), clEnumValN(DwarfDebug::MinimizeAddrInV5::Ranges, "Ranges", "Use rnglists for contiguous ranges if that allows " "using a pre-existing base address"), clEnumValN(DwarfDebug::MinimizeAddrInV5::Disabled, "Disabled", "Stuff")), cl::init(DwarfDebug::MinimizeAddrInV5::Default)); static constexpr unsigned ULEB128PadSize = 4; void DebugLocDwarfExpression::emitOp(uint8_t Op, const char *Comment) { getActiveStreamer().emitInt8( Op, Comment ? Twine(Comment) + " " + dwarf::OperationEncodingString(Op) : dwarf::OperationEncodingString(Op)); } void DebugLocDwarfExpression::emitSigned(int64_t Value) { getActiveStreamer().emitSLEB128(Value, Twine(Value)); } void DebugLocDwarfExpression::emitUnsigned(uint64_t Value) { getActiveStreamer().emitULEB128(Value, Twine(Value)); } void DebugLocDwarfExpression::emitData1(uint8_t Value) { getActiveStreamer().emitInt8(Value, Twine(Value)); } void DebugLocDwarfExpression::emitBaseTypeRef(uint64_t Idx) { assert(Idx < (1ULL << (ULEB128PadSize * 7)) && "Idx wont fit"); getActiveStreamer().emitULEB128(Idx, Twine(Idx), ULEB128PadSize); } bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, llvm::Register MachineReg) { // This information is not available while emitting .debug_loc entries. return false; } void DebugLocDwarfExpression::enableTemporaryBuffer() { assert(!IsBuffering && "Already buffering?"); if (!TmpBuf) TmpBuf = std::make_unique(OutBS.GenerateComments); IsBuffering = true; } void DebugLocDwarfExpression::disableTemporaryBuffer() { IsBuffering = false; } unsigned DebugLocDwarfExpression::getTemporaryBufferSize() { return TmpBuf ? TmpBuf->Bytes.size() : 0; } void DebugLocDwarfExpression::commitTemporaryBuffer() { if (!TmpBuf) return; for (auto Byte : enumerate(TmpBuf->Bytes)) { const char *Comment = (Byte.index() < TmpBuf->Comments.size()) ? TmpBuf->Comments[Byte.index()].c_str() : ""; OutBS.emitInt8(Byte.value(), Comment); } TmpBuf->Bytes.clear(); TmpBuf->Comments.clear(); } const DIType *DbgVariable::getType() const { return getVariable()->getType(); } /// Get .debug_loc entry for the instruction range starting at MI. static DbgValueLoc getDebugLocValue(const MachineInstr *MI) { const DIExpression *Expr = MI->getDebugExpression(); assert(MI->getNumOperands() == 4); if (MI->getDebugOperand(0).isReg()) { const auto &RegOp = MI->getDebugOperand(0); const auto &Op1 = MI->getDebugOffset(); // If the second operand is an immediate, this is a // register-indirect address. assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); MachineLocation MLoc(RegOp.getReg(), Op1.isImm()); return DbgValueLoc(Expr, MLoc); } if (MI->getDebugOperand(0).isTargetIndex()) { const auto &Op = MI->getDebugOperand(0); return DbgValueLoc(Expr, TargetIndexLocation(Op.getIndex(), Op.getOffset())); } if (MI->getDebugOperand(0).isImm()) return DbgValueLoc(Expr, MI->getDebugOperand(0).getImm()); if (MI->getDebugOperand(0).isFPImm()) return DbgValueLoc(Expr, MI->getDebugOperand(0).getFPImm()); if (MI->getDebugOperand(0).isCImm()) return DbgValueLoc(Expr, MI->getDebugOperand(0).getCImm()); llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); } void DbgVariable::initializeDbgValue(const MachineInstr *DbgValue) { assert(FrameIndexExprs.empty() && "Already initialized?"); assert(!ValueLoc.get() && "Already initialized?"); assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable"); assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() && "Wrong inlined-at"); ValueLoc = std::make_unique(getDebugLocValue(DbgValue)); if (auto *E = DbgValue->getDebugExpression()) if (E->getNumElements()) FrameIndexExprs.push_back({0, E}); } ArrayRef DbgVariable::getFrameIndexExprs() const { if (FrameIndexExprs.size() == 1) return FrameIndexExprs; assert(llvm::all_of(FrameIndexExprs, [](const FrameIndexExpr &A) { return A.Expr->isFragment(); }) && "multiple FI expressions without DW_OP_LLVM_fragment"); llvm::sort(FrameIndexExprs, [](const FrameIndexExpr &A, const FrameIndexExpr &B) -> bool { return A.Expr->getFragmentInfo()->OffsetInBits < B.Expr->getFragmentInfo()->OffsetInBits; }); return FrameIndexExprs; } void DbgVariable::addMMIEntry(const DbgVariable &V) { assert(DebugLocListIndex == ~0U && !ValueLoc.get() && "not an MMI entry"); assert(V.DebugLocListIndex == ~0U && !V.ValueLoc.get() && "not an MMI entry"); assert(V.getVariable() == getVariable() && "conflicting variable"); assert(V.getInlinedAt() == getInlinedAt() && "conflicting inlined-at location"); assert(!FrameIndexExprs.empty() && "Expected an MMI entry"); assert(!V.FrameIndexExprs.empty() && "Expected an MMI entry"); // FIXME: This logic should not be necessary anymore, as we now have proper // deduplication. However, without it, we currently run into the assertion // below, which means that we are likely dealing with broken input, i.e. two // non-fragment entries for the same variable at different frame indices. if (FrameIndexExprs.size()) { auto *Expr = FrameIndexExprs.back().Expr; if (!Expr || !Expr->isFragment()) return; } for (const auto &FIE : V.FrameIndexExprs) // Ignore duplicate entries. if (llvm::none_of(FrameIndexExprs, [&](const FrameIndexExpr &Other) { return FIE.FI == Other.FI && FIE.Expr == Other.Expr; })) FrameIndexExprs.push_back(FIE); assert((FrameIndexExprs.size() == 1 || llvm::all_of(FrameIndexExprs, [](FrameIndexExpr &FIE) { return FIE.Expr && FIE.Expr->isFragment(); })) && "conflicting locations for variable"); } static AccelTableKind computeAccelTableKind(unsigned DwarfVersion, bool GenerateTypeUnits, DebuggerKind Tuning, const Triple &TT) { // Honor an explicit request. if (AccelTables != AccelTableKind::Default) return AccelTables; // Accelerator tables with type units are currently not supported. if (GenerateTypeUnits) return AccelTableKind::None; // Accelerator tables get emitted if targetting DWARF v5 or LLDB. DWARF v5 // always implies debug_names. For lower standard versions we use apple // accelerator tables on apple platforms and debug_names elsewhere. if (DwarfVersion >= 5) return AccelTableKind::Dwarf; if (Tuning == DebuggerKind::LLDB) return TT.isOSBinFormatMachO() ? AccelTableKind::Apple : AccelTableKind::Dwarf; return AccelTableKind::None; } DwarfDebug::DwarfDebug(AsmPrinter *A) : DebugHandlerBase(A), DebugLocs(A->OutStreamer->isVerboseAsm()), InfoHolder(A, "info_string", DIEValueAllocator), SkeletonHolder(A, "skel_string", DIEValueAllocator), IsDarwin(A->TM.getTargetTriple().isOSDarwin()) { const Triple &TT = Asm->TM.getTargetTriple(); // Make sure we know our "debugger tuning". The target option takes // precedence; fall back to triple-based defaults. if (Asm->TM.Options.DebuggerTuning != DebuggerKind::Default) DebuggerTuning = Asm->TM.Options.DebuggerTuning; else if (IsDarwin) DebuggerTuning = DebuggerKind::LLDB; else if (TT.isPS4CPU()) DebuggerTuning = DebuggerKind::SCE; else DebuggerTuning = DebuggerKind::GDB; if (DwarfInlinedStrings == Default) UseInlineStrings = TT.isNVPTX(); else UseInlineStrings = DwarfInlinedStrings == Enable; UseLocSection = !TT.isNVPTX(); HasAppleExtensionAttributes = tuneForLLDB(); // Handle split DWARF. HasSplitDwarf = !Asm->TM.Options.MCOptions.SplitDwarfFile.empty(); // SCE defaults to linkage names only for abstract subprograms. if (DwarfLinkageNames == DefaultLinkageNames) UseAllLinkageNames = !tuneForSCE(); else UseAllLinkageNames = DwarfLinkageNames == AllLinkageNames; unsigned DwarfVersionNumber = Asm->TM.Options.MCOptions.DwarfVersion; unsigned DwarfVersion = DwarfVersionNumber ? DwarfVersionNumber : MMI->getModule()->getDwarfVersion(); // Use dwarf 4 by default if nothing is requested. For NVPTX, use dwarf 2. DwarfVersion = TT.isNVPTX() ? 2 : (DwarfVersion ? DwarfVersion : dwarf::DWARF_VERSION); bool Dwarf64 = Asm->TM.Options.MCOptions.Dwarf64 && DwarfVersion >= 3 && // DWARF64 was introduced in DWARFv3. TT.isArch64Bit() && // DWARF64 requires 64-bit relocations. TT.isOSBinFormatELF(); // Support only ELF for now. UseRangesSection = !NoDwarfRangesSection && !TT.isNVPTX(); // Use sections as references. Force for NVPTX. if (DwarfSectionsAsReferences == Default) UseSectionsAsReferences = TT.isNVPTX(); else UseSectionsAsReferences = DwarfSectionsAsReferences == Enable; // Don't generate type units for unsupported object file formats. GenerateTypeUnits = (A->TM.getTargetTriple().isOSBinFormatELF() || A->TM.getTargetTriple().isOSBinFormatWasm()) && GenerateDwarfTypeUnits; TheAccelTableKind = computeAccelTableKind( DwarfVersion, GenerateTypeUnits, DebuggerTuning, A->TM.getTargetTriple()); // Work around a GDB bug. GDB doesn't support the standard opcode; // SCE doesn't support GNU's; LLDB prefers the standard opcode, which // is defined as of DWARF 3. // See GDB bug 11616 - DW_OP_form_tls_address is unimplemented // https://sourceware.org/bugzilla/show_bug.cgi?id=11616 UseGNUTLSOpcode = tuneForGDB() || DwarfVersion < 3; // GDB does not fully support the DWARF 4 representation for bitfields. UseDWARF2Bitfields = (DwarfVersion < 4) || tuneForGDB(); // The DWARF v5 string offsets table has - possibly shared - contributions // from each compile and type unit each preceded by a header. The string // offsets table used by the pre-DWARF v5 split-DWARF implementation uses // a monolithic string offsets table without any header. UseSegmentedStringOffsetsTable = DwarfVersion >= 5; // Emit call-site-param debug info for GDB and LLDB, if the target supports // the debug entry values feature. It can also be enabled explicitly. EmitDebugEntryValues = Asm->TM.Options.ShouldEmitDebugEntryValues(); // It is unclear if the GCC .debug_macro extension is well-specified // for split DWARF. For now, do not allow LLVM to emit it. UseDebugMacroSection = DwarfVersion >= 5 || (UseGNUDebugMacro && !useSplitDwarf()); if (DwarfOpConvert == Default) EnableOpConvert = !((tuneForGDB() && useSplitDwarf()) || (tuneForLLDB() && !TT.isOSBinFormatMachO())); else EnableOpConvert = (DwarfOpConvert == Enable); // Split DWARF would benefit object size significantly by trading reductions // in address pool usage for slightly increased range list encodings. if (DwarfVersion >= 5) { MinimizeAddr = MinimizeAddrInV5Option; // FIXME: In the future, enable this by default for Split DWARF where the // tradeoff is more pronounced due to being able to offload the range // lists to the dwo file and shrink object files/reduce relocations there. if (MinimizeAddr == MinimizeAddrInV5::Default) MinimizeAddr = MinimizeAddrInV5::Disabled; } Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); Asm->OutStreamer->getContext().setDwarfFormat(Dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32); } // Define out of line so we don't have to include DwarfUnit.h in DwarfDebug.h. DwarfDebug::~DwarfDebug() = default; static bool isObjCClass(StringRef Name) { return Name.startswith("+") || Name.startswith("-"); } static bool hasObjCCategory(StringRef Name) { if (!isObjCClass(Name)) return false; return Name.find(") ") != StringRef::npos; } static void getObjCClassCategory(StringRef In, StringRef &Class, StringRef &Category) { if (!hasObjCCategory(In)) { Class = In.slice(In.find('[') + 1, In.find(' ')); Category = ""; return; } Class = In.slice(In.find('[') + 1, In.find('(')); Category = In.slice(In.find('[') + 1, In.find(' ')); } static StringRef getObjCMethodName(StringRef In) { return In.slice(In.find(' ') + 1, In.find(']')); } // Add the various names to the Dwarf accelerator table names. void DwarfDebug::addSubprogramNames(const DICompileUnit &CU, const DISubprogram *SP, DIE &Die) { if (getAccelTableKind() != AccelTableKind::Apple && CU.getNameTableKind() == DICompileUnit::DebugNameTableKind::None) return; if (!SP->isDefinition()) return; if (SP->getName() != "") addAccelName(CU, SP->getName(), Die); // If the linkage name is different than the name, go ahead and output that as // well into the name table. Only do that if we are going to actually emit // that name. if (SP->getLinkageName() != "" && SP->getName() != SP->getLinkageName() && (useAllLinkageNames() || InfoHolder.getAbstractSPDies().lookup(SP))) addAccelName(CU, SP->getLinkageName(), Die); // If this is an Objective-C selector name add it to the ObjC accelerator // too. if (isObjCClass(SP->getName())) { StringRef Class, Category; getObjCClassCategory(SP->getName(), Class, Category); addAccelObjC(CU, Class, Die); if (Category != "") addAccelObjC(CU, Category, Die); // Also add the base method name to the name table. addAccelName(CU, getObjCMethodName(SP->getName()), Die); } } /// Check whether we should create a DIE for the given Scope, return true /// if we don't create a DIE (the corresponding DIE is null). bool DwarfDebug::isLexicalScopeDIENull(LexicalScope *Scope) { if (Scope->isAbstractScope()) return false; // We don't create a DIE if there is no Range. const SmallVectorImpl &Ranges = Scope->getRanges(); if (Ranges.empty()) return true; if (Ranges.size() > 1) return false; // We don't create a DIE if we have a single Range and the end label // is null. return !getLabelAfterInsn(Ranges.front().second); } template static void forBothCUs(DwarfCompileUnit &CU, Func F) { F(CU); if (auto *SkelCU = CU.getSkeleton()) if (CU.getCUNode()->getSplitDebugInlining()) F(*SkelCU); } bool DwarfDebug::shareAcrossDWOCUs() const { return SplitDwarfCrossCuReferences; } void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope) { assert(Scope && Scope->getScopeNode()); assert(Scope->isAbstractScope()); assert(!Scope->getInlinedAt()); auto *SP = cast(Scope->getScopeNode()); // Find the subprogram's DwarfCompileUnit in the SPMap in case the subprogram // was inlined from another compile unit. if (useSplitDwarf() && !shareAcrossDWOCUs() && !SP->getUnit()->getSplitDebugInlining()) // Avoid building the original CU if it won't be used SrcCU.constructAbstractSubprogramScopeDIE(Scope); else { auto &CU = getOrCreateDwarfCompileUnit(SP->getUnit()); if (auto *SkelCU = CU.getSkeleton()) { (shareAcrossDWOCUs() ? CU : SrcCU) .constructAbstractSubprogramScopeDIE(Scope); if (CU.getCUNode()->getSplitDebugInlining()) SkelCU->constructAbstractSubprogramScopeDIE(Scope); } else CU.constructAbstractSubprogramScopeDIE(Scope); } } DIE &DwarfDebug::constructSubprogramDefinitionDIE(const DISubprogram *SP) { DICompileUnit *Unit = SP->getUnit(); assert(SP->isDefinition() && "Subprogram not a definition"); assert(Unit && "Subprogram definition without parent unit"); auto &CU = getOrCreateDwarfCompileUnit(Unit); return *CU.getOrCreateSubprogramDIE(SP); } /// Represents a parameter whose call site value can be described by applying a /// debug expression to a register in the forwarded register worklist. struct FwdRegParamInfo { /// The described parameter register. unsigned ParamReg; /// Debug expression that has been built up when walking through the /// instruction chain that produces the parameter's value. const DIExpression *Expr; }; /// Register worklist for finding call site values. using FwdRegWorklist = MapVector>; /// Append the expression \p Addition to \p Original and return the result. static const DIExpression *combineDIExpressions(const DIExpression *Original, const DIExpression *Addition) { std::vector Elts = Addition->getElements().vec(); // Avoid multiple DW_OP_stack_values. if (Original->isImplicit() && Addition->isImplicit()) erase_value(Elts, dwarf::DW_OP_stack_value); const DIExpression *CombinedExpr = (Elts.size() > 0) ? DIExpression::append(Original, Elts) : Original; return CombinedExpr; } /// Emit call site parameter entries that are described by the given value and /// debug expression. template static void finishCallSiteParams(ValT Val, const DIExpression *Expr, ArrayRef DescribedParams, ParamSet &Params) { for (auto Param : DescribedParams) { bool ShouldCombineExpressions = Expr && Param.Expr->getNumElements() > 0; // TODO: Entry value operations can currently not be combined with any // other expressions, so we can't emit call site entries in those cases. if (ShouldCombineExpressions && Expr->isEntryValue()) continue; // If a parameter's call site value is produced by a chain of // instructions we may have already created an expression for the // parameter when walking through the instructions. Append that to the // base expression. const DIExpression *CombinedExpr = ShouldCombineExpressions ? combineDIExpressions(Expr, Param.Expr) : Expr; assert((!CombinedExpr || CombinedExpr->isValid()) && "Combined debug expression is invalid"); DbgValueLoc DbgLocVal(CombinedExpr, Val); DbgCallSiteParam CSParm(Param.ParamReg, DbgLocVal); Params.push_back(CSParm); ++NumCSParams; } } /// Add \p Reg to the worklist, if it's not already present, and mark that the /// given parameter registers' values can (potentially) be described using /// that register and an debug expression. static void addToFwdRegWorklist(FwdRegWorklist &Worklist, unsigned Reg, const DIExpression *Expr, ArrayRef ParamsToAdd) { auto I = Worklist.insert({Reg, {}}); auto &ParamsForFwdReg = I.first->second; for (auto Param : ParamsToAdd) { assert(none_of(ParamsForFwdReg, [Param](const FwdRegParamInfo &D) { return D.ParamReg == Param.ParamReg; }) && "Same parameter described twice by forwarding reg"); // If a parameter's call site value is produced by a chain of // instructions we may have already created an expression for the // parameter when walking through the instructions. Append that to the // new expression. const DIExpression *CombinedExpr = combineDIExpressions(Expr, Param.Expr); ParamsForFwdReg.push_back({Param.ParamReg, CombinedExpr}); } } /// Interpret values loaded into registers by \p CurMI. static void interpretValues(const MachineInstr *CurMI, FwdRegWorklist &ForwardedRegWorklist, ParamSet &Params) { const MachineFunction *MF = CurMI->getMF(); const DIExpression *EmptyExpr = DIExpression::get(MF->getFunction().getContext(), {}); const auto &TRI = *MF->getSubtarget().getRegisterInfo(); const auto &TII = *MF->getSubtarget().getInstrInfo(); const auto &TLI = *MF->getSubtarget().getTargetLowering(); // If an instruction defines more than one item in the worklist, we may run // into situations where a worklist register's value is (potentially) // described by the previous value of another register that is also defined // by that instruction. // // This can for example occur in cases like this: // // $r1 = mov 123 // $r0, $r1 = mvrr $r1, 456 // call @foo, $r0, $r1 // // When describing $r1's value for the mvrr instruction, we need to make sure // that we don't finalize an entry value for $r0, as that is dependent on the // previous value of $r1 (123 rather than 456). // // In order to not have to distinguish between those cases when finalizing // entry values, we simply postpone adding new parameter registers to the // worklist, by first keeping them in this temporary container until the // instruction has been handled. FwdRegWorklist TmpWorklistItems; // If the MI is an instruction defining one or more parameters' forwarding // registers, add those defines. auto getForwardingRegsDefinedByMI = [&](const MachineInstr &MI, SmallSetVector &Defs) { if (MI.isDebugInstr()) return; for (const MachineOperand &MO : MI.operands()) { if (MO.isReg() && MO.isDef() && Register::isPhysicalRegister(MO.getReg())) { for (auto FwdReg : ForwardedRegWorklist) if (TRI.regsOverlap(FwdReg.first, MO.getReg())) Defs.insert(FwdReg.first); } } }; // Set of worklist registers that are defined by this instruction. SmallSetVector FwdRegDefs; getForwardingRegsDefinedByMI(*CurMI, FwdRegDefs); if (FwdRegDefs.empty()) return; for (auto ParamFwdReg : FwdRegDefs) { if (auto ParamValue = TII.describeLoadedValue(*CurMI, ParamFwdReg)) { if (ParamValue->first.isImm()) { int64_t Val = ParamValue->first.getImm(); finishCallSiteParams(Val, ParamValue->second, ForwardedRegWorklist[ParamFwdReg], Params); } else if (ParamValue->first.isReg()) { Register RegLoc = ParamValue->first.getReg(); Register SP = TLI.getStackPointerRegisterToSaveRestore(); Register FP = TRI.getFrameRegister(*MF); bool IsSPorFP = (RegLoc == SP) || (RegLoc == FP); if (TRI.isCalleeSavedPhysReg(RegLoc, *MF) || IsSPorFP) { MachineLocation MLoc(RegLoc, /*Indirect=*/IsSPorFP); finishCallSiteParams(MLoc, ParamValue->second, ForwardedRegWorklist[ParamFwdReg], Params); } else { // ParamFwdReg was described by the non-callee saved register // RegLoc. Mark that the call site values for the parameters are // dependent on that register instead of ParamFwdReg. Since RegLoc // may be a register that will be handled in this iteration, we // postpone adding the items to the worklist, and instead keep them // in a temporary container. addToFwdRegWorklist(TmpWorklistItems, RegLoc, ParamValue->second, ForwardedRegWorklist[ParamFwdReg]); } } } } // Remove all registers that this instruction defines from the worklist. for (auto ParamFwdReg : FwdRegDefs) ForwardedRegWorklist.erase(ParamFwdReg); // Now that we are done handling this instruction, add items from the // temporary worklist to the real one. for (auto New : TmpWorklistItems) addToFwdRegWorklist(ForwardedRegWorklist, New.first, EmptyExpr, New.second); TmpWorklistItems.clear(); } static bool interpretNextInstr(const MachineInstr *CurMI, FwdRegWorklist &ForwardedRegWorklist, ParamSet &Params) { // Skip bundle headers. if (CurMI->isBundle()) return true; // If the next instruction is a call we can not interpret parameter's // forwarding registers or we finished the interpretation of all // parameters. if (CurMI->isCall()) return false; if (ForwardedRegWorklist.empty()) return false; // Avoid NOP description. if (CurMI->getNumOperands() == 0) return true; interpretValues(CurMI, ForwardedRegWorklist, Params); return true; } /// Try to interpret values loaded into registers that forward parameters /// for \p CallMI. Store parameters with interpreted value into \p Params. static void collectCallSiteParameters(const MachineInstr *CallMI, ParamSet &Params) { const MachineFunction *MF = CallMI->getMF(); auto CalleesMap = MF->getCallSitesInfo(); auto CallFwdRegsInfo = CalleesMap.find(CallMI); // There is no information for the call instruction. if (CallFwdRegsInfo == CalleesMap.end()) return; const MachineBasicBlock *MBB = CallMI->getParent(); // Skip the call instruction. auto I = std::next(CallMI->getReverseIterator()); FwdRegWorklist ForwardedRegWorklist; const DIExpression *EmptyExpr = DIExpression::get(MF->getFunction().getContext(), {}); // Add all the forwarding registers into the ForwardedRegWorklist. for (auto ArgReg : CallFwdRegsInfo->second) { bool InsertedReg = ForwardedRegWorklist.insert({ArgReg.Reg, {{ArgReg.Reg, EmptyExpr}}}) .second; assert(InsertedReg && "Single register used to forward two arguments?"); (void)InsertedReg; } // Do not emit CSInfo for undef forwarding registers. for (auto &MO : CallMI->uses()) if (MO.isReg() && MO.isUndef()) ForwardedRegWorklist.erase(MO.getReg()); // We erase, from the ForwardedRegWorklist, those forwarding registers for // which we successfully describe a loaded value (by using // the describeLoadedValue()). For those remaining arguments in the working // list, for which we do not describe a loaded value by // the describeLoadedValue(), we try to generate an entry value expression // for their call site value description, if the call is within the entry MBB. // TODO: Handle situations when call site parameter value can be described // as the entry value within basic blocks other than the first one. bool ShouldTryEmitEntryVals = MBB->getIterator() == MF->begin(); // Search for a loading value in forwarding registers inside call delay slot. if (CallMI->hasDelaySlot()) { auto Suc = std::next(CallMI->getIterator()); // Only one-instruction delay slot is supported. auto BundleEnd = llvm::getBundleEnd(CallMI->getIterator()); (void)BundleEnd; assert(std::next(Suc) == BundleEnd && "More than one instruction in call delay slot"); // Try to interpret value loaded by instruction. if (!interpretNextInstr(&*Suc, ForwardedRegWorklist, Params)) return; } // Search for a loading value in forwarding registers. for (; I != MBB->rend(); ++I) { // Try to interpret values loaded by instruction. if (!interpretNextInstr(&*I, ForwardedRegWorklist, Params)) return; } // Emit the call site parameter's value as an entry value. if (ShouldTryEmitEntryVals) { // Create an expression where the register's entry value is used. DIExpression *EntryExpr = DIExpression::get( MF->getFunction().getContext(), {dwarf::DW_OP_LLVM_entry_value, 1}); for (auto RegEntry : ForwardedRegWorklist) { MachineLocation MLoc(RegEntry.first); finishCallSiteParams(MLoc, EntryExpr, RegEntry.second, Params); } } } void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, DwarfCompileUnit &CU, DIE &ScopeDIE, const MachineFunction &MF) { // Add a call site-related attribute (DWARF5, Sec. 3.3.1.3). Do this only if // the subprogram is required to have one. if (!SP.areAllCallsDescribed() || !SP.isDefinition()) return; // Use DW_AT_call_all_calls to express that call site entries are present // for both tail and non-tail calls. Don't use DW_AT_call_all_source_calls // because one of its requirements is not met: call site entries for // optimized-out calls are elided. CU.addFlag(ScopeDIE, CU.getDwarf5OrGNUAttr(dwarf::DW_AT_call_all_calls)); const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); assert(TII && "TargetInstrInfo not found: cannot label tail calls"); // Delay slot support check. auto delaySlotSupported = [&](const MachineInstr &MI) { if (!MI.isBundledWithSucc()) return false; auto Suc = std::next(MI.getIterator()); auto CallInstrBundle = getBundleStart(MI.getIterator()); (void)CallInstrBundle; auto DelaySlotBundle = getBundleStart(Suc); (void)DelaySlotBundle; // Ensure that label after call is following delay slot instruction. // Ex. CALL_INSTRUCTION { // DELAY_SLOT_INSTRUCTION } // LABEL_AFTER_CALL assert(getLabelAfterInsn(&*CallInstrBundle) == getLabelAfterInsn(&*DelaySlotBundle) && "Call and its successor instruction don't have same label after."); return true; }; // Emit call site entries for each call or tail call in the function. for (const MachineBasicBlock &MBB : MF) { for (const MachineInstr &MI : MBB.instrs()) { // Bundles with call in them will pass the isCall() test below but do not // have callee operand information so skip them here. Iterator will // eventually reach the call MI. if (MI.isBundle()) continue; // Skip instructions which aren't calls. Both calls and tail-calling jump // instructions (e.g TAILJMPd64) are classified correctly here. if (!MI.isCandidateForCallSiteEntry()) continue; // Skip instructions marked as frame setup, as they are not interesting to // the user. if (MI.getFlag(MachineInstr::FrameSetup)) continue; // Check if delay slot support is enabled. if (MI.hasDelaySlot() && !delaySlotSupported(*&MI)) return; // If this is a direct call, find the callee's subprogram. // In the case of an indirect call find the register that holds // the callee. const MachineOperand &CalleeOp = MI.getOperand(0); if (!CalleeOp.isGlobal() && !CalleeOp.isReg()) continue; unsigned CallReg = 0; DIE *CalleeDIE = nullptr; const Function *CalleeDecl = nullptr; if (CalleeOp.isReg()) { CallReg = CalleeOp.getReg(); if (!CallReg) continue; } else { CalleeDecl = dyn_cast(CalleeOp.getGlobal()); if (!CalleeDecl || !CalleeDecl->getSubprogram()) continue; const DISubprogram *CalleeSP = CalleeDecl->getSubprogram(); if (CalleeSP->isDefinition()) { // Ensure that a subprogram DIE for the callee is available in the // appropriate CU. CalleeDIE = &constructSubprogramDefinitionDIE(CalleeSP); } else { // Create the declaration DIE if it is missing. This is required to // support compilation of old bitcode with an incomplete list of // retained metadata. CalleeDIE = CU.getOrCreateSubprogramDIE(CalleeSP); } assert(CalleeDIE && "Must have a DIE for the callee"); } // TODO: Omit call site entries for runtime calls (objc_msgSend, etc). bool IsTail = TII->isTailCall(MI); // If MI is in a bundle, the label was created after the bundle since // EmitFunctionBody iterates over top-level MIs. Get that top-level MI // to search for that label below. const MachineInstr *TopLevelCallMI = MI.isInsideBundle() ? &*getBundleStart(MI.getIterator()) : &MI; // For non-tail calls, the return PC is needed to disambiguate paths in // the call graph which could lead to some target function. For tail // calls, no return PC information is needed, unless tuning for GDB in // DWARF4 mode in which case we fake a return PC for compatibility. const MCSymbol *PCAddr = (!IsTail || CU.useGNUAnalogForDwarf5Feature()) ? const_cast(getLabelAfterInsn(TopLevelCallMI)) : nullptr; // For tail calls, it's necessary to record the address of the branch // instruction so that the debugger can show where the tail call occurred. const MCSymbol *CallAddr = IsTail ? getLabelBeforeInsn(TopLevelCallMI) : nullptr; assert((IsTail || PCAddr) && "Non-tail call without return PC"); LLVM_DEBUG(dbgs() << "CallSiteEntry: " << MF.getName() << " -> " << (CalleeDecl ? CalleeDecl->getName() : StringRef(MF.getSubtarget() .getRegisterInfo() ->getName(CallReg))) << (IsTail ? " [IsTail]" : "") << "\n"); DIE &CallSiteDIE = CU.constructCallSiteEntryDIE( ScopeDIE, CalleeDIE, IsTail, PCAddr, CallAddr, CallReg); // Optionally emit call-site-param debug info. if (emitDebugEntryValues()) { ParamSet Params; // Try to interpret values of call site parameters. collectCallSiteParameters(&MI, Params); CU.constructCallSiteParmEntryDIEs(CallSiteDIE, Params); } } } } void DwarfDebug::addGnuPubAttributes(DwarfCompileUnit &U, DIE &D) const { if (!U.hasDwarfPubSections()) return; U.addFlag(D, dwarf::DW_AT_GNU_pubnames); } void DwarfDebug::finishUnitAttributes(const DICompileUnit *DIUnit, DwarfCompileUnit &NewCU) { DIE &Die = NewCU.getUnitDie(); StringRef FN = DIUnit->getFilename(); StringRef Producer = DIUnit->getProducer(); StringRef Flags = DIUnit->getFlags(); if (!Flags.empty() && !useAppleExtensionAttributes()) { std::string ProducerWithFlags = Producer.str() + " " + Flags.str(); NewCU.addString(Die, dwarf::DW_AT_producer, ProducerWithFlags); } else NewCU.addString(Die, dwarf::DW_AT_producer, Producer); NewCU.addUInt(Die, dwarf::DW_AT_language, dwarf::DW_FORM_data2, DIUnit->getSourceLanguage()); NewCU.addString(Die, dwarf::DW_AT_name, FN); StringRef SysRoot = DIUnit->getSysRoot(); if (!SysRoot.empty()) NewCU.addString(Die, dwarf::DW_AT_LLVM_sysroot, SysRoot); StringRef SDK = DIUnit->getSDK(); if (!SDK.empty()) NewCU.addString(Die, dwarf::DW_AT_APPLE_sdk, SDK); // Add DW_str_offsets_base to the unit DIE, except for split units. if (useSegmentedStringOffsetsTable() && !useSplitDwarf()) NewCU.addStringOffsetsStart(); if (!useSplitDwarf()) { NewCU.initStmtList(); // If we're using split dwarf the compilation dir is going to be in the // skeleton CU and so we don't need to duplicate it here. if (!CompilationDir.empty()) NewCU.addString(Die, dwarf::DW_AT_comp_dir, CompilationDir); addGnuPubAttributes(NewCU, Die); } if (useAppleExtensionAttributes()) { if (DIUnit->isOptimized()) NewCU.addFlag(Die, dwarf::DW_AT_APPLE_optimized); StringRef Flags = DIUnit->getFlags(); if (!Flags.empty()) NewCU.addString(Die, dwarf::DW_AT_APPLE_flags, Flags); if (unsigned RVer = DIUnit->getRuntimeVersion()) NewCU.addUInt(Die, dwarf::DW_AT_APPLE_major_runtime_vers, dwarf::DW_FORM_data1, RVer); } if (DIUnit->getDWOId()) { // This CU is either a clang module DWO or a skeleton CU. NewCU.addUInt(Die, dwarf::DW_AT_GNU_dwo_id, dwarf::DW_FORM_data8, DIUnit->getDWOId()); if (!DIUnit->getSplitDebugFilename().empty()) { // This is a prefabricated skeleton CU. dwarf::Attribute attrDWOName = getDwarfVersion() >= 5 ? dwarf::DW_AT_dwo_name : dwarf::DW_AT_GNU_dwo_name; NewCU.addString(Die, attrDWOName, DIUnit->getSplitDebugFilename()); } } } // Create new DwarfCompileUnit for the given metadata node with tag // DW_TAG_compile_unit. DwarfCompileUnit & DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) { if (auto *CU = CUMap.lookup(DIUnit)) return *CU; CompilationDir = DIUnit->getDirectory(); auto OwnedUnit = std::make_unique( InfoHolder.getUnits().size(), DIUnit, Asm, this, &InfoHolder); DwarfCompileUnit &NewCU = *OwnedUnit; InfoHolder.addUnit(std::move(OwnedUnit)); for (auto *IE : DIUnit->getImportedEntities()) NewCU.addImportedEntity(IE); // LTO with assembly output shares a single line table amongst multiple CUs. // To avoid the compilation directory being ambiguous, let the line table // explicitly describe the directory of all files, never relying on the // compilation directory. if (!Asm->OutStreamer->hasRawTextSupport() || SingleCU) Asm->OutStreamer->emitDwarfFile0Directive( CompilationDir, DIUnit->getFilename(), getMD5AsBytes(DIUnit->getFile()), DIUnit->getSource(), NewCU.getUniqueID()); if (useSplitDwarf()) { NewCU.setSkeleton(constructSkeletonCU(NewCU)); NewCU.setSection(Asm->getObjFileLowering().getDwarfInfoDWOSection()); } else { finishUnitAttributes(DIUnit, NewCU); NewCU.setSection(Asm->getObjFileLowering().getDwarfInfoSection()); } CUMap.insert({DIUnit, &NewCU}); CUDieMap.insert({&NewCU.getUnitDie(), &NewCU}); return NewCU; } void DwarfDebug::constructAndAddImportedEntityDIE(DwarfCompileUnit &TheCU, const DIImportedEntity *N) { if (isa(N->getScope())) return; if (DIE *D = TheCU.getOrCreateContextDIE(N->getScope())) D->addChild(TheCU.constructImportedEntityDIE(N)); } /// Sort and unique GVEs by comparing their fragment offset. static SmallVectorImpl & sortGlobalExprs(SmallVectorImpl &GVEs) { llvm::sort( GVEs, [](DwarfCompileUnit::GlobalExpr A, DwarfCompileUnit::GlobalExpr B) { // Sort order: first null exprs, then exprs without fragment // info, then sort by fragment offset in bits. // FIXME: Come up with a more comprehensive comparator so // the sorting isn't non-deterministic, and so the following // std::unique call works correctly. if (!A.Expr || !B.Expr) return !!B.Expr; auto FragmentA = A.Expr->getFragmentInfo(); auto FragmentB = B.Expr->getFragmentInfo(); if (!FragmentA || !FragmentB) return !!FragmentB; return FragmentA->OffsetInBits < FragmentB->OffsetInBits; }); GVEs.erase(std::unique(GVEs.begin(), GVEs.end(), [](DwarfCompileUnit::GlobalExpr A, DwarfCompileUnit::GlobalExpr B) { return A.Expr == B.Expr; }), GVEs.end()); return GVEs; } // Emit all Dwarf sections that should come prior to the content. Create // global DIEs and emit initial debug info sections. This is invoked by // the target AsmPrinter. void DwarfDebug::beginModule(Module *M) { DebugHandlerBase::beginModule(M); if (!Asm || !MMI->hasDebugInfo()) return; unsigned NumDebugCUs = std::distance(M->debug_compile_units_begin(), M->debug_compile_units_end()); assert(NumDebugCUs > 0 && "Asm unexpectedly initialized"); assert(MMI->hasDebugInfo() && "DebugInfoAvailabilty unexpectedly not initialized"); SingleCU = NumDebugCUs == 1; DenseMap> GVMap; for (const GlobalVariable &Global : M->globals()) { SmallVector GVs; Global.getDebugInfo(GVs); for (auto *GVE : GVs) GVMap[GVE->getVariable()].push_back({&Global, GVE->getExpression()}); } // Create the symbol that designates the start of the unit's contribution // to the string offsets table. In a split DWARF scenario, only the skeleton // unit has the DW_AT_str_offsets_base attribute (and hence needs the symbol). if (useSegmentedStringOffsetsTable()) (useSplitDwarf() ? SkeletonHolder : InfoHolder) .setStringOffsetsStartSym(Asm->createTempSymbol("str_offsets_base")); // Create the symbols that designates the start of the DWARF v5 range list // and locations list tables. They are located past the table headers. if (getDwarfVersion() >= 5) { DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; Holder.setRnglistsTableBaseSym( Asm->createTempSymbol("rnglists_table_base")); if (useSplitDwarf()) InfoHolder.setRnglistsTableBaseSym( Asm->createTempSymbol("rnglists_dwo_table_base")); } // Create the symbol that points to the first entry following the debug // address table (.debug_addr) header. AddrPool.setLabel(Asm->createTempSymbol("addr_table_base")); DebugLocs.setSym(Asm->createTempSymbol("loclists_table_base")); for (DICompileUnit *CUNode : M->debug_compile_units()) { // FIXME: Move local imported entities into a list attached to the // subprogram, then this search won't be needed and a // getImportedEntities().empty() test should go below with the rest. bool HasNonLocalImportedEntities = llvm::any_of( CUNode->getImportedEntities(), [](const DIImportedEntity *IE) { return !isa(IE->getScope()); }); if (!HasNonLocalImportedEntities && CUNode->getEnumTypes().empty() && CUNode->getRetainedTypes().empty() && CUNode->getGlobalVariables().empty() && CUNode->getMacros().empty()) continue; DwarfCompileUnit &CU = getOrCreateDwarfCompileUnit(CUNode); // Global Variables. for (auto *GVE : CUNode->getGlobalVariables()) { // Don't bother adding DIGlobalVariableExpressions listed in the CU if we // already know about the variable and it isn't adding a constant // expression. auto &GVMapEntry = GVMap[GVE->getVariable()]; auto *Expr = GVE->getExpression(); if (!GVMapEntry.size() || (Expr && Expr->isConstant())) GVMapEntry.push_back({nullptr, Expr}); } DenseSet Processed; for (auto *GVE : CUNode->getGlobalVariables()) { DIGlobalVariable *GV = GVE->getVariable(); if (Processed.insert(GV).second) CU.getOrCreateGlobalVariableDIE(GV, sortGlobalExprs(GVMap[GV])); } for (auto *Ty : CUNode->getEnumTypes()) { // The enum types array by design contains pointers to // MDNodes rather than DIRefs. Unique them here. CU.getOrCreateTypeDIE(cast(Ty)); } for (auto *Ty : CUNode->getRetainedTypes()) { // The retained types array by design contains pointers to // MDNodes rather than DIRefs. Unique them here. if (DIType *RT = dyn_cast(Ty)) // There is no point in force-emitting a forward declaration. CU.getOrCreateTypeDIE(RT); } // Emit imported_modules last so that the relevant context is already // available. for (auto *IE : CUNode->getImportedEntities()) constructAndAddImportedEntityDIE(CU, IE); } } void DwarfDebug::finishEntityDefinitions() { for (const auto &Entity : ConcreteEntities) { DIE *Die = Entity->getDIE(); assert(Die); // FIXME: Consider the time-space tradeoff of just storing the unit pointer // in the ConcreteEntities list, rather than looking it up again here. // DIE::getUnit isn't simple - it walks parent pointers, etc. DwarfCompileUnit *Unit = CUDieMap.lookup(Die->getUnitDie()); assert(Unit); Unit->finishEntityDefinition(Entity.get()); } } void DwarfDebug::finishSubprogramDefinitions() { for (const DISubprogram *SP : ProcessedSPNodes) { assert(SP->getUnit()->getEmissionKind() != DICompileUnit::NoDebug); forBothCUs( getOrCreateDwarfCompileUnit(SP->getUnit()), [&](DwarfCompileUnit &CU) { CU.finishSubprogramDefinition(SP); }); } } void DwarfDebug::finalizeModuleInfo() { const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); finishSubprogramDefinitions(); finishEntityDefinitions(); // Include the DWO file name in the hash if there's more than one CU. // This handles ThinLTO's situation where imported CUs may very easily be // duplicate with the same CU partially imported into another ThinLTO unit. StringRef DWOName; if (CUMap.size() > 1) DWOName = Asm->TM.Options.MCOptions.SplitDwarfFile; // Handle anything that needs to be done on a per-unit basis after // all other generation. for (const auto &P : CUMap) { auto &TheCU = *P.second; if (TheCU.getCUNode()->isDebugDirectivesOnly()) continue; // Emit DW_AT_containing_type attribute to connect types with their // vtable holding type. TheCU.constructContainingTypeDIEs(); // Add CU specific attributes if we need to add any. // If we're splitting the dwarf out now that we've got the entire // CU then add the dwo id to it. auto *SkCU = TheCU.getSkeleton(); bool HasSplitUnit = SkCU && !TheCU.getUnitDie().children().empty(); if (HasSplitUnit) { dwarf::Attribute attrDWOName = getDwarfVersion() >= 5 ? dwarf::DW_AT_dwo_name : dwarf::DW_AT_GNU_dwo_name; finishUnitAttributes(TheCU.getCUNode(), TheCU); TheCU.addString(TheCU.getUnitDie(), attrDWOName, Asm->TM.Options.MCOptions.SplitDwarfFile); SkCU->addString(SkCU->getUnitDie(), attrDWOName, Asm->TM.Options.MCOptions.SplitDwarfFile); // Emit a unique identifier for this CU. uint64_t ID = DIEHash(Asm, &TheCU).computeCUSignature(DWOName, TheCU.getUnitDie()); if (getDwarfVersion() >= 5) { TheCU.setDWOId(ID); SkCU->setDWOId(ID); } else { TheCU.addUInt(TheCU.getUnitDie(), dwarf::DW_AT_GNU_dwo_id, dwarf::DW_FORM_data8, ID); SkCU->addUInt(SkCU->getUnitDie(), dwarf::DW_AT_GNU_dwo_id, dwarf::DW_FORM_data8, ID); } if (getDwarfVersion() < 5 && !SkeletonHolder.getRangeLists().empty()) { const MCSymbol *Sym = TLOF.getDwarfRangesSection()->getBeginSymbol(); SkCU->addSectionLabel(SkCU->getUnitDie(), dwarf::DW_AT_GNU_ranges_base, Sym, Sym); } } else if (SkCU) { finishUnitAttributes(SkCU->getCUNode(), *SkCU); } // If we have code split among multiple sections or non-contiguous // ranges of code then emit a DW_AT_ranges attribute on the unit that will // remain in the .o file, otherwise add a DW_AT_low_pc. // FIXME: We should use ranges allow reordering of code ala // .subsections_via_symbols in mach-o. This would mean turning on // ranges for all subprogram DIEs for mach-o. DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; if (unsigned NumRanges = TheCU.getRanges().size()) { if (NumRanges > 1 && useRangesSection()) // A DW_AT_low_pc attribute may also be specified in combination with // DW_AT_ranges to specify the default base address for use in // location lists (see Section 2.6.2) and range lists (see Section // 2.17.3). U.addUInt(U.getUnitDie(), dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr, 0); else U.setBaseAddress(TheCU.getRanges().front().Begin); U.attachRangesOrLowHighPC(U.getUnitDie(), TheCU.takeRanges()); } // We don't keep track of which addresses are used in which CU so this // is a bit pessimistic under LTO. if ((HasSplitUnit || getDwarfVersion() >= 5) && !AddrPool.isEmpty()) U.addAddrTableBase(); if (getDwarfVersion() >= 5) { if (U.hasRangeLists()) U.addRnglistsBase(); if (!DebugLocs.getLists().empty()) { if (!useSplitDwarf()) U.addSectionLabel(U.getUnitDie(), dwarf::DW_AT_loclists_base, DebugLocs.getSym(), TLOF.getDwarfLoclistsSection()->getBeginSymbol()); } } auto *CUNode = cast(P.first); // If compile Unit has macros, emit "DW_AT_macro_info/DW_AT_macros" // attribute. if (CUNode->getMacros()) { if (UseDebugMacroSection) { if (useSplitDwarf()) TheCU.addSectionDelta( TheCU.getUnitDie(), dwarf::DW_AT_macros, U.getMacroLabelBegin(), TLOF.getDwarfMacroDWOSection()->getBeginSymbol()); else { dwarf::Attribute MacrosAttr = getDwarfVersion() >= 5 ? dwarf::DW_AT_macros : dwarf::DW_AT_GNU_macros; U.addSectionLabel(U.getUnitDie(), MacrosAttr, U.getMacroLabelBegin(), TLOF.getDwarfMacroSection()->getBeginSymbol()); } } else { if (useSplitDwarf()) TheCU.addSectionDelta( TheCU.getUnitDie(), dwarf::DW_AT_macro_info, U.getMacroLabelBegin(), TLOF.getDwarfMacinfoDWOSection()->getBeginSymbol()); else U.addSectionLabel(U.getUnitDie(), dwarf::DW_AT_macro_info, U.getMacroLabelBegin(), TLOF.getDwarfMacinfoSection()->getBeginSymbol()); } } } // Emit all frontend-produced Skeleton CUs, i.e., Clang modules. for (auto *CUNode : MMI->getModule()->debug_compile_units()) if (CUNode->getDWOId()) getOrCreateDwarfCompileUnit(CUNode); // Compute DIE offsets and sizes. InfoHolder.computeSizeAndOffsets(); if (useSplitDwarf()) SkeletonHolder.computeSizeAndOffsets(); } // Emit all Dwarf sections that should come after the content. void DwarfDebug::endModule() { assert(CurFn == nullptr); assert(CurMI == nullptr); for (const auto &P : CUMap) { auto &CU = *P.second; CU.createBaseTypeDIEs(); } // If we aren't actually generating debug info (check beginModule - // conditionalized on the presence of the llvm.dbg.cu metadata node) if (!Asm || !MMI->hasDebugInfo()) return; // Finalize the debug info for the module. finalizeModuleInfo(); if (useSplitDwarf()) // Emit debug_loc.dwo/debug_loclists.dwo section. emitDebugLocDWO(); else // Emit debug_loc/debug_loclists section. emitDebugLoc(); // Corresponding abbreviations into a abbrev section. emitAbbreviations(); // Emit all the DIEs into a debug info section. emitDebugInfo(); // Emit info into a debug aranges section. if (GenerateARangeSection) emitDebugARanges(); // Emit info into a debug ranges section. emitDebugRanges(); if (useSplitDwarf()) // Emit info into a debug macinfo.dwo section. emitDebugMacinfoDWO(); else // Emit info into a debug macinfo/macro section. emitDebugMacinfo(); emitDebugStr(); if (useSplitDwarf()) { emitDebugStrDWO(); emitDebugInfoDWO(); emitDebugAbbrevDWO(); emitDebugLineDWO(); emitDebugRangesDWO(); } emitDebugAddr(); // Emit info into the dwarf accelerator table sections. switch (getAccelTableKind()) { case AccelTableKind::Apple: emitAccelNames(); emitAccelObjC(); emitAccelNamespaces(); emitAccelTypes(); break; case AccelTableKind::Dwarf: emitAccelDebugNames(); break; case AccelTableKind::None: break; case AccelTableKind::Default: llvm_unreachable("Default should have already been resolved."); } // Emit the pubnames and pubtypes sections if requested. emitDebugPubSections(); // clean up. // FIXME: AbstractVariables.clear(); } void DwarfDebug::ensureAbstractEntityIsCreated(DwarfCompileUnit &CU, const DINode *Node, const MDNode *ScopeNode) { if (CU.getExistingAbstractEntity(Node)) return; CU.createAbstractEntity(Node, LScopes.getOrCreateAbstractScope( cast(ScopeNode))); } void DwarfDebug::ensureAbstractEntityIsCreatedIfScoped(DwarfCompileUnit &CU, const DINode *Node, const MDNode *ScopeNode) { if (CU.getExistingAbstractEntity(Node)) return; if (LexicalScope *Scope = LScopes.findAbstractScope(cast_or_null(ScopeNode))) CU.createAbstractEntity(Node, Scope); } // Collect variable information from side table maintained by MF. void DwarfDebug::collectVariableInfoFromMFTable( DwarfCompileUnit &TheCU, DenseSet &Processed) { SmallDenseMap MFVars; LLVM_DEBUG(dbgs() << "DwarfDebug: collecting variables from MF side table\n"); for (const auto &VI : Asm->MF->getVariableDbgInfo()) { if (!VI.Var) continue; assert(VI.Var->isValidLocationForIntrinsic(VI.Loc) && "Expected inlined-at fields to agree"); InlinedEntity Var(VI.Var, VI.Loc->getInlinedAt()); Processed.insert(Var); LexicalScope *Scope = LScopes.findLexicalScope(VI.Loc); // If variable scope is not found then skip this variable. if (!Scope) { LLVM_DEBUG(dbgs() << "Dropping debug info for " << VI.Var->getName() << ", no variable scope found\n"); continue; } ensureAbstractEntityIsCreatedIfScoped(TheCU, Var.first, Scope->getScopeNode()); auto RegVar = std::make_unique( cast(Var.first), Var.second); RegVar->initializeMMI(VI.Expr, VI.Slot); LLVM_DEBUG(dbgs() << "Created DbgVariable for " << VI.Var->getName() << "\n"); if (DbgVariable *DbgVar = MFVars.lookup(Var)) DbgVar->addMMIEntry(*RegVar); else if (InfoHolder.addScopeVariable(Scope, RegVar.get())) { MFVars.insert({Var, RegVar.get()}); ConcreteEntities.push_back(std::move(RegVar)); } } } /// Determine whether a *singular* DBG_VALUE is valid for the entirety of its /// enclosing lexical scope. The check ensures there are no other instructions /// in the same lexical scope preceding the DBG_VALUE and that its range is /// either open or otherwise rolls off the end of the scope. static bool validThroughout(LexicalScopes &LScopes, const MachineInstr *DbgValue, const MachineInstr *RangeEnd, const InstructionOrdering &Ordering) { assert(DbgValue->getDebugLoc() && "DBG_VALUE without a debug location"); auto MBB = DbgValue->getParent(); auto DL = DbgValue->getDebugLoc(); auto *LScope = LScopes.findLexicalScope(DL); // Scope doesn't exist; this is a dead DBG_VALUE. if (!LScope) return false; auto &LSRange = LScope->getRanges(); if (LSRange.size() == 0) return false; const MachineInstr *LScopeBegin = LSRange.front().first; // If the scope starts before the DBG_VALUE then we may have a negative // result. Otherwise the location is live coming into the scope and we // can skip the following checks. if (!Ordering.isBefore(DbgValue, LScopeBegin)) { // Exit if the lexical scope begins outside of the current block. if (LScopeBegin->getParent() != MBB) return false; MachineBasicBlock::const_reverse_iterator Pred(DbgValue); for (++Pred; Pred != MBB->rend(); ++Pred) { if (Pred->getFlag(MachineInstr::FrameSetup)) break; auto PredDL = Pred->getDebugLoc(); if (!PredDL || Pred->isMetaInstruction()) continue; // Check whether the instruction preceding the DBG_VALUE is in the same // (sub)scope as the DBG_VALUE. if (DL->getScope() == PredDL->getScope()) return false; auto *PredScope = LScopes.findLexicalScope(PredDL); if (!PredScope || LScope->dominates(PredScope)) return false; } } // If the range of the DBG_VALUE is open-ended, report success. if (!RangeEnd) return true; // Single, constant DBG_VALUEs in the prologue are promoted to be live // throughout the function. This is a hack, presumably for DWARF v2 and not // necessarily correct. It would be much better to use a dbg.declare instead // if we know the constant is live throughout the scope. if (DbgValue->getDebugOperand(0).isImm() && MBB->pred_empty()) return true; // Test if the location terminates before the end of the scope. const MachineInstr *LScopeEnd = LSRange.back().second; if (Ordering.isBefore(RangeEnd, LScopeEnd)) return false; // There's a single location which starts at the scope start, and ends at or // after the scope end. return true; } /// Build the location list for all DBG_VALUEs in the function that /// describe the same variable. The resulting DebugLocEntries will have /// strict monotonically increasing begin addresses and will never /// overlap. If the resulting list has only one entry that is valid /// throughout variable's scope return true. // // See the definition of DbgValueHistoryMap::Entry for an explanation of the // different kinds of history map entries. One thing to be aware of is that if // a debug value is ended by another entry (rather than being valid until the // end of the function), that entry's instruction may or may not be included in // the range, depending on if the entry is a clobbering entry (it has an // instruction that clobbers one or more preceding locations), or if it is an // (overlapping) debug value entry. This distinction can be seen in the example // below. The first debug value is ended by the clobbering entry 2, and the // second and third debug values are ended by the overlapping debug value entry // 4. // // Input: // // History map entries [type, end index, mi] // // 0 | [DbgValue, 2, DBG_VALUE $reg0, [...] (fragment 0, 32)] // 1 | | [DbgValue, 4, DBG_VALUE $reg1, [...] (fragment 32, 32)] // 2 | | [Clobber, $reg0 = [...], -, -] // 3 | | [DbgValue, 4, DBG_VALUE 123, [...] (fragment 64, 32)] // 4 [DbgValue, ~0, DBG_VALUE @g, [...] (fragment 0, 96)] // // Output [start, end) [Value...]: // // [0-1) [(reg0, fragment 0, 32)] // [1-3) [(reg0, fragment 0, 32), (reg1, fragment 32, 32)] // [3-4) [(reg1, fragment 32, 32), (123, fragment 64, 32)] // [4-) [(@g, fragment 0, 96)] bool DwarfDebug::buildLocationList(SmallVectorImpl &DebugLoc, const DbgValueHistoryMap::Entries &Entries) { using OpenRange = std::pair; SmallVector OpenRanges; bool isSafeForSingleLocation = true; const MachineInstr *StartDebugMI = nullptr; const MachineInstr *EndMI = nullptr; for (auto EB = Entries.begin(), EI = EB, EE = Entries.end(); EI != EE; ++EI) { const MachineInstr *Instr = EI->getInstr(); // Remove all values that are no longer live. size_t Index = std::distance(EB, EI); erase_if(OpenRanges, [&](OpenRange &R) { return R.first <= Index; }); // If we are dealing with a clobbering entry, this iteration will result in // a location list entry starting after the clobbering instruction. const MCSymbol *StartLabel = EI->isClobber() ? getLabelAfterInsn(Instr) : getLabelBeforeInsn(Instr); assert(StartLabel && "Forgot label before/after instruction starting a range!"); const MCSymbol *EndLabel; if (std::next(EI) == Entries.end()) { const MachineBasicBlock &EndMBB = Asm->MF->back(); EndLabel = Asm->MBBSectionRanges[EndMBB.getSectionIDNum()].EndLabel; if (EI->isClobber()) EndMI = EI->getInstr(); } else if (std::next(EI)->isClobber()) EndLabel = getLabelAfterInsn(std::next(EI)->getInstr()); else EndLabel = getLabelBeforeInsn(std::next(EI)->getInstr()); assert(EndLabel && "Forgot label after instruction ending a range!"); if (EI->isDbgValue()) LLVM_DEBUG(dbgs() << "DotDebugLoc: " << *Instr << "\n"); // If this history map entry has a debug value, add that to the list of // open ranges and check if its location is valid for a single value // location. if (EI->isDbgValue()) { // Do not add undef debug values, as they are redundant information in // the location list entries. An undef debug results in an empty location // description. If there are any non-undef fragments then padding pieces // with empty location descriptions will automatically be inserted, and if // all fragments are undef then the whole location list entry is // redundant. if (!Instr->isUndefDebugValue()) { auto Value = getDebugLocValue(Instr); OpenRanges.emplace_back(EI->getEndIndex(), Value); // TODO: Add support for single value fragment locations. if (Instr->getDebugExpression()->isFragment()) isSafeForSingleLocation = false; if (!StartDebugMI) StartDebugMI = Instr; } else { isSafeForSingleLocation = false; } } // Location list entries with empty location descriptions are redundant // information in DWARF, so do not emit those. if (OpenRanges.empty()) continue; // Omit entries with empty ranges as they do not have any effect in DWARF. if (StartLabel == EndLabel) { LLVM_DEBUG(dbgs() << "Omitting location list entry with empty range.\n"); continue; } SmallVector Values; for (auto &R : OpenRanges) Values.push_back(R.second); DebugLoc.emplace_back(StartLabel, EndLabel, Values); // Attempt to coalesce the ranges of two otherwise identical // DebugLocEntries. auto CurEntry = DebugLoc.rbegin(); LLVM_DEBUG({ dbgs() << CurEntry->getValues().size() << " Values:\n"; for (auto &Value : CurEntry->getValues()) Value.dump(); dbgs() << "-----\n"; }); auto PrevEntry = std::next(CurEntry); if (PrevEntry != DebugLoc.rend() && PrevEntry->MergeRanges(*CurEntry)) DebugLoc.pop_back(); } return DebugLoc.size() == 1 && isSafeForSingleLocation && validThroughout(LScopes, StartDebugMI, EndMI, getInstOrdering()); } DbgEntity *DwarfDebug::createConcreteEntity(DwarfCompileUnit &TheCU, LexicalScope &Scope, const DINode *Node, const DILocation *Location, const MCSymbol *Sym) { ensureAbstractEntityIsCreatedIfScoped(TheCU, Node, Scope.getScopeNode()); if (isa(Node)) { ConcreteEntities.push_back( std::make_unique(cast(Node), Location)); InfoHolder.addScopeVariable(&Scope, cast(ConcreteEntities.back().get())); } else if (isa(Node)) { ConcreteEntities.push_back( std::make_unique(cast(Node), Location, Sym)); InfoHolder.addScopeLabel(&Scope, cast(ConcreteEntities.back().get())); } return ConcreteEntities.back().get(); } // Find variables for each lexical scope. void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP, DenseSet &Processed) { // Grab the variable info that was squirreled away in the MMI side-table. collectVariableInfoFromMFTable(TheCU, Processed); for (const auto &I : DbgValues) { InlinedEntity IV = I.first; if (Processed.count(IV)) continue; // Instruction ranges, specifying where IV is accessible. const auto &HistoryMapEntries = I.second; if (HistoryMapEntries.empty()) continue; LexicalScope *Scope = nullptr; const DILocalVariable *LocalVar = cast(IV.first); if (const DILocation *IA = IV.second) Scope = LScopes.findInlinedScope(LocalVar->getScope(), IA); else Scope = LScopes.findLexicalScope(LocalVar->getScope()); // If variable scope is not found then skip this variable. if (!Scope) continue; Processed.insert(IV); DbgVariable *RegVar = cast(createConcreteEntity(TheCU, *Scope, LocalVar, IV.second)); const MachineInstr *MInsn = HistoryMapEntries.front().getInstr(); assert(MInsn->isDebugValue() && "History must begin with debug value"); // Check if there is a single DBG_VALUE, valid throughout the var's scope. // If the history map contains a single debug value, there may be an // additional entry which clobbers the debug value. size_t HistSize = HistoryMapEntries.size(); bool SingleValueWithClobber = HistSize == 2 && HistoryMapEntries[1].isClobber(); if (HistSize == 1 || SingleValueWithClobber) { const auto *End = SingleValueWithClobber ? HistoryMapEntries[1].getInstr() : nullptr; if (validThroughout(LScopes, MInsn, End, getInstOrdering())) { RegVar->initializeDbgValue(MInsn); continue; } } // Do not emit location lists if .debug_loc secton is disabled. if (!useLocSection()) continue; // Handle multiple DBG_VALUE instructions describing one variable. DebugLocStream::ListBuilder List(DebugLocs, TheCU, *Asm, *RegVar, *MInsn); // Build the location list for this variable. SmallVector Entries; bool isValidSingleLocation = buildLocationList(Entries, HistoryMapEntries); // Check whether buildLocationList managed to merge all locations to one // that is valid throughout the variable's scope. If so, produce single // value location. if (isValidSingleLocation) { RegVar->initializeDbgValue(Entries[0].getValues()[0]); continue; } // If the variable has a DIBasicType, extract it. Basic types cannot have // unique identifiers, so don't bother resolving the type with the // identifier map. const DIBasicType *BT = dyn_cast( static_cast(LocalVar->getType())); // Finalize the entry by lowering it into a DWARF bytestream. for (auto &Entry : Entries) Entry.finalize(*Asm, List, BT, TheCU); } // For each InlinedEntity collected from DBG_LABEL instructions, convert to // DWARF-related DbgLabel. for (const auto &I : DbgLabels) { InlinedEntity IL = I.first; const MachineInstr *MI = I.second; if (MI == nullptr) continue; LexicalScope *Scope = nullptr; const DILabel *Label = cast(IL.first); // The scope could have an extra lexical block file. const DILocalScope *LocalScope = Label->getScope()->getNonLexicalBlockFileScope(); // Get inlined DILocation if it is inlined label. if (const DILocation *IA = IL.second) Scope = LScopes.findInlinedScope(LocalScope, IA); else Scope = LScopes.findLexicalScope(LocalScope); // If label scope is not found then skip this label. if (!Scope) continue; Processed.insert(IL); /// At this point, the temporary label is created. /// Save the temporary label to DbgLabel entity to get the /// actually address when generating Dwarf DIE. MCSymbol *Sym = getLabelBeforeInsn(MI); createConcreteEntity(TheCU, *Scope, Label, IL.second, Sym); } // Collect info for variables/labels that were optimized out. for (const DINode *DN : SP->getRetainedNodes()) { if (!Processed.insert(InlinedEntity(DN, nullptr)).second) continue; LexicalScope *Scope = nullptr; if (auto *DV = dyn_cast(DN)) { Scope = LScopes.findLexicalScope(DV->getScope()); } else if (auto *DL = dyn_cast(DN)) { Scope = LScopes.findLexicalScope(DL->getScope()); } if (Scope) createConcreteEntity(TheCU, *Scope, DN, nullptr); } } // Process beginning of an instruction. void DwarfDebug::beginInstruction(const MachineInstr *MI) { const MachineFunction &MF = *MI->getMF(); const auto *SP = MF.getFunction().getSubprogram(); bool NoDebug = !SP || SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug; // Delay slot support check. auto delaySlotSupported = [](const MachineInstr &MI) { if (!MI.isBundledWithSucc()) return false; auto Suc = std::next(MI.getIterator()); (void)Suc; // Ensure that delay slot instruction is successor of the call instruction. // Ex. CALL_INSTRUCTION { // DELAY_SLOT_INSTRUCTION } assert(Suc->isBundledWithPred() && "Call bundle instructions are out of order"); return true; }; // When describing calls, we need a label for the call instruction. if (!NoDebug && SP->areAllCallsDescribed() && MI->isCandidateForCallSiteEntry(MachineInstr::AnyInBundle) && (!MI->hasDelaySlot() || delaySlotSupported(*MI))) { const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); bool IsTail = TII->isTailCall(*MI); // For tail calls, we need the address of the branch instruction for // DW_AT_call_pc. if (IsTail) requestLabelBeforeInsn(MI); // For non-tail calls, we need the return address for the call for // DW_AT_call_return_pc. Under GDB tuning, this information is needed for // tail calls as well. requestLabelAfterInsn(MI); } DebugHandlerBase::beginInstruction(MI); if (!CurMI) return; if (NoDebug) return; // Check if source location changes, but ignore DBG_VALUE and CFI locations. // If the instruction is part of the function frame setup code, do not emit // any line record, as there is no correspondence with any user code. if (MI->isMetaInstruction() || MI->getFlag(MachineInstr::FrameSetup)) return; const DebugLoc &DL = MI->getDebugLoc(); // When we emit a line-0 record, we don't update PrevInstLoc; so look at // the last line number actually emitted, to see if it was line 0. unsigned LastAsmLine = Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine(); if (DL == PrevInstLoc) { // If we have an ongoing unspecified location, nothing to do here. if (!DL) return; // We have an explicit location, same as the previous location. // But we might be coming back to it after a line 0 record. if (LastAsmLine == 0 && DL.getLine() != 0) { // Reinstate the source location but not marked as a statement. const MDNode *Scope = DL.getScope(); recordSourceLine(DL.getLine(), DL.getCol(), Scope, /*Flags=*/0); } return; } if (!DL) { // We have an unspecified location, which might want to be line 0. // If we have already emitted a line-0 record, don't repeat it. if (LastAsmLine == 0) return; // If user said Don't Do That, don't do that. if (UnknownLocations == Disable) return; // See if we have a reason to emit a line-0 record now. // Reasons to emit a line-0 record include: // - User asked for it (UnknownLocations). // - Instruction has a label, so it's referenced from somewhere else, // possibly debug information; we want it to have a source location. // - Instruction is at the top of a block; we don't want to inherit the // location from the physically previous (maybe unrelated) block. if (UnknownLocations == Enable || PrevLabel || (PrevInstBB && PrevInstBB != MI->getParent())) { // Preserve the file and column numbers, if we can, to save space in // the encoded line table. // Do not update PrevInstLoc, it remembers the last non-0 line. const MDNode *Scope = nullptr; unsigned Column = 0; if (PrevInstLoc) { Scope = PrevInstLoc.getScope(); Column = PrevInstLoc.getCol(); } recordSourceLine(/*Line=*/0, Column, Scope, /*Flags=*/0); } return; } // We have an explicit location, different from the previous location. // Don't repeat a line-0 record, but otherwise emit the new location. // (The new location might be an explicit line 0, which we do emit.) if (DL.getLine() == 0 && LastAsmLine == 0) return; unsigned Flags = 0; if (DL == PrologEndLoc) { Flags |= DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_IS_STMT; PrologEndLoc = DebugLoc(); } // If the line changed, we call that a new statement; unless we went to // line 0 and came back, in which case it is not a new statement. unsigned OldLine = PrevInstLoc ? PrevInstLoc.getLine() : LastAsmLine; if (DL.getLine() && DL.getLine() != OldLine) Flags |= DWARF2_FLAG_IS_STMT; const MDNode *Scope = DL.getScope(); recordSourceLine(DL.getLine(), DL.getCol(), Scope, Flags); // If we're not at line 0, remember this location. if (DL.getLine()) PrevInstLoc = DL; } static DebugLoc findPrologueEndLoc(const MachineFunction *MF) { // First known non-DBG_VALUE and non-frame setup location marks // the beginning of the function body. for (const auto &MBB : *MF) for (const auto &MI : MBB) if (!MI.isMetaInstruction() && !MI.getFlag(MachineInstr::FrameSetup) && MI.getDebugLoc()) return MI.getDebugLoc(); return DebugLoc(); } /// Register a source line with debug info. Returns the unique label that was /// emitted and which provides correspondence to the source line list. static void recordSourceLine(AsmPrinter &Asm, unsigned Line, unsigned Col, const MDNode *S, unsigned Flags, unsigned CUID, uint16_t DwarfVersion, ArrayRef> DCUs) { StringRef Fn; unsigned FileNo = 1; unsigned Discriminator = 0; if (auto *Scope = cast_or_null(S)) { Fn = Scope->getFilename(); if (Line != 0 && DwarfVersion >= 4) if (auto *LBF = dyn_cast(Scope)) Discriminator = LBF->getDiscriminator(); FileNo = static_cast(*DCUs[CUID]) .getOrCreateSourceID(Scope->getFile()); } Asm.OutStreamer->emitDwarfLocDirective(FileNo, Line, Col, Flags, 0, Discriminator, Fn); } DebugLoc DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) { // Get beginning of function. if (DebugLoc PrologEndLoc = findPrologueEndLoc(&MF)) { // Ensure the compile unit is created if the function is called before // beginFunction(). (void)getOrCreateDwarfCompileUnit( MF.getFunction().getSubprogram()->getUnit()); // We'd like to list the prologue as "not statements" but GDB behaves // poorly if we do that. Revisit this with caution/GDB (7.5+) testing. const DISubprogram *SP = PrologEndLoc->getInlinedAtScope()->getSubprogram(); ::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT, CUID, getDwarfVersion(), getUnits()); return PrologEndLoc; } return DebugLoc(); } // Gather pre-function debug information. Assumes being called immediately // after the function entry point has been emitted. void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) { CurFn = MF; auto *SP = MF->getFunction().getSubprogram(); assert(LScopes.empty() || SP == LScopes.getCurrentFunctionScope()->getScopeNode()); if (SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug) return; DwarfCompileUnit &CU = getOrCreateDwarfCompileUnit(SP->getUnit()); // Set DwarfDwarfCompileUnitID in MCContext to the Compile Unit this function // belongs to so that we add to the correct per-cu line table in the // non-asm case. if (Asm->OutStreamer->hasRawTextSupport()) // Use a single line table if we are generating assembly. Asm->OutStreamer->getContext().setDwarfCompileUnitID(0); else Asm->OutStreamer->getContext().setDwarfCompileUnitID(CU.getUniqueID()); // Record beginning of function. PrologEndLoc = emitInitialLocDirective( *MF, Asm->OutStreamer->getContext().getDwarfCompileUnitID()); } void DwarfDebug::skippedNonDebugFunction() { // If we don't have a subprogram for this function then there will be a hole // in the range information. Keep note of this by setting the previously used // section to nullptr. PrevCU = nullptr; CurFn = nullptr; } // Gather and emit post-function debug information. void DwarfDebug::endFunctionImpl(const MachineFunction *MF) { const DISubprogram *SP = MF->getFunction().getSubprogram(); assert(CurFn == MF && "endFunction should be called with the same function as beginFunction"); // Set DwarfDwarfCompileUnitID in MCContext to default value. Asm->OutStreamer->getContext().setDwarfCompileUnitID(0); LexicalScope *FnScope = LScopes.getCurrentFunctionScope(); assert(!FnScope || SP == FnScope->getScopeNode()); DwarfCompileUnit &TheCU = *CUMap.lookup(SP->getUnit()); if (TheCU.getCUNode()->isDebugDirectivesOnly()) { PrevLabel = nullptr; CurFn = nullptr; return; } DenseSet Processed; collectEntityInfo(TheCU, SP, Processed); // Add the range of this function to the list of ranges for the CU. // With basic block sections, add ranges for all basic block sections. for (const auto &R : Asm->MBBSectionRanges) TheCU.addRange({R.second.BeginLabel, R.second.EndLabel}); // Under -gmlt, skip building the subprogram if there are no inlined // subroutines inside it. But with -fdebug-info-for-profiling, the subprogram // is still needed as we need its source location. if (!TheCU.getCUNode()->getDebugInfoForProfiling() && TheCU.getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly && LScopes.getAbstractScopesList().empty() && !IsDarwin) { assert(InfoHolder.getScopeVariables().empty()); PrevLabel = nullptr; CurFn = nullptr; return; } #ifndef NDEBUG size_t NumAbstractScopes = LScopes.getAbstractScopesList().size(); #endif // Construct abstract scopes. for (LexicalScope *AScope : LScopes.getAbstractScopesList()) { auto *SP = cast(AScope->getScopeNode()); for (const DINode *DN : SP->getRetainedNodes()) { if (!Processed.insert(InlinedEntity(DN, nullptr)).second) continue; const MDNode *Scope = nullptr; if (auto *DV = dyn_cast(DN)) Scope = DV->getScope(); else if (auto *DL = dyn_cast(DN)) Scope = DL->getScope(); else llvm_unreachable("Unexpected DI type!"); // Collect info for variables/labels that were optimized out. ensureAbstractEntityIsCreated(TheCU, DN, Scope); assert(LScopes.getAbstractScopesList().size() == NumAbstractScopes && "ensureAbstractEntityIsCreated inserted abstract scopes"); } constructAbstractSubprogramScopeDIE(TheCU, AScope); } ProcessedSPNodes.insert(SP); DIE &ScopeDIE = TheCU.constructSubprogramScopeDIE(SP, FnScope); if (auto *SkelCU = TheCU.getSkeleton()) if (!LScopes.getAbstractScopesList().empty() && TheCU.getCUNode()->getSplitDebugInlining()) SkelCU->constructSubprogramScopeDIE(SP, FnScope); // Construct call site entries. constructCallSiteEntryDIEs(*SP, TheCU, ScopeDIE, *MF); // Clear debug info // Ownership of DbgVariables is a bit subtle - ScopeVariables owns all the // DbgVariables except those that are also in AbstractVariables (since they // can be used cross-function) InfoHolder.getScopeVariables().clear(); InfoHolder.getScopeLabels().clear(); PrevLabel = nullptr; CurFn = nullptr; } // Register a source line with debug info. Returns the unique label that was // emitted and which provides correspondence to the source line list. void DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, const MDNode *S, unsigned Flags) { ::recordSourceLine(*Asm, Line, Col, S, Flags, Asm->OutStreamer->getContext().getDwarfCompileUnitID(), getDwarfVersion(), getUnits()); } //===----------------------------------------------------------------------===// // Emit Methods //===----------------------------------------------------------------------===// // Emit the debug info section. void DwarfDebug::emitDebugInfo() { DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; Holder.emitUnits(/* UseOffsets */ false); } // Emit the abbreviation section. void DwarfDebug::emitAbbreviations() { DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; Holder.emitAbbrevs(Asm->getObjFileLowering().getDwarfAbbrevSection()); } void DwarfDebug::emitStringOffsetsTableHeader() { DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; Holder.getStringPool().emitStringOffsetsTableHeader( *Asm, Asm->getObjFileLowering().getDwarfStrOffSection(), Holder.getStringOffsetsStartSym()); } template void DwarfDebug::emitAccel(AccelTableT &Accel, MCSection *Section, StringRef TableName) { Asm->OutStreamer->SwitchSection(Section); // Emit the full data. emitAppleAccelTable(Asm, Accel, TableName, Section->getBeginSymbol()); } void DwarfDebug::emitAccelDebugNames() { // Don't emit anything if we have no compilation units to index. if (getUnits().empty()) return; emitDWARF5AccelTable(Asm, AccelDebugNames, *this, getUnits()); } // Emit visible names into a hashed accelerator table section. void DwarfDebug::emitAccelNames() { emitAccel(AccelNames, Asm->getObjFileLowering().getDwarfAccelNamesSection(), "Names"); } // Emit objective C classes and categories into a hashed accelerator table // section. void DwarfDebug::emitAccelObjC() { emitAccel(AccelObjC, Asm->getObjFileLowering().getDwarfAccelObjCSection(), "ObjC"); } // Emit namespace dies into a hashed accelerator table. void DwarfDebug::emitAccelNamespaces() { emitAccel(AccelNamespace, Asm->getObjFileLowering().getDwarfAccelNamespaceSection(), "namespac"); } // Emit type dies into a hashed accelerator table. void DwarfDebug::emitAccelTypes() { emitAccel(AccelTypes, Asm->getObjFileLowering().getDwarfAccelTypesSection(), "types"); } // Public name handling. // The format for the various pubnames: // // dwarf pubnames - offset/name pairs where the offset is the offset into the CU // for the DIE that is named. // // gnu pubnames - offset/index value/name tuples where the offset is the offset // into the CU and the index value is computed according to the type of value // for the DIE that is named. // // For type units the offset is the offset of the skeleton DIE. For split dwarf // it's the offset within the debug_info/debug_types dwo section, however, the // reference in the pubname header doesn't change. /// computeIndexValue - Compute the gdb index value for the DIE and CU. static dwarf::PubIndexEntryDescriptor computeIndexValue(DwarfUnit *CU, const DIE *Die) { // Entities that ended up only in a Type Unit reference the CU instead (since // the pub entry has offsets within the CU there's no real offset that can be // provided anyway). As it happens all such entities (namespaces and types, // types only in C++ at that) are rendered as TYPE+EXTERNAL. If this turns out // not to be true it would be necessary to persist this information from the // point at which the entry is added to the index data structure - since by // the time the index is built from that, the original type/namespace DIE in a // type unit has already been destroyed so it can't be queried for properties // like tag, etc. if (Die->getTag() == dwarf::DW_TAG_compile_unit) return dwarf::PubIndexEntryDescriptor(dwarf::GIEK_TYPE, dwarf::GIEL_EXTERNAL); dwarf::GDBIndexEntryLinkage Linkage = dwarf::GIEL_STATIC; // We could have a specification DIE that has our most of our knowledge, // look for that now. if (DIEValue SpecVal = Die->findAttribute(dwarf::DW_AT_specification)) { DIE &SpecDIE = SpecVal.getDIEEntry().getEntry(); if (SpecDIE.findAttribute(dwarf::DW_AT_external)) Linkage = dwarf::GIEL_EXTERNAL; } else if (Die->findAttribute(dwarf::DW_AT_external)) Linkage = dwarf::GIEL_EXTERNAL; switch (Die->getTag()) { case dwarf::DW_TAG_class_type: case dwarf::DW_TAG_structure_type: case dwarf::DW_TAG_union_type: case dwarf::DW_TAG_enumeration_type: return dwarf::PubIndexEntryDescriptor( dwarf::GIEK_TYPE, dwarf::isCPlusPlus((dwarf::SourceLanguage)CU->getLanguage()) ? dwarf::GIEL_EXTERNAL : dwarf::GIEL_STATIC); case dwarf::DW_TAG_typedef: case dwarf::DW_TAG_base_type: case dwarf::DW_TAG_subrange_type: return dwarf::PubIndexEntryDescriptor(dwarf::GIEK_TYPE, dwarf::GIEL_STATIC); case dwarf::DW_TAG_namespace: return dwarf::GIEK_TYPE; case dwarf::DW_TAG_subprogram: return dwarf::PubIndexEntryDescriptor(dwarf::GIEK_FUNCTION, Linkage); case dwarf::DW_TAG_variable: return dwarf::PubIndexEntryDescriptor(dwarf::GIEK_VARIABLE, Linkage); case dwarf::DW_TAG_enumerator: return dwarf::PubIndexEntryDescriptor(dwarf::GIEK_VARIABLE, dwarf::GIEL_STATIC); default: return dwarf::GIEK_NONE; } } /// emitDebugPubSections - Emit visible names and types into debug pubnames and /// pubtypes sections. void DwarfDebug::emitDebugPubSections() { for (const auto &NU : CUMap) { DwarfCompileUnit *TheU = NU.second; if (!TheU->hasDwarfPubSections()) continue; bool GnuStyle = TheU->getCUNode()->getNameTableKind() == DICompileUnit::DebugNameTableKind::GNU; Asm->OutStreamer->SwitchSection( GnuStyle ? Asm->getObjFileLowering().getDwarfGnuPubNamesSection() : Asm->getObjFileLowering().getDwarfPubNamesSection()); emitDebugPubSection(GnuStyle, "Names", TheU, TheU->getGlobalNames()); Asm->OutStreamer->SwitchSection( GnuStyle ? Asm->getObjFileLowering().getDwarfGnuPubTypesSection() : Asm->getObjFileLowering().getDwarfPubTypesSection()); emitDebugPubSection(GnuStyle, "Types", TheU, TheU->getGlobalTypes()); } } void DwarfDebug::emitSectionReference(const DwarfCompileUnit &CU) { if (useSectionsAsReferences()) Asm->emitDwarfOffset(CU.getSection()->getBeginSymbol(), CU.getDebugSectionOffset()); else Asm->emitDwarfSymbolReference(CU.getLabelBegin()); } void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, DwarfCompileUnit *TheU, const StringMap &Globals) { if (auto *Skeleton = TheU->getSkeleton()) TheU = Skeleton; // Emit the header. MCSymbol *BeginLabel = Asm->createTempSymbol("pub" + Name + "_begin"); MCSymbol *EndLabel = Asm->createTempSymbol("pub" + Name + "_end"); Asm->emitDwarfUnitLength(EndLabel, BeginLabel, "Length of Public " + Name + " Info"); Asm->OutStreamer->emitLabel(BeginLabel); Asm->OutStreamer->AddComment("DWARF Version"); Asm->emitInt16(dwarf::DW_PUBNAMES_VERSION); Asm->OutStreamer->AddComment("Offset of Compilation Unit Info"); emitSectionReference(*TheU); Asm->OutStreamer->AddComment("Compilation Unit Length"); Asm->emitDwarfLengthOrOffset(TheU->getLength()); // Emit the pubnames for this compilation unit. for (const auto &GI : Globals) { const char *Name = GI.getKeyData(); const DIE *Entity = GI.second; Asm->OutStreamer->AddComment("DIE offset"); Asm->emitDwarfLengthOrOffset(Entity->getOffset()); if (GnuStyle) { dwarf::PubIndexEntryDescriptor Desc = computeIndexValue(TheU, Entity); Asm->OutStreamer->AddComment( Twine("Attributes: ") + dwarf::GDBIndexEntryKindString(Desc.Kind) + ", " + dwarf::GDBIndexEntryLinkageString(Desc.Linkage)); Asm->emitInt8(Desc.toBits()); } Asm->OutStreamer->AddComment("External Name"); Asm->OutStreamer->emitBytes(StringRef(Name, GI.getKeyLength() + 1)); } Asm->OutStreamer->AddComment("End Mark"); Asm->emitDwarfLengthOrOffset(0); Asm->OutStreamer->emitLabel(EndLabel); } /// Emit null-terminated strings into a debug str section. void DwarfDebug::emitDebugStr() { MCSection *StringOffsetsSection = nullptr; if (useSegmentedStringOffsetsTable()) { emitStringOffsetsTableHeader(); StringOffsetsSection = Asm->getObjFileLowering().getDwarfStrOffSection(); } DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; Holder.emitStrings(Asm->getObjFileLowering().getDwarfStrSection(), StringOffsetsSection, /* UseRelativeOffsets = */ true); } void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, const DebugLocStream::Entry &Entry, const DwarfCompileUnit *CU) { auto &&Comments = DebugLocs.getComments(Entry); auto Comment = Comments.begin(); auto End = Comments.end(); // The expressions are inserted into a byte stream rather early (see // DwarfExpression::addExpression) so for those ops (e.g. DW_OP_convert) that // need to reference a base_type DIE the offset of that DIE is not yet known. // To deal with this we instead insert a placeholder early and then extract // it here and replace it with the real reference. unsigned PtrSize = Asm->MAI->getCodePointerSize(); DWARFDataExtractor Data(StringRef(DebugLocs.getBytes(Entry).data(), DebugLocs.getBytes(Entry).size()), Asm->getDataLayout().isLittleEndian(), PtrSize); DWARFExpression Expr(Data, PtrSize, Asm->OutContext.getDwarfFormat()); using Encoding = DWARFExpression::Operation::Encoding; uint64_t Offset = 0; for (auto &Op : Expr) { assert(Op.getCode() != dwarf::DW_OP_const_type && "3 operand ops not yet supported"); Streamer.emitInt8(Op.getCode(), Comment != End ? *(Comment++) : ""); Offset++; for (unsigned I = 0; I < 2; ++I) { if (Op.getDescription().Op[I] == Encoding::SizeNA) continue; if (Op.getDescription().Op[I] == Encoding::BaseTypeRef) { uint64_t Offset = CU->ExprRefedBaseTypes[Op.getRawOperand(I)].Die->getOffset(); assert(Offset < (1ULL << (ULEB128PadSize * 7)) && "Offset wont fit"); Streamer.emitULEB128(Offset, "", ULEB128PadSize); // Make sure comments stay aligned. for (unsigned J = 0; J < ULEB128PadSize; ++J) if (Comment != End) Comment++; } else { for (uint64_t J = Offset; J < Op.getOperandEndOffset(I); ++J) Streamer.emitInt8(Data.getData()[J], Comment != End ? *(Comment++) : ""); } Offset = Op.getOperandEndOffset(I); } assert(Offset == Op.getEndOffset()); } } void DwarfDebug::emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, const DbgValueLoc &Value, DwarfExpression &DwarfExpr) { auto *DIExpr = Value.getExpression(); DIExpressionCursor ExprCursor(DIExpr); DwarfExpr.addFragmentOffset(DIExpr); // Regular entry. if (Value.isInt()) { if (BT && (BT->getEncoding() == dwarf::DW_ATE_signed || BT->getEncoding() == dwarf::DW_ATE_signed_char)) DwarfExpr.addSignedConstant(Value.getInt()); else DwarfExpr.addUnsignedConstant(Value.getInt()); } else if (Value.isLocation()) { MachineLocation Location = Value.getLoc(); DwarfExpr.setLocation(Location, DIExpr); DIExpressionCursor Cursor(DIExpr); if (DIExpr->isEntryValue()) DwarfExpr.beginEntryValueExpression(Cursor); const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo(); if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg())) return; return DwarfExpr.addExpression(std::move(Cursor)); } else if (Value.isTargetIndexLocation()) { TargetIndexLocation Loc = Value.getTargetIndexLocation(); // TODO TargetIndexLocation is a target-independent. Currently only the WebAssembly-specific // encoding is supported. assert(AP.TM.getTargetTriple().isWasm()); DwarfExpr.addWasmLocation(Loc.Index, static_cast(Loc.Offset)); DwarfExpr.addExpression(std::move(ExprCursor)); return; } else if (Value.isConstantFP()) { if (AP.getDwarfVersion() >= 4 && !AP.getDwarfDebug()->tuneForSCE() && !ExprCursor) { DwarfExpr.addConstantFP(Value.getConstantFP()->getValueAPF(), AP); return; } if (Value.getConstantFP()->getValueAPF().bitcastToAPInt().getBitWidth() <= 64 /*bits*/) DwarfExpr.addUnsignedConstant( Value.getConstantFP()->getValueAPF().bitcastToAPInt()); else LLVM_DEBUG( dbgs() << "Skipped DwarfExpression creation for ConstantFP of size" << Value.getConstantFP()->getValueAPF().bitcastToAPInt().getBitWidth() << " bits\n"); } DwarfExpr.addExpression(std::move(ExprCursor)); } void DebugLocEntry::finalize(const AsmPrinter &AP, DebugLocStream::ListBuilder &List, const DIBasicType *BT, DwarfCompileUnit &TheCU) { assert(!Values.empty() && "location list entries without values are redundant"); assert(Begin != End && "unexpected location list entry with empty range"); DebugLocStream::EntryBuilder Entry(List, Begin, End); BufferByteStreamer Streamer = Entry.getStreamer(); DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer, TheCU); const DbgValueLoc &Value = Values[0]; if (Value.isFragment()) { // Emit all fragments that belong to the same variable and range. assert(llvm::all_of(Values, [](DbgValueLoc P) { return P.isFragment(); }) && "all values are expected to be fragments"); assert(llvm::is_sorted(Values) && "fragments are expected to be sorted"); for (const auto &Fragment : Values) DwarfDebug::emitDebugLocValue(AP, BT, Fragment, DwarfExpr); } else { assert(Values.size() == 1 && "only fragments may have >1 value"); DwarfDebug::emitDebugLocValue(AP, BT, Value, DwarfExpr); } DwarfExpr.finalize(); if (DwarfExpr.TagOffset) List.setTagOffset(*DwarfExpr.TagOffset); } void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry, const DwarfCompileUnit *CU) { // Emit the size. Asm->OutStreamer->AddComment("Loc expr size"); if (getDwarfVersion() >= 5) Asm->emitULEB128(DebugLocs.getBytes(Entry).size()); else if (DebugLocs.getBytes(Entry).size() <= std::numeric_limits::max()) Asm->emitInt16(DebugLocs.getBytes(Entry).size()); else { // The entry is too big to fit into 16 bit, drop it as there is nothing we // can do. Asm->emitInt16(0); return; } // Emit the entry. APByteStreamer Streamer(*Asm); emitDebugLocEntry(Streamer, Entry, CU); } // Emit the header of a DWARF 5 range list table list table. Returns the symbol // that designates the end of the table for the caller to emit when the table is // complete. static MCSymbol *emitRnglistsTableHeader(AsmPrinter *Asm, const DwarfFile &Holder) { MCSymbol *TableEnd = mcdwarf::emitListsTableHeaderStart(*Asm->OutStreamer); Asm->OutStreamer->AddComment("Offset entry count"); Asm->emitInt32(Holder.getRangeLists().size()); Asm->OutStreamer->emitLabel(Holder.getRnglistsTableBaseSym()); for (const RangeSpanList &List : Holder.getRangeLists()) Asm->emitLabelDifference(List.Label, Holder.getRnglistsTableBaseSym(), Asm->getDwarfOffsetByteSize()); return TableEnd; } // Emit the header of a DWARF 5 locations list table. Returns the symbol that // designates the end of the table for the caller to emit when the table is // complete. static MCSymbol *emitLoclistsTableHeader(AsmPrinter *Asm, const DwarfDebug &DD) { MCSymbol *TableEnd = mcdwarf::emitListsTableHeaderStart(*Asm->OutStreamer); const auto &DebugLocs = DD.getDebugLocs(); Asm->OutStreamer->AddComment("Offset entry count"); Asm->emitInt32(DebugLocs.getLists().size()); Asm->OutStreamer->emitLabel(DebugLocs.getSym()); for (const auto &List : DebugLocs.getLists()) Asm->emitLabelDifference(List.Label, DebugLocs.getSym(), Asm->getDwarfOffsetByteSize()); return TableEnd; } template static void emitRangeList( DwarfDebug &DD, AsmPrinter *Asm, MCSymbol *Sym, const Ranges &R, const DwarfCompileUnit &CU, unsigned BaseAddressx, unsigned OffsetPair, unsigned StartxLength, unsigned EndOfList, StringRef (*StringifyEnum)(unsigned), bool ShouldUseBaseAddress, PayloadEmitter EmitPayload) { auto Size = Asm->MAI->getCodePointerSize(); bool UseDwarf5 = DD.getDwarfVersion() >= 5; // Emit our symbol so we can find the beginning of the range. Asm->OutStreamer->emitLabel(Sym); // Gather all the ranges that apply to the same section so they can share // a base address entry. MapVector> SectionRanges; for (const auto &Range : R) SectionRanges[&Range.Begin->getSection()].push_back(&Range); const MCSymbol *CUBase = CU.getBaseAddress(); bool BaseIsSet = false; for (const auto &P : SectionRanges) { auto *Base = CUBase; if (!Base && ShouldUseBaseAddress) { const MCSymbol *Begin = P.second.front()->Begin; const MCSymbol *NewBase = DD.getSectionLabel(&Begin->getSection()); if (!UseDwarf5) { Base = NewBase; BaseIsSet = true; Asm->OutStreamer->emitIntValue(-1, Size); Asm->OutStreamer->AddComment(" base address"); Asm->OutStreamer->emitSymbolValue(Base, Size); } else if (NewBase != Begin || P.second.size() > 1) { // Only use a base address if // * the existing pool address doesn't match (NewBase != Begin) // * or, there's more than one entry to share the base address Base = NewBase; BaseIsSet = true; Asm->OutStreamer->AddComment(StringifyEnum(BaseAddressx)); Asm->emitInt8(BaseAddressx); Asm->OutStreamer->AddComment(" base address index"); Asm->emitULEB128(DD.getAddressPool().getIndex(Base)); } } else if (BaseIsSet && !UseDwarf5) { BaseIsSet = false; assert(!Base); Asm->OutStreamer->emitIntValue(-1, Size); Asm->OutStreamer->emitIntValue(0, Size); } for (const auto *RS : P.second) { const MCSymbol *Begin = RS->Begin; const MCSymbol *End = RS->End; assert(Begin && "Range without a begin symbol?"); assert(End && "Range without an end symbol?"); if (Base) { if (UseDwarf5) { // Emit offset_pair when we have a base. Asm->OutStreamer->AddComment(StringifyEnum(OffsetPair)); Asm->emitInt8(OffsetPair); Asm->OutStreamer->AddComment(" starting offset"); Asm->emitLabelDifferenceAsULEB128(Begin, Base); Asm->OutStreamer->AddComment(" ending offset"); Asm->emitLabelDifferenceAsULEB128(End, Base); } else { Asm->emitLabelDifference(Begin, Base, Size); Asm->emitLabelDifference(End, Base, Size); } } else if (UseDwarf5) { Asm->OutStreamer->AddComment(StringifyEnum(StartxLength)); Asm->emitInt8(StartxLength); Asm->OutStreamer->AddComment(" start index"); Asm->emitULEB128(DD.getAddressPool().getIndex(Begin)); Asm->OutStreamer->AddComment(" length"); Asm->emitLabelDifferenceAsULEB128(End, Begin); } else { Asm->OutStreamer->emitSymbolValue(Begin, Size); Asm->OutStreamer->emitSymbolValue(End, Size); } EmitPayload(*RS); } } if (UseDwarf5) { Asm->OutStreamer->AddComment(StringifyEnum(EndOfList)); Asm->emitInt8(EndOfList); } else { // Terminate the list with two 0 values. Asm->OutStreamer->emitIntValue(0, Size); Asm->OutStreamer->emitIntValue(0, Size); } } // Handles emission of both debug_loclist / debug_loclist.dwo static void emitLocList(DwarfDebug &DD, AsmPrinter *Asm, const DebugLocStream::List &List) { emitRangeList(DD, Asm, List.Label, DD.getDebugLocs().getEntries(List), *List.CU, dwarf::DW_LLE_base_addressx, dwarf::DW_LLE_offset_pair, dwarf::DW_LLE_startx_length, dwarf::DW_LLE_end_of_list, llvm::dwarf::LocListEncodingString, /* ShouldUseBaseAddress */ true, [&](const DebugLocStream::Entry &E) { DD.emitDebugLocEntryLocation(E, List.CU); }); } void DwarfDebug::emitDebugLocImpl(MCSection *Sec) { if (DebugLocs.getLists().empty()) return; Asm->OutStreamer->SwitchSection(Sec); MCSymbol *TableEnd = nullptr; if (getDwarfVersion() >= 5) TableEnd = emitLoclistsTableHeader(Asm, *this); for (const auto &List : DebugLocs.getLists()) emitLocList(*this, Asm, List); if (TableEnd) Asm->OutStreamer->emitLabel(TableEnd); } // Emit locations into the .debug_loc/.debug_loclists section. void DwarfDebug::emitDebugLoc() { emitDebugLocImpl( getDwarfVersion() >= 5 ? Asm->getObjFileLowering().getDwarfLoclistsSection() : Asm->getObjFileLowering().getDwarfLocSection()); } // Emit locations into the .debug_loc.dwo/.debug_loclists.dwo section. void DwarfDebug::emitDebugLocDWO() { if (getDwarfVersion() >= 5) { emitDebugLocImpl( Asm->getObjFileLowering().getDwarfLoclistsDWOSection()); return; } for (const auto &List : DebugLocs.getLists()) { Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfLocDWOSection()); Asm->OutStreamer->emitLabel(List.Label); for (const auto &Entry : DebugLocs.getEntries(List)) { // GDB only supports startx_length in pre-standard split-DWARF. // (in v5 standard loclists, it currently* /only/ supports base_address + // offset_pair, so the implementations can't really share much since they // need to use different representations) // * as of October 2018, at least // // In v5 (see emitLocList), this uses SectionLabels to reuse existing // addresses in the address pool to minimize object size/relocations. Asm->emitInt8(dwarf::DW_LLE_startx_length); unsigned idx = AddrPool.getIndex(Entry.Begin); Asm->emitULEB128(idx); // Also the pre-standard encoding is slightly different, emitting this as // an address-length entry here, but its a ULEB128 in DWARFv5 loclists. Asm->emitLabelDifference(Entry.End, Entry.Begin, 4); emitDebugLocEntryLocation(Entry, List.CU); } Asm->emitInt8(dwarf::DW_LLE_end_of_list); } } struct ArangeSpan { const MCSymbol *Start, *End; }; // Emit a debug aranges section, containing a CU lookup for any // address we can tie back to a CU. void DwarfDebug::emitDebugARanges() { // Provides a unique id per text section. MapVector> SectionMap; // Filter labels by section. for (const SymbolCU &SCU : ArangeLabels) { if (SCU.Sym->isInSection()) { // Make a note of this symbol and it's section. MCSection *Section = &SCU.Sym->getSection(); if (!Section->getKind().isMetadata()) SectionMap[Section].push_back(SCU); } else { // Some symbols (e.g. common/bss on mach-o) can have no section but still // appear in the output. This sucks as we rely on sections to build // arange spans. We can do it without, but it's icky. SectionMap[nullptr].push_back(SCU); } } DenseMap> Spans; for (auto &I : SectionMap) { MCSection *Section = I.first; SmallVector &List = I.second; if (List.size() < 1) continue; // If we have no section (e.g. common), just write out // individual spans for each symbol. if (!Section) { for (const SymbolCU &Cur : List) { ArangeSpan Span; Span.Start = Cur.Sym; Span.End = nullptr; assert(Cur.CU); Spans[Cur.CU].push_back(Span); } continue; } // Sort the symbols by offset within the section. llvm::stable_sort(List, [&](const SymbolCU &A, const SymbolCU &B) { unsigned IA = A.Sym ? Asm->OutStreamer->GetSymbolOrder(A.Sym) : 0; unsigned IB = B.Sym ? Asm->OutStreamer->GetSymbolOrder(B.Sym) : 0; // Symbols with no order assigned should be placed at the end. // (e.g. section end labels) if (IA == 0) return false; if (IB == 0) return true; return IA < IB; }); // Insert a final terminator. List.push_back(SymbolCU(nullptr, Asm->OutStreamer->endSection(Section))); // Build spans between each label. const MCSymbol *StartSym = List[0].Sym; for (size_t n = 1, e = List.size(); n < e; n++) { const SymbolCU &Prev = List[n - 1]; const SymbolCU &Cur = List[n]; // Try and build the longest span we can within the same CU. if (Cur.CU != Prev.CU) { ArangeSpan Span; Span.Start = StartSym; Span.End = Cur.Sym; assert(Prev.CU); Spans[Prev.CU].push_back(Span); StartSym = Cur.Sym; } } } // Start the dwarf aranges section. Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfARangesSection()); unsigned PtrSize = Asm->MAI->getCodePointerSize(); // Build a list of CUs used. std::vector CUs; for (const auto &it : Spans) { DwarfCompileUnit *CU = it.first; CUs.push_back(CU); } // Sort the CU list (again, to ensure consistent output order). llvm::sort(CUs, [](const DwarfCompileUnit *A, const DwarfCompileUnit *B) { return A->getUniqueID() < B->getUniqueID(); }); // Emit an arange table for each CU we used. for (DwarfCompileUnit *CU : CUs) { std::vector &List = Spans[CU]; // Describe the skeleton CU's offset and length, not the dwo file's. if (auto *Skel = CU->getSkeleton()) CU = Skel; // Emit size of content not including length itself. unsigned ContentSize = sizeof(int16_t) + // DWARF ARange version number Asm->getDwarfOffsetByteSize() + // Offset of CU in the .debug_info // section sizeof(int8_t) + // Pointer Size (in bytes) sizeof(int8_t); // Segment Size (in bytes) unsigned TupleSize = PtrSize * 2; // 7.20 in the Dwarf specs requires the table to be aligned to a tuple. unsigned Padding = offsetToAlignment( Asm->getUnitLengthFieldByteSize() + ContentSize, Align(TupleSize)); ContentSize += Padding; ContentSize += (List.size() + 1) * TupleSize; // For each compile unit, write the list of spans it covers. Asm->emitDwarfUnitLength(ContentSize, "Length of ARange Set"); Asm->OutStreamer->AddComment("DWARF Arange version number"); Asm->emitInt16(dwarf::DW_ARANGES_VERSION); Asm->OutStreamer->AddComment("Offset Into Debug Info Section"); emitSectionReference(*CU); Asm->OutStreamer->AddComment("Address Size (in bytes)"); Asm->emitInt8(PtrSize); Asm->OutStreamer->AddComment("Segment Size (in bytes)"); Asm->emitInt8(0); Asm->OutStreamer->emitFill(Padding, 0xff); for (const ArangeSpan &Span : List) { Asm->emitLabelReference(Span.Start, PtrSize); // Calculate the size as being from the span start to it's end. if (Span.End) { Asm->emitLabelDifference(Span.End, Span.Start, PtrSize); } else { // For symbols without an end marker (e.g. common), we // write a single arange entry containing just that one symbol. uint64_t Size = SymSize[Span.Start]; if (Size == 0) Size = 1; Asm->OutStreamer->emitIntValue(Size, PtrSize); } } Asm->OutStreamer->AddComment("ARange terminator"); Asm->OutStreamer->emitIntValue(0, PtrSize); Asm->OutStreamer->emitIntValue(0, PtrSize); } } /// Emit a single range list. We handle both DWARF v5 and earlier. static void emitRangeList(DwarfDebug &DD, AsmPrinter *Asm, const RangeSpanList &List) { emitRangeList(DD, Asm, List.Label, List.Ranges, *List.CU, dwarf::DW_RLE_base_addressx, dwarf::DW_RLE_offset_pair, dwarf::DW_RLE_startx_length, dwarf::DW_RLE_end_of_list, llvm::dwarf::RangeListEncodingString, List.CU->getCUNode()->getRangesBaseAddress() || DD.getDwarfVersion() >= 5, [](auto) {}); } void DwarfDebug::emitDebugRangesImpl(const DwarfFile &Holder, MCSection *Section) { if (Holder.getRangeLists().empty()) return; assert(useRangesSection()); assert(!CUMap.empty()); assert(llvm::any_of(CUMap, [](const decltype(CUMap)::value_type &Pair) { return !Pair.second->getCUNode()->isDebugDirectivesOnly(); })); Asm->OutStreamer->SwitchSection(Section); MCSymbol *TableEnd = nullptr; if (getDwarfVersion() >= 5) TableEnd = emitRnglistsTableHeader(Asm, Holder); for (const RangeSpanList &List : Holder.getRangeLists()) emitRangeList(*this, Asm, List); if (TableEnd) Asm->OutStreamer->emitLabel(TableEnd); } /// Emit address ranges into the .debug_ranges section or into the DWARF v5 /// .debug_rnglists section. void DwarfDebug::emitDebugRanges() { const auto &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; emitDebugRangesImpl(Holder, getDwarfVersion() >= 5 ? Asm->getObjFileLowering().getDwarfRnglistsSection() : Asm->getObjFileLowering().getDwarfRangesSection()); } void DwarfDebug::emitDebugRangesDWO() { emitDebugRangesImpl(InfoHolder, Asm->getObjFileLowering().getDwarfRnglistsDWOSection()); } /// Emit the header of a DWARF 5 macro section, or the GNU extension for /// DWARF 4. static void emitMacroHeader(AsmPrinter *Asm, const DwarfDebug &DD, const DwarfCompileUnit &CU, uint16_t DwarfVersion) { enum HeaderFlagMask { #define HANDLE_MACRO_FLAG(ID, NAME) MACRO_FLAG_##NAME = ID, #include "llvm/BinaryFormat/Dwarf.def" }; Asm->OutStreamer->AddComment("Macro information version"); Asm->emitInt16(DwarfVersion >= 5 ? DwarfVersion : 4); // We emit the line offset flag unconditionally here, since line offset should // be mostly present. if (Asm->isDwarf64()) { Asm->OutStreamer->AddComment("Flags: 64 bit, debug_line_offset present"); Asm->emitInt8(MACRO_FLAG_OFFSET_SIZE | MACRO_FLAG_DEBUG_LINE_OFFSET); } else { Asm->OutStreamer->AddComment("Flags: 32 bit, debug_line_offset present"); Asm->emitInt8(MACRO_FLAG_DEBUG_LINE_OFFSET); } Asm->OutStreamer->AddComment("debug_line_offset"); if (DD.useSplitDwarf()) Asm->emitDwarfLengthOrOffset(0); else Asm->emitDwarfSymbolReference(CU.getLineTableStartSym()); } void DwarfDebug::handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U) { for (auto *MN : Nodes) { if (auto *M = dyn_cast(MN)) emitMacro(*M); else if (auto *F = dyn_cast(MN)) emitMacroFile(*F, U); else llvm_unreachable("Unexpected DI type!"); } } void DwarfDebug::emitMacro(DIMacro &M) { StringRef Name = M.getName(); StringRef Value = M.getValue(); // There should be one space between the macro name and the macro value in // define entries. In undef entries, only the macro name is emitted. std::string Str = Value.empty() ? Name.str() : (Name + " " + Value).str(); if (UseDebugMacroSection) { if (getDwarfVersion() >= 5) { unsigned Type = M.getMacinfoType() == dwarf::DW_MACINFO_define ? dwarf::DW_MACRO_define_strx : dwarf::DW_MACRO_undef_strx; Asm->OutStreamer->AddComment(dwarf::MacroString(Type)); Asm->emitULEB128(Type); Asm->OutStreamer->AddComment("Line Number"); Asm->emitULEB128(M.getLine()); Asm->OutStreamer->AddComment("Macro String"); Asm->emitULEB128( InfoHolder.getStringPool().getIndexedEntry(*Asm, Str).getIndex()); } else { unsigned Type = M.getMacinfoType() == dwarf::DW_MACINFO_define ? dwarf::DW_MACRO_GNU_define_indirect : dwarf::DW_MACRO_GNU_undef_indirect; Asm->OutStreamer->AddComment(dwarf::GnuMacroString(Type)); Asm->emitULEB128(Type); Asm->OutStreamer->AddComment("Line Number"); Asm->emitULEB128(M.getLine()); Asm->OutStreamer->AddComment("Macro String"); Asm->emitDwarfSymbolReference( InfoHolder.getStringPool().getEntry(*Asm, Str).getSymbol()); } } else { Asm->OutStreamer->AddComment(dwarf::MacinfoString(M.getMacinfoType())); Asm->emitULEB128(M.getMacinfoType()); Asm->OutStreamer->AddComment("Line Number"); Asm->emitULEB128(M.getLine()); Asm->OutStreamer->AddComment("Macro String"); Asm->OutStreamer->emitBytes(Str); Asm->emitInt8('\0'); } } void DwarfDebug::emitMacroFileImpl( DIMacroFile &MF, DwarfCompileUnit &U, unsigned StartFile, unsigned EndFile, StringRef (*MacroFormToString)(unsigned Form)) { Asm->OutStreamer->AddComment(MacroFormToString(StartFile)); Asm->emitULEB128(StartFile); Asm->OutStreamer->AddComment("Line Number"); Asm->emitULEB128(MF.getLine()); Asm->OutStreamer->AddComment("File Number"); DIFile &F = *MF.getFile(); if (useSplitDwarf()) Asm->emitULEB128(getDwoLineTable(U)->getFile( F.getDirectory(), F.getFilename(), getMD5AsBytes(&F), Asm->OutContext.getDwarfVersion(), F.getSource())); else Asm->emitULEB128(U.getOrCreateSourceID(&F)); handleMacroNodes(MF.getElements(), U); Asm->OutStreamer->AddComment(MacroFormToString(EndFile)); Asm->emitULEB128(EndFile); } void DwarfDebug::emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U) { // DWARFv5 macro and DWARFv4 macinfo share some common encodings, // so for readibility/uniformity, We are explicitly emitting those. assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); if (UseDebugMacroSection) emitMacroFileImpl( F, U, dwarf::DW_MACRO_start_file, dwarf::DW_MACRO_end_file, (getDwarfVersion() >= 5) ? dwarf::MacroString : dwarf::GnuMacroString); else emitMacroFileImpl(F, U, dwarf::DW_MACINFO_start_file, dwarf::DW_MACINFO_end_file, dwarf::MacinfoString); } void DwarfDebug::emitDebugMacinfoImpl(MCSection *Section) { for (const auto &P : CUMap) { auto &TheCU = *P.second; auto *SkCU = TheCU.getSkeleton(); DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; auto *CUNode = cast(P.first); DIMacroNodeArray Macros = CUNode->getMacros(); if (Macros.empty()) continue; Asm->OutStreamer->SwitchSection(Section); Asm->OutStreamer->emitLabel(U.getMacroLabelBegin()); if (UseDebugMacroSection) emitMacroHeader(Asm, *this, U, getDwarfVersion()); handleMacroNodes(Macros, U); Asm->OutStreamer->AddComment("End Of Macro List Mark"); Asm->emitInt8(0); } } /// Emit macros into a debug macinfo/macro section. void DwarfDebug::emitDebugMacinfo() { auto &ObjLower = Asm->getObjFileLowering(); emitDebugMacinfoImpl(UseDebugMacroSection ? ObjLower.getDwarfMacroSection() : ObjLower.getDwarfMacinfoSection()); } void DwarfDebug::emitDebugMacinfoDWO() { auto &ObjLower = Asm->getObjFileLowering(); emitDebugMacinfoImpl(UseDebugMacroSection ? ObjLower.getDwarfMacroDWOSection() : ObjLower.getDwarfMacinfoDWOSection()); } // DWARF5 Experimental Separate Dwarf emitters. void DwarfDebug::initSkeletonUnit(const DwarfUnit &U, DIE &Die, std::unique_ptr NewU) { if (!CompilationDir.empty()) NewU->addString(Die, dwarf::DW_AT_comp_dir, CompilationDir); addGnuPubAttributes(*NewU, Die); SkeletonHolder.addUnit(std::move(NewU)); } DwarfCompileUnit &DwarfDebug::constructSkeletonCU(const DwarfCompileUnit &CU) { auto OwnedUnit = std::make_unique( CU.getUniqueID(), CU.getCUNode(), Asm, this, &SkeletonHolder, UnitKind::Skeleton); DwarfCompileUnit &NewCU = *OwnedUnit; NewCU.setSection(Asm->getObjFileLowering().getDwarfInfoSection()); NewCU.initStmtList(); if (useSegmentedStringOffsetsTable()) NewCU.addStringOffsetsStart(); initSkeletonUnit(CU, NewCU.getUnitDie(), std::move(OwnedUnit)); return NewCU; } // Emit the .debug_info.dwo section for separated dwarf. This contains the // compile units that would normally be in debug_info. void DwarfDebug::emitDebugInfoDWO() { assert(useSplitDwarf() && "No split dwarf debug info?"); // Don't emit relocations into the dwo file. InfoHolder.emitUnits(/* UseOffsets */ true); } // Emit the .debug_abbrev.dwo section for separated dwarf. This contains the // abbreviations for the .debug_info.dwo section. void DwarfDebug::emitDebugAbbrevDWO() { assert(useSplitDwarf() && "No split dwarf?"); InfoHolder.emitAbbrevs(Asm->getObjFileLowering().getDwarfAbbrevDWOSection()); } void DwarfDebug::emitDebugLineDWO() { assert(useSplitDwarf() && "No split dwarf?"); SplitTypeUnitFileTable.Emit( *Asm->OutStreamer, MCDwarfLineTableParams(), Asm->getObjFileLowering().getDwarfLineDWOSection()); } void DwarfDebug::emitStringOffsetsTableHeaderDWO() { assert(useSplitDwarf() && "No split dwarf?"); InfoHolder.getStringPool().emitStringOffsetsTableHeader( *Asm, Asm->getObjFileLowering().getDwarfStrOffDWOSection(), InfoHolder.getStringOffsetsStartSym()); } // Emit the .debug_str.dwo section for separated dwarf. This contains the // string section and is identical in format to traditional .debug_str // sections. void DwarfDebug::emitDebugStrDWO() { if (useSegmentedStringOffsetsTable()) emitStringOffsetsTableHeaderDWO(); assert(useSplitDwarf() && "No split dwarf?"); MCSection *OffSec = Asm->getObjFileLowering().getDwarfStrOffDWOSection(); InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection(), OffSec, /* UseRelativeOffsets = */ false); } // Emit address pool. void DwarfDebug::emitDebugAddr() { AddrPool.emit(*Asm, Asm->getObjFileLowering().getDwarfAddrSection()); } MCDwarfDwoLineTable *DwarfDebug::getDwoLineTable(const DwarfCompileUnit &CU) { if (!useSplitDwarf()) return nullptr; const DICompileUnit *DIUnit = CU.getCUNode(); SplitTypeUnitFileTable.maybeSetRootFile( DIUnit->getDirectory(), DIUnit->getFilename(), getMD5AsBytes(DIUnit->getFile()), DIUnit->getSource()); return &SplitTypeUnitFileTable; } uint64_t DwarfDebug::makeTypeSignature(StringRef Identifier) { MD5 Hash; Hash.update(Identifier); // ... take the least significant 8 bytes and return those. Our MD5 // implementation always returns its results in little endian, so we actually // need the "high" word. MD5::MD5Result Result; Hash.final(Result); return Result.high(); } void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, StringRef Identifier, DIE &RefDie, const DICompositeType *CTy) { // Fast path if we're building some type units and one has already used the // address pool we know we're going to throw away all this work anyway, so // don't bother building dependent types. if (!TypeUnitsUnderConstruction.empty() && AddrPool.hasBeenUsed()) return; auto Ins = TypeSignatures.insert(std::make_pair(CTy, 0)); if (!Ins.second) { CU.addDIETypeSignature(RefDie, Ins.first->second); return; } bool TopLevelType = TypeUnitsUnderConstruction.empty(); AddrPool.resetUsedFlag(); auto OwnedUnit = std::make_unique(CU, Asm, this, &InfoHolder, getDwoLineTable(CU)); DwarfTypeUnit &NewTU = *OwnedUnit; DIE &UnitDie = NewTU.getUnitDie(); TypeUnitsUnderConstruction.emplace_back(std::move(OwnedUnit), CTy); NewTU.addUInt(UnitDie, dwarf::DW_AT_language, dwarf::DW_FORM_data2, CU.getLanguage()); uint64_t Signature = makeTypeSignature(Identifier); NewTU.setTypeSignature(Signature); Ins.first->second = Signature; if (useSplitDwarf()) { MCSection *Section = getDwarfVersion() <= 4 ? Asm->getObjFileLowering().getDwarfTypesDWOSection() : Asm->getObjFileLowering().getDwarfInfoDWOSection(); NewTU.setSection(Section); } else { MCSection *Section = getDwarfVersion() <= 4 ? Asm->getObjFileLowering().getDwarfTypesSection(Signature) : Asm->getObjFileLowering().getDwarfInfoSection(Signature); NewTU.setSection(Section); // Non-split type units reuse the compile unit's line table. CU.applyStmtList(UnitDie); } // Add DW_AT_str_offsets_base to the type unit DIE, but not for split type // units. if (useSegmentedStringOffsetsTable() && !useSplitDwarf()) NewTU.addStringOffsetsStart(); NewTU.setType(NewTU.createTypeDIE(CTy)); if (TopLevelType) { auto TypeUnitsToAdd = std::move(TypeUnitsUnderConstruction); TypeUnitsUnderConstruction.clear(); // Types referencing entries in the address table cannot be placed in type // units. if (AddrPool.hasBeenUsed()) { // Remove all the types built while building this type. // This is pessimistic as some of these types might not be dependent on // the type that used an address. for (const auto &TU : TypeUnitsToAdd) TypeSignatures.erase(TU.second); // Construct this type in the CU directly. // This is inefficient because all the dependent types will be rebuilt // from scratch, including building them in type units, discovering that // they depend on addresses, throwing them out and rebuilding them. CU.constructTypeDIE(RefDie, cast(CTy)); return; } // If the type wasn't dependent on fission addresses, finish adding the type // and all its dependent types. for (auto &TU : TypeUnitsToAdd) { InfoHolder.computeSizeAndOffsetsForUnit(TU.first.get()); InfoHolder.emitUnit(TU.first.get(), useSplitDwarf()); } } CU.addDIETypeSignature(RefDie, Signature); } DwarfDebug::NonTypeUnitContext::NonTypeUnitContext(DwarfDebug *DD) : DD(DD), TypeUnitsUnderConstruction(std::move(DD->TypeUnitsUnderConstruction)), AddrPoolUsed(DD->AddrPool.hasBeenUsed()) { DD->TypeUnitsUnderConstruction.clear(); DD->AddrPool.resetUsedFlag(); } DwarfDebug::NonTypeUnitContext::~NonTypeUnitContext() { DD->TypeUnitsUnderConstruction = std::move(TypeUnitsUnderConstruction); DD->AddrPool.resetUsedFlag(AddrPoolUsed); } DwarfDebug::NonTypeUnitContext DwarfDebug::enterNonTypeUnitContext() { return NonTypeUnitContext(this); } // Add the Name along with its companion DIE to the appropriate accelerator // table (for AccelTableKind::Dwarf it's always AccelDebugNames, for // AccelTableKind::Apple, we use the table we got as an argument). If // accelerator tables are disabled, this function does nothing. template void DwarfDebug::addAccelNameImpl(const DICompileUnit &CU, AccelTable &AppleAccel, StringRef Name, const DIE &Die) { if (getAccelTableKind() == AccelTableKind::None) return; if (getAccelTableKind() != AccelTableKind::Apple && CU.getNameTableKind() != DICompileUnit::DebugNameTableKind::Default) return; DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; DwarfStringPoolEntryRef Ref = Holder.getStringPool().getEntry(*Asm, Name); switch (getAccelTableKind()) { case AccelTableKind::Apple: AppleAccel.addName(Ref, Die); break; case AccelTableKind::Dwarf: AccelDebugNames.addName(Ref, Die); break; case AccelTableKind::Default: llvm_unreachable("Default should have already been resolved."); case AccelTableKind::None: llvm_unreachable("None handled above"); } } void DwarfDebug::addAccelName(const DICompileUnit &CU, StringRef Name, const DIE &Die) { addAccelNameImpl(CU, AccelNames, Name, Die); } void DwarfDebug::addAccelObjC(const DICompileUnit &CU, StringRef Name, const DIE &Die) { // ObjC names go only into the Apple accelerator tables. if (getAccelTableKind() == AccelTableKind::Apple) addAccelNameImpl(CU, AccelObjC, Name, Die); } void DwarfDebug::addAccelNamespace(const DICompileUnit &CU, StringRef Name, const DIE &Die) { addAccelNameImpl(CU, AccelNamespace, Name, Die); } void DwarfDebug::addAccelType(const DICompileUnit &CU, StringRef Name, const DIE &Die, char Flags) { addAccelNameImpl(CU, AccelTypes, Name, Die); } uint16_t DwarfDebug::getDwarfVersion() const { return Asm->OutStreamer->getContext().getDwarfVersion(); } dwarf::Form DwarfDebug::getDwarfSectionOffsetForm() const { if (Asm->getDwarfVersion() >= 4) return dwarf::Form::DW_FORM_sec_offset; assert((!Asm->isDwarf64() || (Asm->getDwarfVersion() == 3)) && "DWARF64 is not defined prior DWARFv3"); return Asm->isDwarf64() ? dwarf::Form::DW_FORM_data8 : dwarf::Form::DW_FORM_data4; } const MCSymbol *DwarfDebug::getSectionLabel(const MCSection *S) { return SectionLabels.find(S)->second; } void DwarfDebug::insertSectionLabel(const MCSymbol *S) { if (SectionLabels.insert(std::make_pair(&S->getSection(), S)).second) if (useSplitDwarf() || getDwarfVersion() >= 5) AddrPool.getIndex(S); } Optional DwarfDebug::getMD5AsBytes(const DIFile *File) const { assert(File); if (getDwarfVersion() < 5) return None; Optional> Checksum = File->getChecksum(); if (!Checksum || Checksum->Kind != DIFile::CSK_MD5) return None; // Convert the string checksum to an MD5Result for the streamer. // The verifier validates the checksum so we assume it's okay. // An MD5 checksum is 16 bytes. std::string ChecksumString = fromHex(Checksum->Value); MD5::MD5Result CKMem; std::copy(ChecksumString.begin(), ChecksumString.end(), CKMem.Bytes.data()); return CKMem; }