Add support for a CU to output a set of ranges for the CU. This is useful

when you want to have the full list of addresses for a particular CU or
when you have multiple modules linked together and can't depend upon the
ordering of a single CU for begin/end ranges.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197776 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Christopher 2013-12-20 04:16:18 +00:00
parent e899f25163
commit ff37ddf185
3 changed files with 124 additions and 20 deletions

View File

@ -108,6 +108,11 @@ static cl::opt<unsigned>
DwarfVersionNumber("dwarf-version", cl::Hidden, DwarfVersionNumber("dwarf-version", cl::Hidden,
cl::desc("Generate DWARF for dwarf version."), cl::init(0)); cl::desc("Generate DWARF for dwarf version."), cl::init(0));
static cl::opt<bool>
DwarfCURanges("generate-dwarf-cu-ranges", cl::Hidden,
cl::desc("Generate DW_AT_ranges for compile units"),
cl::init(false));
static const char *const DWARFGroupName = "DWARF Emission"; static const char *const DWARFGroupName = "DWARF Emission";
static const char *const DbgTimerName = "DWARF Debug Writer"; static const char *const DbgTimerName = "DWARF Debug Writer";
@ -426,6 +431,10 @@ DIE *DwarfDebug::updateSubprogramScopeDIE(DwarfCompileUnit *SPCU,
SPCU->addLabelAddress(SPDie, dwarf::DW_AT_low_pc, FunctionBeginSym); SPCU->addLabelAddress(SPDie, dwarf::DW_AT_low_pc, FunctionBeginSym);
SPCU->addLabelAddress(SPDie, dwarf::DW_AT_high_pc, FunctionEndSym); SPCU->addLabelAddress(SPDie, dwarf::DW_AT_high_pc, FunctionEndSym);
// Add this range to the list of ranges for the CU.
RangeSpan Span(FunctionBeginSym, FunctionEndSym);
SPCU->addRange(llvm_move(Span));
const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo();
MachineLocation Location(RI->getFrameRegister(*Asm->MF)); MachineLocation Location(RI->getFrameRegister(*Asm->MF));
SPCU->addAddress(SPDie, dwarf::DW_AT_frame_base, Location); SPCU->addAddress(SPDie, dwarf::DW_AT_frame_base, Location);
@ -1070,24 +1079,32 @@ void DwarfDebug::finalizeModuleInfo() {
// vtable holding type. // vtable holding type.
TheU->constructContainingTypeDIEs(); TheU->constructContainingTypeDIEs();
// If we're splitting the dwarf out now that we've got the entire // Add CU specific attributes if we need to add any.
// CU then construct a skeleton CU based upon it. if (TheU->getUnitDie()->getTag() == dwarf::DW_TAG_compile_unit) {
if (useSplitDwarf() && // If we're splitting the dwarf out now that we've got the entire
TheU->getUnitDie()->getTag() == dwarf::DW_TAG_compile_unit) { // CU then construct a skeleton CU based upon it.
uint64_t ID = 0; if (useSplitDwarf()) {
if (GenerateCUHash) { // This should be a unique identifier when we want to build .dwp files.
DIEHash CUHash; uint64_t ID = 0;
ID = CUHash.computeCUSignature(*TheU->getUnitDie()); if (GenerateCUHash) {
DIEHash CUHash;
ID = CUHash.computeCUSignature(*TheU->getUnitDie());
}
TheU->addUInt(TheU->getUnitDie(), dwarf::DW_AT_GNU_dwo_id,
dwarf::DW_FORM_data8, ID);
// Now construct the skeleton CU associated.
DwarfCompileUnit *SkCU =
constructSkeletonCU(static_cast<DwarfCompileUnit *>(TheU));
SkCU->addUInt(SkCU->getUnitDie(), dwarf::DW_AT_GNU_dwo_id,
dwarf::DW_FORM_data8, ID);
} else {
// Attribute if we've emitted a range list for the compile unit, this
// will get constructed for the skeleton CU separately if we have one.
if (DwarfCURanges && TheU->getRanges().size())
addSectionLabel(Asm, TheU, TheU->getUnitDie(), dwarf::DW_AT_ranges,
Asm->GetTempSymbol("cu_ranges", TheU->getUniqueID()),
DwarfDebugRangeSectionSym);
} }
// This should be a unique identifier when we want to build .dwp files.
TheU->addUInt(TheU->getUnitDie(), dwarf::DW_AT_GNU_dwo_id,
dwarf::DW_FORM_data8, ID);
// Now construct the skeleton CU associated.
DwarfCompileUnit *SkCU =
constructSkeletonCU(static_cast<DwarfCompileUnit *>(TheU));
// This should be a unique identifier when we want to build .dwp files.
SkCU->addUInt(SkCU->getUnitDie(), dwarf::DW_AT_GNU_dwo_id,
dwarf::DW_FORM_data8, ID);
} }
} }
@ -2935,6 +2952,28 @@ void DwarfDebug::emitDebugRanges() {
Asm->OutStreamer.EmitIntValue(0, Size); Asm->OutStreamer.EmitIntValue(0, Size);
Asm->OutStreamer.EmitIntValue(0, Size); Asm->OutStreamer.EmitIntValue(0, Size);
} }
// Now emit a range for the CU itself.
if (DwarfCURanges) {
Asm->OutStreamer.EmitLabel(
Asm->GetTempSymbol("cu_ranges", TheCU->getUniqueID()));
const SmallVectorImpl<RangeSpan> &Ranges = TheCU->getRanges();
for (uint32_t i = 0, e = Ranges.size(); i != e; ++i) {
RangeSpan Range = Ranges[i];
// We occasionally have ranges without begin/end labels.
// FIXME: Verify and fix.
const MCSymbol *Begin = Range.getStart();
const MCSymbol *End = Range.getEnd();
Begin ? Asm->OutStreamer.EmitSymbolValue(Begin, Size)
: Asm->OutStreamer.EmitIntValue(0, Size);
End ? Asm->OutStreamer.EmitSymbolValue(End, Size)
: Asm->OutStreamer.EmitIntValue(0, Size);
}
// And terminate the list with two 0 values.
Asm->OutStreamer.EmitIntValue(0, Size);
Asm->OutStreamer.EmitIntValue(0, Size);
}
} }
} }
@ -2963,9 +3002,14 @@ DwarfCompileUnit *DwarfDebug::constructSkeletonCU(const DwarfCompileUnit *CU) {
else else
NewCU->addSectionOffset(Die, dwarf::DW_AT_GNU_addr_base, 0); NewCU->addSectionOffset(Die, dwarf::DW_AT_GNU_addr_base, 0);
// 2.17.1 requires that we use DW_AT_low_pc for a single entry point // Attribute if we've emitted a range list for the compile unit, this
// into an entity. We're using 0, or a NULL label for this. // will get constructed for the skeleton CU separately if we have one.
NewCU->addUInt(Die, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr, 0); if (DwarfCURanges && CU->getRanges().size())
addSectionLabel(Asm, NewCU, Die, dwarf::DW_AT_ranges,
Asm->GetTempSymbol("cu_ranges", CU->getUniqueID()),
DwarfDebugRangeSectionSym);
else
NewCU->addUInt(Die, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr, 0);
// DW_AT_stmt_list is a offset of line number information for this // DW_AT_stmt_list is a offset of line number information for this
// compile unit in debug_line section. // compile unit in debug_line section.

View File

@ -118,6 +118,9 @@ protected:
/// corresponds to the MDNode mapped with the subprogram DIE. /// corresponds to the MDNode mapped with the subprogram DIE.
DenseMap<DIE *, const MDNode *> ContainingTypeMap; DenseMap<DIE *, const MDNode *> ContainingTypeMap;
// List of ranges for a given compile unit.
SmallVector<RangeSpan, 1> CURanges;
// List of range lists for a given compile unit, separate from the ranges for // List of range lists for a given compile unit, separate from the ranges for
// the CU itself. // the CU itself.
SmallVector<RangeSpanList, 1> CURangeLists; SmallVector<RangeSpanList, 1> CURangeLists;
@ -216,6 +219,13 @@ public:
/// hasContent - Return true if this compile unit has something to write out. /// hasContent - Return true if this compile unit has something to write out.
bool hasContent() const { return !UnitDie->getChildren().empty(); } bool hasContent() const { return !UnitDie->getChildren().empty(); }
/// addRange - Add an address range to the list of ranges for this unit.
void addRange(RangeSpan Range) { CURanges.push_back(Range); }
/// getRanges - Get the list of ranges for this unit.
const SmallVectorImpl<RangeSpan> &getRanges() const { return CURanges; }
SmallVectorImpl<RangeSpan> &getRanges() { return CURanges; }
/// addRangeList - Add an address range list to the list of range lists. /// addRangeList - Add an address range list to the list of range lists.
void addRangeList(RangeSpanList Ranges) { CURangeLists.push_back(Ranges); } void addRangeList(RangeSpanList Ranges) { CURangeLists.push_back(Ranges); }

View File

@ -0,0 +1,50 @@
; RUN: llc -O0 -filetype=obj -generate-dwarf-cu-ranges %s -o %t
; RUN: llvm-dwarfdump %t | FileCheck %s
; Check that we emit ranges for this when the -generate-dwarf-cu-ranges flag is passed.
; CHECK: DW_TAG_compile_unit
; CHECK: DW_AT_ranges
; CHECK: DW_TAG_subprogram
; CHECK: .debug_ranges contents:
; FIXME: When we get better dumping facilities we'll want to elaborate here.
; CHECK: 00000000 <End of list>
; CHECK: 00000010 <End of list>
; Function Attrs: nounwind uwtable
define i32 @f(i32 %a) #0 {
entry:
%a.addr = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
call void @llvm.dbg.declare(metadata !{i32* %a.addr}, metadata !12), !dbg !13
%0 = load i32* %a.addr, align 4, !dbg !14
%add = add nsw i32 %0, 4, !dbg !14
ret i32 %add, !dbg !14
}
; Function Attrs: nounwind readnone
declare void @llvm.dbg.declare(metadata, metadata) #1
attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!9, !10}
!llvm.ident = !{!11}
!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 (trunk 197756) (llvm/trunk 197768)", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/usr/local/google/home/echristo/tmp/foo.c] [DW_LANG_C99]
!1 = metadata !{metadata !"foo.c", metadata !"/usr/local/google/home/echristo/tmp"}
!2 = metadata !{i32 0}
!3 = metadata !{metadata !4}
!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"f", metadata !"f", metadata !"", i32 1, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @f, null, null, metadata !2, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [f]
!5 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [/usr/local/google/home/echristo/tmp/foo.c]
!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
!7 = metadata !{metadata !8, metadata !8}
!8 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
!9 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
!10 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
!11 = metadata !{metadata !"clang version 3.5 (trunk 197756) (llvm/trunk 197768)"}
!12 = metadata !{i32 786689, metadata !4, metadata !"a", metadata !5, i32 16777217, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [a] [line 1]
!13 = metadata !{i32 1, i32 0, metadata !4, null}
!14 = metadata !{i32 2, i32 0, metadata !4, null}