diff options
Diffstat (limited to 'lib/CodeGen/AsmPrinter/DwarfDebug.cpp')
-rw-r--r-- | lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 665 |
1 files changed, 461 insertions, 204 deletions
diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 2c9c7d4f3146..8761fae9dd22 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -16,7 +16,6 @@ #include "DIEHash.h" #include "DebugLocEntry.h" #include "DebugLocStream.h" -#include "DwarfAccelTable.h" #include "DwarfCompileUnit.h" #include "DwarfExpression.h" #include "DwarfFile.h" @@ -31,6 +30,7 @@ #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" @@ -39,7 +39,6 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/Constants.h" @@ -66,6 +65,7 @@ #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 <algorithm> @@ -94,6 +94,11 @@ static cl::opt<bool> GenerateARangeSection("generate-arange-section", cl::desc("Generate dwarf aranges"), cl::init(false)); +static cl::opt<bool> + GenerateDwarfTypeUnits("generate-type-units", cl::Hidden, + cl::desc("Generate DWARF4 type units."), + cl::init(false)); + static cl::opt<bool> SplitDwarfCrossCuReferences( "split-dwarf-cross-cu-references", cl::Hidden, cl::desc("Enable cross-cu references in DWO files"), cl::init(false)); @@ -107,14 +112,40 @@ static cl::opt<DefaultOnOff> UnknownLocations( clEnumVal(Enable, "In all cases"), clEnumVal(Disable, "Never")), cl::init(Default)); +static cl::opt<AccelTableKind> 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<DefaultOnOff> -DwarfAccelTables("dwarf-accel-tables", cl::Hidden, - cl::desc("Output prototype dwarf accelerator tables."), +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<bool> + NoDwarfPubSections("no-dwarf-pub-sections", cl::Hidden, + cl::desc("Disable emission of DWARF pub sections."), + cl::init(false)); + +static cl::opt<bool> + NoDwarfRangesSection("no-dwarf-ranges-section", cl::Hidden, + cl::desc("Disable emission .debug_ranges section."), + cl::init(false)); + +static cl::opt<DefaultOnOff> 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, @@ -215,11 +246,11 @@ ArrayRef<DbgVariable::FrameIndexExpr> DbgVariable::getFrameIndexExprs() const { return A.Expr->isFragment(); }) && "multiple FI expressions without DW_OP_LLVM_fragment"); - std::sort(FrameIndexExprs.begin(), FrameIndexExprs.end(), - [](const FrameIndexExpr &A, const FrameIndexExpr &B) -> bool { - return A.Expr->getFragmentInfo()->OffsetInBits < - B.Expr->getFragmentInfo()->OffsetInBits; - }); + llvm::sort(FrameIndexExprs.begin(), FrameIndexExprs.end(), + [](const FrameIndexExpr &A, const FrameIndexExpr &B) -> bool { + return A.Expr->getFragmentInfo()->OffsetInBits < + B.Expr->getFragmentInfo()->OffsetInBits; + }); return FrameIndexExprs; } @@ -258,23 +289,34 @@ void DbgVariable::addMMIEntry(const DbgVariable &V) { "conflicting locations for variable"); } -static const DwarfAccelTable::Atom TypeAtoms[] = { - DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), - DwarfAccelTable::Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), - DwarfAccelTable::Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)}; +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()), - AccelNames(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, - dwarf::DW_FORM_data4)), - AccelObjC(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, - dwarf::DW_FORM_data4)), - AccelNamespace(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset, - dwarf::DW_FORM_data4)), - AccelTypes(TypeAtoms) { + IsDarwin(A->TM.getTargetTriple().isOSDarwin()) { const Triple &TT = Asm->TM.getTargetTriple(); // Make sure we know our "debugger tuning." The target option takes @@ -288,11 +330,12 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) else DebuggerTuning = DebuggerKind::GDB; - // Turn on accelerator tables for LLDB by default. - if (DwarfAccelTables == Default) - HasDwarfAccelTables = tuneForLLDB(); + if (DwarfInlinedStrings == Default) + UseInlineStrings = TT.isNVPTX(); else - HasDwarfAccelTables = DwarfAccelTables == Enable; + UseInlineStrings = DwarfInlinedStrings == Enable; + + UseLocSection = !TT.isNVPTX(); HasAppleExtensionAttributes = tuneForLLDB(); @@ -308,8 +351,23 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) unsigned DwarfVersionNumber = Asm->TM.Options.MCOptions.DwarfVersion; unsigned DwarfVersion = DwarfVersionNumber ? DwarfVersionNumber : MMI->getModule()->getDwarfVersion(); - // Use dwarf 4 by default if nothing is requested. - DwarfVersion = DwarfVersion ? DwarfVersion : dwarf::DWARF_VERSION; + // Use dwarf 4 by default if nothing is requested. For NVPTX, use dwarf 2. + DwarfVersion = + TT.isNVPTX() ? 2 : (DwarfVersion ? DwarfVersion : dwarf::DWARF_VERSION); + + UsePubSections = !NoDwarfPubSections && !TT.isNVPTX(); + UseRangesSection = !NoDwarfRangesSection && !TT.isNVPTX(); + + // Use sections as references. Force for NVPTX. + if (DwarfSectionsAsReferences == Default) + UseSectionsAsReferences = TT.isNVPTX(); + else + UseSectionsAsReferences = DwarfSectionsAsReferences == Enable; + + GenerateTypeUnits = 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 @@ -321,6 +379,12 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) // 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); } @@ -355,17 +419,18 @@ static StringRef getObjCMethodName(StringRef In) { } // Add the various names to the Dwarf accelerator table names. -// TODO: Determine whether or not we should add names for programs -// that do not have a DW_AT_name or DW_AT_linkage_name field - this -// is only slightly different than the lookup of non-standard ObjC names. void DwarfDebug::addSubprogramNames(const DISubprogram *SP, DIE &Die) { if (!SP->isDefinition()) return; - addAccelName(SP->getName(), Die); - // If the linkage name is different than the name, go ahead and output - // that as well into the name table. - if (SP->getLinkageName() != "" && SP->getName() != SP->getLinkageName()) + if (SP->getName() != "") + addAccelName(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(SP->getLinkageName(), Die); // If this is an Objective-C selector name add it to the ObjC accelerator @@ -471,8 +536,9 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) { // explicitly describe the directory of all files, never relying on the // compilation directory. if (!Asm->OutStreamer->hasRawTextSupport() || SingleCU) - Asm->OutStreamer->getContext().setMCLineTableCompilationDir( - NewCU.getUniqueID(), CompilationDir); + Asm->OutStreamer->emitDwarfFile0Directive( + CompilationDir, FN, NewCU.getMD5AsBytes(DIUnit->getFile()), + DIUnit->getSource(), NewCU.getUniqueID()); StringRef Producer = DIUnit->getProducer(); StringRef Flags = DIUnit->getFlags(); @@ -486,6 +552,10 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) { 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(); @@ -541,21 +611,22 @@ void DwarfDebug::constructAndAddImportedEntityDIE(DwarfCompileUnit &TheCU, /// Sort and unique GVEs by comparing their fragment offset. static SmallVectorImpl<DwarfCompileUnit::GlobalExpr> & sortGlobalExprs(SmallVectorImpl<DwarfCompileUnit::GlobalExpr> &GVEs) { - std::sort(GVEs.begin(), GVEs.end(), - [](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; - }); + llvm::sort(GVEs.begin(), GVEs.end(), + [](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) { @@ -590,6 +661,19 @@ void DwarfDebug::beginModule() { 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 symbol that designates the start of the DWARF v5 range list + // table. It is located past the header and before the offsets table. + if (getDwarfVersion() >= 5) + (useSplitDwarf() ? SkeletonHolder : InfoHolder) + .setRnglistsTableBaseSym(Asm->createTempSymbol("rnglists_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 @@ -694,11 +778,15 @@ void DwarfDebug::finalizeModuleInfo() { // Emit a unique identifier for this CU. uint64_t ID = DIEHash(Asm).computeCUSignature(DWOName, TheCU.getUnitDie()); - 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) { + 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); + } // We don't keep track of which addresses are used in which CU so this // is a bit pessimistic under LTO. if (!AddrPool.isEmpty()) { @@ -706,7 +794,7 @@ void DwarfDebug::finalizeModuleInfo() { SkCU->addSectionLabel(SkCU->getUnitDie(), dwarf::DW_AT_GNU_addr_base, Sym, Sym); } - if (!SkCU->getRangeLists().empty()) { + if (getDwarfVersion() < 5 && !SkCU->getRangeLists().empty()) { const MCSymbol *Sym = TLOF.getDwarfRangesSection()->getBeginSymbol(); SkCU->addSectionLabel(SkCU->getUnitDie(), dwarf::DW_AT_GNU_ranges_base, Sym, Sym); @@ -721,7 +809,7 @@ void DwarfDebug::finalizeModuleInfo() { // ranges for all subprogram DIEs for mach-o. DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; if (unsigned NumRanges = TheCU.getRanges().size()) { - if (NumRanges > 1) + 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 @@ -732,6 +820,10 @@ void DwarfDebug::finalizeModuleInfo() { U.attachRangesOrLowHighPC(U.getUnitDie(), TheCU.takeRanges()); } + if (getDwarfVersion() >= 5 && !useSplitDwarf() && + !U.getRangeLists().empty()) + U.addRnglistsBase(); + auto *CUNode = cast<DICompileUnit>(P.first); // If compile Unit has macros, emit "DW_AT_macro_info" attribute. if (CUNode->getMacros()) @@ -799,11 +891,20 @@ void DwarfDebug::endModule() { } // Emit info into the dwarf accelerator table sections. - if (useDwarfAccelTables()) { + 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. @@ -887,7 +988,7 @@ static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); } -/// \brief If this and Next are describing different fragments of the same +/// If this and Next are describing different fragments of the same /// variable, merge them by appending Next's values to the current /// list of values. /// Return true if the merge was successful. @@ -903,8 +1004,7 @@ bool DebugLocEntry::MergeValues(const DebugLocEntry &Next) { // sorted. for (unsigned i = 0, j = 0; i < Values.size(); ++i) { for (; j < Next.Values.size(); ++j) { - int res = DebugHandlerBase::fragmentCmp( - cast<DIExpression>(Values[i].Expression), + int res = cast<DIExpression>(Values[i].Expression)->fragmentCmp( cast<DIExpression>(Next.Values[j].Expression)); if (res == 0) // The two expressions overlap, we can't merge. return false; @@ -967,7 +1067,7 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, // If this fragment overlaps with any open ranges, truncate them. const DIExpression *DIExpr = Begin->getDebugExpression(); auto Last = remove_if(OpenRanges, [&](DebugLocEntry::Value R) { - return fragmentsOverlap(DIExpr, R.getExpression()); + return DIExpr->fragmentsOverlap(R.getExpression()); }); OpenRanges.erase(Last, OpenRanges.end()); @@ -983,7 +1083,7 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, EndLabel = getLabelBeforeInsn(std::next(I)->first); assert(EndLabel && "Forgot label after instruction ending a range!"); - DEBUG(dbgs() << "DotDebugLoc: " << *Begin << "\n"); + LLVM_DEBUG(dbgs() << "DotDebugLoc: " << *Begin << "\n"); auto Value = getDebugLocValue(Begin); DebugLocEntry Loc(StartLabel, EndLabel, Value); @@ -1012,7 +1112,7 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc, // Attempt to coalesce the ranges of two otherwise identical // DebugLocEntries. auto CurEntry = DebugLoc.rbegin(); - DEBUG({ + LLVM_DEBUG({ dbgs() << CurEntry->getValues().size() << " Values:\n"; for (auto &Value : CurEntry->getValues()) Value.dump(); @@ -1131,6 +1231,9 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, 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); @@ -1151,10 +1254,12 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, } // Collect info for variables that were optimized out. - for (const DILocalVariable *DV : SP->getVariables()) { - if (Processed.insert(InlinedVariable(DV, nullptr)).second) - if (LexicalScope *Scope = LScopes.findLexicalScope(DV->getScope())) - createConcreteVariable(TheCU, *Scope, InlinedVariable(DV, nullptr)); + for (const DINode *DN : SP->getRetainedNodes()) { + if (auto *DV = dyn_cast<DILocalVariable>(DN)) { + if (Processed.insert(InlinedVariable(DV, nullptr)).second) + if (LexicalScope *Scope = LScopes.findLexicalScope(DV->getScope())) + createConcreteVariable(TheCU, *Scope, InlinedVariable(DV, nullptr)); + } } } @@ -1168,7 +1273,9 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { return; // Check if source location changes, but ignore DBG_VALUE and CFI locations. - if (MI->isMetaInstruction()) + // 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 @@ -1333,14 +1440,16 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) { // Construct abstract scopes. for (LexicalScope *AScope : LScopes.getAbstractScopesList()) { auto *SP = cast<DISubprogram>(AScope->getScopeNode()); - // Collect info for variables that were optimized out. - for (const DILocalVariable *DV : SP->getVariables()) { - if (!ProcessedVars.insert(InlinedVariable(DV, nullptr)).second) - continue; - ensureAbstractVariableIsCreated(TheCU, InlinedVariable(DV, nullptr), - DV->getScope()); - assert(LScopes.getAbstractScopesList().size() == NumAbstractScopes - && "ensureAbstractVariableIsCreated inserted abstract scopes"); + for (const DINode *DN : SP->getRetainedNodes()) { + if (auto *DV = dyn_cast<DILocalVariable>(DN)) { + // Collect info for variables that were optimized out. + if (!ProcessedVars.insert(InlinedVariable(DV, nullptr)).second) + continue; + ensureAbstractVariableIsCreated(TheCU, InlinedVariable(DV, nullptr), + DV->getScope()); + assert(LScopes.getAbstractScopesList().size() == NumAbstractScopes + && "ensureAbstractVariableIsCreated inserted abstract scopes"); + } } constructAbstractSubprogramScopeDIE(TheCU, AScope); } @@ -1366,21 +1475,19 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) { void DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, const MDNode *S, unsigned Flags) { StringRef Fn; - StringRef Dir; - unsigned Src = 1; + unsigned FileNo = 1; unsigned Discriminator = 0; if (auto *Scope = cast_or_null<DIScope>(S)) { Fn = Scope->getFilename(); - Dir = Scope->getDirectory(); if (Line != 0 && getDwarfVersion() >= 4) if (auto *LBF = dyn_cast<DILexicalBlockFile>(Scope)) Discriminator = LBF->getDiscriminator(); unsigned CUID = Asm->OutStreamer->getContext().getDwarfCompileUnitID(); - Src = static_cast<DwarfCompileUnit &>(*InfoHolder.getUnits()[CUID]) - .getOrCreateSourceID(Fn, Dir); + FileNo = static_cast<DwarfCompileUnit &>(*InfoHolder.getUnits()[CUID]) + .getOrCreateSourceID(Scope->getFile()); } - Asm->OutStreamer->EmitDwarfLocDirective(Src, Line, Col, Flags, 0, + Asm->OutStreamer->EmitDwarfLocDirective(FileNo, Line, Col, Flags, 0, Discriminator, Fn); } @@ -1401,13 +1508,30 @@ void DwarfDebug::emitAbbreviations() { Holder.emitAbbrevs(Asm->getObjFileLowering().getDwarfAbbrevSection()); } -void DwarfDebug::emitAccel(DwarfAccelTable &Accel, MCSection *Section, +void DwarfDebug::emitStringOffsetsTableHeader() { + DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; + Holder.getStringPool().emitStringOffsetsTableHeader( + *Asm, Asm->getObjFileLowering().getDwarfStrOffSection(), + Holder.getStringOffsetsStartSym()); +} + +template <typename AccelTableT> +void DwarfDebug::emitAccel(AccelTableT &Accel, MCSection *Section, StringRef TableName) { - Accel.FinalizeTable(Asm, TableName); Asm->OutStreamer->SwitchSection(Section); // Emit the full data. - Accel.emit(Asm, Section->getBeginSymbol(), this); + 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; + + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfDebugNamesSection()); + emitDWARF5AccelTable(Asm, AccelDebugNames, *this, getUnits()); } // Emit visible names into a hashed accelerator table section. @@ -1525,6 +1649,14 @@ void DwarfDebug::emitDebugPubSections() { } } +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<const DIE *> &Globals) { @@ -1540,13 +1672,13 @@ void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, Asm->OutStreamer->EmitLabel(BeginLabel); Asm->OutStreamer->AddComment("DWARF Version"); - Asm->EmitInt16(dwarf::DW_PUBNAMES_VERSION); + Asm->emitInt16(dwarf::DW_PUBNAMES_VERSION); Asm->OutStreamer->AddComment("Offset of Compilation Unit Info"); - Asm->emitDwarfSymbolReference(TheU->getLabelBegin()); + emitSectionReference(*TheU); Asm->OutStreamer->AddComment("Compilation Unit Length"); - Asm->EmitInt32(TheU->getLength()); + Asm->emitInt32(TheU->getLength()); // Emit the pubnames for this compilation unit. for (const auto &GI : Globals) { @@ -1554,14 +1686,14 @@ void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, const DIE *Entity = GI.second; Asm->OutStreamer->AddComment("DIE offset"); - Asm->EmitInt32(Entity->getOffset()); + Asm->emitInt32(Entity->getOffset()); if (GnuStyle) { dwarf::PubIndexEntryDescriptor Desc = computeIndexValue(TheU, Entity); Asm->OutStreamer->AddComment( Twine("Kind: ") + dwarf::GDBIndexEntryKindString(Desc.Kind) + ", " + dwarf::GDBIndexEntryLinkageString(Desc.Linkage)); - Asm->EmitInt8(Desc.toBits()); + Asm->emitInt8(Desc.toBits()); } Asm->OutStreamer->AddComment("External Name"); @@ -1569,14 +1701,20 @@ void DwarfDebug::emitDebugPubSection(bool GnuStyle, StringRef Name, } Asm->OutStreamer->AddComment("End Mark"); - Asm->EmitInt32(0); + 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()); + Holder.emitStrings(Asm->getObjFileLowering().getDwarfStrSection(), + StringOffsetsSection, /* UseRelativeOffsets = */ true); } void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, @@ -1589,7 +1727,6 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, } static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT, - ByteStreamer &Streamer, const DebugLocEntry::Value &Value, DwarfExpression &DwarfExpr) { auto *DIExpr = Value.getExpression(); @@ -1634,11 +1771,11 @@ void DebugLocEntry::finalize(const AsmPrinter &AP, "fragments are expected to be sorted"); for (auto Fragment : Values) - emitDebugLocValue(AP, BT, Streamer, Fragment, DwarfExpr); + emitDebugLocValue(AP, BT, Fragment, DwarfExpr); } else { assert(Values.size() == 1 && "only fragments may have >1 value"); - emitDebugLocValue(AP, BT, Streamer, Value, DwarfExpr); + emitDebugLocValue(AP, BT, Value, DwarfExpr); } DwarfExpr.finalize(); } @@ -1646,7 +1783,7 @@ void DebugLocEntry::finalize(const AsmPrinter &AP, void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) { // Emit the size. Asm->OutStreamer->AddComment("Loc expr size"); - Asm->EmitInt16(DebugLocs.getBytes(Entry).size()); + Asm->emitInt16(DebugLocs.getBytes(Entry).size()); // Emit the entry. APByteStreamer Streamer(*Asm); @@ -1694,14 +1831,14 @@ void DwarfDebug::emitDebugLocDWO() { // rather than two. We could get fancier and try to, say, reuse an // address we know we've emitted elsewhere (the start of the function? // The start of the CU or CU subrange that encloses this range?) - Asm->EmitInt8(dwarf::DW_LLE_startx_length); + Asm->emitInt8(dwarf::DW_LLE_startx_length); unsigned idx = AddrPool.getIndex(Entry.BeginSym); Asm->EmitULEB128(idx); Asm->EmitLabelDifference(Entry.EndSym, Entry.BeginSym, 4); emitDebugLocEntryLocation(Entry); } - Asm->EmitInt8(dwarf::DW_LLE_end_of_list); + Asm->emitInt8(dwarf::DW_LLE_end_of_list); } } @@ -1752,7 +1889,7 @@ void DwarfDebug::emitDebugARanges() { } // Sort the symbols by offset within the section. - std::sort( + std::stable_sort( List.begin(), List.end(), [&](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; @@ -1801,10 +1938,10 @@ void DwarfDebug::emitDebugARanges() { } // Sort the CU list (again, to ensure consistent output order). - std::sort(CUs.begin(), CUs.end(), - [](const DwarfCompileUnit *A, const DwarfCompileUnit *B) { - return A->getUniqueID() < B->getUniqueID(); - }); + llvm::sort(CUs.begin(), CUs.end(), + [](const DwarfCompileUnit *A, const DwarfCompileUnit *B) { + return A->getUniqueID() < B->getUniqueID(); + }); // Emit an arange table for each CU we used. for (DwarfCompileUnit *CU : CUs) { @@ -1832,15 +1969,15 @@ void DwarfDebug::emitDebugARanges() { // For each compile unit, write the list of spans it covers. Asm->OutStreamer->AddComment("Length of ARange Set"); - Asm->EmitInt32(ContentSize); + Asm->emitInt32(ContentSize); Asm->OutStreamer->AddComment("DWARF Arange version number"); - Asm->EmitInt16(dwarf::DW_ARANGES_VERSION); + Asm->emitInt16(dwarf::DW_ARANGES_VERSION); Asm->OutStreamer->AddComment("Offset Into Debug Info Section"); - Asm->emitDwarfSymbolReference(CU->getLabelBegin()); + emitSectionReference(*CU); Asm->OutStreamer->AddComment("Address Size (in bytes)"); - Asm->EmitInt8(PtrSize); + Asm->emitInt8(PtrSize); Asm->OutStreamer->AddComment("Segment Size (in bytes)"); - Asm->EmitInt8(0); + Asm->emitInt8(0); Asm->OutStreamer->emitFill(Padding, 0xff); @@ -1867,17 +2004,151 @@ void DwarfDebug::emitDebugARanges() { } } -/// Emit address ranges into a debug ranges section. +/// Emit a single range list. We handle both DWARF v5 and earlier. +static void emitRangeList(AsmPrinter *Asm, DwarfCompileUnit *CU, + const RangeSpanList &List) { + + auto DwarfVersion = CU->getDwarfVersion(); + // Emit our symbol so we can find the beginning of the range. + Asm->OutStreamer->EmitLabel(List.getSym()); + // Gather all the ranges that apply to the same section so they can share + // a base address entry. + MapVector<const MCSection *, std::vector<const RangeSpan *>> SectionRanges; + // Size for our labels. + auto Size = Asm->MAI->getCodePointerSize(); + + for (const RangeSpan &Range : List.getRanges()) + SectionRanges[&Range.getStart()->getSection()].push_back(&Range); + + auto *CUBase = CU->getBaseAddress(); + bool BaseIsSet = false; + for (const auto &P : SectionRanges) { + // Don't bother with a base address entry if there's only one range in + // this section in this range list - for example ranges for a CU will + // usually consist of single regions from each of many sections + // (-ffunction-sections, or just C++ inline functions) except under LTO + // or optnone where there may be holes in a single CU's section + // contributions. + auto *Base = CUBase; + if (!Base && P.second.size() > 1 && + (UseDwarfRangesBaseAddressSpecifier || DwarfVersion >= 5)) { + BaseIsSet = true; + // FIXME/use care: This may not be a useful base address if it's not + // the lowest address/range in this object. + Base = P.second.front()->getStart(); + if (DwarfVersion >= 5) { + Asm->OutStreamer->AddComment("DW_RLE_base_address"); + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_base_address, 1); + } else + Asm->OutStreamer->EmitIntValue(-1, Size); + Asm->OutStreamer->AddComment(" base address"); + Asm->OutStreamer->EmitSymbolValue(Base, Size); + } else if (BaseIsSet && DwarfVersion < 5) { + BaseIsSet = false; + assert(!Base); + Asm->OutStreamer->EmitIntValue(-1, Size); + Asm->OutStreamer->EmitIntValue(0, Size); + } + + for (const auto *RS : P.second) { + const MCSymbol *Begin = RS->getStart(); + const MCSymbol *End = RS->getEnd(); + assert(Begin && "Range without a begin symbol?"); + assert(End && "Range without an end symbol?"); + if (Base) { + if (DwarfVersion >= 5) { + // Emit DW_RLE_offset_pair when we have a base. + Asm->OutStreamer->AddComment("DW_RLE_offset_pair"); + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_offset_pair, 1); + 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 (DwarfVersion >= 5) { + Asm->OutStreamer->AddComment("DW_RLE_start_length"); + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_start_length, 1); + Asm->OutStreamer->AddComment(" start"); + Asm->OutStreamer->EmitSymbolValue(Begin, Size); + Asm->OutStreamer->AddComment(" length"); + Asm->EmitLabelDifferenceAsULEB128(End, Begin); + } else { + Asm->OutStreamer->EmitSymbolValue(Begin, Size); + Asm->OutStreamer->EmitSymbolValue(End, Size); + } + } + } + if (DwarfVersion >= 5) { + Asm->OutStreamer->AddComment("DW_RLE_end_of_list"); + Asm->OutStreamer->EmitIntValue(dwarf::DW_RLE_end_of_list, 1); + } else { + // Terminate the list with two 0 values. + Asm->OutStreamer->EmitIntValue(0, Size); + Asm->OutStreamer->EmitIntValue(0, Size); + } +} + +// Emit the header of a DWARF 5 range 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, DwarfFile &Holder) { + // The length is described by a starting label right after the length field + // and an end label. + MCSymbol *TableStart = Asm->createTempSymbol("debug_rnglist_table_start"); + MCSymbol *TableEnd = Asm->createTempSymbol("debug_rnglist_table_end"); + // Build the range table header, which starts with the length field. + Asm->EmitLabelDifference(TableEnd, TableStart, 4); + Asm->OutStreamer->EmitLabel(TableStart); + // Version number (DWARF v5 and later). + Asm->emitInt16(Asm->OutStreamer->getContext().getDwarfVersion()); + // Address size. + Asm->emitInt8(Asm->MAI->getCodePointerSize()); + // Segment selector size. + Asm->emitInt8(0); + + MCSymbol *RnglistTableBaseSym = Holder.getRnglistsTableBaseSym(); + + // FIXME: Generate the offsets table and use DW_FORM_rnglistx with the + // DW_AT_ranges attribute. Until then set the number of offsets to 0. + Asm->emitInt32(0); + Asm->OutStreamer->EmitLabel(RnglistTableBaseSym); + return TableEnd; +} + +/// Emit address ranges into the .debug_ranges section or into the DWARF v5 +/// .debug_rnglists section. void DwarfDebug::emitDebugRanges() { if (CUMap.empty()) return; - // Start the dwarf ranges section. - Asm->OutStreamer->SwitchSection( - Asm->getObjFileLowering().getDwarfRangesSection()); + auto NoRangesPresent = [this]() { + return llvm::all_of( + CUMap, [](const decltype(CUMap)::const_iterator::value_type &Pair) { + return Pair.second->getRangeLists().empty(); + }); + }; - // Size for our labels. - unsigned char Size = Asm->MAI->getCodePointerSize(); + if (!useRangesSection()) { + assert(NoRangesPresent() && "No debug ranges expected."); + return; + } + + if (getDwarfVersion() >= 5 && NoRangesPresent()) + return; + + // Start the dwarf ranges section. + MCSymbol *TableEnd = nullptr; + if (getDwarfVersion() >= 5) { + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfRnglistsSection()); + TableEnd = emitRnglistsTableHeader(Asm, useSplitDwarf() ? SkeletonHolder + : InfoHolder); + } else + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getDwarfRangesSection()); // Grab the specific ranges for the compile units in the module. for (const auto &I : CUMap) { @@ -1887,61 +2158,12 @@ void DwarfDebug::emitDebugRanges() { TheCU = Skel; // Iterate over the misc ranges for the compile units in the module. - for (const RangeSpanList &List : TheCU->getRangeLists()) { - // Emit our symbol so we can find the beginning of the range. - Asm->OutStreamer->EmitLabel(List.getSym()); - - // Gather all the ranges that apply to the same section so they can share - // a base address entry. - MapVector<const MCSection *, std::vector<const RangeSpan *>> MV; - for (const RangeSpan &Range : List.getRanges()) { - MV[&Range.getStart()->getSection()].push_back(&Range); - } - - auto *CUBase = TheCU->getBaseAddress(); - bool BaseIsSet = false; - for (const auto &P : MV) { - // Don't bother with a base address entry if there's only one range in - // this section in this range list - for example ranges for a CU will - // usually consist of single regions from each of many sections - // (-ffunction-sections, or just C++ inline functions) except under LTO - // or optnone where there may be holes in a single CU's section - // contrubutions. - auto *Base = CUBase; - if (!Base && P.second.size() > 1 && - UseDwarfRangesBaseAddressSpecifier) { - BaseIsSet = true; - // FIXME/use care: This may not be a useful base address if it's not - // the lowest address/range in this object. - Base = P.second.front()->getStart(); - Asm->OutStreamer->EmitIntValue(-1, Size); - Asm->OutStreamer->EmitSymbolValue(Base, Size); - } else if (BaseIsSet) { - BaseIsSet = false; - Asm->OutStreamer->EmitIntValue(-1, Size); - Asm->OutStreamer->EmitIntValue(0, Size); - } - - for (const auto *RS : P.second) { - const MCSymbol *Begin = RS->getStart(); - const MCSymbol *End = RS->getEnd(); - assert(Begin && "Range without a begin symbol?"); - assert(End && "Range without an end symbol?"); - if (Base) { - Asm->EmitLabelDifference(Begin, Base, Size); - Asm->EmitLabelDifference(End, Base, Size); - } else { - Asm->OutStreamer->EmitSymbolValue(Begin, Size); - Asm->OutStreamer->EmitSymbolValue(End, Size); - } - } - } - - // And terminate the list with two 0 values. - Asm->OutStreamer->EmitIntValue(0, Size); - Asm->OutStreamer->EmitIntValue(0, Size); - } + for (const RangeSpanList &List : TheCU->getRangeLists()) + emitRangeList(Asm, TheCU, List); } + + if (TableEnd) + Asm->OutStreamer->EmitLabel(TableEnd); } void DwarfDebug::handleMacroNodes(DIMacroNodeArray Nodes, DwarfCompileUnit &U) { @@ -1963,20 +2185,17 @@ void DwarfDebug::emitMacro(DIMacro &M) { Asm->OutStreamer->EmitBytes(Name); if (!Value.empty()) { // There should be one space between macro name and macro value. - Asm->EmitInt8(' '); + Asm->emitInt8(' '); Asm->OutStreamer->EmitBytes(Value); } - Asm->EmitInt8('\0'); + 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()); - DIFile *File = F.getFile(); - unsigned FID = - U.getOrCreateSourceID(File->getFilename(), File->getDirectory()); - Asm->EmitULEB128(FID); + Asm->EmitULEB128(U.getOrCreateSourceID(F.getFile())); handleMacroNodes(F.getElements(), U); Asm->EmitULEB128(dwarf::DW_MACINFO_end_file); } @@ -1995,11 +2214,14 @@ void DwarfDebug::emitDebugMacinfo() { auto *SkCU = TheCU.getSkeleton(); DwarfCompileUnit &U = SkCU ? *SkCU : TheCU; auto *CUNode = cast<DICompileUnit>(P.first); - Asm->OutStreamer->EmitLabel(U.getMacroLabelBegin()); - handleMacroNodes(CUNode->getMacros(), U); + 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); + Asm->emitInt8(0); } // DWARF5 Experimental Separate Dwarf emitters. @@ -2017,9 +2239,6 @@ void DwarfDebug::initSkeletonUnit(const DwarfUnit &U, DIE &Die, SkeletonHolder.addUnit(std::move(NewU)); } -// This DIE has the following attributes: DW_AT_comp_dir, DW_AT_stmt_list, -// DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_dwo_name, DW_AT_dwo_id, -// DW_AT_addr_base, DW_AT_ranges_base. DwarfCompileUnit &DwarfDebug::constructSkeletonCU(const DwarfCompileUnit &CU) { auto OwnedUnit = llvm::make_unique<DwarfCompileUnit>( @@ -2029,6 +2248,9 @@ DwarfCompileUnit &DwarfDebug::constructSkeletonCU(const DwarfCompileUnit &CU) { NewCU.initStmtList(); + if (useSegmentedStringOffsetsTable()) + NewCU.addStringOffsetsStart(); + initSkeletonUnit(CU, NewCU.getUnitDie(), std::move(OwnedUnit)); return NewCU; @@ -2051,26 +2273,37 @@ void DwarfDebug::emitDebugAbbrevDWO() { void DwarfDebug::emitDebugLineDWO() { assert(useSplitDwarf() && "No split dwarf?"); - Asm->OutStreamer->SwitchSection( + SplitTypeUnitFileTable.Emit( + *Asm->OutStreamer, MCDwarfLineTableParams(), Asm->getObjFileLowering().getDwarfLineDWOSection()); - SplitTypeUnitFileTable.Emit(*Asm->OutStreamer, MCDwarfLineTableParams()); +} + +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); + OffSec, /* UseRelativeOffsets = */ false); } MCDwarfDwoLineTable *DwarfDebug::getDwoLineTable(const DwarfCompileUnit &CU) { if (!useSplitDwarf()) return nullptr; - if (SingleCU) - SplitTypeUnitFileTable.setCompilationDir(CU.getCUNode()->getDirectory()); + const DICompileUnit *DIUnit = CU.getCUNode(); + SplitTypeUnitFileTable.maybeSetRootFile( + DIUnit->getDirectory(), DIUnit->getFilename(), + CU.getMD5AsBytes(DIUnit->getFile()), DIUnit->getSource()); return &SplitTypeUnitFileTable; } @@ -2119,10 +2352,16 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, if (useSplitDwarf()) NewTU.setSection(Asm->getObjFileLowering().getDwarfTypesDWOSection()); else { - CU.applyStmtList(UnitDie); NewTU.setSection(Asm->getObjFileLowering().getDwarfTypesSection(Signature)); + // 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) { @@ -2157,32 +2396,50 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU, CU.addDIETypeSignature(RefDie, Signature); } -// Accelerator table mutators - add each name along with its companion -// DIE to the proper table while ensuring that the name that we're going -// to reference is in the string table. We do this since the names we -// add may not only be identical to the names in the DIE. -void DwarfDebug::addAccelName(StringRef Name, const DIE &Die) { - if (!useDwarfAccelTables()) +// 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 <typename DataT> +void DwarfDebug::addAccelNameImpl(AccelTable<DataT> &AppleAccel, StringRef Name, + const DIE &Die) { + if (getAccelTableKind() == AccelTableKind::None) return; - AccelNames.AddName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + + 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(StringRef Name, const DIE &Die) { + addAccelNameImpl(AccelNames, Name, Die); } void DwarfDebug::addAccelObjC(StringRef Name, const DIE &Die) { - if (!useDwarfAccelTables()) - return; - AccelObjC.AddName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + // ObjC names go only into the Apple accelerator tables. + if (getAccelTableKind() == AccelTableKind::Apple) + addAccelNameImpl(AccelObjC, Name, Die); } void DwarfDebug::addAccelNamespace(StringRef Name, const DIE &Die) { - if (!useDwarfAccelTables()) - return; - AccelNamespace.AddName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + addAccelNameImpl(AccelNamespace, Name, Die); } void DwarfDebug::addAccelType(StringRef Name, const DIE &Die, char Flags) { - if (!useDwarfAccelTables()) - return; - AccelTypes.AddName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die); + addAccelNameImpl(AccelTypes, Name, Die); } uint16_t DwarfDebug::getDwarfVersion() const { |