DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M)
: Asm(A), MMI(Asm->MMI), FirstCU(0), PrevLabel(NULL), GlobalRangeCount(0),
- InfoHolder(A, "info_string", DIEValueAllocator), HasCURanges(false),
+ InfoHolder(A, "info_string", DIEValueAllocator),
UsedNonDefaultText(false),
SkeletonHolder(A, "skel_string", DIEValueAllocator) {
// Emit offset in .debug_range as a relocatable label. emitDIE will handle
// emitting it appropriately.
MCSymbol *RangeSym = Asm->GetTempSymbol("debug_ranges", GlobalRangeCount++);
- addSectionLabel(Asm, TheCU, ScopeDIE, dwarf::DW_AT_ranges, RangeSym,
- DwarfDebugRangeSectionSym);
+
+ // Under fission, ranges are specified by constant offsets relative to the
+ // CU's DW_AT_GNU_ranges_base.
+ if (useSplitDwarf())
+ TheCU->addSectionDelta(ScopeDIE, dwarf::DW_AT_ranges, RangeSym,
+ DwarfDebugRangeSectionSym);
+ else
+ addSectionLabel(Asm, TheCU, ScopeDIE, dwarf::DW_AT_ranges, RangeSym,
+ DwarfDebugRangeSectionSym);
RangeSpanList List(RangeSym);
for (const InsnRange &R : Range) {
if (!Scope || !Scope->getScopeNode())
return NULL;
- // Unique scope where applicable.
- DIScope DS(resolve(DIScope(Scope->getScopeNode()).getRef()));
+ DIScope DS(Scope->getScopeNode());
SmallVector<DIE *, 8> Children;
DIE *ObjectPointer = NULL;
dwarf::DW_FORM_data8, ID);
}
- // If we have code split among multiple sections or we've requested
- // it 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: Also add a high pc if we can.
- // FIXME: We should use ranges if we have multiple compile units or
- // allow reordering of code ala .subsections_via_symbols in mach-o.
+ // 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 : static_cast<DwarfCompileUnit *>(TheU);
- if (useCURanges() && TheU->getRanges().size()) {
- addSectionLabel(Asm, U, U->getUnitDie(), dwarf::DW_AT_ranges,
- Asm->GetTempSymbol("cu_ranges", U->getUniqueID()),
- DwarfDebugRangeSectionSym);
-
- // 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->addUInt(U->getUnitDie(), dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr,
- 0);
+ unsigned NumRanges = TheU->getRanges().size();
+ if (NumRanges) {
+ if (NumRanges > 1) {
+ addSectionLabel(Asm, U, U->getUnitDie(), dwarf::DW_AT_ranges,
+ Asm->GetTempSymbol("cu_ranges", U->getUniqueID()),
+ DwarfDebugRangeSectionSym);
+
+ // 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 {
+ RangeSpan &Range = TheU->getRanges().back();
+ U->addLocalLabelAddress(U->getUnitDie(), dwarf::DW_AT_low_pc,
+ Range.getStart());
+ U->addLabelDelta(U->getUnitDie(), dwarf::DW_AT_high_pc,
+ Range.getEnd(), Range.getStart());
+ }
+ }
}
}
// Insert a final terminator.
SectionMap[Section].push_back(SymbolCU(NULL, Sym));
}
-
- // For now only turn on CU ranges if we have -ffunction-sections enabled,
- // we've emitted a function into a unique section, or we're using LTO. If
- // we're using LTO then we can't know that any particular function in the
- // module is correlated to a particular CU and so we need to be conservative.
- // At this point all sections should be finalized except for dwarf sections.
- HasCURanges = UsedNonDefaultText || (CUMap.size() > 1) ||
- TargetMachine::getFunctionSections();
}
// Emit all Dwarf sections that should come after the content.
// Get .debug_loc entry for the instruction range starting at MI.
static DebugLocEntry getDebugLocEntry(AsmPrinter *Asm,
- const MCSymbol *FLabel,
- const MCSymbol *SLabel,
- const MachineInstr *MI) {
+ const MCSymbol *FLabel,
+ const MCSymbol *SLabel,
+ const MachineInstr *MI,
+ DwarfCompileUnit *Unit) {
const MDNode *Var = MI->getOperand(MI->getNumOperands() - 1).getMetadata();
assert(MI->getNumOperands() == 3);
MLoc.set(MI->getOperand(0).getReg());
else
MLoc.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm());
- return DebugLocEntry(FLabel, SLabel, MLoc, Var);
+ return DebugLocEntry(FLabel, SLabel, MLoc, Var, Unit);
}
if (MI->getOperand(0).isImm())
- return DebugLocEntry(FLabel, SLabel, MI->getOperand(0).getImm());
+ return DebugLocEntry(FLabel, SLabel, MI->getOperand(0).getImm(), Unit);
if (MI->getOperand(0).isFPImm())
- return DebugLocEntry(FLabel, SLabel, MI->getOperand(0).getFPImm());
+ return DebugLocEntry(FLabel, SLabel, MI->getOperand(0).getFPImm(), Unit);
if (MI->getOperand(0).isCImm())
- return DebugLocEntry(FLabel, SLabel, MI->getOperand(0).getCImm());
+ return DebugLocEntry(FLabel, SLabel, MI->getOperand(0).getCImm(), Unit);
llvm_unreachable("Unexpected 3 operand DBG_VALUE instruction!");
}
// Handle multiple DBG_VALUE instructions describing one variable.
RegVar->setDotDebugLocOffset(DotDebugLocEntries.size());
+ SmallVector<DebugLocEntry, 4> DebugLoc;
for (SmallVectorImpl<const MachineInstr *>::const_iterator
HI = History.begin(),
HE = History.end();
}
// The value is valid until the next DBG_VALUE or clobber.
- DotDebugLocEntries.push_back(
- getDebugLocEntry(Asm, FLabel, SLabel, Begin));
+ LexicalScope *FnScope = LScopes.getCurrentFunctionScope();
+ DwarfCompileUnit *TheCU = SPMap.lookup(FnScope->getScopeNode());
+ DebugLocEntry Loc = getDebugLocEntry(Asm, FLabel, SLabel, Begin, TheCU);
+ if (DebugLoc.empty() || !DebugLoc.back().Merge(Loc))
+ DebugLoc.push_back(std::move(Loc));
}
- DotDebugLocEntries.push_back(DebugLocEntry());
+ DotDebugLocEntries.push_back(std::move(DebugLoc));
}
// Collect info for variables that were optimized out.
// Grab the lexical scopes for the function, if we don't have any of those
// then we're not going to be able to do anything.
LScopes.initialize(*MF);
- if (LScopes.empty()) {
- // If we don't have a lexical scope for this function then there will
- // be a hole in the range information. Keep note of this.
- UsedNonDefaultText = true;
+ if (LScopes.empty())
return;
- }
assert(UserVariables.empty() && DbgValues.empty() && "Maps weren't cleaned");
else
Asm->OutStreamer.getContext().setDwarfCompileUnitID(TheCU->getUniqueID());
- // Check the current section against the standard text section. If different
- // keep track so that we will know when we're emitting functions into multiple
- // sections.
- if (Asm->getObjFileLowering().getTextSection() != Asm->getCurrentSection())
- UsedNonDefaultText = true;
-
// Emit a label for the function so that we have a beginning address.
FunctionBeginSym = Asm->GetTempSymbol("func_begin", Asm->getFunctionNumber());
// Assumes in correct section after the entry point.
assert(CurFn != 0);
if (!MMI->hasDebugInfo() || LScopes.empty()) {
+ // If we don't have a lexical scope 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.
+ PrevSection = nullptr;
+ PrevCU = nullptr;
CurFn = 0;
return;
}
// Add the range of this function to the list of ranges for the CU.
RangeSpan Span(FunctionBeginSym, FunctionEndSym);
TheCU->addRange(std::move(Span));
+ PrevSection = Asm->getCurrentSection();
+ PrevCU = TheCU;
// Clear debug info
for (auto &I : ScopeVariables)
// Emit the various dwarf units to the unit section USection with
// the abbreviations going into ASection.
-void DwarfFile::emitUnits(DwarfDebug *DD, const MCSection *ASection,
- const MCSymbol *ASectionSym) {
+void DwarfFile::emitUnits(DwarfDebug *DD, const MCSymbol *ASectionSym) {
for (DwarfUnit *TheU : CUs) {
DIE *Die = TheU->getUnitDie();
const MCSection *USection = TheU->getSection();
Asm->OutStreamer.AddComment("Length of Unit");
Asm->EmitInt32(TheU->getHeaderSize() + Die->getSize());
- TheU->emitHeader(ASection, ASectionSym);
+ TheU->emitHeader(ASectionSym);
DD->emitDIE(Die);
Asm->OutStreamer.EmitLabel(TheU->getLabelEnd());
void DwarfDebug::emitDebugInfo() {
DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder;
- Holder.emitUnits(this, Asm->getObjFileLowering().getDwarfAbbrevSection(),
- DwarfAbbrevSectionSym);
+ Holder.emitUnits(this, DwarfAbbrevSectionSym);
}
// Emit the abbreviation section.
// Emit locations into the debug loc section.
void DwarfDebug::emitDebugLoc() {
- if (DotDebugLocEntries.empty())
- return;
-
- for (SmallVectorImpl<DebugLocEntry>::iterator
- I = DotDebugLocEntries.begin(),
- E = DotDebugLocEntries.end();
- I != E; ++I) {
- DebugLocEntry &Entry = *I;
- if (I + 1 != DotDebugLocEntries.end())
- Entry.Merge(I + 1);
- }
-
// Start the dwarf loc section.
Asm->OutStreamer.SwitchSection(
Asm->getObjFileLowering().getDwarfLocSection());
unsigned char Size = Asm->getDataLayout().getPointerSize();
- Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("debug_loc", 0));
- unsigned index = 1;
- for (SmallVectorImpl<DebugLocEntry>::const_iterator
- I = DotDebugLocEntries.begin(),
- E = DotDebugLocEntries.end();
- I != E; ++I, ++index) {
- const DebugLocEntry &Entry = *I;
- if (Entry.isMerged())
- continue;
-
- if (Entry.isEmpty()) {
- Asm->OutStreamer.EmitIntValue(0, Size);
- Asm->OutStreamer.EmitIntValue(0, Size);
- Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("debug_loc", index));
- } else {
- // Set up the range.
- Asm->OutStreamer.EmitSymbolValue(Entry.getBeginSym(), Size);
- Asm->OutStreamer.EmitSymbolValue(Entry.getEndSym(), Size);
+ unsigned index = 0;
+ for (const auto &DebugLoc : DotDebugLocEntries) {
+ Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("debug_loc", index));
+ for (const auto &Entry : DebugLoc) {
+ // Set up the range. This range is relative to the entry point of the
+ // compile unit. This is a hard coded 0 for low_pc when we're emitting
+ // ranges, or the DW_AT_low_pc on the compile unit otherwise.
+ const DwarfCompileUnit *CU = Entry.getCU();
+ if (CU->getRanges().size() == 1) {
+ // Grab the begin symbol from the first range as our base.
+ const MCSymbol *Base = CU->getRanges()[0].getStart();
+ Asm->EmitLabelDifference(Entry.getBeginSym(), Base, Size);
+ Asm->EmitLabelDifference(Entry.getEndSym(), Base, Size);
+ } else {
+ Asm->OutStreamer.EmitSymbolValue(Entry.getBeginSym(), Size);
+ Asm->OutStreamer.EmitSymbolValue(Entry.getEndSym(), Size);
+ }
Asm->OutStreamer.AddComment("Loc expr size");
MCSymbol *begin = Asm->OutStreamer.getContext().CreateTempSymbol();
MCSymbol *end = Asm->OutStreamer.getContext().CreateTempSymbol();
// Close the range.
Asm->OutStreamer.EmitLabel(end);
}
+ Asm->OutStreamer.EmitIntValue(0, Size);
+ Asm->OutStreamer.EmitIntValue(0, Size);
+ ++index;
}
}
}
// Now emit a range for the CU itself.
- if (useCURanges() && TheCU->getRanges().size()) {
+ if (TheCU->getRanges().size() > 1) {
Asm->OutStreamer.EmitLabel(
Asm->GetTempSymbol("cu_ranges", TheCU->getUniqueID()));
for (const RangeSpan &Range : TheCU->getRanges()) {
NewU->addLocalString(Die, dwarf::DW_AT_GNU_dwo_name,
U->getCUNode().getSplitDebugFilename());
- // Relocate to the beginning of the addr_base section, else 0 for the
- // beginning of the one for this compile unit.
- if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
- NewU->addSectionLabel(Die, dwarf::DW_AT_GNU_addr_base, DwarfAddrSectionSym);
- else
- NewU->addSectionOffset(Die, dwarf::DW_AT_GNU_addr_base, 0);
-
if (!CompilationDir.empty())
NewU->addLocalString(Die, dwarf::DW_AT_comp_dir, CompilationDir);
// 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_ranges_base, DW_AT_addr_base.
-// TODO: Implement DW_AT_ranges_base.
+// DW_AT_addr_base, DW_AT_ranges_base.
DwarfCompileUnit *DwarfDebug::constructSkeletonCU(const DwarfCompileUnit *CU) {
DIE *Die = new DIE(dwarf::DW_TAG_compile_unit);
initSkeletonUnit(CU, Die, NewCU);
+ // Relocate to the beginning of the addr_base section, else 0 for the
+ // beginning of the one for this compile unit.
+ // We could shave off some space if we deferred adding these attributes until
+ // the end of the CU to see if we have a non-empty debug_addr and debug_ranges
+ // sections so we don't bother with extra attributes and relocations.
+ if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) {
+ NewCU->addSectionLabel(Die, dwarf::DW_AT_GNU_addr_base, DwarfAddrSectionSym);
+ NewCU->addSectionLabel(Die, dwarf::DW_AT_GNU_ranges_base, DwarfDebugRangeSectionSym);
+ } else {
+ NewCU->addSectionOffset(Die, dwarf::DW_AT_GNU_addr_base, 0);
+ NewCU->addSectionOffset(Die, dwarf::DW_AT_GNU_ranges_base, 0);
+ }
+
return NewCU;
}
// compile units that would normally be in debug_info.
void DwarfDebug::emitDebugInfoDWO() {
assert(useSplitDwarf() && "No split dwarf debug info?");
- InfoHolder.emitUnits(this,
- Asm->getObjFileLowering().getDwarfAbbrevDWOSection(),
- DwarfAbbrevDWOSectionSym);
+ InfoHolder.emitUnits(this, nullptr);
}
// Emit the .debug_abbrev.dwo section for separated dwarf. This contains the