Skip to content

Commit

Permalink
[DwarfDebug] Dump call site debug info
Browse files Browse the repository at this point in the history
Dump the DWARF information about call sites and call site parameters into
debug info sections.

The patch also provides an interface for the interpretation of instructions
that could load values of a call site parameters in order to generate DWARF
about the call site parameters.

([13/13] Introduce the debug entry values.)

Co-authored-by: Ananth Sowda <[email protected]>
Co-authored-by: Nikola Prica <[email protected]>
Co-authored-by: Ivan Baev <[email protected]>

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@365467 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
djtodoro committed Jul 9, 2019
1 parent 2a6ebe9 commit 9e7e735
Show file tree
Hide file tree
Showing 23 changed files with 1,100 additions and 49 deletions.
3 changes: 3 additions & 0 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4755,6 +4755,9 @@ 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_reg`` (or ``DW_OP_regx``) represents a physical register location.
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
6 changes: 6 additions & 0 deletions include/llvm/CodeGen/TargetInstrInfo.h
Original file line number Diff line number Diff line change
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,10 @@ class TargetInstrInfo : public MCInstrInfo {
return false;
}

/// Produce RHS description of parameter's loading instruction \p MI.
virtual Optional<ParamLoadedValue>
describeLoadedValue(const MachineInstr &MI) const;

private:
unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode;
unsigned CatchRetOpcode;
Expand Down
4 changes: 1 addition & 3 deletions include/llvm/CodeGen/TargetRegisterInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -531,9 +531,7 @@ class TargetRegisterInfo : public MCRegisterInfo {
/// prior to a call and is guaranteed to be restored (also by the caller)
/// after the call.
virtual bool isCallerPreservedPhysReg(unsigned PhysReg,
const MachineFunction &MF) const {
return false;
}
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
Expand Down
100 changes: 87 additions & 13 deletions lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -890,32 +890,106 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
}

dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUCallSiteTag(dwarf::Tag Tag) {
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");
}
}

dwarf::Attribute DwarfCompileUnit::getDwarf5OrGNUCallSiteAttr(dwarf::Attribute Attr) {
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");
}
}

DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE,
const DISubprogram &CalleeSP,
const DISubprogram *CalleeSP,
bool IsTail,
const MCExpr *PCOffset) {
const MCSymbol *PCAddr,
const MCExpr *PCOffset,
unsigned CallReg) {
// Insert a call site entry DIE within ScopeDIE.
DIE &CallSiteDIE =
createAndAddDIE(dwarf::DW_TAG_call_site, ScopeDIE, nullptr);
createAndAddDIE(getDwarf5OrGNUCallSiteTag(dwarf::DW_TAG_call_site),
ScopeDIE, nullptr);

// 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);
if (CallReg) {
// Indirect call.
addAddress(CallSiteDIE, getDwarf5OrGNUCallSiteAttr(dwarf::DW_AT_call_target),
MachineLocation(CallReg));
} else {
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) {
if (IsTail)
// Attach DW_AT_call_tail_call to tail calls for standards compliance.
addFlag(CallSiteDIE, dwarf::DW_AT_call_tail_call);
} else {
// Attach the return PC to allow the debugger to disambiguate call paths
// from one function to another.
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 (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
18 changes: 14 additions & 4 deletions lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,22 @@ class DwarfCompileUnit final : public DwarfUnit {

void constructAbstractSubprogramScopeDIE(LexicalScope *Scope);

dwarf::Tag getDwarf5OrGNUCallSiteTag(dwarf::Tag Tag);
dwarf::Attribute getDwarf5OrGNUCallSiteAttr(dwarf::Attribute Attr);

/// 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
/// function-local offset to PC value after the call instruction.
DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram &CalleeSP,
bool IsTail, const MCExpr *PCOffset);
/// 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) or be the function-local offset to PC value
/// after the call instruction. \p CallReg is a register location
/// for an indirect call.
DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram *CalleeSP,
bool IsTail, const MCSymbol *PCAddr,
const MCExpr *PCOffset, unsigned CallReg);
void constructCallSiteParmEntryDIEs(DIE &CallSiteDIE,
SmallVector<DbgCallSiteParam, 4> &Params);

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

0 comments on commit 9e7e735

Please sign in to comment.