Keep track of inlined functions and their locations. This information is collected when nested llvm.dbg.func.start intrinsics are seen. (Right now, inliner removes nested llvm.dbg.func.start intrinisics during inlining.)

Create debug_inlined dwarf section using these information. This info is used by gdb, at least on Darwin, to enable better experience debugging inlined functions. See DwarfWriter.cpp for more information on structure of debug_inlined section.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@68847 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Devang Patel
2009-04-11 00:16:47 +00:00
parent dbf1e2b08b
commit 2057532679
7 changed files with 178 additions and 7 deletions

View File

@@ -94,6 +94,9 @@ public:
/// RecordRegionStart - Indicate the start of a region. /// RecordRegionStart - Indicate the start of a region.
unsigned RecordRegionStart(GlobalVariable *V); unsigned RecordRegionStart(GlobalVariable *V);
/// RecordRegionStart - Indicate the start of a region.
unsigned RecordRegionStart(GlobalVariable *V, unsigned ID);
/// RecordRegionEnd - Indicate the end of a region. /// RecordRegionEnd - Indicate the end of a region.
unsigned RecordRegionEnd(GlobalVariable *V); unsigned RecordRegionEnd(GlobalVariable *V);
@@ -107,6 +110,10 @@ public:
/// ShouldEmitDwarfDebug - Returns true if Dwarf debugging declarations should /// ShouldEmitDwarfDebug - Returns true if Dwarf debugging declarations should
/// be emitted. /// be emitted.
bool ShouldEmitDwarfDebug() const; bool ShouldEmitDwarfDebug() const;
//// RecordInlineInfo - Global variable GV is inlined at the location marked
//// by LabelID label.
void RecordInlineInfo(GlobalVariable *GV, unsigned LabelID);
}; };

View File

@@ -507,6 +507,10 @@ namespace llvm {
/// ///
const char *DwarfPubTypesSection; // Defaults to ".debug_pubtypes". const char *DwarfPubTypesSection; // Defaults to ".debug_pubtypes".
/// DwarfDebugInlineSection - Section directive for inline info.
///
const char *DwarfDebugInlineSection; // Defaults to ".debug_inlined"
/// DwarfStrSection - Section directive for Dwarf info. /// DwarfStrSection - Section directive for Dwarf info.
/// ///
const char *DwarfStrSection; // Defaults to ".debug_str". const char *DwarfStrSection; // Defaults to ".debug_str".
@@ -880,6 +884,9 @@ namespace llvm {
const char *getDwarfPubTypesSection() const { const char *getDwarfPubTypesSection() const {
return DwarfPubTypesSection; return DwarfPubTypesSection;
} }
const char *getDwarfDebugInlineSection() const {
return DwarfDebugInlineSection;
}
const char *getDwarfStrSection() const { const char *getDwarfStrSection() const {
return DwarfStrSection; return DwarfStrSection;
} }

View File

@@ -1252,6 +1252,10 @@ class DwarfDebug : public Dwarf {
/// DbgScopeMap - Tracks the scopes in the current function. /// DbgScopeMap - Tracks the scopes in the current function.
DenseMap<GlobalVariable *, DbgScope *> DbgScopeMap; DenseMap<GlobalVariable *, DbgScope *> DbgScopeMap;
/// InlineInfo - Keep track of inlined functions and their location.
/// This information is used to populate debug_inlined section.
DenseMap<GlobalVariable *, SmallVector<unsigned, 4> > InlineInfo;
/// DebugTimer - Timer for the Dwarf debug writer. /// DebugTimer - Timer for the Dwarf debug writer.
Timer *DebugTimer; Timer *DebugTimer;
@@ -2027,15 +2031,18 @@ private:
for (unsigned j = 0, M = Scopes.size(); j < M; ++j) { for (unsigned j = 0, M = Scopes.size(); j < M; ++j) {
// Define the Scope debug information entry. // Define the Scope debug information entry.
DbgScope *Scope = Scopes[j]; DbgScope *Scope = Scopes[j];
// FIXME - Ignore inlined functions for the time being.
if (!Scope->getParent()) continue;
unsigned StartID = MMI->MappedLabel(Scope->getStartLabelID()); unsigned StartID = MMI->MappedLabel(Scope->getStartLabelID());
unsigned EndID = MMI->MappedLabel(Scope->getEndLabelID()); unsigned EndID = MMI->MappedLabel(Scope->getEndLabelID());
// Ignore empty scopes. // Ignore empty scopes.
if (StartID == EndID && StartID != 0) continue; if (StartID == EndID && StartID != 0) continue;
if (Scope->getScopes().empty() && Scope->getVariables().empty()) continue;
// Do not ignore inlined scope even if it is empty. Inlined scope
// does not have any parent.
if (Scope->getParent()
&& Scope->getScopes().empty() && Scope->getVariables().empty())
continue;
if (StartID == ParentStartID && EndID == ParentEndID) { if (StartID == ParentStartID && EndID == ParentEndID) {
// Just add stuff to the parent scope. // Just add stuff to the parent scope.
@@ -2781,6 +2788,74 @@ private:
} }
} }
/// EmitDebugInlineInfo - Emit inline info using following format.
/// Section Header:
/// 1. length of section
/// 2. Dwarf version number
/// 3. address size.
///
/// Entries (one "entry" for each function that was inlined):
///
/// 1. offset into __debug_str section for MIPS linkage name, if exists;
/// otherwise offset into __debug_str for regular function name.
/// 2. offset into __debug_str section for regular function name.
/// 3. an unsigned LEB128 number indicating the number of distinct inlining
/// instances for the function.
///
/// The rest of the entry consists of a {die_offset, low_pc} pair for each
/// inlined instance; the die_offset points to the inlined_subroutine die in
/// the __debug_info section, and the low_pc is the starting address for the
/// inlining instance.
void EmitDebugInlineInfo() {
if (!MainCU)
return;
Asm->SwitchToDataSection(TAI->getDwarfDebugInlineSection());
Asm->EOL();
EmitDifference("debug_inlined_end", 1,
"debug_inlined_begin", 1, true);
Asm->EOL("Length of Debug Inlined Information Entry");
EmitLabel("debug_inlined_begin", 1);
Asm->EmitInt16(DWARF_VERSION); Asm->EOL("Dwarf Version");
Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Address Size (in bytes)");
for (DenseMap<GlobalVariable *, SmallVector<unsigned, 4> >::iterator
I = InlineInfo.begin(), E = InlineInfo.end(); I != E; ++I) {
GlobalVariable *GV = I->first;
SmallVector<unsigned, 4> &Labels = I->second;
DISubprogram SP(GV);
std::string Name;
std::string LName;
SP.getLinkageName(LName);
SP.getName(Name);
Asm->EmitString(LName.empty() ? Name : LName);
Asm->EOL("MIPS linkage name");
Asm->EmitString(Name); Asm->EOL("Function name");
Asm->EmitULEB128Bytes(Labels.size()); Asm->EOL("Inline count");
for (SmallVector<unsigned, 4>::iterator LI = Labels.begin(),
LE = Labels.end(); LI != LE; ++LI) {
DIE *SP = MainCU->getDieMapSlotFor(GV);
Asm->EmitInt32(SP->getOffset()); Asm->EOL("DIE offset");
if (TD->getPointerSize() == sizeof(int32_t))
O << TAI->getData32bitsDirective();
else
O << TAI->getData64bitsDirective();
PrintLabelName("label", *LI); Asm->EOL("low_pc");
}
}
EmitLabel("debug_inlined_end", 1);
Asm->EOL();
}
/// GetOrCreateSourceID - Look up the source id with the given directory and /// GetOrCreateSourceID - Look up the source id with the given directory and
/// source file names. If none currently exists, create a new id and insert it /// source file names. If none currently exists, create a new id and insert it
/// in the SourceIds map. This can update DirectoryNames and SourceFileNames maps /// in the SourceIds map. This can update DirectoryNames and SourceFileNames maps
@@ -3131,6 +3206,9 @@ public:
// Emit info into a debug macinfo section. // Emit info into a debug macinfo section.
EmitDebugMacInfo(); EmitDebugMacInfo();
// Emit inline info.
EmitDebugInlineInfo();
if (TimePassesIsEnabled) if (TimePassesIsEnabled)
DebugTimer->stopTimer(); DebugTimer->stopTimer();
} }
@@ -3337,6 +3415,20 @@ public:
return ID; return ID;
} }
/// RecordRegionStart - Indicate the start of a region.
unsigned RecordRegionStart(GlobalVariable *V, unsigned ID) {
if (TimePassesIsEnabled)
DebugTimer->startTimer();
DbgScope *Scope = getOrCreateScope(V);
if (!Scope->getStartLabelID()) Scope->setStartLabelID(ID);
if (TimePassesIsEnabled)
DebugTimer->stopTimer();
return ID;
}
/// RecordRegionEnd - Indicate the end of a region. /// RecordRegionEnd - Indicate the end of a region.
unsigned RecordRegionEnd(GlobalVariable *V) { unsigned RecordRegionEnd(GlobalVariable *V) {
if (TimePassesIsEnabled) if (TimePassesIsEnabled)
@@ -3377,6 +3469,23 @@ public:
if (TimePassesIsEnabled) if (TimePassesIsEnabled)
DebugTimer->stopTimer(); DebugTimer->stopTimer();
} }
//// RecordInlineInfo - Global variable GV is inlined at the location marked
//// by LabelID label.
void RecordInlineInfo(GlobalVariable *GV, unsigned LabelID) {
MMI->RecordUsedDbgLabel(LabelID);
DenseMap<GlobalVariable *, SmallVector<unsigned, 4> >::iterator
I = InlineInfo.find(GV);
if (I == InlineInfo.end()) {
SmallVector<unsigned, 4> Labels;
Labels.push_back(LabelID);
InlineInfo[GV] = Labels;
return;
}
SmallVector<unsigned, 4> &Labels = I->second;
Labels.push_back(LabelID);
}
}; };
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@@ -4532,6 +4641,11 @@ unsigned DwarfWriter::RecordRegionStart(GlobalVariable *V) {
return DD->RecordRegionStart(V); return DD->RecordRegionStart(V);
} }
/// RecordRegionStart - Indicate the start of a region.
unsigned DwarfWriter::RecordRegionStart(GlobalVariable *V, unsigned ID) {
return DD->RecordRegionStart(V, ID);
}
/// RecordRegionEnd - Indicate the end of a region. /// RecordRegionEnd - Indicate the end of a region.
unsigned DwarfWriter::RecordRegionEnd(GlobalVariable *V) { unsigned DwarfWriter::RecordRegionEnd(GlobalVariable *V) {
return DD->RecordRegionEnd(V); return DD->RecordRegionEnd(V);
@@ -4553,3 +4667,10 @@ void DwarfWriter::RecordVariable(GlobalVariable *GV, unsigned FrameIndex) {
bool DwarfWriter::ShouldEmitDwarfDebug() const { bool DwarfWriter::ShouldEmitDwarfDebug() const {
return DD->ShouldEmitDwarfDebug(); return DD->ShouldEmitDwarfDebug();
} }
//// RecordInlineInfo - Global variable GV is inlined at the location marked
//// by LabelID label.
void DwarfWriter::RecordInlineInfo(GlobalVariable *GV, unsigned LabelID) {
DD->RecordInlineInfo(GV, LabelID);
}

View File

@@ -372,12 +372,24 @@ bool FastISel::SelectCall(User *I) {
// Record the source line. // Record the source line.
unsigned Line = Subprogram.getLineNumber(); unsigned Line = Subprogram.getLineNumber();
DW->RecordSourceLine(Line, 0, SrcFile); unsigned LabelID = DW->RecordSourceLine(Line, 0, SrcFile);
setCurDebugLoc(DebugLoc::get(MF.getOrCreateDebugLocID(SrcFile, Line, 0))); setCurDebugLoc(DebugLoc::get(MF.getOrCreateDebugLocID(SrcFile, Line, 0)));
std::string SPName;
Subprogram.getLinkageName(SPName);
if (!SPName.empty()
&& strcmp(SPName.c_str(), MF.getFunction()->getNameStart())) {
// This is a beginning of inlined function.
DW->RecordRegionStart(cast<GlobalVariable>(FSI->getSubprogram()),
LabelID);
const TargetInstrDesc &II = TII.get(TargetInstrInfo::DBG_LABEL);
BuildMI(MBB, DL, II).addImm(LabelID);
DW->RecordInlineInfo(Subprogram.getGV(), LabelID);
} else {
// llvm.dbg.func_start also defines beginning of function scope. // llvm.dbg.func_start also defines beginning of function scope.
DW->RecordRegionStart(cast<GlobalVariable>(FSI->getSubprogram())); DW->RecordRegionStart(cast<GlobalVariable>(FSI->getSubprogram()));
} }
}
return true; return true;
} }

View File

@@ -3955,6 +3955,18 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
DwarfWriter *DW = DAG.getDwarfWriter(); DwarfWriter *DW = DAG.getDwarfWriter();
DbgRegionEndInst &REI = cast<DbgRegionEndInst>(I); DbgRegionEndInst &REI = cast<DbgRegionEndInst>(I);
if (DW && DW->ValidDebugInfo(REI.getContext())) { if (DW && DW->ValidDebugInfo(REI.getContext())) {
MachineFunction &MF = DAG.getMachineFunction();
DISubprogram Subprogram(cast<GlobalVariable>(REI.getContext()));
std::string SPName;
Subprogram.getLinkageName(SPName);
if (!SPName.empty()
&& strcmp(SPName.c_str(), MF.getFunction()->getNameStart())) {
// This is end of inlined function. Debugging information for
// inlined function is not handled yet (only supported by FastISel).
return 0;
}
unsigned LabelID = unsigned LabelID =
DW->RecordRegionEnd(cast<GlobalVariable>(REI.getContext())); DW->RecordRegionEnd(cast<GlobalVariable>(REI.getContext()));
if (Fast) if (Fast)
@@ -3974,6 +3986,16 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
// what (most?) gdb expects. // what (most?) gdb expects.
MachineFunction &MF = DAG.getMachineFunction(); MachineFunction &MF = DAG.getMachineFunction();
DISubprogram Subprogram(cast<GlobalVariable>(SP)); DISubprogram Subprogram(cast<GlobalVariable>(SP));
std::string SPName;
Subprogram.getLinkageName(SPName);
if (!SPName.empty()
&& strcmp(SPName.c_str(), MF.getFunction()->getNameStart())) {
// This is beginning of inlined function. Debugging information for
// inlined function is not handled yet (only supported by FastISel).
return 0;
}
DICompileUnit CompileUnit = Subprogram.getCompileUnit(); DICompileUnit CompileUnit = Subprogram.getCompileUnit();
std::string Dir, FN; std::string Dir, FN;
unsigned SrcFile = DW->getOrCreateSourceID(CompileUnit.getDirectory(Dir), unsigned SrcFile = DW->getOrCreateSourceID(CompileUnit.getDirectory(Dir),

View File

@@ -112,6 +112,7 @@ void TargetAsmInfo::fillDefaultValues() {
DwarfFrameSection = ".debug_frame"; DwarfFrameSection = ".debug_frame";
DwarfPubNamesSection = ".debug_pubnames"; DwarfPubNamesSection = ".debug_pubnames";
DwarfPubTypesSection = ".debug_pubtypes"; DwarfPubTypesSection = ".debug_pubtypes";
DwarfDebugInlineSection = ".debug_inlined";
DwarfStrSection = ".debug_str"; DwarfStrSection = ".debug_str";
DwarfLocSection = ".debug_loc"; DwarfLocSection = ".debug_loc";
DwarfARangesSection = ".debug_aranges"; DwarfARangesSection = ".debug_aranges";

View File

@@ -112,6 +112,7 @@ X86DarwinTargetAsmInfo::X86DarwinTargetAsmInfo(const X86TargetMachine &TM):
DwarfFrameSection = ".section __DWARF,__debug_frame,regular,debug"; DwarfFrameSection = ".section __DWARF,__debug_frame,regular,debug";
DwarfPubNamesSection = ".section __DWARF,__debug_pubnames,regular,debug"; DwarfPubNamesSection = ".section __DWARF,__debug_pubnames,regular,debug";
DwarfPubTypesSection = ".section __DWARF,__debug_pubtypes,regular,debug"; DwarfPubTypesSection = ".section __DWARF,__debug_pubtypes,regular,debug";
DwarfDebugInlineSection = ".section __DWARF,__debug_inlined,regular,debug";
DwarfStrSection = ".section __DWARF,__debug_str,regular,debug"; DwarfStrSection = ".section __DWARF,__debug_str,regular,debug";
DwarfLocSection = ".section __DWARF,__debug_loc,regular,debug"; DwarfLocSection = ".section __DWARF,__debug_loc,regular,debug";
DwarfARangesSection = ".section __DWARF,__debug_aranges,regular,debug"; DwarfARangesSection = ".section __DWARF,__debug_aranges,regular,debug";