From 94d04b8f808bc3ea9de0120c3a7da593771a438a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 20 May 2009 23:21:38 +0000 Subject: [PATCH] Move 'Emit' methods down to their own place. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@72194 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 2282 ++++++++++++------------- 1 file changed, 1141 insertions(+), 1141 deletions(-) diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 086a8a5f60e..3e6ac356a5a 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1196,1445 +1196,1445 @@ void DwarfDebug::ConstructDefaultDbgScope(MachineFunction *MF) { #endif } -/// 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; - - // Dwarf sections base addresses. - if (TAI->doesDwarfRequireFrameSection()) { - Asm->SwitchToDataSection(TAI->getDwarfFrameSection()); - EmitLabel("section_debug_frame", 0); +/// 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::iterator DI = DirectoryIdMap.find(DirName); + if (DI != DirectoryIdMap.end()) { + DId = DI->getValue(); + } else { + DId = DirectoryNames.size() + 1; + DirectoryIdMap[DirName] = DId; + DirectoryNames.push_back(DirName); } - Asm->SwitchToDataSection(TAI->getDwarfInfoSection()); - EmitLabel("section_info", 0); - Asm->SwitchToDataSection(TAI->getDwarfAbbrevSection()); - EmitLabel("section_abbrev", 0); - Asm->SwitchToDataSection(TAI->getDwarfARangesSection()); - EmitLabel("section_aranges", 0); - - if (TAI->doesSupportMacInfoSection()) { - Asm->SwitchToDataSection(TAI->getDwarfMacInfoSection()); - EmitLabel("section_macinfo", 0); + unsigned FId; + StringMap::iterator FI = SourceFileIdMap.find(FileName); + if (FI != SourceFileIdMap.end()) { + FId = FI->getValue(); + } else { + FId = SourceFileNames.size() + 1; + SourceFileIdMap[FileName] = FId; + SourceFileNames.push_back(FileName); } - 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); - - Asm->SwitchToSection(TAI->getTextSection()); - EmitLabel("text_begin", 0); - Asm->SwitchToSection(TAI->getDataSection()); - EmitLabel("data_begin", 0); -} + DenseMap, unsigned>::iterator SI = + SourceIdMap.find(std::make_pair(DId, FId)); + if (SI != SourceIdMap.end()) + return SI->second; -/// 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]; + 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)); - Asm->EOL(); + return SrcId; +} - // Emit the code (index) for the abbreviation. - Asm->EmitULEB128Bytes(AbbrevNumber); +void DwarfDebug::ConstructCompileUnit(GlobalVariable *GV) { + DICompileUnit DIUnit(GV); + std::string Dir, FN, Prod; + unsigned ID = GetOrCreateSourceID(DIUnit.getDirectory(Dir), + DIUnit.getFilename(FN)); - 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(); + 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); - SmallVector &Values = Die->getValues(); - const SmallVector &AbbrevData = Abbrev->getData(); + 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); - // 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)"); + std::string Flags; + DIUnit.getFlags(Flags); + if (!Flags.empty()) + AddString(Die, dwarf::DW_AT_APPLE_flags, dwarf::DW_FORM_string, Flags); - switch (Attr) { - case dwarf::DW_AT_sibling: - Asm->EmitInt32(Die->SiblingOffset()); - break; - case dwarf::DW_AT_abstract_origin: { - DIEEntry *E = cast(Values[i]); - DIE *Origin = E->getEntry(); - unsigned Addr = - CompileUnitOffsets[Die->getAbstractCompileUnit()] + - Origin->getOffset(); + unsigned RVer = DIUnit.getRunTimeVersion(); + if (RVer) + AddUInt(Die, dwarf::DW_AT_APPLE_major_runtime_vers, + dwarf::DW_FORM_data1, RVer); - Asm->EmitInt32(Addr); - break; - } - default: - // Emit an attribute using the defined form. - Values[i]->EmitValue(this, Form); - break; + CompileUnit *Unit = new CompileUnit(ID, Die); + if (DIUnit.isMain()) { + assert(!MainCU && "Multiple main compile units are found!"); + MainCU = Unit; } - Asm->EOL(dwarf::AttributeString(Attr)); - } - - // Emit the DIE children if any. - if (Abbrev->getChildrenFlag() == dwarf::DW_CHILDREN_yes) { - const std::vector &Children = Die->getChildren(); - - for (unsigned j = 0, M = Children.size(); j < M; ++j) - EmitDIE(Children[j]); - - Asm->EmitInt8(0); Asm->EOL("End Of Children Mark"); - } + CompileUnitMap[DIUnit.getGV()] = Unit; + CompileUnits.push_back(Unit); } -/// SizeAndOffsetDie - Compute the size and offset of a DIE. -/// -unsigned DwarfDebug::SizeAndOffsetDie(DIE *Die, unsigned Offset, bool Last) { - // Get the children. - const std::vector &Children = Die->getChildren(); - - // If not last sibling and has children then add sibling offset attribute. - if (!Last && !Children.empty()) Die->AddSiblingOffset(); - - // Record the abbreviation. - AssignAbbrevNumber(Die->getAbbrev()); - - // Get the abbreviation for this DIE. - unsigned AbbrevNumber = Die->getAbbrevNumber(); - const DIEAbbrev *Abbrev = Abbreviations[AbbrevNumber - 1]; +/// 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(*Root->use_begin()); + assert(RootC->hasNUsesOrMore(1) && + "Malformed compile unit descriptor anchor type"); - // Set DIE offset - Die->setOffset(Offset); + 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(*UUI); + ConstructCompileUnit(GV); + } +} - // Start the size with the size of abbreviation code. - Offset += TargetAsmInfo::getULEB128Size(AbbrevNumber); +bool DwarfDebug::ConstructGlobalVariableDIE(GlobalVariable *GV) { + DIGlobalVariable DI_GV(GV); + CompileUnit *DW_Unit = MainCU; + if (!DW_Unit) + DW_Unit = &FindCompileUnit(DI_GV.getCompileUnit()); - const SmallVector &Values = Die->getValues(); - const SmallVector &AbbrevData = Abbrev->getData(); + // Check for pre-existence. + DIE *&Slot = DW_Unit->getDieMapSlotFor(DI_GV.getGV()); + if (Slot) + return false; - // 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 *VariableDie = CreateGlobalVariableDIE(DW_Unit, DI_GV); - // Size the DIE children if any. - if (!Children.empty()) { - assert(Abbrev->getChildrenFlag() == dwarf::DW_CHILDREN_yes && - "Children flag not set"); + // 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); - for (unsigned j = 0, M = Children.size(); j < M; ++j) - Offset = SizeAndOffsetDie(Children[j], Offset, (j + 1) == M); + // Add to map. + Slot = VariableDie; - // End of children marker. - Offset += sizeof(int8_t); - } + // Add to context owner. + DW_Unit->getDie()->AddChild(VariableDie); - Die->setSize(Offset - Die->getOffset()); - return Offset; + // Expose as global. FIXME - need to check external flag. + std::string Name; + DW_Unit->AddGlobal(DI_GV.getName(Name), VariableDie); + return true; } -/// 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) +/// 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; - // Process base compile unit. - if (MainCU) { - SizeAndOffsetDie(MainCU->getDie(), Offset, true); - CompileUnitOffsets[MainCU] = 0; - return; - } + assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() && + "Malformed global variable descriptor anchor type"); + Constant *RootC = cast(*Root->use_begin()); + assert(RootC->hasNUsesOrMore(1) && + "Malformed global variable descriptor anchor type"); - // Process all compile units. - unsigned PrevOffset = 0; + 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(*UUI)); - 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. - } + return Result; } -/// EmitDebugInfo / EmitDebugInfoPerCU - Emit the debug info section. -/// -void DwarfDebug::EmitDebugInfoPerCU(CompileUnit *Unit) { - DIE *Die = Unit->getDie(); - - // Emit the compile units header. - EmitLabel("info_begin", Unit->getID()); - - // 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 DwarfDebug::ConstructSubprogram(GlobalVariable *GV) { + DISubprogram SP(GV); + CompileUnit *Unit = MainCU; + if (!Unit) + Unit = &FindCompileUnit(SP.getCompileUnit()); - 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)"); + // Check for pre-existence. + DIE *&Slot = Unit->getDieMapSlotFor(GV); + if (Slot) + return false; - 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()); + if (!SP.isDefinition()) + // This is a method declaration which will be handled while constructing + // class type. + return false; - Asm->EOL(); -} + DIE *SubprogramDie = CreateSubprogramDIE(Unit, SP); -void DwarfDebug::EmitDebugInfo() { - // Start debug info section. - Asm->SwitchToDataSection(TAI->getDwarfInfoSection()); + // Add to map. + Slot = SubprogramDie; - if (MainCU) { - EmitDebugInfoPerCU(MainCU); - return; - } + // Add to context owner. + Unit->getDie()->AddChild(SubprogramDie); - for (unsigned i = 0, e = CompileUnits.size(); i != e; ++i) - EmitDebugInfoPerCU(CompileUnits[i]); + // Expose as global. + std::string Name; + Unit->AddGlobal(SP.getName(Name), SubprogramDie); + return true; } -/// 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()); - - EmitLabel("abbrev_begin", 0); - - // For each abbrevation. - for (unsigned i = 0, N = Abbreviations.size(); i < N; ++i) { - // Get abbreviation data - const DIEAbbrev *Abbrev = Abbreviations[i]; - - // Emit the abbrevations code (base 1 index.) - Asm->EmitULEB128Bytes(Abbrev->getNumber()); - Asm->EOL("Abbreviation Code"); - - // Emit the abbreviations data. - Abbrev->Emit(Asm); - - Asm->EOL(); - } - - // Mark end of abbreviations. - Asm->EmitULEB128Bytes(0); Asm->EOL("EOM(3)"); +/// 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; - EmitLabel("abbrev_end", 0); - Asm->EOL(); - } -} + assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() && + "Malformed subprogram descriptor anchor type"); + Constant *RootC = cast(*Root->use_begin()); + assert(RootC->hasNUsesOrMore(1) && + "Malformed subprogram descriptor anchor type"); -/// 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"); + 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(*UUI)); - // Mark end of matrix. - Asm->EmitInt8(0); Asm->EOL("DW_LNE_end_sequence"); - Asm->EmitULEB128Bytes(1); Asm->EOL(); - Asm->EmitInt8(1); Asm->EOL(); + return Result; } -/// 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; - - // 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; - - // Start the dwarf line section. - Asm->SwitchToDataSection(TAI->getDwarfLineSection()); - - // Construct the section header. - EmitDifference("line_end", 0, "line_begin", 0, true); - Asm->EOL("Length of Source Line Info"); - EmitLabel("line_begin", 0); - - Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("DWARF version number"); - - EmitDifference("line_prolog_end", 0, "line_prolog_begin", 0, true); - Asm->EOL("Prolog Length"); - EmitLabel("line_prolog_begin", 0); +/// 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->EmitInt8(1); Asm->EOL("Minimum Instruction Length"); + // Create all the compile unit DIEs. + ConstructCompileUnits(); - Asm->EmitInt8(1); Asm->EOL("Default is_stmt_start flag"); + if (CompileUnits.empty()) { + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); - Asm->EmitInt8(MinLineDelta); Asm->EOL("Line Base Value (Special Opcodes)"); + return; + } - Asm->EmitInt8(MaxLineDelta); Asm->EOL("Line Range Value (Special Opcodes)"); + // Create DIEs for each of the externally visible global variables. + bool globalDIEs = ConstructGlobalVariableDIEs(); - Asm->EmitInt8(-MinLineDelta); Asm->EOL("Special Opcode Base"); + // Create DIEs for each of the externally visible subprograms. + bool subprogramDIEs = ConstructSubprograms(); - // 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"); + // 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(); - // Emit directories. - for (unsigned DI = 1, DE = getNumSourceDirectories()+1; DI != DE; ++DI) { - Asm->EmitString(getSourceDirectoryName(DI)); - Asm->EOL("Directory"); + return; } - Asm->EmitInt8(0); Asm->EOL("End of directories"); + MMI = mmi; + shouldEmit = true; + MMI->setDebugInfoAvailability(true); - // Emit files. - for (unsigned SI = 1, SE = getNumSourceIds()+1; SI != SE; ++SI) { - // Remember source id starts at 1. - std::pair 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"); + // 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 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(); + } } - Asm->EmitInt8(0); Asm->EOL("End of files"); + // Emit initial sections + EmitInitial(); - EmitLabel("line_prolog_end", 0); + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); +} - // A sequence for each text section. - unsigned SecSrcLinesSize = SectionSourceLines.size(); +/// EndModule - Emit all Dwarf sections that should come after the content. +/// +void DwarfDebug::EndModule() { + if (!ShouldEmitDwarfDebug()) + return; - for (unsigned j = 0; j < SecSrcLinesSize; ++j) { - // Isolate current sections line info. - const std::vector &LineInfos = SectionSourceLines[j]; + if (TimePassesIsEnabled) + DebugTimer->startTimer(); - if (Asm->isVerbose()) { - const Section* S = SectionMap[j + 1]; - O << '\t' << TAI->getCommentString() << " Section" - << S->getName() << '\n'; - } else { - Asm->EOL(); - } + // Standard sections final addresses. + Asm->SwitchToSection(TAI->getTextSection()); + EmitLabel("text_end", 0); + Asm->SwitchToSection(TAI->getDataSection()); + EmitLabel("data_end", 0); - // Dwarf assumes we start with first line of first source file. - unsigned Source = 1; - unsigned Line = 1; + // End text sections. + for (unsigned i = 1, N = SectionMap.size(); i <= N; ++i) { + Asm->SwitchToSection(SectionMap[i]); + EmitLabel("section_end", i); + } - // 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; + // Emit common frame information. + EmitCommonDebugFrame(); - if (!Asm->isVerbose()) - Asm->EOL(); - else { - std::pair SourceID = - getSourceDirectoryAndFileIds(LineInfo.getSourceID()); - O << '\t' << TAI->getCommentString() << ' ' - << getSourceDirectoryName(SourceID.first) << ' ' - << getSourceFileName(SourceID.second) - <<" :" << utostr_32(LineInfo.getLine()) << '\n'; - } + // Emit function debug frame information + for (std::vector::iterator I = DebugFrames.begin(), + E = DebugFrames.end(); I != E; ++I) + EmitFunctionDebugFrame(*I); - // 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"); + // Compute DIE offsets and sizes. + SizeAndOffsets(); - // 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"); - } + // Emit all the DIEs into a debug info section + EmitDebugInfo(); - // If change of line. - if (Line != LineInfo.getLine()) { - // Determine offset. - int Offset = LineInfo.getLine() - Line; - int Delta = Offset - MinLineDelta; + // Corresponding abbreviations into a abbrev section. + EmitAbbreviations(); - // Update line. - Line = LineInfo.getLine(); + // Emit source line correspondence into a debug line section. + EmitDebugLines(); - // 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"); - } - } + // Emit info into a debug pubnames section. + EmitDebugPubNames(); - EmitEndOfLineMatrix(j + 1); - } + // Emit info into a debug str section. + EmitDebugStr(); - 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); + // Emit info into a debug loc section. + EmitDebugLoc(); - EmitLabel("line_end", 0); - Asm->EOL(); -} + // Emit info into a debug aranges section. + EmitDebugARanges(); -/// EmitCommonDebugFrame - Emit common frame info into a debug frame section. -/// -void DwarfDebug::EmitCommonDebugFrame() { - if (!TAI->doesDwarfRequireFrameSection()) - return; + // Emit info into a debug ranges section. + EmitDebugRanges(); - int stackGrowth = - Asm->TM.getFrameInfo()->getStackGrowthDirection() == - TargetFrameInfo::StackGrowsUp ? - TD->getPointerSize() : -TD->getPointerSize(); + // Emit info into a debug macinfo section. + EmitDebugMacInfo(); - // Start the dwarf frame section. - Asm->SwitchToDataSection(TAI->getDwarfFrameSection()); + // Emit inline info. + EmitDebugInlineInfo(); - 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"); +/// BeginFunction - Gather pre-function debug information. Assumes being +/// emitted immediately after the function entry point. +void DwarfDebug::BeginFunction(MachineFunction *MF) { + this->MF = MF; - std::vector Moves; - RI->getInitialFrameState(Moves); + if (!ShouldEmitDwarfDebug()) return; - EmitFrameMoves(NULL, 0, Moves, false); + if (TimePassesIsEnabled) + DebugTimer->startTimer(); - Asm->EmitAlignment(2, 0, 0, false); - EmitLabel("debug_frame_common_end", 0); + // Begin accumulating function debug information. + MMI->BeginFunction(MF); - Asm->EOL(); + // Assumes in correct section after the entry point. + EmitLabel("func_begin", ++SubprogramCount); + + // 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 (TimePassesIsEnabled) + DebugTimer->stopTimer(); } -/// EmitFunctionDebugFrame - Emit per function frame info into a debug frame -/// section. -void -DwarfDebug::EmitFunctionDebugFrame(const FunctionDebugFrameInfo&DebugFrameInfo){ - if (!TAI->doesDwarfRequireFrameSection()) - return; +/// EndFunction - Gather and emit post-function debug information. +/// +void DwarfDebug::EndFunction(MachineFunction *MF) { + if (!ShouldEmitDwarfDebug()) return; - // Start the dwarf frame section. - Asm->SwitchToDataSection(TAI->getDwarfFrameSection()); + if (TimePassesIsEnabled) + DebugTimer->startTimer(); - EmitDifference("debug_frame_end", DebugFrameInfo.Number, - "debug_frame_begin", DebugFrameInfo.Number, true); - Asm->EOL("Length of Frame Information Entry"); + // Define end label for subprogram. + EmitLabel("func_end", SubprogramCount); - EmitLabel("debug_frame_begin", DebugFrameInfo.Number); + // 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 &SectionLineInfos = SectionSourceLines[ID-1]; + // Append the function info to section info. + SectionLineInfos.insert(SectionLineInfos.end(), + Lines.begin(), Lines.end()); + } - EmitSectionOffset("debug_frame_common", "section_debug_frame", - 0, 0, true, false); - Asm->EOL("FDE CIE offset"); + // Construct the DbgScope for abstract instances. + for (SmallVector::iterator + I = AbstractInstanceRootList.begin(), + E = AbstractInstanceRootList.end(); I != E; ++I) + ConstructAbstractDbgScope(*I); - EmitReference("func_begin", DebugFrameInfo.Number); - Asm->EOL("FDE initial location"); - EmitDifference("func_end", DebugFrameInfo.Number, - "func_begin", DebugFrameInfo.Number); - Asm->EOL("FDE address range"); + // 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); - EmitFrameMoves("func_begin", DebugFrameInfo.Number, DebugFrameInfo.Moves, - false); + DebugFrames.push_back(FunctionDebugFrameInfo(SubprogramCount, + MMI->getFrameMoves())); + + // Clear debug info + if (FunctionDbgScope) { + delete FunctionDbgScope; + DbgScopeMap.clear(); + DbgAbstractScopeMap.clear(); + DbgConcreteScopeMap.clear(); + InlinedVariableScopes.clear(); + FunctionDbgScope = NULL; + LexicalScopeStack.clear(); + AbstractInstanceRootList.clear(); + } - Asm->EmitAlignment(2, 0, 0, false); - EmitLabel("debug_frame_end", DebugFrameInfo.Number); + Lines.clear(); - Asm->EOL(); + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); } -void DwarfDebug::EmitDebugPubNamesPerCU(CompileUnit *Unit) { - EmitDifference("pubnames_end", Unit->getID(), - "pubnames_begin", Unit->getID(), true); - Asm->EOL("Length of Public Names Info"); - - EmitLabel("pubnames_begin", Unit->getID()); +/// 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(); - Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("DWARF Version"); + CompileUnit *Unit = CompileUnitMap[V]; + assert(Unit && "Unable to find CompileUnit"); + unsigned ID = MMI->NextLabelID(); + Lines.push_back(SrcLineInfo(Line, Col, Unit->getID(), ID)); - EmitSectionOffset("info_begin", "section_info", - Unit->getID(), 0, true, false); - Asm->EOL("Offset of Compilation Unit Info"); + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); - EmitDifference("info_end", Unit->getID(), "info_begin", Unit->getID(), - true); - Asm->EOL("Compilation Unit Length"); + return ID; +} - StringMap &Globals = Unit->getGlobals(); - for (StringMap::const_iterator - GI = Globals.begin(), GE = Globals.end(); GI != GE; ++GI) { - const char *Name = GI->getKeyData(); - DIE * Entity = GI->second; +/// 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(); - Asm->EmitInt32(Entity->getOffset()); Asm->EOL("DIE offset"); - Asm->EmitString(Name, strlen(Name)); Asm->EOL("External Name"); - } + 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->EmitInt32(0); Asm->EOL("End Mark"); - EmitLabel("pubnames_end", Unit->getID()); + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); - Asm->EOL(); + return ID; } -/// EmitDebugPubNames - Emit visible names into a debug pubnames section. -/// -void DwarfDebug::EmitDebugPubNames() { - // Start the dwarf pubnames section. - Asm->SwitchToDataSection(TAI->getDwarfPubNamesSection()); +/// 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(); - if (MainCU) { - EmitDebugPubNamesPerCU(MainCU); - return; - } + unsigned SrcId = GetOrCreateSourceID(DirName, FileName); - for (unsigned i = 0, e = CompileUnits.size(); i != e; ++i) - EmitDebugPubNamesPerCU(CompileUnits[i]); + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); + + return SrcId; } -/// 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()); +/// RecordRegionStart - Indicate the start of a region. +unsigned DwarfDebug::RecordRegionStart(GlobalVariable *V) { + 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); + DbgScope *Scope = getOrCreateScope(V); + unsigned ID = MMI->NextLabelID(); + if (!Scope->getStartLabelID()) Scope->setStartLabelID(ID); + LexicalScopeStack.push_back(Scope); - // Emit the string itself. - const std::string &String = StringPool[StringID]; - Asm->EmitString(String); Asm->EOL(); - } + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); - Asm->EOL(); - } + return ID; } -/// EmitDebugLoc - Emit visible names into a debug loc section. -/// -void DwarfDebug::EmitDebugLoc() { - // Start the dwarf loc section. - Asm->SwitchToDataSection(TAI->getDwarfLocSection()); - Asm->EOL(); -} +/// RecordRegionEnd - Indicate the end of a region. +unsigned DwarfDebug::RecordRegionEnd(GlobalVariable *V) { + if (TimePassesIsEnabled) + DebugTimer->startTimer(); -/// EmitDebugARanges - Emit visible names into a debug aranges section. -/// -void DwarfDebug::EmitDebugARanges() { - // Start the dwarf aranges section. - Asm->SwitchToDataSection(TAI->getDwarfARangesSection()); + DbgScope *Scope = getOrCreateScope(V); + unsigned ID = MMI->NextLabelID(); + Scope->setEndLabelID(ID); + if (LexicalScopeStack.size() != 0) + LexicalScopeStack.pop_back(); - // FIXME - Mock up -#if 0 - CompileUnit *Unit = GetBaseCompileUnit(); + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); - // Don't include size of length - Asm->EmitInt32(0x1c); Asm->EOL("Length of Address Ranges Info"); + 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(); - EmitReference("info_begin", Unit->getID()); - Asm->EOL("Offset of Compilation Unit Info"); + DIDescriptor Desc(GV); + DbgScope *Scope = NULL; + bool InlinedFnVar = false; - Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Size of Address"); + if (Desc.getTag() == dwarf::DW_TAG_variable) { + // GV is a global variable. + DIGlobalVariable DG(GV); + Scope = getOrCreateScope(DG.getContext().getGV()); + } else { + DenseMap::iterator + SI = InlinedVariableScopes.find(MI); - Asm->EmitInt8(0); Asm->EOL("Size of Segment Descriptor"); + if (SI != InlinedVariableScopes.end()) { + // or GV is an inlined local variable. + Scope = SI->second; + } else { + DIVariable DV(GV); + GlobalVariable *V = DV.getContext().getGV(); - Asm->EmitInt16(0); Asm->EOL("Pad (1)"); - Asm->EmitInt16(0); Asm->EOL("Pad (2)"); + // FIXME: The code that checks for the inlined local variable is a hack! + DenseMap::iterator + AI = AbstractInstanceRootMap.find(V); - // Range 1 - EmitReference("text_begin", 0); Asm->EOL("Address"); - EmitDifference("text_end", 0, "text_begin", 0, true); Asm->EOL("Length"); + 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 >::iterator + IP = InlinedParamMap.find(V); - Asm->EmitInt32(0); Asm->EOL("EOM (1)"); - Asm->EmitInt32(0); Asm->EOL("EOM (2)"); -#endif + if (IP != InlinedParamMap.end() && IP->second.count(GV) > 0) { + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); + return; + } - Asm->EOL(); -} + // 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); + } + } + } -/// EmitDebugRanges - Emit visible names into a debug ranges section. -/// -void DwarfDebug::EmitDebugRanges() { - // Start the dwarf ranges section. - Asm->SwitchToDataSection(TAI->getDwarfRangesSection()); - Asm->EOL(); -} + assert(Scope && "Unable to find the variable's scope"); + DbgVariable *DV = new DbgVariable(DIVariable(GV), FrameIndex, InlinedFnVar); + Scope->AddVariable(DV); -/// 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(); - } + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); } -/// 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; +//// RecordInlinedFnStart - Indicate the start of inlined subroutine. +unsigned DwarfDebug::RecordInlinedFnStart(DISubprogram &SP, DICompileUnit CU, + unsigned Line, unsigned Col) { + unsigned LabelID = MMI->NextLabelID(); - if (!MainCU) - return; + if (!TAI->doesDwarfUsesInlineInfoSection()) + return LabelID; - 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::iterator + II = AbstractInstanceRootMap.find(GV); - Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("Dwarf Version"); - Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Address Size (in bytes)"); + 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)); - for (DenseMap >::iterator - I = InlineInfo.begin(), E = InlineInfo.end(); I != E; ++I) { - GlobalVariable *GV = I->first; - SmallVector &Labels = I->second; - DISubprogram SP(GV); - std::string Name; - std::string LName; + // Get the compile unit context. + CompileUnit *Unit = &FindCompileUnit(SP.getCompileUnit()); + DIE *SPDie = Unit->getDieMapSlotFor(GV); + if (!SPDie) + SPDie = CreateSubprogramDIE(Unit, SP, false, true); - SP.getLinkageName(LName); - SP.getName(Name); + // 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); - Asm->EmitString(LName.empty() ? Name : LName); - Asm->EOL("MIPS linkage name"); + // Keep track of the abstract scope for this function. + DbgAbstractScopeMap[GV] = Scope; - Asm->EmitString(Name); Asm->EOL("Function name"); + AbstractInstanceRootMap[GV] = Scope; + AbstractInstanceRootList.push_back(Scope); + } - Asm->EmitULEB128Bytes(Labels.size()); Asm->EOL("Inline count"); + // 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); - for (SmallVector::iterator LI = Labels.begin(), - LE = Labels.end(); LI != LE; ++LI) { - DIE *SP = MainCU->getDieMapSlotFor(GV); - Asm->EmitInt32(SP->getOffset()); Asm->EOL("DIE offset"); + 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); - if (TD->getPointerSize() == sizeof(int32_t)) - O << TAI->getData32bitsDirective(); - else - O << TAI->getData64bitsDirective(); + ConcreteScope->setDie(ScopeDie); + ConcreteScope->setStartLabelID(LabelID); + MMI->RecordUsedDbgLabel(LabelID); - PrintLabelName("label", *LI); Asm->EOL("low_pc"); - } - } + LexicalScopeStack.back()->AddConcreteInst(ConcreteScope); - EmitLabel("debug_inlined_end", 1); - Asm->EOL(); -} + // Keep track of the concrete scope that's inlined into this function. + DenseMap >::iterator + SI = DbgConcreteScopeMap.find(GV); -/// 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::iterator DI = DirectoryIdMap.find(DirName); - if (DI != DirectoryIdMap.end()) { - DId = DI->getValue(); - } else { - DId = DirectoryNames.size() + 1; - DirectoryIdMap[DirName] = DId; - DirectoryNames.push_back(DirName); - } + if (SI == DbgConcreteScopeMap.end()) + DbgConcreteScopeMap[GV].push_back(ConcreteScope); + else + SI->second.push_back(ConcreteScope); - unsigned FId; - StringMap::iterator FI = SourceFileIdMap.find(FileName); - if (FI != SourceFileIdMap.end()) { - FId = FI->getValue(); - } else { - FId = SourceFileNames.size() + 1; - SourceFileIdMap[FileName] = FId; - SourceFileNames.push_back(FileName); - } + // Track the start label for this inlined function. + DenseMap >::iterator + I = InlineInfo.find(GV); - DenseMap, unsigned>::iterator SI = - SourceIdMap.find(std::make_pair(DId, FId)); - if (SI != SourceIdMap.end()) - return SI->second; + if (I == InlineInfo.end()) + InlineInfo[GV].push_back(LabelID); + else + I->second.push_back(LabelID); - 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 (TimePassesIsEnabled) + DebugTimer->stopTimer(); - return SrcId; + return LabelID; } -void DwarfDebug::ConstructCompileUnit(GlobalVariable *GV) { - DICompileUnit DIUnit(GV); - std::string Dir, FN, Prod; - unsigned ID = GetOrCreateSourceID(DIUnit.getDirectory(Dir), - DIUnit.getFilename(FN)); +/// RecordInlinedFnEnd - Indicate the end of inlined subroutine. +unsigned DwarfDebug::RecordInlinedFnEnd(DISubprogram &SP) { + if (!TAI->doesDwarfUsesInlineInfoSection()) + return 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); + if (TimePassesIsEnabled) + DebugTimer->startTimer(); - 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); + GlobalVariable *GV = SP.getGV(); + DenseMap >::iterator + I = DbgConcreteScopeMap.find(GV); - std::string Flags; - DIUnit.getFlags(Flags); - if (!Flags.empty()) - AddString(Die, dwarf::DW_AT_APPLE_flags, dwarf::DW_FORM_string, Flags); + if (I == DbgConcreteScopeMap.end()) { + // FIXME: Can this situation actually happen? And if so, should it? + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); - unsigned RVer = DIUnit.getRunTimeVersion(); - if (RVer) - AddUInt(Die, dwarf::DW_AT_APPLE_major_runtime_vers, - dwarf::DW_FORM_data1, RVer); + return 0; + } - CompileUnit *Unit = new CompileUnit(ID, Die); - if (DIUnit.isMain()) { - assert(!MainCU && "Multiple main compile units are found!"); - MainCU = Unit; - } + SmallVector &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); - CompileUnitMap[DIUnit.getGV()] = Unit; - CompileUnits.push_back(Unit); + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); + + return ID; } -/// ConstructCompileUnits - Create a compile unit DIEs. -void DwarfDebug::ConstructCompileUnits() { - GlobalVariable *Root = M->getGlobalVariable("llvm.dbg.compile_units"); - if (!Root) +/// 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(); + + DISubprogram SP(DV.getContext().getGV()); + + if (SP.isNull()) { + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); + return; - assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() && - "Malformed compile unit descriptor anchor type"); - Constant *RootC = cast(*Root->use_begin()); - assert(RootC->hasNUsesOrMore(1) && - "Malformed compile unit descriptor anchor type"); + } - 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(*UUI); - ConstructCompileUnit(GV); - } + DenseMap::iterator + I = DbgAbstractScopeMap.find(SP.getGV()); + if (I != DbgAbstractScopeMap.end()) + InlinedVariableScopes[DeclareMI] = I->second; + + if (TimePassesIsEnabled) + DebugTimer->stopTimer(); } -bool DwarfDebug::ConstructGlobalVariableDIE(GlobalVariable *GV) { - DIGlobalVariable DI_GV(GV); - CompileUnit *DW_Unit = MainCU; - if (!DW_Unit) - DW_Unit = &FindCompileUnit(DI_GV.getCompileUnit()); +/// SizeAndOffsetDie - Compute the size and offset of a DIE. +/// +unsigned DwarfDebug::SizeAndOffsetDie(DIE *Die, unsigned Offset, bool Last) { + // Get the children. + const std::vector &Children = Die->getChildren(); - // Check for pre-existence. - DIE *&Slot = DW_Unit->getDieMapSlotFor(DI_GV.getGV()); - if (Slot) - return false; + // If not last sibling and has children then add sibling offset attribute. + if (!Last && !Children.empty()) Die->AddSiblingOffset(); + + // Record the abbreviation. + AssignAbbrevNumber(Die->getAbbrev()); + + // Get the abbreviation for this DIE. + unsigned AbbrevNumber = Die->getAbbrevNumber(); + const DIEAbbrev *Abbrev = Abbreviations[AbbrevNumber - 1]; + + // Set DIE offset + Die->setOffset(Offset); + + // Start the size with the size of abbreviation code. + Offset += TargetAsmInfo::getULEB128Size(AbbrevNumber); + + const SmallVector &Values = Die->getValues(); + const SmallVector &AbbrevData = Abbrev->getData(); - DIE *VariableDie = CreateGlobalVariableDIE(DW_Unit, DI_GV); + // 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()); - // 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); + // Size the DIE children if any. + if (!Children.empty()) { + assert(Abbrev->getChildrenFlag() == dwarf::DW_CHILDREN_yes && + "Children flag not set"); - // Add to map. - Slot = VariableDie; + for (unsigned j = 0, M = Children.size(); j < M; ++j) + Offset = SizeAndOffsetDie(Children[j], Offset, (j + 1) == M); - // Add to context owner. - DW_Unit->getDie()->AddChild(VariableDie); + // End of children marker. + Offset += sizeof(int8_t); + } - // Expose as global. FIXME - need to check external flag. - std::string Name; - DW_Unit->AddGlobal(DI_GV.getName(Name), VariableDie); - return true; + Die->setSize(Offset - Die->getOffset()); + return Offset; } -/// 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; +/// 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) - assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() && - "Malformed global variable descriptor anchor type"); - Constant *RootC = cast(*Root->use_begin()); - assert(RootC->hasNUsesOrMore(1) && - "Malformed global variable descriptor anchor type"); + // Process base compile unit. + if (MainCU) { + SizeAndOffsetDie(MainCU->getDie(), Offset, true); + CompileUnitOffsets[MainCU] = 0; + return; + } - 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(*UUI)); + // Process all compile units. + unsigned PrevOffset = 0; - return Result; + 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. + } } -bool DwarfDebug::ConstructSubprogram(GlobalVariable *GV) { - DISubprogram SP(GV); - CompileUnit *Unit = MainCU; - if (!Unit) - Unit = &FindCompileUnit(SP.getCompileUnit()); - - // Check for pre-existence. - DIE *&Slot = Unit->getDieMapSlotFor(GV); - if (Slot) - return false; +/// 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; - if (!SP.isDefinition()) - // This is a method declaration which will be handled while constructing - // class type. - return false; + // Dwarf sections base addresses. + if (TAI->doesDwarfRequireFrameSection()) { + Asm->SwitchToDataSection(TAI->getDwarfFrameSection()); + EmitLabel("section_debug_frame", 0); + } - DIE *SubprogramDie = CreateSubprogramDIE(Unit, SP); + Asm->SwitchToDataSection(TAI->getDwarfInfoSection()); + EmitLabel("section_info", 0); + Asm->SwitchToDataSection(TAI->getDwarfAbbrevSection()); + EmitLabel("section_abbrev", 0); + Asm->SwitchToDataSection(TAI->getDwarfARangesSection()); + EmitLabel("section_aranges", 0); - // Add to map. - Slot = SubprogramDie; + if (TAI->doesSupportMacInfoSection()) { + Asm->SwitchToDataSection(TAI->getDwarfMacInfoSection()); + EmitLabel("section_macinfo", 0); + } - // Add to context owner. - Unit->getDie()->AddChild(SubprogramDie); + 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); - // Expose as global. - std::string Name; - Unit->AddGlobal(SP.getName(Name), SubprogramDie); - return true; + Asm->SwitchToSection(TAI->getTextSection()); + EmitLabel("text_begin", 0); + Asm->SwitchToSection(TAI->getDataSection()); + EmitLabel("data_begin", 0); } -/// 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; +/// 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]; - assert(Root->hasLinkOnceLinkage() && Root->hasOneUse() && - "Malformed subprogram descriptor anchor type"); - Constant *RootC = cast(*Root->use_begin()); - assert(RootC->hasNUsesOrMore(1) && - "Malformed subprogram descriptor anchor type"); + 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 |= ConstructSubprogram(cast(*UUI)); + // Emit the code (index) for the abbreviation. + Asm->EmitULEB128Bytes(AbbrevNumber); - return Result; -} + 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(); -/// 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(); + SmallVector &Values = Die->getValues(); + const SmallVector &AbbrevData = Abbrev->getData(); - // Create all the compile unit DIEs. - ConstructCompileUnits(); + // 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)"); - if (CompileUnits.empty()) { - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); + switch (Attr) { + case dwarf::DW_AT_sibling: + Asm->EmitInt32(Die->SiblingOffset()); + break; + case dwarf::DW_AT_abstract_origin: { + DIEEntry *E = cast(Values[i]); + DIE *Origin = E->getEntry(); + unsigned Addr = + CompileUnitOffsets[Die->getAbstractCompileUnit()] + + Origin->getOffset(); - return; - } + Asm->EmitInt32(Addr); + break; + } + default: + // Emit an attribute using the defined form. + Values[i]->EmitValue(this, Form); + break; + } - // Create DIEs for each of the externally visible global variables. - bool globalDIEs = ConstructGlobalVariableDIEs(); + Asm->EOL(dwarf::AttributeString(Attr)); + } - // Create DIEs for each of the externally visible subprograms. - bool subprogramDIEs = ConstructSubprograms(); + // Emit the DIE children if any. + if (Abbrev->getChildrenFlag() == dwarf::DW_CHILDREN_yes) { + const std::vector &Children = Die->getChildren(); - // 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 (unsigned j = 0, M = Children.size(); j < M; ++j) + EmitDIE(Children[j]); - return; + Asm->EmitInt8(0); Asm->EOL("End Of Children Mark"); } +} - MMI = mmi; - shouldEmit = true; - MMI->setDebugInfoAvailability(true); +/// EmitDebugInfo / EmitDebugInfoPerCU - Emit the debug info section. +/// +void DwarfDebug::EmitDebugInfoPerCU(CompileUnit *Unit) { + DIE *Die = Unit->getDie(); + + // Emit the compile units header. + EmitLabel("info_begin", Unit->getID()); + + // 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. + + 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)"); + + 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()); + + Asm->EOL(); +} - // Prime section data. - SectionMap.insert(TAI->getTextSection()); +void DwarfDebug::EmitDebugInfo() { + // Start debug info section. + Asm->SwitchToDataSection(TAI->getDwarfInfoSection()); - // 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 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(); - } + if (MainCU) { + EmitDebugInfoPerCU(MainCU); + return; } - // Emit initial sections - EmitInitial(); - - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); + for (unsigned i = 0, e = CompileUnits.size(); i != e; ++i) + EmitDebugInfoPerCU(CompileUnits[i]); } -/// EndModule - Emit all Dwarf sections that should come after the content. +/// EmitAbbreviations - Emit the abbreviation section. /// -void DwarfDebug::EndModule() { - if (!ShouldEmitDwarfDebug()) - return; +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 (TimePassesIsEnabled) - DebugTimer->startTimer(); + EmitLabel("abbrev_begin", 0); - // Standard sections final addresses. - Asm->SwitchToSection(TAI->getTextSection()); - EmitLabel("text_end", 0); - Asm->SwitchToSection(TAI->getDataSection()); - EmitLabel("data_end", 0); + // For each abbrevation. + for (unsigned i = 0, N = Abbreviations.size(); i < N; ++i) { + // Get abbreviation data + const DIEAbbrev *Abbrev = Abbreviations[i]; - // End text sections. - for (unsigned i = 1, N = SectionMap.size(); i <= N; ++i) { - Asm->SwitchToSection(SectionMap[i]); - EmitLabel("section_end", i); - } + // Emit the abbrevations code (base 1 index.) + Asm->EmitULEB128Bytes(Abbrev->getNumber()); + Asm->EOL("Abbreviation Code"); - // Emit common frame information. - EmitCommonDebugFrame(); + // Emit the abbreviations data. + Abbrev->Emit(Asm); - // Emit function debug frame information - for (std::vector::iterator I = DebugFrames.begin(), - E = DebugFrames.end(); I != E; ++I) - EmitFunctionDebugFrame(*I); + Asm->EOL(); + } - // Compute DIE offsets and sizes. - SizeAndOffsets(); + // Mark end of abbreviations. + Asm->EmitULEB128Bytes(0); Asm->EOL("EOM(3)"); - // Emit all the DIEs into a debug info section - EmitDebugInfo(); + EmitLabel("abbrev_end", 0); + Asm->EOL(); + } +} - // Corresponding abbreviations into a abbrev section. - EmitAbbreviations(); +/// 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 source line correspondence into a debug line section. - EmitDebugLines(); + // Mark end of matrix. + Asm->EmitInt8(0); Asm->EOL("DW_LNE_end_sequence"); + Asm->EmitULEB128Bytes(1); Asm->EOL(); + Asm->EmitInt8(1); Asm->EOL(); +} - // Emit info into a debug pubnames section. - EmitDebugPubNames(); +/// 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; - // Emit info into a debug str section. - EmitDebugStr(); + // 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 info into a debug loc section. - EmitDebugLoc(); + // Start the dwarf line section. + Asm->SwitchToDataSection(TAI->getDwarfLineSection()); - // Emit info into a debug aranges section. - EmitDebugARanges(); + // Construct the section header. + EmitDifference("line_end", 0, "line_begin", 0, true); + Asm->EOL("Length of Source Line Info"); + EmitLabel("line_begin", 0); - // Emit info into a debug ranges section. - EmitDebugRanges(); + Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("DWARF version number"); - // Emit info into a debug macinfo section. - EmitDebugMacInfo(); + EmitDifference("line_prolog_end", 0, "line_prolog_begin", 0, true); + Asm->EOL("Prolog Length"); + EmitLabel("line_prolog_begin", 0); - // Emit inline info. - EmitDebugInlineInfo(); + Asm->EmitInt8(1); Asm->EOL("Minimum Instruction Length"); - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); -} + Asm->EmitInt8(1); Asm->EOL("Default is_stmt_start flag"); -/// BeginFunction - Gather pre-function debug information. Assumes being -/// emitted immediately after the function entry point. -void DwarfDebug::BeginFunction(MachineFunction *MF) { - this->MF = MF; + Asm->EmitInt8(MinLineDelta); Asm->EOL("Line Base Value (Special Opcodes)"); - if (!ShouldEmitDwarfDebug()) return; + Asm->EmitInt8(MaxLineDelta); Asm->EOL("Line Range Value (Special Opcodes)"); - if (TimePassesIsEnabled) - DebugTimer->startTimer(); + Asm->EmitInt8(-MinLineDelta); Asm->EOL("Special Opcode Base"); - // Begin accumulating function debug information. - MMI->BeginFunction(MF); + // 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"); - // Assumes in correct section after the entry point. - EmitLabel("func_begin", ++SubprogramCount); + // Emit directories. + for (unsigned DI = 1, DE = getNumSourceDirectories()+1; DI != DE; ++DI) { + Asm->EmitString(getSourceDirectoryName(DI)); + Asm->EOL("Directory"); + } - // 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); + Asm->EmitInt8(0); Asm->EOL("End of directories"); + + // Emit files. + for (unsigned SI = 1, SE = getNumSourceIds()+1; SI != SE; ++SI) { + // Remember source id starts at 1. + std::pair 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 (TimePassesIsEnabled) - DebugTimer->stopTimer(); -} + Asm->EmitInt8(0); Asm->EOL("End of files"); -/// EndFunction - Gather and emit post-function debug information. -/// -void DwarfDebug::EndFunction(MachineFunction *MF) { - if (!ShouldEmitDwarfDebug()) return; + EmitLabel("line_prolog_end", 0); - if (TimePassesIsEnabled) - DebugTimer->startTimer(); + // A sequence for each text section. + unsigned SecSrcLinesSize = SectionSourceLines.size(); - // Define end label for subprogram. - EmitLabel("func_end", SubprogramCount); + for (unsigned j = 0; j < SecSrcLinesSize; ++j) { + // Isolate current sections line info. + const std::vector &LineInfos = SectionSourceLines[j]; - // 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 &SectionLineInfos = SectionSourceLines[ID-1]; - // Append the function info to section info. - SectionLineInfos.insert(SectionLineInfos.end(), - Lines.begin(), Lines.end()); - } + if (Asm->isVerbose()) { + const Section* S = SectionMap[j + 1]; + O << '\t' << TAI->getCommentString() << " Section" + << S->getName() << '\n'; + } else { + Asm->EOL(); + } - // Construct the DbgScope for abstract instances. - for (SmallVector::iterator - I = AbstractInstanceRootList.begin(), - E = AbstractInstanceRootList.end(); I != E; ++I) - ConstructAbstractDbgScope(*I); + // Dwarf assumes we start with first line of first source file. + unsigned Source = 1; + unsigned Line = 1; - // 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); + // 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 (!Asm->isVerbose()) + Asm->EOL(); + else { + std::pair SourceID = + getSourceDirectoryAndFileIds(LineInfo.getSourceID()); + O << '\t' << TAI->getCommentString() << ' ' + << getSourceDirectoryName(SourceID.first) << ' ' + << getSourceFileName(SourceID.second) + <<" :" << utostr_32(LineInfo.getLine()) << '\n'; + } - DebugFrames.push_back(FunctionDebugFrameInfo(SubprogramCount, - MMI->getFrameMoves())); + // 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"); - // Clear debug info - if (FunctionDbgScope) { - delete FunctionDbgScope; - DbgScopeMap.clear(); - DbgAbstractScopeMap.clear(); - DbgConcreteScopeMap.clear(); - InlinedVariableScopes.clear(); - FunctionDbgScope = NULL; - LexicalScopeStack.clear(); - AbstractInstanceRootList.clear(); - } + // 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"); + } - Lines.clear(); + // If change of line. + if (Line != LineInfo.getLine()) { + // Determine offset. + int Offset = LineInfo.getLine() - Line; + int Delta = Offset - MinLineDelta; - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); -} + // Update line. + Line = LineInfo.getLine(); -/// 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(); + // 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"); + } + } - CompileUnit *Unit = CompileUnitMap[V]; - assert(Unit && "Unable to find CompileUnit"); - unsigned ID = MMI->NextLabelID(); - Lines.push_back(SrcLineInfo(Line, Col, Unit->getID(), ID)); + EmitEndOfLineMatrix(j + 1); + } - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); + 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); - return ID; + 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(unsigned Line, unsigned Col, - DICompileUnit CU) { - if (TimePassesIsEnabled) - DebugTimer->startTimer(); +/// EmitCommonDebugFrame - Emit common frame info into a debug frame section. +/// +void DwarfDebug::EmitCommonDebugFrame() { + if (!TAI->doesDwarfRequireFrameSection()) + return; - 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)); + 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"); -/// 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(); + 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"); - unsigned SrcId = GetOrCreateSourceID(DirName, FileName); + std::vector Moves; + RI->getInitialFrameState(Moves); - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); + EmitFrameMoves(NULL, 0, Moves, false); - return SrcId; -} + Asm->EmitAlignment(2, 0, 0, false); + EmitLabel("debug_frame_common_end", 0); -/// RecordRegionStart - Indicate the start of a region. -unsigned DwarfDebug::RecordRegionStart(GlobalVariable *V) { - if (TimePassesIsEnabled) - DebugTimer->startTimer(); + Asm->EOL(); +} - DbgScope *Scope = getOrCreateScope(V); - unsigned ID = MMI->NextLabelID(); - if (!Scope->getStartLabelID()) Scope->setStartLabelID(ID); - LexicalScopeStack.push_back(Scope); +/// EmitFunctionDebugFrame - Emit per function frame info into a debug frame +/// section. +void +DwarfDebug::EmitFunctionDebugFrame(const FunctionDebugFrameInfo&DebugFrameInfo){ + if (!TAI->doesDwarfRequireFrameSection()) + return; - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); + // Start the dwarf frame section. + Asm->SwitchToDataSection(TAI->getDwarfFrameSection()); - return ID; -} + EmitDifference("debug_frame_end", DebugFrameInfo.Number, + "debug_frame_begin", DebugFrameInfo.Number, true); + Asm->EOL("Length of Frame Information Entry"); -/// RecordRegionEnd - Indicate the end of a region. -unsigned DwarfDebug::RecordRegionEnd(GlobalVariable *V) { - if (TimePassesIsEnabled) - DebugTimer->startTimer(); + EmitLabel("debug_frame_begin", DebugFrameInfo.Number); - DbgScope *Scope = getOrCreateScope(V); - unsigned ID = MMI->NextLabelID(); - Scope->setEndLabelID(ID); - if (LexicalScopeStack.size() != 0) - LexicalScopeStack.pop_back(); + EmitSectionOffset("debug_frame_common", "section_debug_frame", + 0, 0, true, false); + Asm->EOL("FDE CIE offset"); - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); + EmitReference("func_begin", DebugFrameInfo.Number); + Asm->EOL("FDE initial location"); + EmitDifference("func_end", DebugFrameInfo.Number, + "func_begin", DebugFrameInfo.Number); + Asm->EOL("FDE address range"); - return ID; -} + EmitFrameMoves("func_begin", DebugFrameInfo.Number, DebugFrameInfo.Moves, + false); -/// RecordVariable - Indicate the declaration of a local variable. -void DwarfDebug::RecordVariable(GlobalVariable *GV, unsigned FrameIndex, - const MachineInstr *MI) { - if (TimePassesIsEnabled) - DebugTimer->startTimer(); + Asm->EmitAlignment(2, 0, 0, false); + EmitLabel("debug_frame_end", DebugFrameInfo.Number); - DIDescriptor Desc(GV); - DbgScope *Scope = NULL; - bool InlinedFnVar = false; + Asm->EOL(); +} - if (Desc.getTag() == dwarf::DW_TAG_variable) { - // GV is a global variable. - DIGlobalVariable DG(GV); - Scope = getOrCreateScope(DG.getContext().getGV()); - } else { - DenseMap::iterator - SI = InlinedVariableScopes.find(MI); +void DwarfDebug::EmitDebugPubNamesPerCU(CompileUnit *Unit) { + EmitDifference("pubnames_end", Unit->getID(), + "pubnames_begin", Unit->getID(), true); + Asm->EOL("Length of Public Names Info"); - if (SI != InlinedVariableScopes.end()) { - // or GV is an inlined local variable. - Scope = SI->second; - } else { - DIVariable DV(GV); - GlobalVariable *V = DV.getContext().getGV(); + EmitLabel("pubnames_begin", Unit->getID()); - // FIXME: The code that checks for the inlined local variable is a hack! - DenseMap::iterator - AI = AbstractInstanceRootMap.find(V); + Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("DWARF Version"); - 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 >::iterator - IP = InlinedParamMap.find(V); + EmitSectionOffset("info_begin", "section_info", + Unit->getID(), 0, true, false); + Asm->EOL("Offset of Compilation Unit Info"); - if (IP != InlinedParamMap.end() && IP->second.count(GV) > 0) { - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); - return; - } + EmitDifference("info_end", Unit->getID(), "info_begin", Unit->getID(), + true); + Asm->EOL("Compilation Unit Length"); - // 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); - } - } + StringMap &Globals = Unit->getGlobals(); + for (StringMap::const_iterator + GI = Globals.begin(), GE = Globals.end(); GI != GE; ++GI) { + const char *Name = GI->getKeyData(); + DIE * Entity = GI->second; + + Asm->EmitInt32(Entity->getOffset()); Asm->EOL("DIE offset"); + Asm->EmitString(Name, strlen(Name)); Asm->EOL("External Name"); } - assert(Scope && "Unable to find the variable's scope"); - DbgVariable *DV = new DbgVariable(DIVariable(GV), FrameIndex, InlinedFnVar); - Scope->AddVariable(DV); + Asm->EmitInt32(0); Asm->EOL("End Mark"); + EmitLabel("pubnames_end", Unit->getID()); - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); + Asm->EOL(); } -//// RecordInlinedFnStart - Indicate the start of inlined subroutine. -unsigned DwarfDebug::RecordInlinedFnStart(DISubprogram &SP, DICompileUnit CU, - unsigned Line, unsigned Col) { - unsigned LabelID = MMI->NextLabelID(); +/// EmitDebugPubNames - Emit visible names into a debug pubnames section. +/// +void DwarfDebug::EmitDebugPubNames() { + // Start the dwarf pubnames section. + Asm->SwitchToDataSection(TAI->getDwarfPubNamesSection()); - if (!TAI->doesDwarfUsesInlineInfoSection()) - return LabelID; + if (MainCU) { + EmitDebugPubNamesPerCU(MainCU); + return; + } - if (TimePassesIsEnabled) - DebugTimer->startTimer(); + for (unsigned i = 0, e = CompileUnits.size(); i != e; ++i) + EmitDebugPubNamesPerCU(CompileUnits[i]); +} - GlobalVariable *GV = SP.getGV(); - DenseMap::iterator - II = AbstractInstanceRootMap.find(GV); +/// 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 (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)); + // 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); - // Get the compile unit context. - CompileUnit *Unit = &FindCompileUnit(SP.getCompileUnit()); - DIE *SPDie = Unit->getDieMapSlotFor(GV); - if (!SPDie) - SPDie = CreateSubprogramDIE(Unit, SP, false, true); + // Emit the string itself. + const std::string &String = StringPool[StringID]; + Asm->EmitString(String); 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); + Asm->EOL(); + } +} - // Keep track of the abstract scope for this function. - DbgAbstractScopeMap[GV] = Scope; +/// EmitDebugLoc - Emit visible names into a debug loc section. +/// +void DwarfDebug::EmitDebugLoc() { + // Start the dwarf loc section. + Asm->SwitchToDataSection(TAI->getDwarfLocSection()); + Asm->EOL(); +} - AbstractInstanceRootMap[GV] = Scope; - AbstractInstanceRootList.push_back(Scope); - } +/// EmitDebugARanges - Emit visible names into a debug aranges section. +/// +void DwarfDebug::EmitDebugARanges() { + // Start the dwarf aranges section. + Asm->SwitchToDataSection(TAI->getDwarfARangesSection()); - // 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); + // FIXME - Mock up +#if 0 + CompileUnit *Unit = GetBaseCompileUnit(); - 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); + // Don't include size of length + Asm->EmitInt32(0x1c); Asm->EOL("Length of Address Ranges Info"); - ConcreteScope->setDie(ScopeDie); - ConcreteScope->setStartLabelID(LabelID); - MMI->RecordUsedDbgLabel(LabelID); + Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->EOL("Dwarf Version"); - LexicalScopeStack.back()->AddConcreteInst(ConcreteScope); + EmitReference("info_begin", Unit->getID()); + Asm->EOL("Offset of Compilation Unit Info"); - // Keep track of the concrete scope that's inlined into this function. - DenseMap >::iterator - SI = DbgConcreteScopeMap.find(GV); + Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Size of Address"); - if (SI == DbgConcreteScopeMap.end()) - DbgConcreteScopeMap[GV].push_back(ConcreteScope); - else - SI->second.push_back(ConcreteScope); + Asm->EmitInt8(0); Asm->EOL("Size of Segment Descriptor"); - // Track the start label for this inlined function. - DenseMap >::iterator - I = InlineInfo.find(GV); + Asm->EmitInt16(0); Asm->EOL("Pad (1)"); + Asm->EmitInt16(0); Asm->EOL("Pad (2)"); - if (I == InlineInfo.end()) - InlineInfo[GV].push_back(LabelID); - else - I->second.push_back(LabelID); + // Range 1 + EmitReference("text_begin", 0); Asm->EOL("Address"); + EmitDifference("text_end", 0, "text_begin", 0, true); Asm->EOL("Length"); - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); + Asm->EmitInt32(0); Asm->EOL("EOM (1)"); + Asm->EmitInt32(0); Asm->EOL("EOM (2)"); +#endif - return LabelID; + Asm->EOL(); } -/// RecordInlinedFnEnd - Indicate the end of inlined subroutine. -unsigned DwarfDebug::RecordInlinedFnEnd(DISubprogram &SP) { +/// EmitDebugRanges - Emit visible names into a debug ranges section. +/// +void DwarfDebug::EmitDebugRanges() { + // Start the dwarf ranges section. + Asm->SwitchToDataSection(TAI->getDwarfRangesSection()); + Asm->EOL(); +} + +/// 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(); + } +} + +/// 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 >::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 &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); + for (DenseMap >::iterator + I = InlineInfo.begin(), E = InlineInfo.end(); I != E; ++I) { + GlobalVariable *GV = I->first; + SmallVector &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::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::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(); } -- 2.34.1