//
//===----------------------------------------------------------------------===//
-#include "ByteStreamer.h"
#include "DwarfDebug.h"
+
+#include "ByteStreamer.h"
+#include "DwarfCompileUnit.h"
#include "DIE.h"
#include "DIEHash.h"
#include "DwarfUnit.h"
GlobalRangeCount(0), InfoHolder(A, "info_string", DIEValueAllocator),
UsedNonDefaultText(false),
SkeletonHolder(A, "skel_string", DIEValueAllocator),
+ IsDarwin(Triple(A->getTargetTriple()).isOSDarwin()),
AccelNames(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset,
dwarf::DW_FORM_data4)),
AccelObjC(DwarfAccelTable::Atom(dwarf::DW_ATOM_die_offset,
// Turn on accelerator tables for Darwin by default, pubnames by
// default for non-Darwin, and handle split dwarf.
- bool IsDarwin = Triple(A->getTargetTriple()).isOSDarwin();
-
if (DwarfAccelTables == Default)
HasDwarfAccelTables = IsDarwin;
else
DIE *SPDie = SPCU.getOrCreateSubprogramDIE(SP);
attachLowHighPC(SPCU, *SPDie, FunctionBeginSym, FunctionEndSym);
-
- const TargetRegisterInfo *RI = Asm->TM.getSubtargetImpl()->getRegisterInfo();
- MachineLocation Location(RI->getFrameRegister(*Asm->MF));
- SPCU.addAddress(*SPDie, dwarf::DW_AT_frame_base, Location);
+ if (!CurFn->getTarget().Options.DisableFramePointerElim(*CurFn))
+ SPCU.addFlag(*SPDie, dwarf::DW_AT_APPLE_omit_frame_ptr);
+
+ // Only include DW_AT_frame_base in full debug info
+ if (SPCU.getCUNode().getEmissionKind() != DIBuilder::LineTablesOnly) {
+ const TargetRegisterInfo *RI =
+ Asm->TM.getSubtargetImpl()->getRegisterInfo();
+ MachineLocation Location(RI->getFrameRegister(*Asm->MF));
+ SPCU.addAddress(*SPDie, dwarf::DW_AT_frame_base, Location);
+ }
// Add name to the name table, we do this here because we're guaranteed
// to have concrete versions of our DW_TAG_subprogram nodes.
DIDescriptor());
SPCU.applySubprogramAttributesToDefinition(SP, *AbsDef);
- SPCU.addUInt(*AbsDef, dwarf::DW_AT_inline, None, dwarf::DW_INL_inlined);
+ if (TheCU.getCUNode().getEmissionKind() != DIBuilder::LineTablesOnly)
+ SPCU.addUInt(*AbsDef, dwarf::DW_AT_inline, None, dwarf::DW_INL_inlined);
if (DIE *ObjectPointer = createAndAddScopeChildren(SPCU, Scope, *AbsDef))
SPCU.addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
}
-DIE &DwarfDebug::constructSubprogramScopeDIE(DwarfCompileUnit &TheCU,
+void DwarfDebug::constructSubprogramScopeDIE(DwarfCompileUnit &TheCU,
LexicalScope *Scope) {
assert(Scope && Scope->getScopeNode());
assert(!Scope->getInlinedAt());
if (ObjectPointer)
TheCU.addDIEEntry(ScopeDIE, dwarf::DW_AT_object_pointer, *ObjectPointer);
-
- return ScopeDIE;
}
// Construct a DIE for this scope.
ScopesWithImportedEntities.end(), less_first());
DIArray GVs = CUNode.getGlobalVariables();
for (unsigned i = 0, e = GVs.getNumElements(); i != e; ++i)
- CU.createGlobalVariableDIE(DIGlobalVariable(GVs.getElement(i)));
+ CU.getOrCreateGlobalVariableDIE(DIGlobalVariable(GVs.getElement(i)));
DIArray SPs = CUNode.getSubprograms();
for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i)
SPMap.insert(std::make_pair(SPs.getElement(i), &CU));
// If this subprogram has an abstract definition, reference that
SPCU->addDIEEntry(*D, dwarf::DW_AT_abstract_origin, *AbsSPDIE);
} else {
- if (!D)
+ if (!D && TheCU.getEmissionKind() != DIBuilder::LineTablesOnly)
// Lazily construct the subprogram if we didn't see either concrete or
- // inlined versions during codegen.
+ // inlined versions during codegen. (except in -gmlt ^ where we want
+ // to omit these entirely)
D = SPCU->getOrCreateSubprogramDIE(SP);
- // And attach the attributes
- SPCU->applySubprogramAttributesToDefinition(SP, *D);
+ if (D)
+ // And attach the attributes
+ SPCU->applySubprogramAttributesToDefinition(SP, *D);
}
}
}
for (unsigned vi = 0, ve = Variables.getNumElements(); vi != ve; ++vi) {
DIVariable DV(Variables.getElement(vi));
assert(DV.isVariable());
- DbgVariable NewVar(DV, this);
+ DbgVariable NewVar(DV, DIExpression(nullptr), this);
auto VariableDie = SPCU->constructVariableDIE(NewVar);
SPCU->applyVariableAttributes(NewVar, *VariableDie);
SPDIE->addChild(std::move(VariableDie));
void DwarfDebug::createAbstractVariable(const DIVariable &Var,
LexicalScope *Scope) {
- auto AbsDbgVariable = make_unique<DbgVariable>(Var, this);
+ auto AbsDbgVariable = make_unique<DbgVariable>(Var, DIExpression(), this);
addScopeVariable(Scope, AbsDbgVariable.get());
AbstractVariables[Var] = std::move(AbsDbgVariable);
}
continue;
Processed.insert(VI.Var);
DIVariable DV(VI.Var);
+ DIExpression Expr(VI.Expr);
LexicalScope *Scope = LScopes.findLexicalScope(VI.Loc);
// If variable scope is not found then skip this variable.
continue;
ensureAbstractVariableIsCreatedIfScoped(DV, Scope->getScopeNode());
- ConcreteVariables.push_back(make_unique<DbgVariable>(DV, this));
+ ConcreteVariables.push_back(make_unique<DbgVariable>(DV, Expr, this));
DbgVariable *RegVar = ConcreteVariables.back().get();
RegVar->setFrameIndex(VI.Slot);
addScopeVariable(Scope, RegVar);
// Get .debug_loc entry for the instruction range starting at MI.
static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) {
+ const MDNode *Expr = MI->getDebugExpression();
const MDNode *Var = MI->getDebugVariable();
- assert(MI->getNumOperands() == 3);
+ assert(MI->getNumOperands() == 4);
if (MI->getOperand(0).isReg()) {
MachineLocation MLoc;
// If the second operand is an immediate, this is a
MLoc.set(MI->getOperand(0).getReg());
else
MLoc.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm());
- return DebugLocEntry::Value(Var, MLoc);
+ return DebugLocEntry::Value(Var, Expr, MLoc);
}
if (MI->getOperand(0).isImm())
- return DebugLocEntry::Value(Var, MI->getOperand(0).getImm());
+ return DebugLocEntry::Value(Var, Expr, MI->getOperand(0).getImm());
if (MI->getOperand(0).isFPImm())
- return DebugLocEntry::Value(Var, MI->getOperand(0).getFPImm());
+ return DebugLocEntry::Value(Var, Expr, MI->getOperand(0).getFPImm());
if (MI->getOperand(0).isCImm())
- return DebugLocEntry::Value(Var, MI->getOperand(0).getCImm());
+ return DebugLocEntry::Value(Var, Expr, MI->getOperand(0).getCImm());
- llvm_unreachable("Unexpected 3 operand DBG_VALUE instruction!");
+ llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!");
}
/// Determine whether two variable pieces overlap.
-static bool piecesOverlap(DIVariable P1, DIVariable P2) {
+static bool piecesOverlap(DIExpression P1, DIExpression P2) {
if (!P1.isVariablePiece() || !P2.isVariablePiece())
return true;
unsigned l1 = P1.getPieceOffset();
}
// If this piece overlaps with any open ranges, truncate them.
- DIVariable DIVar = Begin->getDebugVariable();
+ DIExpression DIExpr = Begin->getDebugExpression();
auto Last = std::remove_if(OpenRanges.begin(), OpenRanges.end(),
[&](DebugLocEntry::Value R) {
- return piecesOverlap(DIVar, R.getVariable());
- });
+ return piecesOverlap(DIExpr, R.getExpression());
+ });
OpenRanges.erase(Last, OpenRanges.end());
const MCSymbol *StartLabel = getLabelBeforeInsn(Begin);
bool couldMerge = false;
// If this is a piece, it may belong to the current DebugLocEntry.
- if (DIVar.isVariablePiece()) {
+ if (DIExpr.isVariablePiece()) {
// Add this value to the list of open ranges.
OpenRanges.push_back(Value);
if (PrevEntry != DebugLoc.rend() && PrevEntry->MergeRanges(*CurEntry))
DebugLoc.pop_back();
- DEBUG(dbgs() << "Values:\n";
- for (auto Value : CurEntry->getValues())
- Value.getVariable()->dump();
- dbgs() << "-----\n");
+ DEBUG({
+ dbgs() << CurEntry->getValues().size() << " Values:\n";
+ for (auto Value : CurEntry->getValues()) {
+ Value.getVariable()->dump();
+ Value.getExpression()->dump();
+ }
+ dbgs() << "-----\n";
+ });
}
}
if (!Scope)
continue;
- Processed.insert(getEntireVariable(DV));
+ Processed.insert(DV);
const MachineInstr *MInsn = Ranges.front().first;
assert(MInsn->isDebugValue() && "History must begin with debug value");
ensureAbstractVariableIsCreatedIfScoped(DV, Scope->getScopeNode());
continue;
if (LexicalScope *Scope = LScopes.findLexicalScope(DV.getContext())) {
ensureAbstractVariableIsCreatedIfScoped(DV, Scope->getScopeNode());
- ConcreteVariables.push_back(make_unique<DbgVariable>(DV, this));
+ DIExpression NoExpr;
+ ConcreteVariables.push_back(make_unique<DbgVariable>(DV, NoExpr, this));
addScopeVariable(Scope, ConcreteVariables.back().get());
}
}
// The first mention of a function argument gets the FunctionBeginSym
// label, so arguments are visible when breaking at function entry.
- DIVariable DV(Ranges.front().first->getDebugVariable());
- if (DV.isVariable() && DV.getTag() == dwarf::DW_TAG_arg_variable &&
- getDISubprogram(DV.getContext()).describes(MF->getFunction())) {
- if (!DV.isVariablePiece())
- LabelsBeforeInsn[Ranges.front().first] = FunctionBeginSym;
- else {
+ DIVariable DIVar(Ranges.front().first->getDebugVariable());
+ if (DIVar.isVariable() && DIVar.getTag() == dwarf::DW_TAG_arg_variable &&
+ getDISubprogram(DIVar.getContext()).describes(MF->getFunction())) {
+ LabelsBeforeInsn[Ranges.front().first] = FunctionBeginSym;
+ if (Ranges.front().first->getDebugExpression().isVariablePiece()) {
// Mark all non-overlapping initial pieces.
for (auto I = Ranges.begin(); I != Ranges.end(); ++I) {
- DIVariable Piece = I->first->getDebugVariable();
+ DIExpression Piece = I->first->getDebugExpression();
if (std::all_of(Ranges.begin(), I,
- [&](DbgValueHistoryMap::InstrRange Pred){
- return !piecesOverlap(Piece, Pred.first->getDebugVariable());
+ [&](DbgValueHistoryMap::InstrRange Pred) {
+ return !piecesOverlap(Piece, Pred.first->getDebugExpression());
}))
LabelsBeforeInsn[I->first] = FunctionBeginSym;
else
LexicalScope *FnScope = LScopes.getCurrentFunctionScope();
DwarfCompileUnit &TheCU = *SPMap.lookup(FnScope->getScopeNode());
+ // Add the range of this function to the list of ranges for the CU.
+ TheCU.addRange(RangeSpan(FunctionBeginSym, FunctionEndSym));
+
+ // Under -gmlt, skip building the subprogram if there are no inlined
+ // subroutines inside it.
+ if (TheCU.getCUNode().getEmissionKind() == DIBuilder::LineTablesOnly &&
+ LScopes.getAbstractScopesList().empty() && !IsDarwin) {
+ assert(ScopeVariables.empty());
+ assert(CurrentFnArguments.empty());
+ assert(DbgValues.empty());
+ assert(AbstractVariables.empty());
+ LabelsBeforeInsn.clear();
+ LabelsAfterInsn.clear();
+ PrevLabel = nullptr;
+ CurFn = nullptr;
+ return;
+ }
+
// Construct abstract scopes.
for (LexicalScope *AScope : LScopes.getAbstractScopesList()) {
DISubprogram SP(AScope->getScopeNode());
constructAbstractSubprogramScopeDIE(TheCU, AScope);
}
- DIE &CurFnDIE = constructSubprogramScopeDIE(TheCU, FnScope);
- if (!CurFn->getTarget().Options.DisableFramePointerElim(*CurFn))
- TheCU.addFlag(CurFnDIE, dwarf::DW_AT_APPLE_omit_frame_ptr);
-
- // Add the range of this function to the list of ranges for the CU.
- RangeSpan Span(FunctionBeginSym, FunctionEndSym);
- TheCU.addRange(std::move(Span));
+ constructSubprogramScopeDIE(TheCU, FnScope);
// Clear debug info
// Ownership of DbgVariables is a bit subtle - ScopeVariables owns all the
Asm->EmitInt8(1);
}
-// Emit visible names into a hashed accelerator table section.
-void DwarfDebug::emitAccelNames() {
- AccelNames.FinalizeTable(Asm, "Names");
- Asm->OutStreamer.SwitchSection(
- Asm->getObjFileLowering().getDwarfAccelNamesSection());
- MCSymbol *SectionBegin = Asm->GetTempSymbol("names_begin");
+void DwarfDebug::emitAccel(DwarfAccelTable &Accel, const MCSection *Section,
+ StringRef TableName, StringRef SymName) {
+ Accel.FinalizeTable(Asm, TableName);
+ Asm->OutStreamer.SwitchSection(Section);
+ auto *SectionBegin = Asm->GetTempSymbol(SymName);
Asm->OutStreamer.EmitLabel(SectionBegin);
// Emit the full data.
- AccelNames.Emit(Asm, SectionBegin, &InfoHolder);
+ Accel.Emit(Asm, SectionBegin, &InfoHolder, DwarfStrSectionSym);
+}
+
+// Emit visible names into a hashed accelerator table section.
+void DwarfDebug::emitAccelNames() {
+ emitAccel(AccelNames, Asm->getObjFileLowering().getDwarfAccelNamesSection(),
+ "Names", "names_begin");
}
// Emit objective C classes and categories into a hashed accelerator table
// section.
void DwarfDebug::emitAccelObjC() {
- AccelObjC.FinalizeTable(Asm, "ObjC");
- Asm->OutStreamer.SwitchSection(
- Asm->getObjFileLowering().getDwarfAccelObjCSection());
- MCSymbol *SectionBegin = Asm->GetTempSymbol("objc_begin");
- Asm->OutStreamer.EmitLabel(SectionBegin);
-
- // Emit the full data.
- AccelObjC.Emit(Asm, SectionBegin, &InfoHolder);
+ emitAccel(AccelObjC, Asm->getObjFileLowering().getDwarfAccelObjCSection(),
+ "ObjC", "objc_begin");
}
// Emit namespace dies into a hashed accelerator table.
void DwarfDebug::emitAccelNamespaces() {
- AccelNamespace.FinalizeTable(Asm, "namespac");
- Asm->OutStreamer.SwitchSection(
- Asm->getObjFileLowering().getDwarfAccelNamespaceSection());
- MCSymbol *SectionBegin = Asm->GetTempSymbol("namespac_begin");
- Asm->OutStreamer.EmitLabel(SectionBegin);
-
- // Emit the full data.
- AccelNamespace.Emit(Asm, SectionBegin, &InfoHolder);
+ emitAccel(AccelNamespace,
+ Asm->getObjFileLowering().getDwarfAccelNamespaceSection(),
+ "namespac", "namespac_begin");
}
// Emit type dies into a hashed accelerator table.
void DwarfDebug::emitAccelTypes() {
-
- AccelTypes.FinalizeTable(Asm, "types");
- Asm->OutStreamer.SwitchSection(
- Asm->getObjFileLowering().getDwarfAccelTypesSection());
- MCSymbol *SectionBegin = Asm->GetTempSymbol("types_begin");
- Asm->OutStreamer.EmitLabel(SectionBegin);
-
- // Emit the full data.
- AccelTypes.Emit(Asm, SectionBegin, &InfoHolder);
+ emitAccel(AccelTypes, Asm->getObjFileLowering().getDwarfAccelTypesSection(),
+ "types", "types_begin");
}
// Public name handling.
unsigned Offset = 0;
for (auto Piece : Values) {
- DIVariable Var = Piece.getVariable();
- unsigned PieceOffset = Var.getPieceOffset();
- unsigned PieceSize = Var.getPieceSize();
+ DIExpression Expr = Piece.getExpression();
+ unsigned PieceOffset = Expr.getPieceOffset();
+ unsigned PieceSize = Expr.getPieceSize();
assert(Offset <= PieceOffset && "overlapping or duplicate pieces");
if (Offset < PieceOffset) {
// The DWARF spec seriously mandates pieces with no locations for gaps.
Offset += PieceSize;
const unsigned SizeOfByte = 8;
- assert(!Var.isIndirect() && "indirect address for piece");
#ifndef NDEBUG
+ DIVariable Var = Piece.getVariable();
+ assert(!Var.isIndirect() && "indirect address for piece");
unsigned VarSize = Var.getSizeInBits(Map);
assert(PieceSize+PieceOffset <= VarSize/SizeOfByte
&& "piece is larger than or outside of variable");
}
} else if (Value.isLocation()) {
MachineLocation Loc = Value.getLoc();
- if (!DV.hasComplexAddress())
+ DIExpression Expr = Value.getExpression();
+ if (!Expr)
// Regular entry.
Asm->EmitDwarfRegOp(Streamer, Loc, DV.isIndirect());
else {
// Complex address entry.
- unsigned N = DV.getNumAddrElements();
+ unsigned N = Expr.getNumElements();
unsigned i = 0;
- if (N >= 2 && DV.getAddrElement(0) == DIBuilder::OpPlus) {
+ if (N >= 2 && Expr.getElement(0) == dwarf::DW_OP_plus) {
if (Loc.getOffset()) {
i = 2;
Asm->EmitDwarfRegOp(Streamer, Loc, DV.isIndirect());
Streamer.EmitInt8(dwarf::DW_OP_deref, "DW_OP_deref");
Streamer.EmitInt8(dwarf::DW_OP_plus_uconst, "DW_OP_plus_uconst");
- Streamer.EmitSLEB128(DV.getAddrElement(1));
+ Streamer.EmitSLEB128(Expr.getElement(1));
} else {
// If first address element is OpPlus then emit
// DW_OP_breg + Offset instead of DW_OP_reg + Offset.
- MachineLocation TLoc(Loc.getReg(), DV.getAddrElement(1));
+ MachineLocation TLoc(Loc.getReg(), Expr.getElement(1));
Asm->EmitDwarfRegOp(Streamer, TLoc, DV.isIndirect());
i = 2;
}
// Emit remaining complex address elements.
for (; i < N; ++i) {
- uint64_t Element = DV.getAddrElement(i);
- if (Element == DIBuilder::OpPlus) {
+ uint64_t Element = Expr.getElement(i);
+ if (Element == dwarf::DW_OP_plus) {
Streamer.EmitInt8(dwarf::DW_OP_plus_uconst, "DW_OP_plus_uconst");
- Streamer.EmitULEB128(DV.getAddrElement(++i));
- } else if (Element == DIBuilder::OpDeref) {
+ Streamer.EmitULEB128(Expr.getElement(++i));
+ } else if (Element == dwarf::DW_OP_deref) {
if (!Loc.isReg())
Streamer.EmitInt8(dwarf::DW_OP_deref, "DW_OP_deref");
- } else if (Element == DIBuilder::OpPiece) {
+ } else if (Element == dwarf::DW_OP_piece) {
i += 3;
// handled in emitDebugLocEntry.
} else
assert(useSplitDwarf() && "No split dwarf?");
const MCSection *OffSec =
Asm->getObjFileLowering().getDwarfStrOffDWOSection();
- const MCSymbol *StrSym = DwarfStrSectionSym;
InfoHolder.emitStrings(Asm->getObjFileLowering().getDwarfStrDWOSection(),
- OffSec, StrSym);
+ OffSec);
}
MCDwarfDwoLineTable *DwarfDebug::getDwoLineTable(const DwarfCompileUnit &CU) {