Skip to content

Commit

Permalink
Reland "[DwarfDebug] Dump call site debug info"
Browse files Browse the repository at this point in the history
The build failure found after the rL365467 has been
resolved.

Differential Revision: https://reviews.llvm.org/D60716

llvm-svn: 367446
  • Loading branch information
djtodoro committed Jul 31, 2019
1 parent f7ef705 commit b9973f8
Show file tree
Hide file tree
Showing 23 changed files with 1,143 additions and 52 deletions.
4 changes: 4 additions & 0 deletions llvm/docs/LangRef.rst
Expand Up @@ -4769,6 +4769,10 @@ The current supported opcode vocabulary is limited:
``DW_OP_entry_value`` may also appear after the ``AsmPrinter`` pass when
a call site parameter value (``DW_AT_call_site_parameter_value``)
is represented as entry value of the parameter.
- ``DW_OP_breg`` (or ``DW_OP_bregx``) represents a content on the provided
signed offset of the specified register. The opcode is only generated by the
``AsmPrinter`` pass to describe call site parameter value which requires an
expression over two registers.

DWARF specifies three kinds of simple location descriptions: Register, memory,
and implicit location descriptions. Note that a location description is
Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/CodeGen/TargetInstrInfo.h
Expand Up @@ -60,6 +60,8 @@ class TargetSubtargetInfo;

template <class T> class SmallVectorImpl;

using ParamLoadedValue = std::pair<const MachineOperand*, DIExpression*>;

//---------------------------------------------------------------------------
///
/// TargetInstrInfo - Interface to description of machine instruction set
Expand Down Expand Up @@ -1691,6 +1693,11 @@ class TargetInstrInfo : public MCInstrInfo {
return false;
}

/// Produce the expression describing the \p MI loading a value into
/// the parameter's forwarding register.
virtual Optional<ParamLoadedValue>
describeLoadedValue(const MachineInstr &MI) const;

private:
unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode;
unsigned CatchRetOpcode;
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/CodeGen/TargetRegisterInfo.h
Expand Up @@ -535,6 +535,11 @@ class TargetRegisterInfo : public MCRegisterInfo {
return false;
}

/// This is a wrapper around getCallPreservedMask().
/// Return true if the register is preserved after the call.
virtual bool isCalleeSavedPhysReg(unsigned PhysReg,
const MachineFunction &MF) const;

/// Prior to adding the live-out mask to a stackmap or patchpoint
/// instruction, provide the target the opportunity to adjust it (mainly to
/// remove pseudo-registers that should be ignored).
Expand Down
108 changes: 91 additions & 17 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Expand Up @@ -892,32 +892,106 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
}

DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE,
const DISubprogram &CalleeSP,
bool IsTail,
const MCExpr *PCOffset) {
// Insert a call site entry DIE within ScopeDIE.
DIE &CallSiteDIE =
createAndAddDIE(dwarf::DW_TAG_call_site, ScopeDIE, nullptr);
dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUCallSiteTag(dwarf::Tag Tag) const {
bool ApplyGNUExtensions = DD->getDwarfVersion() == 4 && DD->tuneForGDB();
if (!ApplyGNUExtensions)
return Tag;
switch (Tag) {
case dwarf::DW_TAG_call_site:
return dwarf::DW_TAG_GNU_call_site;
case dwarf::DW_TAG_call_site_parameter:
return dwarf::DW_TAG_GNU_call_site_parameter;
default:
llvm_unreachable("unhandled call site tag");
}
}

// For the purposes of showing tail call frames in backtraces, a key piece of
// information is DW_AT_call_origin, a pointer to the callee DIE.
DIE *CalleeDIE = getOrCreateSubprogramDIE(&CalleeSP);
assert(CalleeDIE && "Could not create DIE for call site entry origin");
addDIEEntry(CallSiteDIE, dwarf::DW_AT_call_origin, *CalleeDIE);
dwarf::Attribute
DwarfCompileUnit::getDwarf5OrGNUCallSiteAttr(dwarf::Attribute Attr) const {
bool ApplyGNUExtensions = DD->getDwarfVersion() == 4 && DD->tuneForGDB();
if (!ApplyGNUExtensions)
return Attr;
switch (Attr) {
case dwarf::DW_AT_call_all_calls:
return dwarf::DW_AT_GNU_all_call_sites;
case dwarf::DW_AT_call_target:
return dwarf::DW_AT_GNU_call_site_target;
case dwarf::DW_AT_call_origin:
return dwarf::DW_AT_abstract_origin;
case dwarf::DW_AT_call_pc:
return dwarf::DW_AT_low_pc;
case dwarf::DW_AT_call_value:
return dwarf::DW_AT_GNU_call_site_value;
case dwarf::DW_AT_call_tail_call:
return dwarf::DW_AT_GNU_tail_call;
default:
llvm_unreachable("unhandled call site attribute");
}
}

if (IsTail) {
// Attach DW_AT_call_tail_call to tail calls for standards compliance.
addFlag(CallSiteDIE, dwarf::DW_AT_call_tail_call);
DIE &DwarfCompileUnit::constructCallSiteEntryDIE(
DIE &ScopeDIE, const DISubprogram *CalleeSP, bool IsTail,
const MCSymbol *PCAddr, const MCExpr *PCOffset, unsigned CallReg) {
// Insert a call site entry DIE within ScopeDIE.
DIE &CallSiteDIE = createAndAddDIE(
getDwarf5OrGNUCallSiteTag(dwarf::DW_TAG_call_site), ScopeDIE, nullptr);

if (CallReg) {
// Indirect call.
addAddress(CallSiteDIE,
getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_target),
MachineLocation(CallReg));
} else {
// Attach the return PC to allow the debugger to disambiguate call paths
// from one function to another.
DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP);
assert(CalleeDIE && "Could not create DIE for call site entry origin");
addDIEEntry(CallSiteDIE,
getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_origin),
*CalleeDIE);
}

if (IsTail)
// Attach DW_AT_call_tail_call to tail calls for standards compliance.
addFlag(CallSiteDIE,
getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_tail_call));

// Attach the return PC to allow the debugger to disambiguate call paths
// from one function to another.
if (DD->getDwarfVersion() == 4 && DD->tuneForGDB()) {
assert(PCAddr && "Missing PC information for a call");
addLabelAddress(CallSiteDIE, dwarf::DW_AT_low_pc, PCAddr);
} else if (!IsTail || DD->tuneForGDB()) {
assert(PCOffset && "Missing return PC information for a call");
addAddressExpr(CallSiteDIE, dwarf::DW_AT_call_return_pc, PCOffset);
}

return CallSiteDIE;
}

void DwarfCompileUnit::constructCallSiteParmEntryDIEs(
DIE &CallSiteDIE, SmallVector<DbgCallSiteParam, 4> &Params) {
for (const auto &Param : Params) {
unsigned Register = Param.getRegister();
auto CallSiteDieParam =
DIE::get(DIEValueAllocator,
getDwarf5OrGNUCallSiteTag(dwarf::DW_TAG_call_site_parameter));
insertDIE(CallSiteDieParam);
addAddress(*CallSiteDieParam, dwarf::DW_AT_location,
MachineLocation(Register));

DIELoc *Loc = new (DIEValueAllocator) DIELoc;
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
DwarfExpr.setCallSiteParamValueFlag();

DwarfDebug::emitDebugLocValue(*Asm, nullptr, Param.getValue(), DwarfExpr);

addBlock(*CallSiteDieParam,
getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_value),
DwarfExpr.finalize());

CallSiteDIE.addChild(CallSiteDieParam);
}
}

DIE *DwarfCompileUnit::constructImportedEntityDIE(
const DIImportedEntity *Module) {
DIE *IMDie = DIE::get(DIEValueAllocator, (dwarf::Tag)Module->getTag());
Expand Down
29 changes: 25 additions & 4 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
Expand Up @@ -227,12 +227,33 @@ class DwarfCompileUnit final : public DwarfUnit {

void constructAbstractSubprogramScopeDIE(LexicalScope *Scope);

/// This takes the official DWARF 5 tag and returns the appropriate
/// GNU tag if needed.
dwarf::Tag getDwarf5OrGNUCallSiteTag(dwarf::Tag Tag) const;
/// This takes the official DWARF 5 attribute and returns the appropriate
/// GNU attribute if needed.
dwarf::Attribute getDwarf5OrGNUCallSiteAttr(dwarf::Attribute Attr) const;

/// Construct a call site entry DIE describing a call within \p Scope to a
/// callee described by \p CalleeSP. \p IsTail specifies whether the call is
/// a tail call. \p PCOffset must be non-zero for non-tail calls or be the
/// callee described by \p CalleeSP.
/// \p IsTail specifies whether the call is a tail call.
/// \p PCAddr (used for GDB + DWARF 4 tuning) points to the PC value after
/// the call instruction.
/// \p PCOffset (used for cases other than GDB + DWARF 4 tuning) must be
/// non-zero for non-tail calls (in the case of non-gdb tuning, since for
/// GDB + DWARF 5 tuning we still generate PC info for tail calls) or be the
/// function-local offset to PC value after the call instruction.
DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram &CalleeSP,
bool IsTail, const MCExpr *PCOffset);
/// \p CallReg is a register location for an indirect call. For direct calls
/// the \p CallReg is set to 0.
DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram *CalleeSP,
bool IsTail, const MCSymbol *PCAddr,
const MCExpr *PCOffset, unsigned CallReg);
/// Construct call site parameter DIEs for the \p CallSiteDIE. The \p Params
/// were collected by the \ref collectCallSiteParameters.
/// Note: The order of parameters does not matter, since debuggers recognize
/// call site parameters by the DW_AT_location attribute.
void constructCallSiteParmEntryDIEs(DIE &CallSiteDIE,
SmallVector<DbgCallSiteParam, 4> &Params);

/// Construct import_module DIE.
DIE *constructImportedEntityDIE(const DIImportedEntity *Module);
Expand Down

0 comments on commit b9973f8

Please sign in to comment.