//===- 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 "DebugLocEntry.h" #include "DebugLocStream.h" #include "DwarfCompileUnit.h" #include "DwarfExpression.h" #include "DwarfFile.h" #include "DwarfUnit.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/AccelTable.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/MachineInstr.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/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.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/MCDwarf.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 "llvm/Target/TargetOptions.h" #include #include #include #include #include #include #include #include using namespace llvm; #define DEBUG_TYPE "dwarfdebug" STATISTIC(NumCSParams, "Number of dbg call site params created"); static cl::opt DisableDebugInfoPrinting("disable-debug-info-print", cl::Hidden, cl::desc("Disable debug info printing")); 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)); 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 const char *const DWARFGroupName = "dwarf"; static const char *const DWARFGroupDescription = "DWARF Emission"; static const char *const DbgTimerName = "writer"; static const char *const DbgTimerDescription = "DWARF Debug Writer"; 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, unsigned 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->getOperand(0).isReg()) { auto RegOp = MI->getOperand(0); auto Op1 = MI->getOperand(1); // 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->getOperand(0).isImm()) return DbgValueLoc(Expr, MI->getOperand(0).getImm()); if (MI->getOperand(0).isFPImm()) return DbgValueLoc(Expr, MI->getOperand(0).getFPImm()); if (MI->getOperand(0).isCImm()) return DbgValueLoc(Expr, MI->getOperand(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, Module *M) : 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); 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() && 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; Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); } // 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); } } /// 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) { auto *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; auto *MBB = CallMI->getParent(); const auto &TRI = MF->getSubtarget().getRegisterInfo(); const auto &TII = MF->getSubtarget().getInstrInfo(); const auto &TLI = MF->getSubtarget().getTargetLowering(); // Skip the call instruction. auto I = std::next(CallMI->getReverseIterator()); DenseSet ForwardedRegWorklist; // Add all the forwarding registers into the ForwardedRegWorklist. for (auto ArgReg : CallFwdRegsInfo->second) { bool InsertedReg = ForwardedRegWorklist.insert(ArgReg.Reg).second; assert(InsertedReg && "Single register used to forward two arguments?"); (void)InsertedReg; } // 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 desctipion, if the call is within the entry MBB. // The RegsForEntryValues maps a forwarding register into the register holding // the entry value. // TODO: Handle situations when call site parameter value can be described // as the entry value within basic blocks other then the first one. bool ShouldTryEmitEntryVals = MBB->getIterator() == MF->begin(); DenseMap RegsForEntryValues; // If the MI is an instruction defining one or more parameters' forwarding // registers, add those defines. We can currently only describe forwarded // registers that are explicitly defined, but keep track of implicit defines // also to remove those registers from the work list. auto getForwardingRegsDefinedByMI = [&](const MachineInstr &MI, SmallVectorImpl &Explicit, SmallVectorImpl &Implicit) { 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, MO.getReg())) { if (MO.isImplicit()) Implicit.push_back(FwdReg); else Explicit.push_back(FwdReg); break; } } } } }; auto finishCallSiteParam = [&](DbgValueLoc DbgLocVal, unsigned Reg) { unsigned FwdReg = Reg; if (ShouldTryEmitEntryVals) { auto EntryValReg = RegsForEntryValues.find(Reg); if (EntryValReg != RegsForEntryValues.end()) FwdReg = EntryValReg->second; } DbgCallSiteParam CSParm(FwdReg, DbgLocVal); Params.push_back(CSParm); ++NumCSParams; }; // Search for a loading value in forwaring registers. for (; I != MBB->rend(); ++I) { // If the next instruction is a call we can not interpret parameter's // forwarding registers or we finished the interpretation of all parameters. if (I->isCall()) return; if (ForwardedRegWorklist.empty()) return; SmallVector ExplicitFwdRegDefs; SmallVector ImplicitFwdRegDefs; getForwardingRegsDefinedByMI(*I, ExplicitFwdRegDefs, ImplicitFwdRegDefs); if (ExplicitFwdRegDefs.empty() && ImplicitFwdRegDefs.empty()) continue; // If the MI clobbers more then one forwarding register we must remove // all of them from the working list. for (auto Reg : concat(ExplicitFwdRegDefs, ImplicitFwdRegDefs)) ForwardedRegWorklist.erase(Reg); // The describeLoadedValue() hook currently does not have any information // about which register it should describe in case of multiple defines, so // for now we only handle instructions where a forwarded register is (at // least partially) defined by the instruction's single explicit define. if (I->getNumExplicitDefs() != 1 || ExplicitFwdRegDefs.empty()) continue; unsigned Reg = ExplicitFwdRegDefs[0]; if (auto ParamValue = TII->describeLoadedValue(*I)) { if (ParamValue->first.isImm()) { int64_t Val = ParamValue->first.getImm(); DbgValueLoc DbgLocVal(ParamValue->second, Val); finishCallSiteParam(DbgLocVal, Reg); } else if (ParamValue->first.isReg()) { Register RegLoc = ParamValue->first.getReg(); unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); Register FP = TRI->getFrameRegister(*MF); bool IsSPorFP = (RegLoc == SP) || (RegLoc == FP); if (TRI->isCalleeSavedPhysReg(RegLoc, *MF) || IsSPorFP) { DbgValueLoc DbgLocVal(ParamValue->second, MachineLocation(RegLoc, /*IsIndirect=*/IsSPorFP)); finishCallSiteParam(DbgLocVal, Reg); } else if (ShouldTryEmitEntryVals) { ForwardedRegWorklist.insert(RegLoc); RegsForEntryValues[RegLoc] = Reg; } } } } // 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) { unsigned FwdReg = RegEntry; auto EntryValReg = RegsForEntryValues.find(RegEntry); if (EntryValReg != RegsForEntryValues.end()) FwdReg = EntryValReg->second; DbgValueLoc DbgLocVal(EntryExpr, MachineLocation(RegEntry)); DbgCallSiteParam CSParm(FwdReg, DbgLocVal); Params.push_back(CSParm); ++NumCSParams; } } } 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"); bool ApplyGNUExtensions = getDwarfVersion() == 4 && tuneForGDB(); // Emit call site entries for each call or tail call in the function. for (const MachineBasicBlock &MBB : MF) { for (const MachineInstr &MI : MBB.instrs()) { // Skip instructions which aren't calls. Both calls and tail-calling jump // instructions (e.g TAILJMPd64) are classified correctly here. if (!MI.isCall()) continue; // TODO: Add support for targets with delay slots (see: beginInstruction). if (MI.hasDelaySlot()) 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; const DISubprogram *CalleeSP = 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; CalleeSP = CalleeDecl->getSubprogram(); } // TODO: Omit call site entries for runtime calls (objc_msgSend, etc). bool IsTail = TII->isTailCall(MI); // For tail calls, for non-gdb tuning, no return PC information is needed. // For regular calls (and tail calls in GDB tuning), the return PC // is needed to disambiguate paths in the call graph which could lead to // some target function. const MCExpr *PCOffset = (IsTail && !tuneForGDB()) ? nullptr : getFunctionLocalOffsetAfterInsn(&MI); // Address of a call-like instruction for a normal call or a jump-like // instruction for a tail call. This is needed for GDB + DWARF 4 tuning. const MCSymbol *PCAddr = ApplyGNUExtensions ? const_cast(getLabelAfterInsn(&MI)) : nullptr; assert((IsTail || PCOffset || PCAddr) && "Call without return PC information"); LLVM_DEBUG(dbgs() << "CallSiteEntry: " << MF.getName() << " -> " << (CalleeDecl ? CalleeDecl->getName() : StringRef(MF.getSubtarget() .getRegisterInfo() ->getName(CallReg))) << (IsTail ? " [IsTail]" : "") << "\n"); DIE &CallSiteDIE = CU.constructCallSiteEntryDIE(ScopeDIE, CalleeSP, IsTail, PCAddr, PCOffset, CallReg); // GDB and LLDB support call site parameter debug info. if (Asm->TM.Options.EnableDebugEntryValues && (tuneForGDB() || tuneForLLDB())) { 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); // 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. NewCU.addString(Die, dwarf::DW_AT_GNU_dwo_name, 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(), NewCU.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()); } // Create DIEs for function declarations used for call site debug info. for (auto Scope : DIUnit->getRetainedTypes()) if (auto *SP = dyn_cast_or_null(Scope)) NewCU.getOrCreateSubprogramDIE(SP); 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() { NamedRegionTimer T(DbgTimerName, DbgTimerDescription, DWARFGroupName, DWARFGroupDescription, TimePassesIsEnabled); if (DisableDebugInfoPrinting) { MMI->setDebugInfoAvailability(false); return; } const Module *M = MMI->getModule(); unsigned NumDebugCUs = std::distance(M->debug_compile_units_begin(), M->debug_compile_units_end()); // Tell MMI whether we have debug info. assert(MMI->hasDebugInfo() == (NumDebugCUs > 0) && "DebugInfoAvailabilty initialized unexpectedly"); 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")); 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(); if (useSplitDwarf() && !TheCU.getUnitDie().children().empty()) { finishUnitAttributes(TheCU.getCUNode(), TheCU); TheCU.addString(TheCU.getUnitDie(), dwarf::DW_AT_GNU_dwo_name, Asm->TM.Options.MCOptions.SplitDwarfFile); SkCU->addString(SkCU->getUnitDie(), dwarf::DW_AT_GNU_dwo_name, Asm->TM.Options.MCOptions.SplitDwarfFile); // Emit a unique identifier for this CU. uint64_t ID = DIEHash(Asm).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 (!AddrPool.isEmpty() && (getDwarfVersion() >= 5 || (SkCU && !TheCU.getUnitDie().children().empty()))) U.addAddrTableBase(); if (getDwarfVersion() >= 5) { if (U.hasRangeLists()) U.addRnglistsBase(); if (!DebugLocs.getLists().empty() && !useSplitDwarf()) { DebugLocs.setSym(Asm->createTempSymbol("loclists_table_base")); 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" attribute. if (CUNode->getMacros()) 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 !DisableDebugInfoPrinting and the presence of the // llvm.dbg.cu metadata node) if (!MMI->hasDebugInfo()) return; // Finalize the debug info for the module. finalizeModuleInfo(); emitDebugStr(); if (useSplitDwarf()) emitDebugLocDWO(); else // Emit info into a debug loc 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(); // Emit info into a debug macinfo section. emitDebugMacinfo(); 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; 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) continue; ensureAbstractEntityIsCreatedIfScoped(TheCU, Var.first, Scope->getScopeNode()); auto RegVar = std::make_unique( cast(Var.first), Var.second); RegVar->initializeMMI(VI.Expr, VI.Slot); 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) { 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; // Determine if the DBG_VALUE is valid at the beginning of its lexical block. const MachineInstr *LScopeBegin = LSRange.front().first; // Early 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; // Fail if there are instructions belonging to our scope in another block. const MachineInstr *LScopeEnd = LSRange.back().second; if (LScopeEnd->getParent() != MBB) return false; // 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->getOperand(0).isImm() && MBB->pred_empty()) return true; return false; } /// 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); auto Last = remove_if(OpenRanges, [&](OpenRange &R) { return R.first <= Index; }); OpenRanges.erase(Last, OpenRanges.end()); // 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()) { EndLabel = Asm->getFunctionEnd(); 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); } 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)) { 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) { DebugHandlerBase::beginInstruction(MI); assert(CurMI); const auto *SP = MI->getMF()->getFunction().getSubprogram(); if (!SP || SP->getUnit()->getEmissionKind() == DICompileUnit::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(); // Request a label after the call in order to emit AT_return_pc information // in call site entries. TODO: Add support for targets with delay slots. if (SP->areAllCallsDescribed() && MI->isCall() && !MI->hasDelaySlot()) requestLabelAfterInsn(MI); 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; SectionLabels.insert(std::make_pair(&Asm->getFunctionBegin()->getSection(), Asm->getFunctionBegin())); 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. TheCU.addRange({Asm->getFunctionBegin(), Asm->getFunctionEnd()}); // 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. Asm->OutStreamer->AddComment("Length of Public " + Name + " Info"); MCSymbol *BeginLabel = Asm->createTempSymbol("pub" + Name + "_begin"); MCSymbol *EndLabel = Asm->createTempSymbol("pub" + Name + "_end"); Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); 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->emitInt32(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->emitInt32(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->emitInt32(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, getDwarfVersion(), PtrSize); 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) { if (CU) { uint64_t Offset = CU->ExprRefedBaseTypes[Op.getRawOperand(I)].Die->getOffset(); assert(Offset < (1ULL << (ULEB128PadSize * 7)) && "Offset wont fit"); Asm->EmitULEB128(Offset, nullptr, ULEB128PadSize); } else { // Emit a reference to the 'generic type'. Asm->EmitULEB128(0, nullptr, 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(); if (Location.isIndirect()) DwarfExpr.setMemoryLocationKind(); DIExpressionCursor Cursor(DIExpr); if (DIExpr->isEntryValue()) { DwarfExpr.setEntryValueFlag(); 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.isConstantFP()) { APInt RawBytes = Value.getConstantFP()->getValueAPF().bitcastToAPInt(); DwarfExpr.addUnsignedConstant(RawBytes); } 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(std::is_sorted(Values.begin(), Values.end()) && "fragments are expected to be sorted"); for (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(); } 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 common part of the DWARF 5 range/locations list tables header. static void emitListsTableHeaderStart(AsmPrinter *Asm, MCSymbol *TableStart, MCSymbol *TableEnd) { // Build the table header, which starts with the length field. Asm->OutStreamer->AddComment("Length"); Asm->EmitLabelDifference(TableEnd, TableStart, 4); Asm->OutStreamer->EmitLabel(TableStart); // Version number (DWARF v5 and later). Asm->OutStreamer->AddComment("Version"); Asm->emitInt16(Asm->OutStreamer->getContext().getDwarfVersion()); // Address size. Asm->OutStreamer->AddComment("Address size"); Asm->emitInt8(Asm->MAI->getCodePointerSize()); // Segment selector size. Asm->OutStreamer->AddComment("Segment selector size"); Asm->emitInt8(0); } // 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 *TableStart = Asm->createTempSymbol("debug_rnglist_table_start"); MCSymbol *TableEnd = Asm->createTempSymbol("debug_rnglist_table_end"); emitListsTableHeaderStart(Asm, TableStart, TableEnd); 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.getSym(), Holder.getRnglistsTableBaseSym(), 4); 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 *TableStart = Asm->createTempSymbol("debug_loclist_table_start"); MCSymbol *TableEnd = Asm->createTempSymbol("debug_loclist_table_end"); emitListsTableHeaderStart(Asm, TableStart, TableEnd); const auto &DebugLocs = DD.getDebugLocs(); // FIXME: Generate the offsets table and use DW_FORM_loclistx with the // DW_AT_loclists_base attribute. Until then set the number of offsets to 0. Asm->OutStreamer->AddComment("Offset entry count"); Asm->emitInt32(0); Asm->OutStreamer->EmitLabel(DebugLocs.getSym()); 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); } } 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); }); } // Emit locations into the .debug_loc/.debug_rnglists section. void DwarfDebug::emitDebugLoc() { if (DebugLocs.getLists().empty()) return; MCSymbol *TableEnd = nullptr; if (getDwarfVersion() >= 5) { Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfLoclistsSection()); TableEnd = emitLoclistsTableHeader(Asm, *this); } else { Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfLocSection()); } for (const auto &List : DebugLocs.getLists()) emitLocList(*this, Asm, List); if (TableEnd) Asm->OutStreamer->EmitLabel(TableEnd); } void DwarfDebug::emitDebugLocDWO() { 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 // Ideally/in v5, this could use 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); 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 sizeof(int32_t) + // 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(sizeof(int32_t) + ContentSize, Align(TupleSize)); ContentSize += Padding; ContentSize += (List.size() + 1) * TupleSize; // For each compile unit, write the list of spans it covers. Asm->OutStreamer->AddComment("Length of ARange Set"); Asm->emitInt32(ContentSize); 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.getSym(), List.getRanges(), List.getCU(), 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.getCU().getCUNode()->getRangesBaseAddress() || DD.getDwarfVersion() >= 5, [](auto) {}); } static void emitDebugRangesImpl(DwarfDebug &DD, AsmPrinter *Asm, const DwarfFile &Holder, MCSymbol *TableEnd) { for (const RangeSpanList &List : Holder.getRangeLists()) emitRangeList(DD, 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() { if (CUMap.empty()) return; const auto &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; if (Holder.getRangeLists().empty()) return; assert(useRangesSection()); assert(llvm::none_of(CUMap, [](const decltype(CUMap)::value_type &Pair) { return Pair.second->getCUNode()->isDebugDirectivesOnly(); })); // Start the dwarf ranges section. MCSymbol *TableEnd = nullptr; if (getDwarfVersion() >= 5) { Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfRnglistsSection()); TableEnd = emitRnglistsTableHeader(Asm, Holder); } else Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfRangesSection()); emitDebugRangesImpl(*this, Asm, Holder, TableEnd); } void DwarfDebug::emitDebugRangesDWO() { assert(useSplitDwarf()); if (CUMap.empty()) return; const auto &Holder = InfoHolder; if (Holder.getRangeLists().empty()) return; assert(getDwarfVersion() >= 5); assert(useRangesSection()); assert(llvm::none_of(CUMap, [](const decltype(CUMap)::value_type &Pair) { return Pair.second->getCUNode()->isDebugDirectivesOnly(); })); // Start the dwarf ranges section. Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfRnglistsDWOSection()); MCSymbol *TableEnd = emitRnglistsTableHeader(Asm, Holder); emitDebugRangesImpl(*this, Asm, Holder, TableEnd); } 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) { Asm->EmitULEB128(M.getMacinfoType()); Asm->EmitULEB128(M.getLine()); StringRef Name = M.getName(); StringRef Value = M.getValue(); Asm->OutStreamer->EmitBytes(Name); if (!Value.empty()) { // There should be one space between macro name and macro value. Asm->emitInt8(' '); Asm->OutStreamer->EmitBytes(Value); } Asm->emitInt8('\0'); } void DwarfDebug::emitMacroFile(DIMacroFile &F, DwarfCompileUnit &U) { assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file); Asm->EmitULEB128(dwarf::DW_MACINFO_start_file); Asm->EmitULEB128(F.getLine()); Asm->EmitULEB128(U.getOrCreateSourceID(F.getFile())); handleMacroNodes(F.getElements(), U); Asm->EmitULEB128(dwarf::DW_MACINFO_end_file); } /// Emit macros into a debug macinfo section. void DwarfDebug::emitDebugMacinfo() { if (CUMap.empty()) return; if (llvm::all_of(CUMap, [](const decltype(CUMap)::value_type &Pair) { return Pair.second->getCUNode()->isDebugDirectivesOnly(); })) return; // Start the dwarf macinfo section. Asm->OutStreamer->SwitchSection( Asm->getObjFileLowering().getDwarfMacinfoSection()); for (const auto &P : CUMap) { auto &TheCU = *P.second; if (TheCU.getCUNode()->isDebugDirectivesOnly()) continue; auto *SkCU = TheCU.getSkeleton(); DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; auto *CUNode = cast(P.first); DIMacroNodeArray Macros = CUNode->getMacros(); if (!Macros.empty()) { Asm->OutStreamer->EmitLabel(U.getMacroLabelBegin()); handleMacroNodes(Macros, U); } } Asm->OutStreamer->AddComment("End Of Macro List Mark"); Asm->emitInt8(0); } // 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); 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(), CU.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)) { DD->TypeUnitsUnderConstruction.clear(); assert(TypeUnitsUnderConstruction.empty() || !DD->AddrPool.hasBeenUsed()); } DwarfDebug::NonTypeUnitContext::~NonTypeUnitContext() { DD->TypeUnitsUnderConstruction = std::move(TypeUnitsUnderConstruction); DD->AddrPool.resetUsedFlag(); } 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(); } const MCSymbol *DwarfDebug::getSectionLabel(const MCSection *S) { return SectionLabels.find(S)->second; }