[llvm-commits] [llvm] r72193 - in /llvm/trunk/lib/CodeGen/AsmPrinter: DwarfDebug.cpp DwarfDebug.h
Bill Wendling
isanbard at gmail.com
Wed May 20 16:19:14 PDT 2009
Author: void
Date: Wed May 20 18:19:06 2009
New Revision: 72193
URL: http://llvm.org/viewvc/llvm-project?rev=72193&view=rev
Log:
Revert r72192. It was causing a build failure.
Modified:
llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h
Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp?rev=72193&r1=72192&r2=72193&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Wed May 20 18:19:06 2009
@@ -275,9 +275,9 @@
}
}
-/// CreateDIEEntry - Creates a new DIEEntry to be a proxy for a debug
-/// information entry.
-DIEEntry *DwarfDebug::CreateDIEEntry(DIE *Entry) {
+/// NewDIEEntry - Creates a new DIEEntry to be a proxy for a debug information
+/// entry.
+DIEEntry *DwarfDebug::NewDIEEntry(DIE *Entry) {
DIEEntry *Value;
if (Entry) {
@@ -545,7 +545,7 @@
}
// Set up proxy.
- Slot = CreateDIEEntry();
+ Slot = NewDIEEntry();
// Construct type.
DIE Buffer(dwarf::DW_TAG_base_type);
@@ -925,9 +925,9 @@
return *I->second;
}
-/// CreateDbgScopeVariable - Create a new scope variable.
+/// NewDbgScopeVariable - Create a new scope variable.
///
-DIE *DwarfDebug::CreateDbgScopeVariable(DbgVariable *DV, CompileUnit *Unit) {
+DIE *DwarfDebug::NewDbgScopeVariable(DbgVariable *DV, CompileUnit *Unit) {
// Get the descriptor.
const DIVariable &VD = DV->getVariable();
@@ -1012,7 +1012,7 @@
// Add variables to scope.
SmallVector<DbgVariable *, 8> &Variables = ParentScope->getVariables();
for (unsigned i = 0, N = Variables.size(); i < N; ++i) {
- DIE *VariableDie = CreateDbgScopeVariable(Variables[i], Unit);
+ DIE *VariableDie = NewDbgScopeVariable(Variables[i], Unit);
if (VariableDie) ParentDie->AddChild(VariableDie);
}
@@ -1092,8 +1092,7 @@
/// ConstructFunctionDbgScope - Construct the scope for the subprogram.
///
-void DwarfDebug::ConstructFunctionDbgScope(DbgScope *RootScope,
- bool AbstractScope) {
+void DwarfDebug::ConstructFunctionDbgScope(DbgScope *RootScope) {
// Exit if there is no root scope.
if (!RootScope) return;
DIDescriptor Desc = RootScope->getDesc();
@@ -1112,19 +1111,43 @@
DIE *SPDie = Unit->getDieMapSlotFor(SPD.getGV());
assert(SPDie && "Missing subprogram descriptor");
- if (!AbstractScope) {
- // Add the function bounds.
- AddLabel(SPDie, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr,
- DWLabel("func_begin", SubprogramCount));
- AddLabel(SPDie, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr,
- DWLabel("func_end", SubprogramCount));
- MachineLocation Location(RI->getFrameRegister(*MF));
- AddAddress(SPDie, dwarf::DW_AT_frame_base, Location);
- }
+ // Add the function bounds.
+ AddLabel(SPDie, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr,
+ DWLabel("func_begin", SubprogramCount));
+ AddLabel(SPDie, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr,
+ DWLabel("func_end", SubprogramCount));
+ MachineLocation Location(RI->getFrameRegister(*MF));
+ AddAddress(SPDie, dwarf::DW_AT_frame_base, Location);
ConstructDbgScope(RootScope, 0, 0, SPDie, Unit);
}
+/// ConstructFunctionDbgScope - Construct the scope for the abstract debug
+/// scope.
+///
+void DwarfDebug::ConstructAbstractDbgScope(DbgScope *AbsScope) {
+ // Exit if there is no root scope.
+ if (!AbsScope) return;
+
+ DIDescriptor Desc = AbsScope->getDesc();
+ if (Desc.isNull())
+ return;
+
+ // Get the subprogram debug information entry.
+ DISubprogram SPD(Desc.getGV());
+
+ // Get the compile unit context.
+ CompileUnit *Unit = MainCU;
+ if (!Unit)
+ Unit = &FindCompileUnit(SPD.getCompileUnit());
+
+ // Get the subprogram die.
+ DIE *SPDie = Unit->getDieMapSlotFor(SPD.getGV());
+ assert(SPDie && "Missing subprogram descriptor");
+
+ ConstructDbgScope(AbsScope, 0, 0, SPDie, Unit);
+}
+
/// ConstructDefaultDbgScope - Construct a default scope for the subprogram.
///
void DwarfDebug::ConstructDefaultDbgScope(MachineFunction *MF) {
@@ -1173,1451 +1196,1445 @@
#endif
}
-/// 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
-/// in the SourceIds map. This can update DirectoryNames and SourceFileNames
-/// maps as well.
-unsigned DwarfDebug::GetOrCreateSourceID(const std::string &DirName,
- const std::string &FileName) {
- unsigned DId;
- StringMap<unsigned>::iterator DI = DirectoryIdMap.find(DirName);
- if (DI != DirectoryIdMap.end()) {
- DId = DI->getValue();
- } else {
- DId = DirectoryNames.size() + 1;
- DirectoryIdMap[DirName] = DId;
- DirectoryNames.push_back(DirName);
- }
+/// EmitInitial - Emit initial Dwarf declarations. This is necessary for cc
+/// tools to recognize the object file contains Dwarf information.
+void DwarfDebug::EmitInitial() {
+ // Check to see if we already emitted intial headers.
+ if (didInitial) return;
+ didInitial = true;
- unsigned FId;
- StringMap<unsigned>::iterator FI = SourceFileIdMap.find(FileName);
- if (FI != SourceFileIdMap.end()) {
- FId = FI->getValue();
- } else {
- FId = SourceFileNames.size() + 1;
- SourceFileIdMap[FileName] = FId;
- SourceFileNames.push_back(FileName);
+ // Dwarf sections base addresses.
+ if (TAI->doesDwarfRequireFrameSection()) {
+ Asm->SwitchToDataSection(TAI->getDwarfFrameSection());
+ EmitLabel("section_debug_frame", 0);
}
- DenseMap<std::pair<unsigned, unsigned>, unsigned>::iterator SI =
- SourceIdMap.find(std::make_pair(DId, FId));
- if (SI != SourceIdMap.end())
- return SI->second;
+ Asm->SwitchToDataSection(TAI->getDwarfInfoSection());
+ EmitLabel("section_info", 0);
+ Asm->SwitchToDataSection(TAI->getDwarfAbbrevSection());
+ EmitLabel("section_abbrev", 0);
+ Asm->SwitchToDataSection(TAI->getDwarfARangesSection());
+ EmitLabel("section_aranges", 0);
- unsigned SrcId = SourceIds.size() + 1; // DW_AT_decl_file cannot be 0.
- SourceIdMap[std::make_pair(DId, FId)] = SrcId;
- SourceIds.push_back(std::make_pair(DId, FId));
+ if (TAI->doesSupportMacInfoSection()) {
+ Asm->SwitchToDataSection(TAI->getDwarfMacInfoSection());
+ EmitLabel("section_macinfo", 0);
+ }
- return SrcId;
-}
+ Asm->SwitchToDataSection(TAI->getDwarfLineSection());
+ EmitLabel("section_line", 0);
+ Asm->SwitchToDataSection(TAI->getDwarfLocSection());
+ EmitLabel("section_loc", 0);
+ Asm->SwitchToDataSection(TAI->getDwarfPubNamesSection());
+ EmitLabel("section_pubnames", 0);
+ Asm->SwitchToDataSection(TAI->getDwarfStrSection());
+ EmitLabel("section_str", 0);
+ Asm->SwitchToDataSection(TAI->getDwarfRangesSection());
+ EmitLabel("section_ranges", 0);
-void DwarfDebug::ConstructCompileUnit(GlobalVariable *GV) {
- DICompileUnit DIUnit(GV);
- std::string Dir, FN, Prod;
- unsigned ID = GetOrCreateSourceID(DIUnit.getDirectory(Dir),
- DIUnit.getFilename(FN));
+ Asm->SwitchToSection(TAI->getTextSection());
+ EmitLabel("text_begin", 0);
+ Asm->SwitchToSection(TAI->getDataSection());
+ EmitLabel("data_begin", 0);
+}
- DIE *Die = new DIE(dwarf::DW_TAG_compile_unit);
- AddSectionOffset(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4,
- DWLabel("section_line", 0), DWLabel("section_line", 0),
- false);
- AddString(Die, dwarf::DW_AT_producer, dwarf::DW_FORM_string,
- DIUnit.getProducer(Prod));
- AddUInt(Die, dwarf::DW_AT_language, dwarf::DW_FORM_data1,
- DIUnit.getLanguage());
- AddString(Die, dwarf::DW_AT_name, dwarf::DW_FORM_string, FN);
+/// EmitDIE - Recusively Emits a debug information entry.
+///
+void DwarfDebug::EmitDIE(DIE *Die) {
+ // Get the abbreviation for this DIE.
+ unsigned AbbrevNumber = Die->getAbbrevNumber();
+ const DIEAbbrev *Abbrev = Abbreviations[AbbrevNumber - 1];
- if (!Dir.empty())
- AddString(Die, dwarf::DW_AT_comp_dir, dwarf::DW_FORM_string, Dir);
- if (DIUnit.isOptimized())
- AddUInt(Die, dwarf::DW_AT_APPLE_optimized, dwarf::DW_FORM_flag, 1);
+ Asm->EOL();
- std::string Flags;
- DIUnit.getFlags(Flags);
- if (!Flags.empty())
- AddString(Die, dwarf::DW_AT_APPLE_flags, dwarf::DW_FORM_string, Flags);
+ // Emit the code (index) for the abbreviation.
+ Asm->EmitULEB128Bytes(AbbrevNumber);
- unsigned RVer = DIUnit.getRunTimeVersion();
- if (RVer)
- AddUInt(Die, dwarf::DW_AT_APPLE_major_runtime_vers,
- dwarf::DW_FORM_data1, RVer);
+ if (Asm->isVerbose())
+ Asm->EOL(std::string("Abbrev [" +
+ utostr(AbbrevNumber) +
+ "] 0x" + utohexstr(Die->getOffset()) +
+ ":0x" + utohexstr(Die->getSize()) + " " +
+ dwarf::TagString(Abbrev->getTag())));
+ else
+ Asm->EOL();
- CompileUnit *Unit = new CompileUnit(ID, Die);
- if (DIUnit.isMain()) {
- assert(!MainCU && "Multiple main compile units are found!");
- MainCU = Unit;
- }
+ SmallVector<DIEValue*, 32> &Values = Die->getValues();
+ const SmallVector<DIEAbbrevData, 8> &AbbrevData = Abbrev->getData();
- CompileUnitMap[DIUnit.getGV()] = Unit;
- CompileUnits.push_back(Unit);
-}
+ // Emit the DIE attribute values.
+ for (unsigned i = 0, N = Values.size(); i < N; ++i) {
+ unsigned Attr = AbbrevData[i].getAttribute();
+ unsigned Form = AbbrevData[i].getForm();
+ assert(Form && "Too many attributes for DIE (check abbreviation)");
-/// ConstructCompileUnits - Create a compile unit DIEs.
-void DwarfDebug::ConstructCompileUnits() {
- GlobalVariable *Root = M->getGlobalVariable("llvm.dbg.compile_units");
- if (!Root)
- return;
- assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() &&
- "Malformed compile unit descriptor anchor type");
- Constant *RootC = cast<Constant>(*Root->use_begin());
- assert(RootC->hasNUsesOrMore(1) &&
- "Malformed compile unit descriptor anchor type");
+ switch (Attr) {
+ case dwarf::DW_AT_sibling:
+ Asm->EmitInt32(Die->SiblingOffset());
+ break;
+ case dwarf::DW_AT_abstract_origin: {
+ DIEEntry *E = cast<DIEEntry>(Values[i]);
+ DIE *Origin = E->getEntry();
+ unsigned Addr =
+ CompileUnitOffsets[Die->getAbstractCompileUnit()] +
+ Origin->getOffset();
- for (Value::use_iterator UI = RootC->use_begin(), UE = Root->use_end();
- UI != UE; ++UI)
- for (Value::use_iterator UUI = UI->use_begin(), UUE = UI->use_end();
- UUI != UUE; ++UUI) {
- GlobalVariable *GV = cast<GlobalVariable>(*UUI);
- ConstructCompileUnit(GV);
+ Asm->EmitInt32(Addr);
+ break;
+ }
+ default:
+ // Emit an attribute using the defined form.
+ Values[i]->EmitValue(this, Form);
+ break;
}
-}
-bool DwarfDebug::ConstructGlobalVariableDIE(GlobalVariable *GV) {
- DIGlobalVariable DI_GV(GV);
- CompileUnit *DW_Unit = MainCU;
- if (!DW_Unit)
- DW_Unit = &FindCompileUnit(DI_GV.getCompileUnit());
+ Asm->EOL(dwarf::AttributeString(Attr));
+ }
- // Check for pre-existence.
- DIE *&Slot = DW_Unit->getDieMapSlotFor(DI_GV.getGV());
- if (Slot)
- return false;
+ // Emit the DIE children if any.
+ if (Abbrev->getChildrenFlag() == dwarf::DW_CHILDREN_yes) {
+ const std::vector<DIE *> &Children = Die->getChildren();
- DIE *VariableDie = CreateGlobalVariableDIE(DW_Unit, DI_GV);
+ for (unsigned j = 0, M = Children.size(); j < M; ++j)
+ EmitDIE(Children[j]);
- // Add address.
- DIEBlock *Block = new DIEBlock();
- AddUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_addr);
- std::string GLN;
- AddObjectLabel(Block, 0, dwarf::DW_FORM_udata,
- Asm->getGlobalLinkName(DI_GV.getGlobal(), GLN));
- AddBlock(VariableDie, dwarf::DW_AT_location, 0, Block);
+ Asm->EmitInt8(0); Asm->EOL("End Of Children Mark");
+ }
+}
- // Add to map.
- Slot = VariableDie;
+/// SizeAndOffsetDie - Compute the size and offset of a DIE.
+///
+unsigned DwarfDebug::SizeAndOffsetDie(DIE *Die, unsigned Offset, bool Last) {
+ // Get the children.
+ const std::vector<DIE *> &Children = Die->getChildren();
- // Add to context owner.
- DW_Unit->getDie()->AddChild(VariableDie);
+ // If not last sibling and has children then add sibling offset attribute.
+ if (!Last && !Children.empty()) Die->AddSiblingOffset();
- // Expose as global. FIXME - need to check external flag.
- std::string Name;
- DW_Unit->AddGlobal(DI_GV.getName(Name), VariableDie);
- return true;
-}
+ // Record the abbreviation.
+ AssignAbbrevNumber(Die->getAbbrev());
-/// ConstructGlobalVariableDIEs - Create DIEs for each of the externally visible
-/// global variables. Return true if at least one global DIE is created.
-bool DwarfDebug::ConstructGlobalVariableDIEs() {
- GlobalVariable *Root = M->getGlobalVariable("llvm.dbg.global_variables");
- if (!Root)
- return false;
+ // Get the abbreviation for this DIE.
+ unsigned AbbrevNumber = Die->getAbbrevNumber();
+ const DIEAbbrev *Abbrev = Abbreviations[AbbrevNumber - 1];
- assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() &&
- "Malformed global variable descriptor anchor type");
- Constant *RootC = cast<Constant>(*Root->use_begin());
- assert(RootC->hasNUsesOrMore(1) &&
- "Malformed global variable descriptor anchor type");
+ // Set DIE offset
+ Die->setOffset(Offset);
- bool Result = false;
- for (Value::use_iterator UI = RootC->use_begin(), UE = Root->use_end();
- UI != UE; ++UI)
- for (Value::use_iterator UUI = UI->use_begin(), UUE = UI->use_end();
- UUI != UUE; ++UUI)
- Result |= ConstructGlobalVariableDIE(cast<GlobalVariable>(*UUI));
+ // Start the size with the size of abbreviation code.
+ Offset += TargetAsmInfo::getULEB128Size(AbbrevNumber);
- return Result;
-}
+ const SmallVector<DIEValue*, 32> &Values = Die->getValues();
+ const SmallVector<DIEAbbrevData, 8> &AbbrevData = Abbrev->getData();
-bool DwarfDebug::ConstructSubprogram(GlobalVariable *GV) {
- DISubprogram SP(GV);
- CompileUnit *Unit = MainCU;
- if (!Unit)
- Unit = &FindCompileUnit(SP.getCompileUnit());
+ // Size the DIE attribute values.
+ for (unsigned i = 0, N = Values.size(); i < N; ++i)
+ // Size attribute value.
+ Offset += Values[i]->SizeOf(TD, AbbrevData[i].getForm());
- // Check for pre-existence.
- DIE *&Slot = Unit->getDieMapSlotFor(GV);
- if (Slot)
- return false;
+ // Size the DIE children if any.
+ if (!Children.empty()) {
+ assert(Abbrev->getChildrenFlag() == dwarf::DW_CHILDREN_yes &&
+ "Children flag not set");
- if (!SP.isDefinition())
- // This is a method declaration which will be handled while constructing
- // class type.
- return false;
+ for (unsigned j = 0, M = Children.size(); j < M; ++j)
+ Offset = SizeAndOffsetDie(Children[j], Offset, (j + 1) == M);
- DIE *SubprogramDie = CreateSubprogramDIE(Unit, SP);
+ // End of children marker.
+ Offset += sizeof(int8_t);
+ }
- // Add to map.
- Slot = SubprogramDie;
+ Die->setSize(Offset - Die->getOffset());
+ return Offset;
+}
- // Add to context owner.
- Unit->getDie()->AddChild(SubprogramDie);
+/// SizeAndOffsets - Compute the size and offset of all the DIEs.
+///
+void DwarfDebug::SizeAndOffsets() {
+ // Compute size of compile unit header.
+ static unsigned Offset =
+ sizeof(int32_t) + // Length of Compilation Unit Info
+ sizeof(int16_t) + // DWARF version number
+ sizeof(int32_t) + // Offset Into Abbrev. Section
+ sizeof(int8_t); // Pointer Size (in bytes)
- // Expose as global.
- std::string Name;
- Unit->AddGlobal(SP.getName(Name), SubprogramDie);
- return true;
+ // Process base compile unit.
+ if (MainCU) {
+ SizeAndOffsetDie(MainCU->getDie(), Offset, true);
+ CompileUnitOffsets[MainCU] = 0;
+ return;
+ }
+
+ // Process all compile units.
+ unsigned PrevOffset = 0;
+
+ for (unsigned i = 0, e = CompileUnits.size(); i != e; ++i) {
+ CompileUnit *Unit = CompileUnits[i];
+ CompileUnitOffsets[Unit] = PrevOffset;
+ PrevOffset += SizeAndOffsetDie(Unit->getDie(), Offset, true)
+ + sizeof(int32_t); // FIXME - extra pad for gdb bug.
+ }
}
-/// ConstructSubprograms - Create DIEs for each of the externally visible
-/// subprograms. Return true if at least one subprogram DIE is created.
-bool DwarfDebug::ConstructSubprograms() {
- GlobalVariable *Root = M->getGlobalVariable("llvm.dbg.subprograms");
- if (!Root)
- return false;
+/// EmitDebugInfo / EmitDebugInfoPerCU - Emit the debug info section.
+///
+void DwarfDebug::EmitDebugInfoPerCU(CompileUnit *Unit) {
+ DIE *Die = Unit->getDie();
- assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() &&
- "Malformed subprogram descriptor anchor type");
- Constant *RootC = cast<Constant>(*Root->use_begin());
- assert(RootC->hasNUsesOrMore(1) &&
- "Malformed subprogram descriptor anchor type");
+ // Emit the compile units header.
+ EmitLabel("info_begin", Unit->getID());
- bool Result = false;
- for (Value::use_iterator UI = RootC->use_begin(), UE = Root->use_end();
- UI != UE; ++UI)
- for (Value::use_iterator UUI = UI->use_begin(), UUE = UI->use_end();
- UUI != UUE; ++UUI)
- Result |= ConstructSubprogram(cast<GlobalVariable>(*UUI));
+ // Emit size of content not including length itself
+ unsigned ContentSize = Die->getSize() +
+ sizeof(int16_t) + // DWARF version number
+ sizeof(int32_t) + // Offset Into Abbrev. Section
+ sizeof(int8_t) + // Pointer Size (in bytes)
+ sizeof(int32_t); // FIXME - extra pad for gdb bug.
- return Result;
-}
+ Asm->EmitInt32(ContentSize); Asm->EOL("Length of Compilation Unit Info");
+ Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("DWARF version number");
+ EmitSectionOffset("abbrev_begin", "section_abbrev", 0, 0, true, false);
+ Asm->EOL("Offset Into Abbrev. Section");
+ Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Address Size (in bytes)");
-/// SetDebugInfo - Create global DIEs and emit initial debug info sections.
-/// This is inovked by the target AsmPrinter.
-void DwarfDebug::SetDebugInfo(MachineModuleInfo *mmi) {
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ EmitDIE(Die);
+ // FIXME - extra padding for gdb bug.
+ Asm->EmitInt8(0); Asm->EOL("Extra Pad For GDB");
+ Asm->EmitInt8(0); Asm->EOL("Extra Pad For GDB");
+ Asm->EmitInt8(0); Asm->EOL("Extra Pad For GDB");
+ Asm->EmitInt8(0); Asm->EOL("Extra Pad For GDB");
+ EmitLabel("info_end", Unit->getID());
- // Create all the compile unit DIEs.
- ConstructCompileUnits();
+ Asm->EOL();
+}
- if (CompileUnits.empty()) {
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+void DwarfDebug::EmitDebugInfo() {
+ // Start debug info section.
+ Asm->SwitchToDataSection(TAI->getDwarfInfoSection());
+ if (MainCU) {
+ EmitDebugInfoPerCU(MainCU);
return;
}
- // Create DIEs for each of the externally visible global variables.
- bool globalDIEs = ConstructGlobalVariableDIEs();
+ for (unsigned i = 0, e = CompileUnits.size(); i != e; ++i)
+ EmitDebugInfoPerCU(CompileUnits[i]);
+}
- // Create DIEs for each of the externally visible subprograms.
- bool subprogramDIEs = ConstructSubprograms();
+/// EmitAbbreviations - Emit the abbreviation section.
+///
+void DwarfDebug::EmitAbbreviations() const {
+ // Check to see if it is worth the effort.
+ if (!Abbreviations.empty()) {
+ // Start the debug abbrev section.
+ Asm->SwitchToDataSection(TAI->getDwarfAbbrevSection());
- // If there is not any debug info available for any global variables and any
- // subprograms then there is not any debug info to emit.
- if (!globalDIEs && !subprogramDIEs) {
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ EmitLabel("abbrev_begin", 0);
- return;
- }
+ // For each abbrevation.
+ for (unsigned i = 0, N = Abbreviations.size(); i < N; ++i) {
+ // Get abbreviation data
+ const DIEAbbrev *Abbrev = Abbreviations[i];
- MMI = mmi;
- shouldEmit = true;
- MMI->setDebugInfoAvailability(true);
+ // Emit the abbrevations code (base 1 index.)
+ Asm->EmitULEB128Bytes(Abbrev->getNumber());
+ Asm->EOL("Abbreviation Code");
- // Prime section data.
- SectionMap.insert(TAI->getTextSection());
+ // Emit the abbreviations data.
+ Abbrev->Emit(Asm);
- // Print out .file directives to specify files for .loc directives. These are
- // printed out early so that they precede any .loc directives.
- if (TAI->hasDotLocAndDotFile()) {
- for (unsigned i = 1, e = getNumSourceIds()+1; i != e; ++i) {
- // Remember source id starts at 1.
- std::pair<unsigned, unsigned> Id = getSourceDirectoryAndFileIds(i);
- sys::Path FullPath(getSourceDirectoryName(Id.first));
- bool AppendOk =
- FullPath.appendComponent(getSourceFileName(Id.second));
- assert(AppendOk && "Could not append filename to directory!");
- AppendOk = false;
- Asm->EmitFile(i, FullPath.toString());
Asm->EOL();
}
- }
- // Emit initial sections
- EmitInitial();
+ // Mark end of abbreviations.
+ Asm->EmitULEB128Bytes(0); Asm->EOL("EOM(3)");
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ EmitLabel("abbrev_end", 0);
+ Asm->EOL();
+ }
}
-/// EndModule - Emit all Dwarf sections that should come after the content.
+/// EmitEndOfLineMatrix - Emit the last address of the section and the end of
+/// the line matrix.
///
-void DwarfDebug::EndModule() {
- if (!ShouldEmitDwarfDebug())
- return;
+void DwarfDebug::EmitEndOfLineMatrix(unsigned SectionEnd) {
+ // Define last address of section.
+ Asm->EmitInt8(0); Asm->EOL("Extended Op");
+ Asm->EmitInt8(TD->getPointerSize() + 1); Asm->EOL("Op size");
+ Asm->EmitInt8(dwarf::DW_LNE_set_address); Asm->EOL("DW_LNE_set_address");
+ EmitReference("section_end", SectionEnd); Asm->EOL("Section end label");
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ // Mark end of matrix.
+ Asm->EmitInt8(0); Asm->EOL("DW_LNE_end_sequence");
+ Asm->EmitULEB128Bytes(1); Asm->EOL();
+ Asm->EmitInt8(1); Asm->EOL();
+}
- // Standard sections final addresses.
- Asm->SwitchToSection(TAI->getTextSection());
- EmitLabel("text_end", 0);
- Asm->SwitchToSection(TAI->getDataSection());
- EmitLabel("data_end", 0);
+/// EmitDebugLines - Emit source line information.
+///
+void DwarfDebug::EmitDebugLines() {
+ // If the target is using .loc/.file, the assembler will be emitting the
+ // .debug_line table automatically.
+ if (TAI->hasDotLocAndDotFile())
+ return;
- // End text sections.
- for (unsigned i = 1, N = SectionMap.size(); i <= N; ++i) {
- Asm->SwitchToSection(SectionMap[i]);
- EmitLabel("section_end", i);
- }
+ // Minimum line delta, thus ranging from -10..(255-10).
+ const int MinLineDelta = -(dwarf::DW_LNS_fixed_advance_pc + 1);
+ // Maximum line delta, thus ranging from -10..(255-10).
+ const int MaxLineDelta = 255 + MinLineDelta;
- // Emit common frame information.
- EmitCommonDebugFrame();
+ // Start the dwarf line section.
+ Asm->SwitchToDataSection(TAI->getDwarfLineSection());
- // Emit function debug frame information
- for (std::vector<FunctionDebugFrameInfo>::iterator I = DebugFrames.begin(),
- E = DebugFrames.end(); I != E; ++I)
- EmitFunctionDebugFrame(*I);
+ // Construct the section header.
+ EmitDifference("line_end", 0, "line_begin", 0, true);
+ Asm->EOL("Length of Source Line Info");
+ EmitLabel("line_begin", 0);
- // Compute DIE offsets and sizes.
- SizeAndOffsets();
+ Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("DWARF version number");
- // Emit all the DIEs into a debug info section
- EmitDebugInfo();
+ EmitDifference("line_prolog_end", 0, "line_prolog_begin", 0, true);
+ Asm->EOL("Prolog Length");
+ EmitLabel("line_prolog_begin", 0);
- // Corresponding abbreviations into a abbrev section.
- EmitAbbreviations();
+ Asm->EmitInt8(1); Asm->EOL("Minimum Instruction Length");
- // Emit source line correspondence into a debug line section.
- EmitDebugLines();
+ Asm->EmitInt8(1); Asm->EOL("Default is_stmt_start flag");
- // Emit info into a debug pubnames section.
- EmitDebugPubNames();
+ Asm->EmitInt8(MinLineDelta); Asm->EOL("Line Base Value (Special Opcodes)");
- // Emit info into a debug str section.
- EmitDebugStr();
+ Asm->EmitInt8(MaxLineDelta); Asm->EOL("Line Range Value (Special Opcodes)");
- // Emit info into a debug loc section.
- EmitDebugLoc();
+ Asm->EmitInt8(-MinLineDelta); Asm->EOL("Special Opcode Base");
- // Emit info into a debug aranges section.
- EmitDebugARanges();
-
- // Emit info into a debug ranges section.
- EmitDebugRanges();
-
- // Emit info into a debug macinfo section.
- EmitDebugMacInfo();
+ // Line number standard opcode encodings argument count
+ Asm->EmitInt8(0); Asm->EOL("DW_LNS_copy arg count");
+ Asm->EmitInt8(1); Asm->EOL("DW_LNS_advance_pc arg count");
+ Asm->EmitInt8(1); Asm->EOL("DW_LNS_advance_line arg count");
+ Asm->EmitInt8(1); Asm->EOL("DW_LNS_set_file arg count");
+ Asm->EmitInt8(1); Asm->EOL("DW_LNS_set_column arg count");
+ Asm->EmitInt8(0); Asm->EOL("DW_LNS_negate_stmt arg count");
+ Asm->EmitInt8(0); Asm->EOL("DW_LNS_set_basic_block arg count");
+ Asm->EmitInt8(0); Asm->EOL("DW_LNS_const_add_pc arg count");
+ Asm->EmitInt8(1); Asm->EOL("DW_LNS_fixed_advance_pc arg count");
- // Emit inline info.
- EmitDebugInlineInfo();
+ // Emit directories.
+ for (unsigned DI = 1, DE = getNumSourceDirectories()+1; DI != DE; ++DI) {
+ Asm->EmitString(getSourceDirectoryName(DI));
+ Asm->EOL("Directory");
+ }
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
-}
+ Asm->EmitInt8(0); Asm->EOL("End of directories");
-/// BeginFunction - Gather pre-function debug information. Assumes being
-/// emitted immediately after the function entry point.
-void DwarfDebug::BeginFunction(MachineFunction *MF) {
- this->MF = MF;
+ // Emit files.
+ for (unsigned SI = 1, SE = getNumSourceIds()+1; SI != SE; ++SI) {
+ // Remember source id starts at 1.
+ std::pair<unsigned, unsigned> Id = getSourceDirectoryAndFileIds(SI);
+ Asm->EmitString(getSourceFileName(Id.second));
+ Asm->EOL("Source");
+ Asm->EmitULEB128Bytes(Id.first);
+ Asm->EOL("Directory #");
+ Asm->EmitULEB128Bytes(0);
+ Asm->EOL("Mod date");
+ Asm->EmitULEB128Bytes(0);
+ Asm->EOL("File size");
+ }
- if (!ShouldEmitDwarfDebug()) return;
+ Asm->EmitInt8(0); Asm->EOL("End of files");
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ EmitLabel("line_prolog_end", 0);
- // Begin accumulating function debug information.
- MMI->BeginFunction(MF);
+ // A sequence for each text section.
+ unsigned SecSrcLinesSize = SectionSourceLines.size();
- // Assumes in correct section after the entry point.
- EmitLabel("func_begin", ++SubprogramCount);
+ for (unsigned j = 0; j < SecSrcLinesSize; ++j) {
+ // Isolate current sections line info.
+ const std::vector<SrcLineInfo> &LineInfos = SectionSourceLines[j];
- // Emit label for the implicitly defined dbg.stoppoint at the start of the
- // function.
- DebugLoc FDL = MF->getDefaultDebugLoc();
- if (!FDL.isUnknown()) {
- DebugLocTuple DLT = MF->getDebugLocTuple(FDL);
- unsigned LabelID = RecordSourceLine(DLT.Line, DLT.Col,
- DICompileUnit(DLT.CompileUnit));
- Asm->printLabel(LabelID);
- }
+ if (Asm->isVerbose()) {
+ const Section* S = SectionMap[j + 1];
+ O << '\t' << TAI->getCommentString() << " Section"
+ << S->getName() << '\n';
+ } else {
+ Asm->EOL();
+ }
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
-}
+ // Dwarf assumes we start with first line of first source file.
+ unsigned Source = 1;
+ unsigned Line = 1;
-/// EndFunction - Gather and emit post-function debug information.
-///
-void DwarfDebug::EndFunction(MachineFunction *MF) {
- if (!ShouldEmitDwarfDebug()) return;
+ // Construct rows of the address, source, line, column matrix.
+ for (unsigned i = 0, N = LineInfos.size(); i < N; ++i) {
+ const SrcLineInfo &LineInfo = LineInfos[i];
+ unsigned LabelID = MMI->MappedLabel(LineInfo.getLabelID());
+ if (!LabelID) continue;
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ if (!Asm->isVerbose())
+ Asm->EOL();
+ else {
+ std::pair<unsigned, unsigned> SourceID =
+ getSourceDirectoryAndFileIds(LineInfo.getSourceID());
+ O << '\t' << TAI->getCommentString() << ' '
+ << getSourceDirectoryName(SourceID.first) << ' '
+ << getSourceFileName(SourceID.second)
+ <<" :" << utostr_32(LineInfo.getLine()) << '\n';
+ }
- // Define end label for subprogram.
- EmitLabel("func_end", SubprogramCount);
+ // Define the line address.
+ Asm->EmitInt8(0); Asm->EOL("Extended Op");
+ Asm->EmitInt8(TD->getPointerSize() + 1); Asm->EOL("Op size");
+ Asm->EmitInt8(dwarf::DW_LNE_set_address); Asm->EOL("DW_LNE_set_address");
+ EmitReference("label", LabelID); Asm->EOL("Location label");
- // Get function line info.
- if (!Lines.empty()) {
- // Get section line info.
- unsigned ID = SectionMap.insert(Asm->CurrentSection_);
- if (SectionSourceLines.size() < ID) SectionSourceLines.resize(ID);
- std::vector<SrcLineInfo> &SectionLineInfos = SectionSourceLines[ID-1];
- // Append the function info to section info.
- SectionLineInfos.insert(SectionLineInfos.end(),
- Lines.begin(), Lines.end());
- }
+ // If change of source, then switch to the new source.
+ if (Source != LineInfo.getSourceID()) {
+ Source = LineInfo.getSourceID();
+ Asm->EmitInt8(dwarf::DW_LNS_set_file); Asm->EOL("DW_LNS_set_file");
+ Asm->EmitULEB128Bytes(Source); Asm->EOL("New Source");
+ }
- // Construct the DbgScope for abstract instances.
- for (SmallVector<DbgScope *, 32>::iterator
- I = AbstractInstanceRootList.begin(),
- E = AbstractInstanceRootList.end(); I != E; ++I)
- ConstructFunctionDbgScope(*I, true);
+ // If change of line.
+ if (Line != LineInfo.getLine()) {
+ // Determine offset.
+ int Offset = LineInfo.getLine() - Line;
+ int Delta = Offset - MinLineDelta;
- // Construct scopes for subprogram.
- if (FunctionDbgScope)
- ConstructFunctionDbgScope(FunctionDbgScope);
- else
- // FIXME: This is wrong. We are essentially getting past a problem with
- // debug information not being able to handle unreachable blocks that have
- // debug information in them. In particular, those unreachable blocks that
- // have "region end" info in them. That situation results in the "root
- // scope" not being created. If that's the case, then emit a "default"
- // scope, i.e., one that encompasses the whole function. This isn't
- // desirable. And a better way of handling this (and all of the debugging
- // information) needs to be explored.
- ConstructDefaultDbgScope(MF);
+ // Update line.
+ Line = LineInfo.getLine();
- DebugFrames.push_back(FunctionDebugFrameInfo(SubprogramCount,
- MMI->getFrameMoves()));
+ // If delta is small enough and in range...
+ if (Delta >= 0 && Delta < (MaxLineDelta - 1)) {
+ // ... then use fast opcode.
+ Asm->EmitInt8(Delta - MinLineDelta); Asm->EOL("Line Delta");
+ } else {
+ // ... otherwise use long hand.
+ Asm->EmitInt8(dwarf::DW_LNS_advance_line);
+ Asm->EOL("DW_LNS_advance_line");
+ Asm->EmitSLEB128Bytes(Offset); Asm->EOL("Line Offset");
+ Asm->EmitInt8(dwarf::DW_LNS_copy); Asm->EOL("DW_LNS_copy");
+ }
+ } else {
+ // Copy the previous row (different address or source)
+ Asm->EmitInt8(dwarf::DW_LNS_copy); Asm->EOL("DW_LNS_copy");
+ }
+ }
- // Clear debug info
- if (FunctionDbgScope) {
- delete FunctionDbgScope;
- DbgScopeMap.clear();
- DbgAbstractScopeMap.clear();
- DbgConcreteScopeMap.clear();
- InlinedVariableScopes.clear();
- FunctionDbgScope = NULL;
- LexicalScopeStack.clear();
- AbstractInstanceRootList.clear();
+ EmitEndOfLineMatrix(j + 1);
}
- Lines.clear();
+ if (SecSrcLinesSize == 0)
+ // Because we're emitting a debug_line section, we still need a line
+ // table. The linker and friends expect it to exist. If there's nothing to
+ // put into it, emit an empty table.
+ EmitEndOfLineMatrix(1);
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ EmitLabel("line_end", 0);
+ Asm->EOL();
}
-/// RecordSourceLine - Records location information and associates it with a
-/// label. Returns a unique label ID used to generate a label and provide
-/// correspondence to the source line list.
-unsigned DwarfDebug::RecordSourceLine(Value *V, unsigned Line, unsigned Col) {
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+/// EmitCommonDebugFrame - Emit common frame info into a debug frame section.
+///
+void DwarfDebug::EmitCommonDebugFrame() {
+ if (!TAI->doesDwarfRequireFrameSection())
+ return;
- CompileUnit *Unit = CompileUnitMap[V];
- assert(Unit && "Unable to find CompileUnit");
- unsigned ID = MMI->NextLabelID();
- Lines.push_back(SrcLineInfo(Line, Col, Unit->getID(), ID));
+ int stackGrowth =
+ Asm->TM.getFrameInfo()->getStackGrowthDirection() ==
+ TargetFrameInfo::StackGrowsUp ?
+ TD->getPointerSize() : -TD->getPointerSize();
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ // Start the dwarf frame section.
+ Asm->SwitchToDataSection(TAI->getDwarfFrameSection());
- return ID;
-}
+ EmitLabel("debug_frame_common", 0);
+ EmitDifference("debug_frame_common_end", 0,
+ "debug_frame_common_begin", 0, true);
+ Asm->EOL("Length of Common Information Entry");
-/// RecordSourceLine - Records location information and associates it with a
-/// label. Returns a unique label ID used to generate a label and provide
-/// correspondence to the source line list.
-unsigned DwarfDebug::RecordSourceLine(unsigned Line, unsigned Col,
- DICompileUnit CU) {
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ EmitLabel("debug_frame_common_begin", 0);
+ Asm->EmitInt32((int)dwarf::DW_CIE_ID);
+ Asm->EOL("CIE Identifier Tag");
+ Asm->EmitInt8(dwarf::DW_CIE_VERSION);
+ Asm->EOL("CIE Version");
+ Asm->EmitString("");
+ Asm->EOL("CIE Augmentation");
+ Asm->EmitULEB128Bytes(1);
+ Asm->EOL("CIE Code Alignment Factor");
+ Asm->EmitSLEB128Bytes(stackGrowth);
+ Asm->EOL("CIE Data Alignment Factor");
+ Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), false));
+ Asm->EOL("CIE RA Column");
- std::string Dir, Fn;
- unsigned Src = GetOrCreateSourceID(CU.getDirectory(Dir),
- CU.getFilename(Fn));
- unsigned ID = MMI->NextLabelID();
- Lines.push_back(SrcLineInfo(Line, Col, Src, ID));
+ std::vector<MachineMove> Moves;
+ RI->getInitialFrameState(Moves);
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ EmitFrameMoves(NULL, 0, Moves, false);
- return ID;
+ Asm->EmitAlignment(2, 0, 0, false);
+ EmitLabel("debug_frame_common_end", 0);
+
+ Asm->EOL();
}
-/// getOrCreateSourceID - Public version of GetOrCreateSourceID. This can be
-/// timed. Look up the source id with the given directory and 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 as
-/// well.
-unsigned DwarfDebug::getOrCreateSourceID(const std::string &DirName,
- const std::string &FileName) {
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+/// EmitFunctionDebugFrame - Emit per function frame info into a debug frame
+/// section.
+void
+DwarfDebug::EmitFunctionDebugFrame(const FunctionDebugFrameInfo&DebugFrameInfo){
+ if (!TAI->doesDwarfRequireFrameSection())
+ return;
- unsigned SrcId = GetOrCreateSourceID(DirName, FileName);
+ // Start the dwarf frame section.
+ Asm->SwitchToDataSection(TAI->getDwarfFrameSection());
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ EmitDifference("debug_frame_end", DebugFrameInfo.Number,
+ "debug_frame_begin", DebugFrameInfo.Number, true);
+ Asm->EOL("Length of Frame Information Entry");
- return SrcId;
-}
+ EmitLabel("debug_frame_begin", DebugFrameInfo.Number);
-/// RecordRegionStart - Indicate the start of a region.
-unsigned DwarfDebug::RecordRegionStart(GlobalVariable *V) {
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ EmitSectionOffset("debug_frame_common", "section_debug_frame",
+ 0, 0, true, false);
+ Asm->EOL("FDE CIE offset");
- DbgScope *Scope = getOrCreateScope(V);
- unsigned ID = MMI->NextLabelID();
- if (!Scope->getStartLabelID()) Scope->setStartLabelID(ID);
- LexicalScopeStack.push_back(Scope);
+ EmitReference("func_begin", DebugFrameInfo.Number);
+ Asm->EOL("FDE initial location");
+ EmitDifference("func_end", DebugFrameInfo.Number,
+ "func_begin", DebugFrameInfo.Number);
+ Asm->EOL("FDE address range");
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ EmitFrameMoves("func_begin", DebugFrameInfo.Number, DebugFrameInfo.Moves,
+ false);
- return ID;
-}
+ Asm->EmitAlignment(2, 0, 0, false);
+ EmitLabel("debug_frame_end", DebugFrameInfo.Number);
-/// RecordRegionEnd - Indicate the end of a region.
-unsigned DwarfDebug::RecordRegionEnd(GlobalVariable *V) {
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ Asm->EOL();
+}
- DbgScope *Scope = getOrCreateScope(V);
- unsigned ID = MMI->NextLabelID();
- Scope->setEndLabelID(ID);
- if (LexicalScopeStack.size() != 0)
- LexicalScopeStack.pop_back();
+void DwarfDebug::EmitDebugPubNamesPerCU(CompileUnit *Unit) {
+ EmitDifference("pubnames_end", Unit->getID(),
+ "pubnames_begin", Unit->getID(), true);
+ Asm->EOL("Length of Public Names Info");
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ EmitLabel("pubnames_begin", Unit->getID());
- return ID;
-}
+ Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("DWARF Version");
-/// RecordVariable - Indicate the declaration of a local variable.
-void DwarfDebug::RecordVariable(GlobalVariable *GV, unsigned FrameIndex,
- const MachineInstr *MI) {
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ EmitSectionOffset("info_begin", "section_info",
+ Unit->getID(), 0, true, false);
+ Asm->EOL("Offset of Compilation Unit Info");
- DIDescriptor Desc(GV);
- DbgScope *Scope = NULL;
- bool InlinedFnVar = false;
+ EmitDifference("info_end", Unit->getID(), "info_begin", Unit->getID(),
+ true);
+ Asm->EOL("Compilation Unit Length");
- if (Desc.getTag() == dwarf::DW_TAG_variable) {
- // GV is a global variable.
- DIGlobalVariable DG(GV);
- Scope = getOrCreateScope(DG.getContext().getGV());
- } else {
- DenseMap<const MachineInstr *, DbgScope *>::iterator
- SI = InlinedVariableScopes.find(MI);
+ StringMap<DIE*> &Globals = Unit->getGlobals();
+ for (StringMap<DIE*>::const_iterator
+ GI = Globals.begin(), GE = Globals.end(); GI != GE; ++GI) {
+ const char *Name = GI->getKeyData();
+ DIE * Entity = GI->second;
- if (SI != InlinedVariableScopes.end()) {
- // or GV is an inlined local variable.
- Scope = SI->second;
- } else {
- DIVariable DV(GV);
- GlobalVariable *V = DV.getContext().getGV();
+ Asm->EmitInt32(Entity->getOffset()); Asm->EOL("DIE offset");
+ Asm->EmitString(Name, strlen(Name)); Asm->EOL("External Name");
+ }
- // FIXME: The code that checks for the inlined local variable is a hack!
- DenseMap<const GlobalVariable *, DbgScope *>::iterator
- AI = AbstractInstanceRootMap.find(V);
+ Asm->EmitInt32(0); Asm->EOL("End Mark");
+ EmitLabel("pubnames_end", Unit->getID());
- if (AI != AbstractInstanceRootMap.end()) {
- // This method is called each time a DECLARE node is encountered. For an
- // inlined function, this could be many, many times. We don't want to
- // re-add variables to that DIE for each time. We just want to add them
- // once. Check to make sure that we haven't added them already.
- DenseMap<const GlobalVariable *,
- SmallSet<const GlobalVariable *, 32> >::iterator
- IP = InlinedParamMap.find(V);
+ Asm->EOL();
+}
- if (IP != InlinedParamMap.end() && IP->second.count(GV) > 0) {
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
- return;
- }
+/// EmitDebugPubNames - Emit visible names into a debug pubnames section.
+///
+void DwarfDebug::EmitDebugPubNames() {
+ // Start the dwarf pubnames section.
+ Asm->SwitchToDataSection(TAI->getDwarfPubNamesSection());
- // or GV is an inlined local variable.
- Scope = AI->second;
- InlinedParamMap[V].insert(GV);
- InlinedFnVar = true;
- } else {
- // or GV is a local variable.
- Scope = getOrCreateScope(V);
- }
- }
+ if (MainCU) {
+ EmitDebugPubNamesPerCU(MainCU);
+ return;
}
- assert(Scope && "Unable to find the variable's scope");
- DbgVariable *DV = new DbgVariable(DIVariable(GV), FrameIndex, InlinedFnVar);
- Scope->AddVariable(DV);
-
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ for (unsigned i = 0, e = CompileUnits.size(); i != e; ++i)
+ EmitDebugPubNamesPerCU(CompileUnits[i]);
}
-/// RecordInlinedFnStart - Indicate the start of inlined subroutine.
-unsigned DwarfDebug::RecordInlinedFnStart(DISubprogram &SP, DICompileUnit CU,
- unsigned Line, unsigned Col) {
- unsigned LabelID = MMI->NextLabelID();
-
- if (!TAI->doesDwarfUsesInlineInfoSection())
- return LabelID;
+/// EmitDebugStr - Emit visible names into a debug str section.
+///
+void DwarfDebug::EmitDebugStr() {
+ // Check to see if it is worth the effort.
+ if (!StringPool.empty()) {
+ // Start the dwarf str section.
+ Asm->SwitchToDataSection(TAI->getDwarfStrSection());
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ // For each of strings in the string pool.
+ for (unsigned StringID = 1, N = StringPool.size();
+ StringID <= N; ++StringID) {
+ // Emit a label for reference from debug information entries.
+ EmitLabel("string", StringID);
- GlobalVariable *GV = SP.getGV();
- DenseMap<const GlobalVariable *, DbgScope *>::iterator
- II = AbstractInstanceRootMap.find(GV);
+ // Emit the string itself.
+ const std::string &String = StringPool[StringID];
+ Asm->EmitString(String); Asm->EOL();
+ }
- if (II == AbstractInstanceRootMap.end()) {
- // Create an abstract instance entry for this inlined function if it doesn't
- // already exist.
- DbgScope *Scope = new DbgScope(NULL, DIDescriptor(GV));
+ Asm->EOL();
+ }
+}
- // Get the compile unit context.
- CompileUnit *Unit = &FindCompileUnit(SP.getCompileUnit());
- DIE *SPDie = Unit->getDieMapSlotFor(GV);
- if (!SPDie)
- SPDie = CreateSubprogramDIE(Unit, SP, false, true);
+/// EmitDebugLoc - Emit visible names into a debug loc section.
+///
+void DwarfDebug::EmitDebugLoc() {
+ // Start the dwarf loc section.
+ Asm->SwitchToDataSection(TAI->getDwarfLocSection());
+ Asm->EOL();
+}
- // Mark as being inlined. This makes this subprogram entry an abstract
- // instance root.
- // FIXME: Our debugger doesn't care about the value of DW_AT_inline, only
- // that it's defined. That probably won't change in the future. However,
- // this could be more elegant.
- AddUInt(SPDie, dwarf::DW_AT_inline, 0, dwarf::DW_INL_declared_not_inlined);
+/// EmitDebugARanges - Emit visible names into a debug aranges section.
+///
+void DwarfDebug::EmitDebugARanges() {
+ // Start the dwarf aranges section.
+ Asm->SwitchToDataSection(TAI->getDwarfARangesSection());
- // Keep track of the abstract scope for this function.
- DbgAbstractScopeMap[GV] = Scope;
+ // FIXME - Mock up
+#if 0
+ CompileUnit *Unit = GetBaseCompileUnit();
- AbstractInstanceRootMap[GV] = Scope;
- AbstractInstanceRootList.push_back(Scope);
- }
+ // Don't include size of length
+ Asm->EmitInt32(0x1c); Asm->EOL("Length of Address Ranges Info");
- // Create a concrete inlined instance for this inlined function.
- DbgConcreteScope *ConcreteScope = new DbgConcreteScope(DIDescriptor(GV));
- DIE *ScopeDie = new DIE(dwarf::DW_TAG_inlined_subroutine);
- CompileUnit *Unit = &FindCompileUnit(SP.getCompileUnit());
- ScopeDie->setAbstractCompileUnit(Unit);
+ Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("Dwarf Version");
- DIE *Origin = Unit->getDieMapSlotFor(GV);
- AddDIEEntry(ScopeDie, dwarf::DW_AT_abstract_origin,
- dwarf::DW_FORM_ref4, Origin);
- AddUInt(ScopeDie, dwarf::DW_AT_call_file, 0, Unit->getID());
- AddUInt(ScopeDie, dwarf::DW_AT_call_line, 0, Line);
- AddUInt(ScopeDie, dwarf::DW_AT_call_column, 0, Col);
+ EmitReference("info_begin", Unit->getID());
+ Asm->EOL("Offset of Compilation Unit Info");
- ConcreteScope->setDie(ScopeDie);
- ConcreteScope->setStartLabelID(LabelID);
- MMI->RecordUsedDbgLabel(LabelID);
+ Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Size of Address");
- LexicalScopeStack.back()->AddConcreteInst(ConcreteScope);
- LexicalScopeStack.push_back(ConcreteScope);
+ Asm->EmitInt8(0); Asm->EOL("Size of Segment Descriptor");
- // Keep track of the concrete scope that's inlined into this function.
- DenseMap<GlobalVariable *, SmallVector<DbgScope *, 8> >::iterator
- SI = DbgConcreteScopeMap.find(GV);
+ Asm->EmitInt16(0); Asm->EOL("Pad (1)");
+ Asm->EmitInt16(0); Asm->EOL("Pad (2)");
- if (SI == DbgConcreteScopeMap.end())
- DbgConcreteScopeMap[GV].push_back(ConcreteScope);
- else
- SI->second.push_back(ConcreteScope);
+ // Range 1
+ EmitReference("text_begin", 0); Asm->EOL("Address");
+ EmitDifference("text_end", 0, "text_begin", 0, true); Asm->EOL("Length");
- // Track the start label for this inlined function.
- DenseMap<GlobalVariable *, SmallVector<unsigned, 4> >::iterator
- I = InlineInfo.find(GV);
+ Asm->EmitInt32(0); Asm->EOL("EOM (1)");
+ Asm->EmitInt32(0); Asm->EOL("EOM (2)");
+#endif
- if (I == InlineInfo.end())
- InlineInfo[GV].push_back(LabelID);
- else
- I->second.push_back(LabelID);
+ Asm->EOL();
+}
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+/// EmitDebugRanges - Emit visible names into a debug ranges section.
+///
+void DwarfDebug::EmitDebugRanges() {
+ // Start the dwarf ranges section.
+ Asm->SwitchToDataSection(TAI->getDwarfRangesSection());
+ Asm->EOL();
+}
- return LabelID;
+/// EmitDebugMacInfo - Emit visible names into a debug macinfo section.
+///
+void DwarfDebug::EmitDebugMacInfo() {
+ if (TAI->doesSupportMacInfoSection()) {
+ // Start the dwarf macinfo section.
+ Asm->SwitchToDataSection(TAI->getDwarfMacInfoSection());
+ Asm->EOL();
+ }
}
-/// RecordInlinedFnEnd - Indicate the end of inlined subroutine.
-unsigned DwarfDebug::RecordInlinedFnEnd(DISubprogram &SP) {
+/// 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 DwarfDebug::EmitDebugInlineInfo() {
if (!TAI->doesDwarfUsesInlineInfoSection())
- return 0;
+ return;
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ if (!MainCU)
+ return;
- GlobalVariable *GV = SP.getGV();
- DenseMap<GlobalVariable *, SmallVector<DbgScope *, 8> >::iterator
- I = DbgConcreteScopeMap.find(GV);
+ Asm->SwitchToDataSection(TAI->getDwarfDebugInlineSection());
+ Asm->EOL();
+ EmitDifference("debug_inlined_end", 1,
+ "debug_inlined_begin", 1, true);
+ Asm->EOL("Length of Debug Inlined Information Entry");
- if (I == DbgConcreteScopeMap.end()) {
- // FIXME: Can this situation actually happen? And if so, should it?
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ EmitLabel("debug_inlined_begin", 1);
- return 0;
- }
+ Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("Dwarf Version");
+ Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Address Size (in bytes)");
- SmallVector<DbgScope *, 8> &Scopes = I->second;
- assert(!Scopes.empty() && "We should have at least one debug scope!");
- DbgScope *Scope = Scopes.back(); Scopes.pop_back();
- unsigned ID = MMI->NextLabelID();
- MMI->RecordUsedDbgLabel(ID);
- Scope->setEndLabelID(ID);
- LexicalScopeStack.pop_back();
+ 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;
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ SP.getLinkageName(LName);
+ SP.getName(Name);
- return ID;
-}
+ Asm->EmitString(LName.empty() ? Name : LName);
+ Asm->EOL("MIPS linkage name");
-/// RecordVariableScope - Record scope for the variable declared by
-/// DeclareMI. DeclareMI must describe TargetInstrInfo::DECLARE. Record scopes
-/// for only inlined subroutine variables. Other variables's scopes are
-/// determined during RecordVariable().
-void DwarfDebug::RecordVariableScope(DIVariable &DV,
- const MachineInstr *DeclareMI) {
- if (TimePassesIsEnabled)
- DebugTimer->startTimer();
+ Asm->EmitString(Name); Asm->EOL("Function name");
- DISubprogram SP(DV.getContext().getGV());
+ Asm->EmitULEB128Bytes(Labels.size()); Asm->EOL("Inline count");
- if (SP.isNull()) {
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ 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");
- return;
- }
+ if (TD->getPointerSize() == sizeof(int32_t))
+ O << TAI->getData32bitsDirective();
+ else
+ O << TAI->getData64bitsDirective();
- DenseMap<GlobalVariable *, DbgScope *>::iterator
- I = DbgAbstractScopeMap.find(SP.getGV());
- if (I != DbgAbstractScopeMap.end())
- InlinedVariableScopes[DeclareMI] = I->second;
+ PrintLabelName("label", *LI); Asm->EOL("low_pc");
+ }
+ }
- if (TimePassesIsEnabled)
- DebugTimer->stopTimer();
+ EmitLabel("debug_inlined_end", 1);
+ Asm->EOL();
}
-//===----------------------------------------------------------------------===//
-// Emit Methods
-//===----------------------------------------------------------------------===//
-
-/// SizeAndOffsetDie - Compute the size and offset of a DIE.
-///
-unsigned DwarfDebug::SizeAndOffsetDie(DIE *Die, unsigned Offset, bool Last) {
- // Get the children.
- const std::vector<DIE *> &Children = Die->getChildren();
-
- // If not last sibling and has children then add sibling offset attribute.
- if (!Last && !Children.empty()) Die->AddSiblingOffset();
+/// 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
+/// in the SourceIds map. This can update DirectoryNames and SourceFileNames
+/// maps as well.
+unsigned DwarfDebug::GetOrCreateSourceID(const std::string &DirName,
+ const std::string &FileName) {
+ unsigned DId;
+ StringMap<unsigned>::iterator DI = DirectoryIdMap.find(DirName);
+ if (DI != DirectoryIdMap.end()) {
+ DId = DI->getValue();
+ } else {
+ DId = DirectoryNames.size() + 1;
+ DirectoryIdMap[DirName] = DId;
+ DirectoryNames.push_back(DirName);
+ }
- // Record the abbreviation.
- AssignAbbrevNumber(Die->getAbbrev());
+ unsigned FId;
+ StringMap<unsigned>::iterator FI = SourceFileIdMap.find(FileName);
+ if (FI != SourceFileIdMap.end()) {
+ FId = FI->getValue();
+ } else {
+ FId = SourceFileNames.size() + 1;
+ SourceFileIdMap[FileName] = FId;
+ SourceFileNames.push_back(FileName);
+ }
- // Get the abbreviation for this DIE.
- unsigned AbbrevNumber = Die->getAbbrevNumber();
- const DIEAbbrev *Abbrev = Abbreviations[AbbrevNumber - 1];
+ DenseMap<std::pair<unsigned, unsigned>, unsigned>::iterator SI =
+ SourceIdMap.find(std::make_pair(DId, FId));
+ if (SI != SourceIdMap.end())
+ return SI->second;
- // Set DIE offset
- Die->setOffset(Offset);
+ unsigned SrcId = SourceIds.size() + 1; // DW_AT_decl_file cannot be 0.
+ SourceIdMap[std::make_pair(DId, FId)] = SrcId;
+ SourceIds.push_back(std::make_pair(DId, FId));
- // Start the size with the size of abbreviation code.
- Offset += TargetAsmInfo::getULEB128Size(AbbrevNumber);
+ return SrcId;
+}
- const SmallVector<DIEValue*, 32> &Values = Die->getValues();
- const SmallVector<DIEAbbrevData, 8> &AbbrevData = Abbrev->getData();
+void DwarfDebug::ConstructCompileUnit(GlobalVariable *GV) {
+ DICompileUnit DIUnit(GV);
+ std::string Dir, FN, Prod;
+ unsigned ID = GetOrCreateSourceID(DIUnit.getDirectory(Dir),
+ DIUnit.getFilename(FN));
- // Size the DIE attribute values.
- for (unsigned i = 0, N = Values.size(); i < N; ++i)
- // Size attribute value.
- Offset += Values[i]->SizeOf(TD, AbbrevData[i].getForm());
+ DIE *Die = new DIE(dwarf::DW_TAG_compile_unit);
+ AddSectionOffset(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4,
+ DWLabel("section_line", 0), DWLabel("section_line", 0),
+ false);
+ AddString(Die, dwarf::DW_AT_producer, dwarf::DW_FORM_string,
+ DIUnit.getProducer(Prod));
+ AddUInt(Die, dwarf::DW_AT_language, dwarf::DW_FORM_data1,
+ DIUnit.getLanguage());
+ AddString(Die, dwarf::DW_AT_name, dwarf::DW_FORM_string, FN);
- // Size the DIE children if any.
- if (!Children.empty()) {
- assert(Abbrev->getChildrenFlag() == dwarf::DW_CHILDREN_yes &&
- "Children flag not set");
+ if (!Dir.empty())
+ AddString(Die, dwarf::DW_AT_comp_dir, dwarf::DW_FORM_string, Dir);
+ if (DIUnit.isOptimized())
+ AddUInt(Die, dwarf::DW_AT_APPLE_optimized, dwarf::DW_FORM_flag, 1);
- for (unsigned j = 0, M = Children.size(); j < M; ++j)
- Offset = SizeAndOffsetDie(Children[j], Offset, (j + 1) == M);
+ std::string Flags;
+ DIUnit.getFlags(Flags);
+ if (!Flags.empty())
+ AddString(Die, dwarf::DW_AT_APPLE_flags, dwarf::DW_FORM_string, Flags);
- // End of children marker.
- Offset += sizeof(int8_t);
- }
+ unsigned RVer = DIUnit.getRunTimeVersion();
+ if (RVer)
+ AddUInt(Die, dwarf::DW_AT_APPLE_major_runtime_vers,
+ dwarf::DW_FORM_data1, RVer);
- Die->setSize(Offset - Die->getOffset());
- return Offset;
-}
+ CompileUnit *Unit = new CompileUnit(ID, Die);
+ if (DIUnit.isMain()) {
+ assert(!MainCU && "Multiple main compile units are found!");
+ MainCU = Unit;
+ }
-/// SizeAndOffsets - Compute the size and offset of all the DIEs.
-///
-void DwarfDebug::SizeAndOffsets() {
- // Compute size of compile unit header.
- static unsigned Offset =
- sizeof(int32_t) + // Length of Compilation Unit Info
- sizeof(int16_t) + // DWARF version number
- sizeof(int32_t) + // Offset Into Abbrev. Section
- sizeof(int8_t); // Pointer Size (in bytes)
+ CompileUnitMap[DIUnit.getGV()] = Unit;
+ CompileUnits.push_back(Unit);
+}
- // Process base compile unit.
- if (MainCU) {
- SizeAndOffsetDie(MainCU->getDie(), Offset, true);
- CompileUnitOffsets[MainCU] = 0;
+/// ConstructCompileUnits - Create a compile unit DIEs.
+void DwarfDebug::ConstructCompileUnits() {
+ GlobalVariable *Root = M->getGlobalVariable("llvm.dbg.compile_units");
+ if (!Root)
return;
- }
-
- // Process all compile units.
- unsigned PrevOffset = 0;
+ assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() &&
+ "Malformed compile unit descriptor anchor type");
+ Constant *RootC = cast<Constant>(*Root->use_begin());
+ assert(RootC->hasNUsesOrMore(1) &&
+ "Malformed compile unit descriptor anchor type");
- for (unsigned i = 0, e = CompileUnits.size(); i != e; ++i) {
- CompileUnit *Unit = CompileUnits[i];
- CompileUnitOffsets[Unit] = PrevOffset;
- PrevOffset += SizeAndOffsetDie(Unit->getDie(), Offset, true)
- + sizeof(int32_t); // FIXME - extra pad for gdb bug.
- }
+ for (Value::use_iterator UI = RootC->use_begin(), UE = Root->use_end();
+ UI != UE; ++UI)
+ for (Value::use_iterator UUI = UI->use_begin(), UUE = UI->use_end();
+ UUI != UUE; ++UUI) {
+ GlobalVariable *GV = cast<GlobalVariable>(*UUI);
+ ConstructCompileUnit(GV);
+ }
}
-/// EmitInitial - Emit initial Dwarf declarations. This is necessary for cc
-/// tools to recognize the object file contains Dwarf information.
-void DwarfDebug::EmitInitial() {
- // Check to see if we already emitted intial headers.
- if (didInitial) return;
- didInitial = true;
+bool DwarfDebug::ConstructGlobalVariableDIE(GlobalVariable *GV) {
+ DIGlobalVariable DI_GV(GV);
+ CompileUnit *DW_Unit = MainCU;
+ if (!DW_Unit)
+ DW_Unit = &FindCompileUnit(DI_GV.getCompileUnit());
- // Dwarf sections base addresses.
- if (TAI->doesDwarfRequireFrameSection()) {
- Asm->SwitchToDataSection(TAI->getDwarfFrameSection());
- EmitLabel("section_debug_frame", 0);
- }
+ // Check for pre-existence.
+ DIE *&Slot = DW_Unit->getDieMapSlotFor(DI_GV.getGV());
+ if (Slot)
+ return false;
- Asm->SwitchToDataSection(TAI->getDwarfInfoSection());
- EmitLabel("section_info", 0);
- Asm->SwitchToDataSection(TAI->getDwarfAbbrevSection());
- EmitLabel("section_abbrev", 0);
- Asm->SwitchToDataSection(TAI->getDwarfARangesSection());
- EmitLabel("section_aranges", 0);
+ DIE *VariableDie = CreateGlobalVariableDIE(DW_Unit, DI_GV);
- if (TAI->doesSupportMacInfoSection()) {
- Asm->SwitchToDataSection(TAI->getDwarfMacInfoSection());
- EmitLabel("section_macinfo", 0);
- }
+ // Add address.
+ DIEBlock *Block = new DIEBlock();
+ AddUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_addr);
+ std::string GLN;
+ AddObjectLabel(Block, 0, dwarf::DW_FORM_udata,
+ Asm->getGlobalLinkName(DI_GV.getGlobal(), GLN));
+ AddBlock(VariableDie, dwarf::DW_AT_location, 0, Block);
- Asm->SwitchToDataSection(TAI->getDwarfLineSection());
- EmitLabel("section_line", 0);
- Asm->SwitchToDataSection(TAI->getDwarfLocSection());
- EmitLabel("section_loc", 0);
- Asm->SwitchToDataSection(TAI->getDwarfPubNamesSection());
- EmitLabel("section_pubnames", 0);
- Asm->SwitchToDataSection(TAI->getDwarfStrSection());
- EmitLabel("section_str", 0);
- Asm->SwitchToDataSection(TAI->getDwarfRangesSection());
- EmitLabel("section_ranges", 0);
+ // Add to map.
+ Slot = VariableDie;
- Asm->SwitchToSection(TAI->getTextSection());
- EmitLabel("text_begin", 0);
- Asm->SwitchToSection(TAI->getDataSection());
- EmitLabel("data_begin", 0);
-}
+ // Add to context owner.
+ DW_Unit->getDie()->AddChild(VariableDie);
-/// EmitDIE - Recusively Emits a debug information entry.
-///
-void DwarfDebug::EmitDIE(DIE *Die) {
- // Get the abbreviation for this DIE.
- unsigned AbbrevNumber = Die->getAbbrevNumber();
- const DIEAbbrev *Abbrev = Abbreviations[AbbrevNumber - 1];
+ // Expose as global. FIXME - need to check external flag.
+ std::string Name;
+ DW_Unit->AddGlobal(DI_GV.getName(Name), VariableDie);
+ return true;
+}
- Asm->EOL();
+/// ConstructGlobalVariableDIEs - Create DIEs for each of the externally visible
+/// global variables. Return true if at least one global DIE is created.
+bool DwarfDebug::ConstructGlobalVariableDIEs() {
+ GlobalVariable *Root = M->getGlobalVariable("llvm.dbg.global_variables");
+ if (!Root)
+ return false;
- // Emit the code (index) for the abbreviation.
- Asm->EmitULEB128Bytes(AbbrevNumber);
+ assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() &&
+ "Malformed global variable descriptor anchor type");
+ Constant *RootC = cast<Constant>(*Root->use_begin());
+ assert(RootC->hasNUsesOrMore(1) &&
+ "Malformed global variable descriptor anchor type");
- if (Asm->isVerbose())
- Asm->EOL(std::string("Abbrev [" +
- utostr(AbbrevNumber) +
- "] 0x" + utohexstr(Die->getOffset()) +
- ":0x" + utohexstr(Die->getSize()) + " " +
- dwarf::TagString(Abbrev->getTag())));
- else
- Asm->EOL();
+ bool Result = false;
+ for (Value::use_iterator UI = RootC->use_begin(), UE = Root->use_end();
+ UI != UE; ++UI)
+ for (Value::use_iterator UUI = UI->use_begin(), UUE = UI->use_end();
+ UUI != UUE; ++UUI)
+ Result |= ConstructGlobalVariableDIE(cast<GlobalVariable>(*UUI));
- SmallVector<DIEValue*, 32> &Values = Die->getValues();
- const SmallVector<DIEAbbrevData, 8> &AbbrevData = Abbrev->getData();
+ return Result;
+}
- // Emit the DIE attribute values.
- for (unsigned i = 0, N = Values.size(); i < N; ++i) {
- unsigned Attr = AbbrevData[i].getAttribute();
- unsigned Form = AbbrevData[i].getForm();
- assert(Form && "Too many attributes for DIE (check abbreviation)");
+bool DwarfDebug::ConstructSubprogram(GlobalVariable *GV) {
+ DISubprogram SP(GV);
+ CompileUnit *Unit = MainCU;
+ if (!Unit)
+ Unit = &FindCompileUnit(SP.getCompileUnit());
- switch (Attr) {
- case dwarf::DW_AT_sibling:
- Asm->EmitInt32(Die->SiblingOffset());
- break;
- case dwarf::DW_AT_abstract_origin: {
- DIEEntry *E = cast<DIEEntry>(Values[i]);
- DIE *Origin = E->getEntry();
- unsigned Addr =
- CompileUnitOffsets[Die->getAbstractCompileUnit()] +
- Origin->getOffset();
+ // Check for pre-existence.
+ DIE *&Slot = Unit->getDieMapSlotFor(GV);
+ if (Slot)
+ return false;
- Asm->EmitInt32(Addr);
- break;
- }
- default:
- // Emit an attribute using the defined form.
- Values[i]->EmitValue(this, Form);
- break;
- }
+ if (!SP.isDefinition())
+ // This is a method declaration which will be handled while constructing
+ // class type.
+ return false;
- Asm->EOL(dwarf::AttributeString(Attr));
- }
+ DIE *SubprogramDie = CreateSubprogramDIE(Unit, SP);
- // Emit the DIE children if any.
- if (Abbrev->getChildrenFlag() == dwarf::DW_CHILDREN_yes) {
- const std::vector<DIE *> &Children = Die->getChildren();
+ // Add to map.
+ Slot = SubprogramDie;
- for (unsigned j = 0, M = Children.size(); j < M; ++j)
- EmitDIE(Children[j]);
+ // Add to context owner.
+ Unit->getDie()->AddChild(SubprogramDie);
- Asm->EmitInt8(0); Asm->EOL("End Of Children Mark");
- }
+ // Expose as global.
+ std::string Name;
+ Unit->AddGlobal(SP.getName(Name), SubprogramDie);
+ return true;
}
-/// EmitDebugInfo / EmitDebugInfoPerCU - Emit the debug info section.
-///
-void DwarfDebug::EmitDebugInfoPerCU(CompileUnit *Unit) {
- DIE *Die = Unit->getDie();
+/// ConstructSubprograms - Create DIEs for each of the externally visible
+/// subprograms. Return true if at least one subprogram DIE is created.
+bool DwarfDebug::ConstructSubprograms() {
+ GlobalVariable *Root = M->getGlobalVariable("llvm.dbg.subprograms");
+ if (!Root)
+ return false;
- // Emit the compile units header.
- EmitLabel("info_begin", Unit->getID());
+ assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() &&
+ "Malformed subprogram descriptor anchor type");
+ Constant *RootC = cast<Constant>(*Root->use_begin());
+ assert(RootC->hasNUsesOrMore(1) &&
+ "Malformed subprogram descriptor anchor type");
- // Emit size of content not including length itself
- unsigned ContentSize = Die->getSize() +
- sizeof(int16_t) + // DWARF version number
- sizeof(int32_t) + // Offset Into Abbrev. Section
- sizeof(int8_t) + // Pointer Size (in bytes)
- sizeof(int32_t); // FIXME - extra pad for gdb bug.
+ bool Result = false;
+ for (Value::use_iterator UI = RootC->use_begin(), UE = Root->use_end();
+ UI != UE; ++UI)
+ for (Value::use_iterator UUI = UI->use_begin(), UUE = UI->use_end();
+ UUI != UUE; ++UUI)
+ Result |= ConstructSubprogram(cast<GlobalVariable>(*UUI));
- Asm->EmitInt32(ContentSize); Asm->EOL("Length of Compilation Unit Info");
- Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("DWARF version number");
- EmitSectionOffset("abbrev_begin", "section_abbrev", 0, 0, true, false);
- Asm->EOL("Offset Into Abbrev. Section");
- Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Address Size (in bytes)");
+ return Result;
+}
- EmitDIE(Die);
- // FIXME - extra padding for gdb bug.
- Asm->EmitInt8(0); Asm->EOL("Extra Pad For GDB");
- Asm->EmitInt8(0); Asm->EOL("Extra Pad For GDB");
- Asm->EmitInt8(0); Asm->EOL("Extra Pad For GDB");
- Asm->EmitInt8(0); Asm->EOL("Extra Pad For GDB");
- EmitLabel("info_end", Unit->getID());
+/// SetDebugInfo - Create global DIEs and emit initial debug info sections.
+/// This is inovked by the target AsmPrinter.
+void DwarfDebug::SetDebugInfo(MachineModuleInfo *mmi) {
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- Asm->EOL();
-}
+ // Create all the compile unit DIEs.
+ ConstructCompileUnits();
-void DwarfDebug::EmitDebugInfo() {
- // Start debug info section.
- Asm->SwitchToDataSection(TAI->getDwarfInfoSection());
+ if (CompileUnits.empty()) {
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
- if (MainCU) {
- EmitDebugInfoPerCU(MainCU);
return;
}
- for (unsigned i = 0, e = CompileUnits.size(); i != e; ++i)
- EmitDebugInfoPerCU(CompileUnits[i]);
-}
+ // Create DIEs for each of the externally visible global variables.
+ bool globalDIEs = ConstructGlobalVariableDIEs();
-/// EmitAbbreviations - Emit the abbreviation section.
-///
-void DwarfDebug::EmitAbbreviations() const {
- // Check to see if it is worth the effort.
- if (!Abbreviations.empty()) {
- // Start the debug abbrev section.
- Asm->SwitchToDataSection(TAI->getDwarfAbbrevSection());
+ // Create DIEs for each of the externally visible subprograms.
+ bool subprogramDIEs = ConstructSubprograms();
- EmitLabel("abbrev_begin", 0);
+ // If there is not any debug info available for any global variables and any
+ // subprograms then there is not any debug info to emit.
+ if (!globalDIEs && !subprogramDIEs) {
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
- // For each abbrevation.
- for (unsigned i = 0, N = Abbreviations.size(); i < N; ++i) {
- // Get abbreviation data
- const DIEAbbrev *Abbrev = Abbreviations[i];
+ return;
+ }
- // Emit the abbrevations code (base 1 index.)
- Asm->EmitULEB128Bytes(Abbrev->getNumber());
- Asm->EOL("Abbreviation Code");
+ MMI = mmi;
+ shouldEmit = true;
+ MMI->setDebugInfoAvailability(true);
- // Emit the abbreviations data.
- Abbrev->Emit(Asm);
+ // Prime section data.
+ SectionMap.insert(TAI->getTextSection());
+ // Print out .file directives to specify files for .loc directives. These are
+ // printed out early so that they precede any .loc directives.
+ if (TAI->hasDotLocAndDotFile()) {
+ for (unsigned i = 1, e = getNumSourceIds()+1; i != e; ++i) {
+ // Remember source id starts at 1.
+ std::pair<unsigned, unsigned> Id = getSourceDirectoryAndFileIds(i);
+ sys::Path FullPath(getSourceDirectoryName(Id.first));
+ bool AppendOk =
+ FullPath.appendComponent(getSourceFileName(Id.second));
+ assert(AppendOk && "Could not append filename to directory!");
+ AppendOk = false;
+ Asm->EmitFile(i, FullPath.toString());
Asm->EOL();
}
-
- // Mark end of abbreviations.
- Asm->EmitULEB128Bytes(0); Asm->EOL("EOM(3)");
-
- EmitLabel("abbrev_end", 0);
- Asm->EOL();
}
-}
-/// EmitEndOfLineMatrix - Emit the last address of the section and the end of
-/// the line matrix.
-///
-void DwarfDebug::EmitEndOfLineMatrix(unsigned SectionEnd) {
- // Define last address of section.
- Asm->EmitInt8(0); Asm->EOL("Extended Op");
- Asm->EmitInt8(TD->getPointerSize() + 1); Asm->EOL("Op size");
- Asm->EmitInt8(dwarf::DW_LNE_set_address); Asm->EOL("DW_LNE_set_address");
- EmitReference("section_end", SectionEnd); Asm->EOL("Section end label");
+ // Emit initial sections
+ EmitInitial();
- // Mark end of matrix.
- Asm->EmitInt8(0); Asm->EOL("DW_LNE_end_sequence");
- Asm->EmitULEB128Bytes(1); Asm->EOL();
- Asm->EmitInt8(1); Asm->EOL();
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
}
-/// EmitDebugLines - Emit source line information.
+/// EndModule - Emit all Dwarf sections that should come after the content.
///
-void DwarfDebug::EmitDebugLines() {
- // If the target is using .loc/.file, the assembler will be emitting the
- // .debug_line table automatically.
- if (TAI->hasDotLocAndDotFile())
+void DwarfDebug::EndModule() {
+ if (!ShouldEmitDwarfDebug())
return;
- // Minimum line delta, thus ranging from -10..(255-10).
- const int MinLineDelta = -(dwarf::DW_LNS_fixed_advance_pc + 1);
- // Maximum line delta, thus ranging from -10..(255-10).
- const int MaxLineDelta = 255 + MinLineDelta;
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- // Start the dwarf line section.
- Asm->SwitchToDataSection(TAI->getDwarfLineSection());
+ // Standard sections final addresses.
+ Asm->SwitchToSection(TAI->getTextSection());
+ EmitLabel("text_end", 0);
+ Asm->SwitchToSection(TAI->getDataSection());
+ EmitLabel("data_end", 0);
- // Construct the section header.
- EmitDifference("line_end", 0, "line_begin", 0, true);
- Asm->EOL("Length of Source Line Info");
- EmitLabel("line_begin", 0);
+ // End text sections.
+ for (unsigned i = 1, N = SectionMap.size(); i <= N; ++i) {
+ Asm->SwitchToSection(SectionMap[i]);
+ EmitLabel("section_end", i);
+ }
- Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("DWARF version number");
+ // Emit common frame information.
+ EmitCommonDebugFrame();
- EmitDifference("line_prolog_end", 0, "line_prolog_begin", 0, true);
- Asm->EOL("Prolog Length");
- EmitLabel("line_prolog_begin", 0);
+ // Emit function debug frame information
+ for (std::vector<FunctionDebugFrameInfo>::iterator I = DebugFrames.begin(),
+ E = DebugFrames.end(); I != E; ++I)
+ EmitFunctionDebugFrame(*I);
- Asm->EmitInt8(1); Asm->EOL("Minimum Instruction Length");
+ // Compute DIE offsets and sizes.
+ SizeAndOffsets();
- Asm->EmitInt8(1); Asm->EOL("Default is_stmt_start flag");
+ // Emit all the DIEs into a debug info section
+ EmitDebugInfo();
- Asm->EmitInt8(MinLineDelta); Asm->EOL("Line Base Value (Special Opcodes)");
+ // Corresponding abbreviations into a abbrev section.
+ EmitAbbreviations();
- Asm->EmitInt8(MaxLineDelta); Asm->EOL("Line Range Value (Special Opcodes)");
+ // Emit source line correspondence into a debug line section.
+ EmitDebugLines();
- Asm->EmitInt8(-MinLineDelta); Asm->EOL("Special Opcode Base");
+ // Emit info into a debug pubnames section.
+ EmitDebugPubNames();
- // Line number standard opcode encodings argument count
- Asm->EmitInt8(0); Asm->EOL("DW_LNS_copy arg count");
- Asm->EmitInt8(1); Asm->EOL("DW_LNS_advance_pc arg count");
- Asm->EmitInt8(1); Asm->EOL("DW_LNS_advance_line arg count");
- Asm->EmitInt8(1); Asm->EOL("DW_LNS_set_file arg count");
- Asm->EmitInt8(1); Asm->EOL("DW_LNS_set_column arg count");
- Asm->EmitInt8(0); Asm->EOL("DW_LNS_negate_stmt arg count");
- Asm->EmitInt8(0); Asm->EOL("DW_LNS_set_basic_block arg count");
- Asm->EmitInt8(0); Asm->EOL("DW_LNS_const_add_pc arg count");
- Asm->EmitInt8(1); Asm->EOL("DW_LNS_fixed_advance_pc arg count");
+ // Emit info into a debug str section.
+ EmitDebugStr();
- // Emit directories.
- for (unsigned DI = 1, DE = getNumSourceDirectories()+1; DI != DE; ++DI) {
- Asm->EmitString(getSourceDirectoryName(DI));
- Asm->EOL("Directory");
- }
+ // Emit info into a debug loc section.
+ EmitDebugLoc();
- Asm->EmitInt8(0); Asm->EOL("End of directories");
+ // Emit info into a debug aranges section.
+ EmitDebugARanges();
- // Emit files.
- for (unsigned SI = 1, SE = getNumSourceIds()+1; SI != SE; ++SI) {
- // Remember source id starts at 1.
- std::pair<unsigned, unsigned> Id = getSourceDirectoryAndFileIds(SI);
- Asm->EmitString(getSourceFileName(Id.second));
- Asm->EOL("Source");
- Asm->EmitULEB128Bytes(Id.first);
- Asm->EOL("Directory #");
- Asm->EmitULEB128Bytes(0);
- Asm->EOL("Mod date");
- Asm->EmitULEB128Bytes(0);
- Asm->EOL("File size");
- }
+ // Emit info into a debug ranges section.
+ EmitDebugRanges();
- Asm->EmitInt8(0); Asm->EOL("End of files");
+ // Emit info into a debug macinfo section.
+ EmitDebugMacInfo();
- EmitLabel("line_prolog_end", 0);
+ // Emit inline info.
+ EmitDebugInlineInfo();
- // A sequence for each text section.
- unsigned SecSrcLinesSize = SectionSourceLines.size();
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
+}
- for (unsigned j = 0; j < SecSrcLinesSize; ++j) {
- // Isolate current sections line info.
- const std::vector<SrcLineInfo> &LineInfos = SectionSourceLines[j];
+/// BeginFunction - Gather pre-function debug information. Assumes being
+/// emitted immediately after the function entry point.
+void DwarfDebug::BeginFunction(MachineFunction *MF) {
+ this->MF = MF;
- if (Asm->isVerbose()) {
- const Section* S = SectionMap[j + 1];
- O << '\t' << TAI->getCommentString() << " Section"
- << S->getName() << '\n';
- } else {
- Asm->EOL();
- }
+ if (!ShouldEmitDwarfDebug()) return;
- // Dwarf assumes we start with first line of first source file.
- unsigned Source = 1;
- unsigned Line = 1;
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- // Construct rows of the address, source, line, column matrix.
- for (unsigned i = 0, N = LineInfos.size(); i < N; ++i) {
- const SrcLineInfo &LineInfo = LineInfos[i];
- unsigned LabelID = MMI->MappedLabel(LineInfo.getLabelID());
- if (!LabelID) continue;
+ // Begin accumulating function debug information.
+ MMI->BeginFunction(MF);
- if (!Asm->isVerbose())
- Asm->EOL();
- else {
- std::pair<unsigned, unsigned> SourceID =
- getSourceDirectoryAndFileIds(LineInfo.getSourceID());
- O << '\t' << TAI->getCommentString() << ' '
- << getSourceDirectoryName(SourceID.first) << ' '
- << getSourceFileName(SourceID.second)
- <<" :" << utostr_32(LineInfo.getLine()) << '\n';
- }
+ // Assumes in correct section after the entry point.
+ EmitLabel("func_begin", ++SubprogramCount);
- // Define the line address.
- Asm->EmitInt8(0); Asm->EOL("Extended Op");
- Asm->EmitInt8(TD->getPointerSize() + 1); Asm->EOL("Op size");
- Asm->EmitInt8(dwarf::DW_LNE_set_address); Asm->EOL("DW_LNE_set_address");
- EmitReference("label", LabelID); Asm->EOL("Location label");
+ // Emit label for the implicitly defined dbg.stoppoint at the start of the
+ // function.
+ DebugLoc FDL = MF->getDefaultDebugLoc();
+ if (!FDL.isUnknown()) {
+ DebugLocTuple DLT = MF->getDebugLocTuple(FDL);
+ unsigned LabelID = RecordSourceLine(DLT.Line, DLT.Col,
+ DICompileUnit(DLT.CompileUnit));
+ Asm->printLabel(LabelID);
+ }
- // If change of source, then switch to the new source.
- if (Source != LineInfo.getSourceID()) {
- Source = LineInfo.getSourceID();
- Asm->EmitInt8(dwarf::DW_LNS_set_file); Asm->EOL("DW_LNS_set_file");
- Asm->EmitULEB128Bytes(Source); Asm->EOL("New Source");
- }
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
+}
+
+/// EndFunction - Gather and emit post-function debug information.
+///
+void DwarfDebug::EndFunction(MachineFunction *MF) {
+ if (!ShouldEmitDwarfDebug()) return;
+
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
+
+ // Define end label for subprogram.
+ EmitLabel("func_end", SubprogramCount);
+
+ // Get function line info.
+ if (!Lines.empty()) {
+ // Get section line info.
+ unsigned ID = SectionMap.insert(Asm->CurrentSection_);
+ if (SectionSourceLines.size() < ID) SectionSourceLines.resize(ID);
+ std::vector<SrcLineInfo> &SectionLineInfos = SectionSourceLines[ID-1];
+ // Append the function info to section info.
+ SectionLineInfos.insert(SectionLineInfos.end(),
+ Lines.begin(), Lines.end());
+ }
- // If change of line.
- if (Line != LineInfo.getLine()) {
- // Determine offset.
- int Offset = LineInfo.getLine() - Line;
- int Delta = Offset - MinLineDelta;
+ // Construct the DbgScope for abstract instances.
+ for (SmallVector<DbgScope *, 32>::iterator
+ I = AbstractInstanceRootList.begin(),
+ E = AbstractInstanceRootList.end(); I != E; ++I)
+ ConstructAbstractDbgScope(*I);
- // Update line.
- Line = LineInfo.getLine();
+ // Construct scopes for subprogram.
+ if (FunctionDbgScope)
+ ConstructFunctionDbgScope(FunctionDbgScope);
+ else
+ // FIXME: This is wrong. We are essentially getting past a problem with
+ // debug information not being able to handle unreachable blocks that have
+ // debug information in them. In particular, those unreachable blocks that
+ // have "region end" info in them. That situation results in the "root
+ // scope" not being created. If that's the case, then emit a "default"
+ // scope, i.e., one that encompasses the whole function. This isn't
+ // desirable. And a better way of handling this (and all of the debugging
+ // information) needs to be explored.
+ ConstructDefaultDbgScope(MF);
- // If delta is small enough and in range...
- if (Delta >= 0 && Delta < (MaxLineDelta - 1)) {
- // ... then use fast opcode.
- Asm->EmitInt8(Delta - MinLineDelta); Asm->EOL("Line Delta");
- } else {
- // ... otherwise use long hand.
- Asm->EmitInt8(dwarf::DW_LNS_advance_line);
- Asm->EOL("DW_LNS_advance_line");
- Asm->EmitSLEB128Bytes(Offset); Asm->EOL("Line Offset");
- Asm->EmitInt8(dwarf::DW_LNS_copy); Asm->EOL("DW_LNS_copy");
- }
- } else {
- // Copy the previous row (different address or source)
- Asm->EmitInt8(dwarf::DW_LNS_copy); Asm->EOL("DW_LNS_copy");
- }
- }
+ DebugFrames.push_back(FunctionDebugFrameInfo(SubprogramCount,
+ MMI->getFrameMoves()));
- EmitEndOfLineMatrix(j + 1);
+ // Clear debug info
+ if (FunctionDbgScope) {
+ delete FunctionDbgScope;
+ DbgScopeMap.clear();
+ DbgAbstractScopeMap.clear();
+ DbgConcreteScopeMap.clear();
+ InlinedVariableScopes.clear();
+ FunctionDbgScope = NULL;
+ LexicalScopeStack.clear();
+ AbstractInstanceRootList.clear();
}
- if (SecSrcLinesSize == 0)
- // Because we're emitting a debug_line section, we still need a line
- // table. The linker and friends expect it to exist. If there's nothing to
- // put into it, emit an empty table.
- EmitEndOfLineMatrix(1);
+ Lines.clear();
- EmitLabel("line_end", 0);
- Asm->EOL();
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
}
-/// EmitCommonDebugFrame - Emit common frame info into a debug frame section.
-///
-void DwarfDebug::EmitCommonDebugFrame() {
- if (!TAI->doesDwarfRequireFrameSection())
- return;
-
- int stackGrowth =
- Asm->TM.getFrameInfo()->getStackGrowthDirection() ==
- TargetFrameInfo::StackGrowsUp ?
- TD->getPointerSize() : -TD->getPointerSize();
+/// RecordSourceLine - Records location information and associates it with a
+/// label. Returns a unique label ID used to generate a label and provide
+/// correspondence to the source line list.
+unsigned DwarfDebug::RecordSourceLine(Value *V, unsigned Line, unsigned Col) {
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- // Start the dwarf frame section.
- Asm->SwitchToDataSection(TAI->getDwarfFrameSection());
+ CompileUnit *Unit = CompileUnitMap[V];
+ assert(Unit && "Unable to find CompileUnit");
+ unsigned ID = MMI->NextLabelID();
+ Lines.push_back(SrcLineInfo(Line, Col, Unit->getID(), ID));
- EmitLabel("debug_frame_common", 0);
- EmitDifference("debug_frame_common_end", 0,
- "debug_frame_common_begin", 0, true);
- Asm->EOL("Length of Common Information Entry");
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
- EmitLabel("debug_frame_common_begin", 0);
- Asm->EmitInt32((int)dwarf::DW_CIE_ID);
- Asm->EOL("CIE Identifier Tag");
- Asm->EmitInt8(dwarf::DW_CIE_VERSION);
- Asm->EOL("CIE Version");
- Asm->EmitString("");
- Asm->EOL("CIE Augmentation");
- Asm->EmitULEB128Bytes(1);
- Asm->EOL("CIE Code Alignment Factor");
- Asm->EmitSLEB128Bytes(stackGrowth);
- Asm->EOL("CIE Data Alignment Factor");
- Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), false));
- Asm->EOL("CIE RA Column");
+ return ID;
+}
- std::vector<MachineMove> Moves;
- RI->getInitialFrameState(Moves);
+/// RecordSourceLine - Records location information and associates it with a
+/// label. Returns a unique label ID used to generate a label and provide
+/// correspondence to the source line list.
+unsigned DwarfDebug::RecordSourceLine(unsigned Line, unsigned Col,
+ DICompileUnit CU) {
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- EmitFrameMoves(NULL, 0, Moves, false);
+ std::string Dir, Fn;
+ unsigned Src = GetOrCreateSourceID(CU.getDirectory(Dir),
+ CU.getFilename(Fn));
+ unsigned ID = MMI->NextLabelID();
+ Lines.push_back(SrcLineInfo(Line, Col, Src, ID));
- Asm->EmitAlignment(2, 0, 0, false);
- EmitLabel("debug_frame_common_end", 0);
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
- Asm->EOL();
+ return ID;
}
-/// EmitFunctionDebugFrame - Emit per function frame info into a debug frame
-/// section.
-void
-DwarfDebug::EmitFunctionDebugFrame(const FunctionDebugFrameInfo&DebugFrameInfo){
- if (!TAI->doesDwarfRequireFrameSection())
- return;
+/// getOrCreateSourceID - Public version of GetOrCreateSourceID. This can be
+/// timed. Look up the source id with the given directory and 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 as
+/// well.
+unsigned DwarfDebug::getOrCreateSourceID(const std::string &DirName,
+ const std::string &FileName) {
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- // Start the dwarf frame section.
- Asm->SwitchToDataSection(TAI->getDwarfFrameSection());
+ unsigned SrcId = GetOrCreateSourceID(DirName, FileName);
- EmitDifference("debug_frame_end", DebugFrameInfo.Number,
- "debug_frame_begin", DebugFrameInfo.Number, true);
- Asm->EOL("Length of Frame Information Entry");
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
- EmitLabel("debug_frame_begin", DebugFrameInfo.Number);
+ return SrcId;
+}
- EmitSectionOffset("debug_frame_common", "section_debug_frame",
- 0, 0, true, false);
- Asm->EOL("FDE CIE offset");
+/// RecordRegionStart - Indicate the start of a region.
+unsigned DwarfDebug::RecordRegionStart(GlobalVariable *V) {
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- EmitReference("func_begin", DebugFrameInfo.Number);
- Asm->EOL("FDE initial location");
- EmitDifference("func_end", DebugFrameInfo.Number,
- "func_begin", DebugFrameInfo.Number);
- Asm->EOL("FDE address range");
+ DbgScope *Scope = getOrCreateScope(V);
+ unsigned ID = MMI->NextLabelID();
+ if (!Scope->getStartLabelID()) Scope->setStartLabelID(ID);
+ LexicalScopeStack.push_back(Scope);
- EmitFrameMoves("func_begin", DebugFrameInfo.Number, DebugFrameInfo.Moves,
- false);
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
- Asm->EmitAlignment(2, 0, 0, false);
- EmitLabel("debug_frame_end", DebugFrameInfo.Number);
+ return ID;
+}
- Asm->EOL();
+/// RecordRegionEnd - Indicate the end of a region.
+unsigned DwarfDebug::RecordRegionEnd(GlobalVariable *V) {
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
+
+ DbgScope *Scope = getOrCreateScope(V);
+ unsigned ID = MMI->NextLabelID();
+ Scope->setEndLabelID(ID);
+ if (LexicalScopeStack.size() != 0)
+ LexicalScopeStack.pop_back();
+
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
+
+ return ID;
}
-void DwarfDebug::EmitDebugPubNamesPerCU(CompileUnit *Unit) {
- EmitDifference("pubnames_end", Unit->getID(),
- "pubnames_begin", Unit->getID(), true);
- Asm->EOL("Length of Public Names Info");
+/// RecordVariable - Indicate the declaration of a local variable.
+void DwarfDebug::RecordVariable(GlobalVariable *GV, unsigned FrameIndex,
+ const MachineInstr *MI) {
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- EmitLabel("pubnames_begin", Unit->getID());
+ DIDescriptor Desc(GV);
+ DbgScope *Scope = NULL;
+ bool InlinedFnVar = false;
- Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("DWARF Version");
+ if (Desc.getTag() == dwarf::DW_TAG_variable) {
+ // GV is a global variable.
+ DIGlobalVariable DG(GV);
+ Scope = getOrCreateScope(DG.getContext().getGV());
+ } else {
+ DenseMap<const MachineInstr *, DbgScope *>::iterator
+ SI = InlinedVariableScopes.find(MI);
- EmitSectionOffset("info_begin", "section_info",
- Unit->getID(), 0, true, false);
- Asm->EOL("Offset of Compilation Unit Info");
+ if (SI != InlinedVariableScopes.end()) {
+ // or GV is an inlined local variable.
+ Scope = SI->second;
+ } else {
+ DIVariable DV(GV);
+ GlobalVariable *V = DV.getContext().getGV();
- EmitDifference("info_end", Unit->getID(), "info_begin", Unit->getID(),
- true);
- Asm->EOL("Compilation Unit Length");
+ // FIXME: The code that checks for the inlined local variable is a hack!
+ DenseMap<const GlobalVariable *, DbgScope *>::iterator
+ AI = AbstractInstanceRootMap.find(V);
- StringMap<DIE*> &Globals = Unit->getGlobals();
- for (StringMap<DIE*>::const_iterator
- GI = Globals.begin(), GE = Globals.end(); GI != GE; ++GI) {
- const char *Name = GI->getKeyData();
- DIE * Entity = GI->second;
+ if (AI != AbstractInstanceRootMap.end()) {
+ // This method is called each time a DECLARE node is encountered. For an
+ // inlined function, this could be many, many times. We don't want to
+ // re-add variables to that DIE for each time. We just want to add them
+ // once. Check to make sure that we haven't added them already.
+ DenseMap<const GlobalVariable *,
+ SmallSet<const GlobalVariable *, 32> >::iterator
+ IP = InlinedParamMap.find(V);
- Asm->EmitInt32(Entity->getOffset()); Asm->EOL("DIE offset");
- Asm->EmitString(Name, strlen(Name)); Asm->EOL("External Name");
+ if (IP != InlinedParamMap.end() && IP->second.count(GV) > 0) {
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
+ return;
+ }
+
+ // or GV is an inlined local variable.
+ Scope = AI->second;
+ InlinedParamMap[V].insert(GV);
+ InlinedFnVar = true;
+ } else {
+ // or GV is a local variable.
+ Scope = getOrCreateScope(V);
+ }
+ }
}
- Asm->EmitInt32(0); Asm->EOL("End Mark");
- EmitLabel("pubnames_end", Unit->getID());
+ assert(Scope && "Unable to find the variable's scope");
+ DbgVariable *DV = new DbgVariable(DIVariable(GV), FrameIndex, InlinedFnVar);
+ Scope->AddVariable(DV);
- Asm->EOL();
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
}
-/// EmitDebugPubNames - Emit visible names into a debug pubnames section.
-///
-void DwarfDebug::EmitDebugPubNames() {
- // Start the dwarf pubnames section.
- Asm->SwitchToDataSection(TAI->getDwarfPubNamesSection());
-
- if (MainCU) {
- EmitDebugPubNamesPerCU(MainCU);
- return;
- }
-
- for (unsigned i = 0, e = CompileUnits.size(); i != e; ++i)
- EmitDebugPubNamesPerCU(CompileUnits[i]);
-}
+//// RecordInlinedFnStart - Indicate the start of inlined subroutine.
+unsigned DwarfDebug::RecordInlinedFnStart(DISubprogram &SP, DICompileUnit CU,
+ unsigned Line, unsigned Col) {
+ unsigned LabelID = MMI->NextLabelID();
-/// EmitDebugStr - Emit visible names into a debug str section.
-///
-void DwarfDebug::EmitDebugStr() {
- // Check to see if it is worth the effort.
- if (!StringPool.empty()) {
- // Start the dwarf str section.
- Asm->SwitchToDataSection(TAI->getDwarfStrSection());
+ if (!TAI->doesDwarfUsesInlineInfoSection())
+ return LabelID;
- // For each of strings in the string pool.
- for (unsigned StringID = 1, N = StringPool.size();
- StringID <= N; ++StringID) {
- // Emit a label for reference from debug information entries.
- EmitLabel("string", StringID);
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- // Emit the string itself.
- const std::string &String = StringPool[StringID];
- Asm->EmitString(String); Asm->EOL();
- }
+ GlobalVariable *GV = SP.getGV();
+ DenseMap<const GlobalVariable *, DbgScope *>::iterator
+ II = AbstractInstanceRootMap.find(GV);
- Asm->EOL();
- }
-}
+ if (II == AbstractInstanceRootMap.end()) {
+ // Create an abstract instance entry for this inlined function if it doesn't
+ // already exist.
+ DbgScope *Scope = new DbgScope(NULL, DIDescriptor(GV));
-/// EmitDebugLoc - Emit visible names into a debug loc section.
-///
-void DwarfDebug::EmitDebugLoc() {
- // Start the dwarf loc section.
- Asm->SwitchToDataSection(TAI->getDwarfLocSection());
- Asm->EOL();
-}
+ // Get the compile unit context.
+ CompileUnit *Unit = &FindCompileUnit(SP.getCompileUnit());
+ DIE *SPDie = Unit->getDieMapSlotFor(GV);
+ if (!SPDie)
+ SPDie = CreateSubprogramDIE(Unit, SP, false, true);
-/// EmitDebugARanges - Emit visible names into a debug aranges section.
-///
-void DwarfDebug::EmitDebugARanges() {
- // Start the dwarf aranges section.
- Asm->SwitchToDataSection(TAI->getDwarfARangesSection());
+ // Mark as being inlined. This makes this subprogram entry an abstract
+ // instance root.
+ // FIXME: Our debugger doesn't care about the value of DW_AT_inline, only
+ // that it's defined. That probably won't change in the future. However,
+ // this could be more elegant.
+ AddUInt(SPDie, dwarf::DW_AT_inline, 0, dwarf::DW_INL_declared_not_inlined);
- // FIXME - Mock up
-#if 0
- CompileUnit *Unit = GetBaseCompileUnit();
+ // Keep track of the abstract scope for this function.
+ DbgAbstractScopeMap[GV] = Scope;
- // Don't include size of length
- Asm->EmitInt32(0x1c); Asm->EOL("Length of Address Ranges Info");
+ AbstractInstanceRootMap[GV] = Scope;
+ AbstractInstanceRootList.push_back(Scope);
+ }
- Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("Dwarf Version");
+ // Create a concrete inlined instance for this inlined function.
+ DbgConcreteScope *ConcreteScope = new DbgConcreteScope(DIDescriptor(GV));
+ DIE *ScopeDie = new DIE(dwarf::DW_TAG_inlined_subroutine);
+ CompileUnit *Unit = &FindCompileUnit(SP.getCompileUnit());
+ ScopeDie->setAbstractCompileUnit(Unit);
- EmitReference("info_begin", Unit->getID());
- Asm->EOL("Offset of Compilation Unit Info");
+ DIE *Origin = Unit->getDieMapSlotFor(GV);
+ AddDIEEntry(ScopeDie, dwarf::DW_AT_abstract_origin,
+ dwarf::DW_FORM_ref4, Origin);
+ AddUInt(ScopeDie, dwarf::DW_AT_call_file, 0, Unit->getID());
+ AddUInt(ScopeDie, dwarf::DW_AT_call_line, 0, Line);
+ AddUInt(ScopeDie, dwarf::DW_AT_call_column, 0, Col);
- Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Size of Address");
+ ConcreteScope->setDie(ScopeDie);
+ ConcreteScope->setStartLabelID(LabelID);
+ MMI->RecordUsedDbgLabel(LabelID);
- Asm->EmitInt8(0); Asm->EOL("Size of Segment Descriptor");
+ LexicalScopeStack.back()->AddConcreteInst(ConcreteScope);
- Asm->EmitInt16(0); Asm->EOL("Pad (1)");
- Asm->EmitInt16(0); Asm->EOL("Pad (2)");
+ // Keep track of the concrete scope that's inlined into this function.
+ DenseMap<GlobalVariable *, SmallVector<DbgScope *, 8> >::iterator
+ SI = DbgConcreteScopeMap.find(GV);
- // Range 1
- EmitReference("text_begin", 0); Asm->EOL("Address");
- EmitDifference("text_end", 0, "text_begin", 0, true); Asm->EOL("Length");
+ if (SI == DbgConcreteScopeMap.end())
+ DbgConcreteScopeMap[GV].push_back(ConcreteScope);
+ else
+ SI->second.push_back(ConcreteScope);
- Asm->EmitInt32(0); Asm->EOL("EOM (1)");
- Asm->EmitInt32(0); Asm->EOL("EOM (2)");
-#endif
+ // Track the start label for this inlined function.
+ DenseMap<GlobalVariable *, SmallVector<unsigned, 4> >::iterator
+ I = InlineInfo.find(GV);
- Asm->EOL();
-}
+ if (I == InlineInfo.end())
+ InlineInfo[GV].push_back(LabelID);
+ else
+ I->second.push_back(LabelID);
-/// EmitDebugRanges - Emit visible names into a debug ranges section.
-///
-void DwarfDebug::EmitDebugRanges() {
- // Start the dwarf ranges section.
- Asm->SwitchToDataSection(TAI->getDwarfRangesSection());
- Asm->EOL();
-}
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
-/// EmitDebugMacInfo - Emit visible names into a debug macinfo section.
-///
-void DwarfDebug::EmitDebugMacInfo() {
- if (TAI->doesSupportMacInfoSection()) {
- // Start the dwarf macinfo section.
- Asm->SwitchToDataSection(TAI->getDwarfMacInfoSection());
- Asm->EOL();
- }
+ return LabelID;
}
-/// 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 DwarfDebug::EmitDebugInlineInfo() {
+/// RecordInlinedFnEnd - Indicate the end of inlined subroutine.
+unsigned DwarfDebug::RecordInlinedFnEnd(DISubprogram &SP) {
if (!TAI->doesDwarfUsesInlineInfoSection())
- return;
-
- if (!MainCU)
- return;
+ return 0;
- Asm->SwitchToDataSection(TAI->getDwarfDebugInlineSection());
- Asm->EOL();
- EmitDifference("debug_inlined_end", 1,
- "debug_inlined_begin", 1, true);
- Asm->EOL("Length of Debug Inlined Information Entry");
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- EmitLabel("debug_inlined_begin", 1);
+ GlobalVariable *GV = SP.getGV();
+ DenseMap<GlobalVariable *, SmallVector<DbgScope *, 8> >::iterator
+ I = DbgConcreteScopeMap.find(GV);
- Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("Dwarf Version");
- Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Address Size (in bytes)");
+ if (I == DbgConcreteScopeMap.end()) {
+ // FIXME: Can this situation actually happen? And if so, should it?
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
- 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;
+ return 0;
+ }
- SP.getLinkageName(LName);
- SP.getName(Name);
+ SmallVector<DbgScope *, 8> &Scopes = I->second;
+ assert(!Scopes.empty() && "We should have at least one debug scope!");
+ DbgScope *Scope = Scopes.back(); Scopes.pop_back();
+ unsigned ID = MMI->NextLabelID();
+ MMI->RecordUsedDbgLabel(ID);
+ Scope->setEndLabelID(ID);
- Asm->EmitString(LName.empty() ? Name : LName);
- Asm->EOL("MIPS linkage name");
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
- Asm->EmitString(Name); Asm->EOL("Function name");
+ return ID;
+}
- Asm->EmitULEB128Bytes(Labels.size()); Asm->EOL("Inline count");
+/// RecordVariableScope - Record scope for the variable declared by
+/// DeclareMI. DeclareMI must describe TargetInstrInfo::DECLARE. Record scopes
+/// for only inlined subroutine variables. Other variables's scopes are
+/// determined during RecordVariable().
+void DwarfDebug::RecordVariableScope(DIVariable &DV,
+ const MachineInstr *DeclareMI) {
+ if (TimePassesIsEnabled)
+ DebugTimer->startTimer();
- 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");
+ DISubprogram SP(DV.getContext().getGV());
- if (TD->getPointerSize() == sizeof(int32_t))
- O << TAI->getData32bitsDirective();
- else
- O << TAI->getData64bitsDirective();
+ if (SP.isNull()) {
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
- PrintLabelName("label", *LI); Asm->EOL("low_pc");
- }
+ return;
}
- EmitLabel("debug_inlined_end", 1);
- Asm->EOL();
+ DenseMap<GlobalVariable *, DbgScope *>::iterator
+ I = DbgAbstractScopeMap.find(SP.getGV());
+ if (I != DbgAbstractScopeMap.end())
+ InlinedVariableScopes[DeclareMI] = I->second;
+
+ if (TimePassesIsEnabled)
+ DebugTimer->stopTimer();
}
Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h?rev=72193&r1=72192&r2=72193&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h Wed May 20 18:19:06 2009
@@ -230,9 +230,16 @@
///
void AssignAbbrevNumber(DIEAbbrev &Abbrev);
- /// CreateDIEEntry - Creates a new DIEEntry to be a proxy for a debug
- /// information entry.
- DIEEntry *CreateDIEEntry(DIE *Entry = NULL);
+ /// NewString - Add a string to the constant pool and returns a label.
+ ///
+ DWLabel NewString(const std::string &String) {
+ unsigned StringID = StringPool.insert(String);
+ return DWLabel("string", StringID);
+ }
+
+ /// NewDIEEntry - Creates a new DIEEntry to be a proxy for a debug information
+ /// entry.
+ DIEEntry *NewDIEEntry(DIE *Entry = NULL);
/// SetDIEEntry - Set a DIEEntry once the debug information entry is defined.
///
@@ -275,7 +282,7 @@
/// AddDIEEntry - Add a DIE attribute data and value.
///
void AddDIEEntry(DIE *Die, unsigned Attribute, unsigned Form, DIE *Entry) {
- Die->AddValue(Attribute, Form, CreateDIEEntry(Entry));
+ Die->AddValue(Attribute, Form, NewDIEEntry(Entry));
}
/// AddBlock - Add block data.
@@ -339,9 +346,9 @@
///
CompileUnit &FindCompileUnit(DICompileUnit Unit) const;
- /// CreateDbgScopeVariable - Create a new debug scope variable.
+ /// NewDbgScopeVariable - Create a new scope variable.
///
- DIE *CreateDbgScopeVariable(DbgVariable *DV, CompileUnit *Unit);
+ DIE *NewDbgScopeVariable(DbgVariable *DV, CompileUnit *Unit);
/// getOrCreateScope - Returns the scope associated with the given descriptor.
///
@@ -355,38 +362,17 @@
/// ConstructFunctionDbgScope - Construct the scope for the subprogram.
///
- void ConstructFunctionDbgScope(DbgScope *RootScope,
- bool AbstractScope = false);
+ void ConstructFunctionDbgScope(DbgScope *RootScope);
+
+ /// ConstructFunctionDbgScope - Construct the scope for the abstract debug
+ /// scope.
+ ///
+ void ConstructAbstractDbgScope(DbgScope *AbsScope);
/// ConstructDefaultDbgScope - Construct a default scope for the subprogram.
///
void ConstructDefaultDbgScope(MachineFunction *MF);
- /// 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
- /// in the SourceIds map. This can update DirectoryNames and SourceFileNames maps
- /// as well.
- unsigned GetOrCreateSourceID(const std::string &DirName,
- const std::string &FileName);
-
- void ConstructCompileUnit(GlobalVariable *GV);
-
- /// ConstructCompileUnits - Create a compile unit DIEs.
- void ConstructCompileUnits();
-
- bool ConstructGlobalVariableDIE(GlobalVariable *GV);
-
- /// ConstructGlobalVariableDIEs - Create DIEs for each of the externally
- /// visible global variables. Return true if at least one global DIE is
- /// created.
- bool ConstructGlobalVariableDIEs();
-
- bool ConstructSubprogram(GlobalVariable *GV);
-
- /// ConstructSubprograms - Create DIEs for each of the externally visible
- /// subprograms. Return true if at least one subprogram DIE is created.
- bool ConstructSubprograms();
-
/// EmitInitial - Emit initial Dwarf declarations. This is necessary for cc
/// tools to recognize the object file contains Dwarf information.
void EmitInitial();
@@ -475,6 +461,31 @@
/// the __debug_info section, and the low_pc is the starting address for the
/// inlining instance.
void EmitDebugInlineInfo();
+
+ /// 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
+ /// in the SourceIds map. This can update DirectoryNames and SourceFileNames maps
+ /// as well.
+ unsigned GetOrCreateSourceID(const std::string &DirName,
+ const std::string &FileName);
+
+ void ConstructCompileUnit(GlobalVariable *GV);
+
+ /// ConstructCompileUnits - Create a compile unit DIEs.
+ void ConstructCompileUnits();
+
+ bool ConstructGlobalVariableDIE(GlobalVariable *GV);
+
+ /// ConstructGlobalVariableDIEs - Create DIEs for each of the externally
+ /// visible global variables. Return true if at least one global DIE is
+ /// created.
+ bool ConstructGlobalVariableDIEs();
+
+ bool ConstructSubprogram(GlobalVariable *GV);
+
+ /// ConstructSubprograms - Create DIEs for each of the externally visible
+ /// subprograms. Return true if at least one subprogram DIE is created.
+ bool ConstructSubprograms();
public:
//===--------------------------------------------------------------------===//
// Main entry points.
More information about the llvm-commits
mailing list