diff options
author | Jim Laskey <jlaskey@mac.com> | 2006-03-23 18:07:55 +0000 |
---|---|---|
committer | Jim Laskey <jlaskey@mac.com> | 2006-03-23 18:07:55 +0000 |
commit | b8509c5752d58280178f611e0c3f8b89ed076598 (patch) | |
tree | 157587ffc45f84b426d127c4efc48e2fd8c8baec /lib | |
parent | 43970fec322d9e0153ca513de41d80af1c79bdde (diff) | |
download | external_llvm-b8509c5752d58280178f611e0c3f8b89ed076598.zip external_llvm-b8509c5752d58280178f611e0c3f8b89ed076598.tar.gz external_llvm-b8509c5752d58280178f611e0c3f8b89ed076598.tar.bz2 |
Generate local variable and scope information and equivalent dwarf forms.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26989 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CodeGen/DwarfWriter.cpp | 324 | ||||
-rw-r--r-- | lib/CodeGen/MachineDebugInfo.cpp | 189 |
2 files changed, 434 insertions, 79 deletions
diff --git a/lib/CodeGen/DwarfWriter.cpp b/lib/CodeGen/DwarfWriter.cpp index b77721d..9896faa 100644 --- a/lib/CodeGen/DwarfWriter.cpp +++ b/lib/CodeGen/DwarfWriter.cpp @@ -18,9 +18,11 @@ #include "llvm/Type.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineDebugInfo.h" +#include "llvm/CodeGen/MachineLocation.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Mangler.h" +#include "llvm/Target/MRegisterInfo.h" #include "llvm/Target/TargetMachine.h" #include <iostream> @@ -47,7 +49,7 @@ class CompileUnit { private: CompileUnitDesc *Desc; // Compile unit debug descriptor. unsigned ID; // File ID for source. - DIE *Die; // Compile unit die. + DIE *Die; // Compile unit debug information entry. std::map<std::string, DIE *> Globals; // A map of globally visible named // entities for this unit. @@ -153,6 +155,12 @@ public: Data.push_back(DIEAbbrevData(Attribute, Form)); } + /// AddFirstAttribute - Adds a set of attribute information to the front + /// of the abbreviation. + void AddFirstAttribute(unsigned Attribute, unsigned Form) { + Data.insert(Data.begin(), DIEAbbrevData(Attribute, Form)); + } + /// Emit - Print the abbreviation using the specified Dwarf writer. /// void Emit(const DwarfWriter &DW) const; @@ -321,11 +329,11 @@ struct DIEntry : public DIEValue { static bool classof(const DIEntry *) { return true; } static bool classof(const DIEValue *E) { return E->Type == isEntry; } - /// EmitValue - Emit die entry offset. + /// EmitValue - Emit debug information entry offset. /// virtual void EmitValue(const DwarfWriter &DW, unsigned Form) const; - /// SizeOf - Determine size of die entry in bytes. + /// SizeOf - Determine size of debug information entry in bytes. /// virtual unsigned SizeOf(const DwarfWriter &DW, unsigned Form) const; }; @@ -424,6 +432,10 @@ public: /// SiblingOffset - Return the offset of the debug information entry's /// sibling. unsigned SiblingOffset() const { return Offset + Size; } + + /// AddSiblingOffset - Add a sibling offset field to the front of the DIE. + /// + void AddSiblingOffset(); /// AddUInt - Add an unsigned integer attribute data and value. /// @@ -591,9 +603,13 @@ unsigned DIEInteger::BestForm(bool IsSigned) { void DIEInteger::EmitValue(const DwarfWriter &DW, unsigned Form) const { switch (Form) { case DW_FORM_flag: // Fall thru + case DW_FORM_ref1: // Fall thru case DW_FORM_data1: DW.EmitInt8(Integer); break; + case DW_FORM_ref2: // Fall thru case DW_FORM_data2: DW.EmitInt16(Integer); break; + case DW_FORM_ref4: // Fall thru case DW_FORM_data4: DW.EmitInt32(Integer); break; + case DW_FORM_ref8: // Fall thru case DW_FORM_data8: DW.EmitInt64(Integer); break; case DW_FORM_udata: DW.EmitULEB128Bytes(Integer); break; case DW_FORM_sdata: DW.EmitSLEB128Bytes(Integer); break; @@ -606,9 +622,13 @@ void DIEInteger::EmitValue(const DwarfWriter &DW, unsigned Form) const { unsigned DIEInteger::SizeOf(const DwarfWriter &DW, unsigned Form) const { switch (Form) { case DW_FORM_flag: // Fall thru + case DW_FORM_ref1: // Fall thru case DW_FORM_data1: return sizeof(int8_t); + case DW_FORM_ref2: // Fall thru case DW_FORM_data2: return sizeof(int16_t); + case DW_FORM_ref4: // Fall thru case DW_FORM_data4: return sizeof(int32_t); + case DW_FORM_ref8: // Fall thru case DW_FORM_data8: return sizeof(int64_t); case DW_FORM_udata: return DW.SizeULEB128(Integer); case DW_FORM_sdata: return DW.SizeSLEB128(Integer); @@ -674,13 +694,13 @@ unsigned DIEDelta::SizeOf(const DwarfWriter &DW, unsigned Form) const { } //===----------------------------------------------------------------------===// -/// EmitValue - Emit die entry offset. +/// EmitValue - Emit debug information entry offset. /// void DIEntry::EmitValue(const DwarfWriter &DW, unsigned Form) const { DW.EmitInt32(Entry->getOffset()); } -/// SizeOf - Determine size of die value in bytes. +/// SizeOf - Determine size of debug information entry value in bytes. /// unsigned DIEntry::SizeOf(const DwarfWriter &DW, unsigned Form) const { return sizeof(int32_t); @@ -818,6 +838,14 @@ DIE::~DIE() { } } +/// AddSiblingOffset - Add a sibling offset field to the front of the DIE. +/// +void DIE::AddSiblingOffset() { + DIEInteger *DI = new DIEInteger(0); + Values.insert(Values.begin(), DI); + Abbrev->AddFirstAttribute(DW_AT_sibling, DW_FORM_ref4); +} + /// AddUInt - Add an unsigned integer attribute data and value. /// void DIE::AddUInt(unsigned Attribute, unsigned Form, uint64_t Integer) { @@ -924,6 +952,12 @@ void DwarfWriter::EOL(const std::string &Comment) const { O << "\n"; } +/// EmitAlign - Print a align directive. +/// +void DwarfWriter::EmitAlign(unsigned Alignment) const { + O << Asm->AlignDirective << Alignment << "\n"; +} + /// EmitULEB128Bytes - Emit an assembler byte data directive to compose an /// unsigned leb128 value. void DwarfWriter::EmitULEB128Bytes(unsigned Value) const { @@ -1159,6 +1193,18 @@ DWLabel DwarfWriter::NewString(const std::string &String) { return DWLabel("string", StringID); } +/// AddSourceLine - Add location information to specified debug information +/// entry. +void DwarfWriter::AddSourceLine(DIE *Die, CompileUnitDesc *File, unsigned Line) { + if (File && Line) { + CompileUnit *FileUnit = FindCompileUnit(File); + unsigned FileID = FileUnit->getID(); + Die->AddUInt(DW_AT_decl_file, 0, FileID); + Die->AddUInt(DW_AT_decl_line, 0, Line); + } +} + + /// NewBasicType - Creates a new basic type if necessary, then adds to the /// owner. /// FIXME - Should never be needed. @@ -1320,24 +1366,18 @@ DIE *DwarfWriter::NewType(DIE *Context, TypeDesc *TyDesc) { // Extract the basic information. const std::string &Name = MemberDesc->getName(); - unsigned Line = MemberDesc->getLine(); TypeDesc *MemTy = MemberDesc->getFromType(); uint64_t Size = MemberDesc->getSize(); uint64_t Align = MemberDesc->getAlign(); uint64_t Offset = MemberDesc->getOffset(); - // Construct member die. + // Construct member debug information entry. DIE *Member = new DIE(DW_TAG_member); - // Add details. + // Add name if not "". if (!Name.empty()) Member->AddString(DW_AT_name, DW_FORM_string, Name); - if (CompileUnitDesc *File = MemberDesc->getFile()) { - CompileUnit *FileUnit = FindCompileUnit(File); - unsigned FileID = FileUnit->getID(); - int Line = MemberDesc->getLine(); - Member->AddUInt(DW_AT_decl_file, 0, FileID); - Member->AddUInt(DW_AT_decl_line, 0, Line); - } + // Add location if available. + AddSourceLine(Member, MemberDesc->getFile(), MemberDesc->getLine()); // Most of the time the field info is the same as the members. uint64_t FieldSize = Size; @@ -1406,14 +1446,8 @@ DIE *DwarfWriter::NewType(DIE *Context, TypeDesc *TyDesc) { if (Size) Ty->AddUInt(DW_AT_byte_size, 0, Size); // Add name if not anonymous or intermediate type. if (!Name.empty()) Ty->AddString(DW_AT_name, DW_FORM_string, Name); - // Add source line info if present. - if (CompileUnitDesc *File = TyDesc->getFile()) { - CompileUnit *FileUnit = FindCompileUnit(File); - unsigned FileID = FileUnit->getID(); - int Line = TyDesc->getLine(); - Ty->AddUInt(DW_AT_decl_file, 0, FileID); - Ty->AddUInt(DW_AT_decl_line, 0, Line); - } + // Add source line info if available. + AddSourceLine(Ty, TyDesc->getFile(), TyDesc->getLine()); // Add to context owner. Context->AddChild(Ty); @@ -1421,7 +1455,7 @@ DIE *DwarfWriter::NewType(DIE *Context, TypeDesc *TyDesc) { return Slot; } -/// NewCompileUnit - Create new compile unit and it's die. +/// NewCompileUnit - Create new compile unit and it's debug information entry. /// CompileUnit *DwarfWriter::NewCompileUnit(CompileUnitDesc *UnitDesc, unsigned ID) { @@ -1435,7 +1469,7 @@ CompileUnit *DwarfWriter::NewCompileUnit(CompileUnitDesc *UnitDesc, Die->AddString(DW_AT_name, DW_FORM_string, UnitDesc->getFileName()); Die->AddString(DW_AT_comp_dir, DW_FORM_string, UnitDesc->getDirectory()); - // Add die to descriptor map. + // Add debug information entry to descriptor map. DescToDieMap[UnitDesc] = Die; // Construct compile unit. @@ -1472,20 +1506,20 @@ DIE *DwarfWriter::NewGlobalVariable(GlobalVariableDesc *GVD) { // Gather the details (simplify add attribute code.) const std::string &Name = GVD->getName(); - unsigned FileID = Unit->getID(); - unsigned Line = GVD->getLine(); // Get the global's type. - DIE *Type = NewType(Unit->getDie(), GVD->getTypeDesc()); + DIE *Type = NewType(Unit->getDie(), GVD->getType()); // Create the globale variable DIE. DIE *VariableDie = new DIE(DW_TAG_variable); VariableDie->AddString (DW_AT_name, DW_FORM_string, Name); - VariableDie->AddUInt (DW_AT_decl_file, 0, FileID); - VariableDie->AddUInt (DW_AT_decl_line, 0, Line); VariableDie->AddDIEntry (DW_AT_type, DW_FORM_ref4, Type); VariableDie->AddUInt (DW_AT_external, DW_FORM_flag, 1); + + // Add source line info if available. + AddSourceLine(VariableDie, UnitDesc, GVD->getLine()); + // Add address. DIEBlock *Block = new DIEBlock(); Block->AddUInt(DW_FORM_data1, DW_OP_addr); Block->AddObjectLabel(DW_FORM_udata, MangledName); @@ -1518,20 +1552,17 @@ DIE *DwarfWriter::NewSubprogram(SubprogramDesc *SPD) { // Gather the details (simplify add attribute code.) const std::string &Name = SPD->getName(); - CompileUnitDesc *FileDesc = static_cast<CompileUnitDesc *>(SPD->getFile()); - CompileUnit *File = FindCompileUnit(FileDesc); - unsigned FileID = File->getID(); DIE *Type = NewBasicType(Unit->getDie(), Type::IntTy); - unsigned Line = SPD->getLine(); unsigned IsExternal = SPD->isStatic() ? 0 : 1; DIE *SubprogramDie = new DIE(DW_TAG_subprogram); SubprogramDie->AddString (DW_AT_name, DW_FORM_string, Name); - SubprogramDie->AddUInt (DW_AT_decl_file, 0, FileID); - SubprogramDie->AddUInt (DW_AT_decl_line, 0, Line); SubprogramDie->AddDIEntry (DW_AT_type, DW_FORM_ref4, Type); SubprogramDie->AddUInt (DW_AT_external, DW_FORM_flag, IsExternal); + // Add source line info if available. + AddSourceLine(SubprogramDie, UnitDesc, SPD->getLine()); + // Add to map. Slot = SubprogramDie; @@ -1544,6 +1575,119 @@ DIE *DwarfWriter::NewSubprogram(SubprogramDesc *SPD) { return SubprogramDie; } + +/// NewScopeVariable - Create a new scope variable. +/// +DIE *DwarfWriter::NewScopeVariable(DebugVariable *DV, CompileUnit *Unit) { + // Get the descriptor. + VariableDesc *VD = DV->getDesc(); + + // Translate tag to proper Dwarf tag. The result variable is dropped for now. + unsigned Tag; + switch (VD->getTag()) { + case DW_TAG_return_variable: return NULL; + case DW_TAG_arg_variable: Tag = DW_TAG_formal_parameter; break; + case DW_TAG_auto_variable: // fall thru + default: Tag = DW_TAG_variable; break; + } + + // Define variable debug information entry. + DIE *VariableDie = new DIE(Tag); + VariableDie->AddString(DW_AT_name, DW_FORM_string, VD->getName()); + + // Add source line info if available. + AddSourceLine(VariableDie, VD->getFile(), VD->getLine()); + + // Add variable type. + DIE *Type = NewType(Unit->getDie(), VD->getType()); + VariableDie->AddDIEntry(DW_AT_type, DW_FORM_ref4, Type); + + // Get variable address. + MachineLocation Location; + Asm->TM.getRegisterInfo()->getLocation(*MF, DV->getFrameIndex(), Location); + + // Add computation for variable. + DIEBlock *Block = new DIEBlock(); + if (Location.isRegister()) { + // FIXME - This is a real hack. + Block->AddUInt(DW_FORM_data1, DW_OP_reg0 + Location.getRegister()); + } else { + // FIXME - This is a real hack. + Block->AddUInt(DW_FORM_data1, DW_OP_breg0 + Location.getRegister()); + Block->AddUInt(DW_FORM_sdata, Location.getOffset()); + } + Block->ComputeSize(*this); + VariableDie->AddBlock(DW_AT_location, 0, Block); + + return VariableDie; +} + +/// ConstructScope - Construct the components of a scope. +/// +void DwarfWriter::ConstructScope(DebugScope *ParentScope, + DIE *ParentDie, CompileUnit *Unit) { + // Add variables to scope. + std::vector<DebugVariable *> &Variables = ParentScope->getVariables(); + for (unsigned i = 0, N = Variables.size(); i < N; ++i) { + DIE *VariableDie = NewScopeVariable(Variables[i], Unit); + if (VariableDie) ParentDie->AddChild(VariableDie); + } + + // Add nested scopes. + std::vector<DebugScope *> &Scopes = ParentScope->getScopes(); + for (unsigned j = 0, M = Scopes.size(); j < M; ++j) { + // Define the Scope debug information entry. + DebugScope *Scope = Scopes[j]; + // FIXME - Ignore inlined functions for the time being. + if (Scope->getParent()) continue; + + DIE *ScopeDie = new DIE(DW_TAG_lexical_block); + + // Add the scope bounds. + if (unsigned StartID = Scope->getStartLabelID()) { + ScopeDie->AddLabel(DW_AT_low_pc, DW_FORM_addr, + DWLabel("loc", StartID)); + } else { + ScopeDie->AddLabel(DW_AT_low_pc, DW_FORM_addr, + DWLabel("func_begin", SubprogramCount)); + } + if (unsigned EndID = Scope->getEndLabelID()) { + ScopeDie->AddLabel(DW_AT_high_pc, DW_FORM_addr, + DWLabel("loc", EndID)); + } else { + ScopeDie->AddLabel(DW_AT_high_pc, DW_FORM_addr, + DWLabel("func_end", SubprogramCount)); + } + + // Add the scope contents. + ConstructScope(Scope, ScopeDie, Unit); + ParentDie->AddChild(ScopeDie); + } +} + +/// ConstructRootScope - Construct the scope for the subprogram. +/// +void DwarfWriter::ConstructRootScope(DebugScope *RootScope) { + // Exit if there is no root scope. + if (!RootScope) return; + + // Get the subprogram debug information entry. + SubprogramDesc *SPD = cast<SubprogramDesc>(RootScope->getDesc()); + DIE *SPDie = DescToDieMap[SPD]; + assert(SPDie && "Missing subprogram descriptor"); + + // Add the function bounds. + SPDie->AddLabel(DW_AT_low_pc, DW_FORM_addr, + DWLabel("func_begin", SubprogramCount)); + SPDie->AddLabel(DW_AT_high_pc, DW_FORM_addr, + DWLabel("func_end", SubprogramCount)); + + CompileUnitDesc *UnitDesc = static_cast<CompileUnitDesc *>(SPD->getContext()); + CompileUnit *Unit = FindCompileUnit(UnitDesc); + + ConstructScope(RootScope, SPDie, Unit); +} + /// EmitInitial - Emit initial Dwarf declarations. This is necessary for cc /// tools to recognize the object file contains Dwarf information. /// @@ -1625,8 +1769,6 @@ void DwarfWriter::EmitDIE(DIE *Die) const { const std::vector<DIE *> &Children = Die->getChildren(); for (unsigned j = 0, M = Children.size(); j < M; ++j) { - // FIXME - handle sibling offsets. - // FIXME - handle all DIE types. EmitDIE(Children[j]); } @@ -1636,7 +1778,13 @@ void DwarfWriter::EmitDIE(DIE *Die) const { /// SizeAndOffsetDie - Compute the size and offset of a DIE. /// -unsigned DwarfWriter::SizeAndOffsetDie(DIE *Die, unsigned Offset) { +unsigned DwarfWriter::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(); + // Record the abbreviation. Die->Complete(*this); @@ -1660,13 +1808,12 @@ unsigned DwarfWriter::SizeAndOffsetDie(DIE *Die, unsigned Offset) { } // Emit the DIE children if any. - if (Abbrev.getChildrenFlag() == DW_CHILDREN_yes) { - const std::vector<DIE *> &Children = Die->getChildren(); + if (!Children.empty()) { + assert(Abbrev.getChildrenFlag() == DW_CHILDREN_yes && + "Children flag not set"); for (unsigned j = 0, M = Children.size(); j < M; ++j) { - // FIXME - handle sibling offsets. - // FIXME - handle all DIE types. - Offset = SizeAndOffsetDie(Children[j], Offset); + Offset = SizeAndOffsetDie(Children[j], Offset, (j + 1) == M); } // End of children marker. @@ -1690,8 +1837,7 @@ void DwarfWriter::SizeAndOffsets() { sizeof(int16_t) + // DWARF version number sizeof(int32_t) + // Offset Into Abbrev. Section sizeof(int8_t); // Pointer Size (in bytes) - - SizeAndOffsetDie(Unit->getDie(), Offset); + SizeAndOffsetDie(Unit->getDie(), Offset, (i + 1) == N); } } } @@ -1853,7 +1999,7 @@ void DwarfWriter::EmitDebugLines() const { EmitInt8(0); EOL("Extended Op"); EmitInt8(4 + 1); EOL("Op size"); EmitInt8(DW_LNE_set_address); EOL("DW_LNE_set_address"); - EmitReference("loc", i + 1); EOL("Location label"); + EmitReference("loc", LineInfo->getLabelID()); EOL("Location label"); // If change of source, then switch to the new source. if (Source != LineInfo->getSourceID()) { @@ -1906,7 +2052,30 @@ void DwarfWriter::EmitDebugLines() const { /// EmitDebugFrame - Emit visible names into a debug frame section. /// void DwarfWriter::EmitDebugFrame() { - // FIXME - Should be per frame + // Start the dwarf pubnames section. + Asm->SwitchSection(DwarfFrameSection, 0); + + EmitDifference("frame_common_end", 0, + "frame_common_begin", 0); + EOL("Length of Common Information Entry"); + + EmitLabel("frame_common_begin", 0); + EmitInt32(DW_CIE_ID); EOL("CIE Identifier Tag"); + EmitInt8(DW_CIE_VERSION); EOL("CIE Version"); + EmitString(""); EOL("CIE Augmentation"); + EmitULEB128Bytes(1); EOL("CIE Code Alignment Factor"); + // FIXME - needs to change based on stack direction. + EmitSLEB128Bytes(-sizeof(int32_t)); EOL("CIE Data Alignment Factor"); + // FIXME - hard coded for PPC (LR). + EmitInt8(0x41); EOL("CIE RA Column Hardcoded (PPC LR)"); + // FIXME - hard coded for PPC 0(SP). + EmitULEB128Bytes(DW_CFA_def_cfa); EOL("DW_CFA_def_cfa"); + EmitULEB128Bytes(1); EOL("PPC Register SP"); + EmitULEB128Bytes(0); EOL("PPC offset 0 as in 0(SP)"); + EmitAlign(2); + EmitLabel("frame_common_end", 0); + + O << "\n"; } /// EmitDebugPubNames - Emit visible names into a debug pubnames section. @@ -1962,7 +2131,7 @@ void DwarfWriter::EmitDebugStr() { // Start the dwarf str section. Asm->SwitchSection(DwarfStrSection, 0); - // For each of strings in teh string pool. + // 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. @@ -2057,9 +2226,9 @@ void DwarfWriter::ConstructCompileUnitDIEs() { /// ConstructGlobalDIEs - Create DIEs for each of the externally visible global /// variables. -void DwarfWriter::ConstructGlobalDIEs(Module &M) { +void DwarfWriter::ConstructGlobalDIEs() { std::vector<GlobalVariableDesc *> GlobalVariables = - DebugInfo->getAnchoredDescriptors<GlobalVariableDesc>(M); + DebugInfo->getAnchoredDescriptors<GlobalVariableDesc>(*M); for (unsigned i = 0, N = GlobalVariables.size(); i < N; ++i) { GlobalVariableDesc *GVD = GlobalVariables[i]; @@ -2069,9 +2238,9 @@ void DwarfWriter::ConstructGlobalDIEs(Module &M) { /// ConstructSubprogramDIEs - Create DIEs for each of the externally visible /// subprograms. -void DwarfWriter::ConstructSubprogramDIEs(Module &M) { +void DwarfWriter::ConstructSubprogramDIEs() { std::vector<SubprogramDesc *> Subprograms = - DebugInfo->getAnchoredDescriptors<SubprogramDesc>(M); + DebugInfo->getAnchoredDescriptors<SubprogramDesc>(*M); for (unsigned i = 0, N = Subprograms.size(); i < N; ++i) { SubprogramDesc *SPD = Subprograms[i]; @@ -2088,6 +2257,16 @@ bool DwarfWriter::ShouldEmitDwarf() { // Make sure initial declarations are made. if (!didInitial) { EmitInitial(); + + // Create all the compile unit DIEs. + ConstructCompileUnitDIEs(); + + // Create DIEs for each of the externally visible global variables. + ConstructGlobalDIEs(); + + // Create DIEs for each of the externally visible subprograms. + ConstructSubprogramDIEs(); + didInitial = true; } @@ -2102,8 +2281,11 @@ bool DwarfWriter::ShouldEmitDwarf() { DwarfWriter::DwarfWriter(std::ostream &OS, AsmPrinter *A) : O(OS) , Asm(A) +, M(NULL) +, MF(NULL) , DebugInfo(NULL) , didInitial(false) +, SubprogramCount(0) , CompileUnits() , Abbreviations() , StringPool() @@ -2137,14 +2319,16 @@ DwarfWriter::~DwarfWriter() { /// BeginModule - Emit all Dwarf sections that should come prior to the content. /// -void DwarfWriter::BeginModule(Module &M) { +void DwarfWriter::BeginModule(Module *M) { + this->M = M; + if (!ShouldEmitDwarf()) return; EOL("Dwarf Begin Module"); } /// EndModule - Emit all Dwarf sections that should come after the content. /// -void DwarfWriter::EndModule(Module &M) { +void DwarfWriter::EndModule() { if (!ShouldEmitDwarf()) return; EOL("Dwarf End Module"); @@ -2154,15 +2338,6 @@ void DwarfWriter::EndModule(Module &M) { Asm->SwitchSection(DataSection, 0); EmitLabel("data_end", 0); - // Create all the compile unit DIEs. - ConstructCompileUnitDIEs(); - - // Create DIEs for each of the externally visible global variables. - ConstructGlobalDIEs(M); - - // Create DIEs for each of the externally visible subprograms. - ConstructSubprogramDIEs(M); - // Compute DIE offsets and sizes. SizeAndOffsets(); @@ -2176,7 +2351,7 @@ void DwarfWriter::EndModule(Module &M) { EmitDebugLines(); // Emit info into a debug frame section. - // EmitDebugFrame(); + EmitDebugFrame(); // Emit info into a debug pubnames section. EmitDebugPubNames(); @@ -2199,14 +2374,29 @@ void DwarfWriter::EndModule(Module &M) { /// BeginFunction - Gather pre-function debug information. /// -void DwarfWriter::BeginFunction(MachineFunction &MF) { +void DwarfWriter::BeginFunction(MachineFunction *MF) { + this->MF = MF; + if (!ShouldEmitDwarf()) return; EOL("Dwarf Begin Function"); + + // Define begin label for subprogram. + Asm->SwitchSection(TextSection, 0); + EmitLabel("func_begin", ++SubprogramCount); } + /// EndFunction - Gather and emit post-function debug information. /// -void DwarfWriter::EndFunction(MachineFunction &MF) { +void DwarfWriter::EndFunction() { if (!ShouldEmitDwarf()) return; EOL("Dwarf End Function"); + + // Define end label for subprogram. + Asm->SwitchSection(TextSection, 0); + EmitLabel("func_end", SubprogramCount); + + // Construct scopes for subprogram. + ConstructRootScope(DebugInfo->getRootScope()); + DebugInfo->ClearScopes(); } diff --git a/lib/CodeGen/MachineDebugInfo.cpp b/lib/CodeGen/MachineDebugInfo.cpp index e867c88..d2b7f41 100644 --- a/lib/CodeGen/MachineDebugInfo.cpp +++ b/lib/CodeGen/MachineDebugInfo.cpp @@ -477,7 +477,6 @@ DebugInfoDesc *DebugInfoDesc::DescFactory(unsigned Tag) { case DW_TAG_const_type: case DW_TAG_volatile_type: case DW_TAG_restrict_type: - case DW_TAG_formal_parameter: case DW_TAG_member: return new DerivedTypeDesc(Tag); case DW_TAG_array_type: case DW_TAG_structure_type: @@ -485,6 +484,9 @@ DebugInfoDesc *DebugInfoDesc::DescFactory(unsigned Tag) { case DW_TAG_enumeration_type: return new CompositeTypeDesc(Tag); case DW_TAG_subrange_type: return new SubrangeDesc(); case DW_TAG_enumerator: return new EnumeratorDesc(); + case DW_TAG_return_variable: + case DW_TAG_arg_variable: + case DW_TAG_auto_variable: return new VariableDesc(Tag); default: break; } return NULL; @@ -654,6 +656,7 @@ TypeDesc::TypeDesc(unsigned T) , Context(NULL) , Name("") , File(NULL) +, Line(0) , Size(0) , Align(0) , Offset(0) @@ -759,7 +762,6 @@ bool DerivedTypeDesc::classof(const DebugInfoDesc *D) { case DW_TAG_const_type: case DW_TAG_volatile_type: case DW_TAG_restrict_type: - case DW_TAG_formal_parameter: case DW_TAG_member: return true; default: break; @@ -943,6 +945,66 @@ void EnumeratorDesc::dump() { //===----------------------------------------------------------------------===// +VariableDesc::VariableDesc(unsigned T) +: DebugInfoDesc(T) +, Context(NULL) +, Name("") +, File(NULL) +, Line(0) +, TyDesc(0) +{} + +// Implement isa/cast/dyncast. +bool VariableDesc::classof(const DebugInfoDesc *D) { + unsigned T = D->getTag(); + switch (T) { + case DW_TAG_auto_variable: + case DW_TAG_arg_variable: + case DW_TAG_return_variable: + return true; + default: break; + } + return false; +} + +/// ApplyToFields - Target the visitor to the fields of the VariableDesc. +/// +void VariableDesc::ApplyToFields(DIVisitor *Visitor) { + DebugInfoDesc::ApplyToFields(Visitor); + + Visitor->Apply(Context); + Visitor->Apply(Name); + Visitor->Apply((DebugInfoDesc *&)File); + Visitor->Apply(Line); + Visitor->Apply((DebugInfoDesc *&)TyDesc); +} + +/// getDescString - Return a string used to compose global names and labels. +/// +const char *VariableDesc::getDescString() const { + return "llvm.dbg.variable"; +} + +/// getTypeString - Return a string used to label this descriptor's type. +/// +const char *VariableDesc::getTypeString() const { + return "llvm.dbg.variable.type"; +} + +#ifndef NDEBUG +void VariableDesc::dump() { + std::cerr << getDescString() << " " + << "Tag(" << getTag() << "), " + << "Context(" << Context << "), " + << "Name(\"" << Name << "\"), " + << "File(" << File << "), " + << "Line(" << Line << "), " + << "TyDesc(" << TyDesc << ")\n"; +} +#endif + +//===----------------------------------------------------------------------===// + GlobalDesc::GlobalDesc(unsigned T) : AnchoredDesc(T) , Context(0) @@ -1015,7 +1077,7 @@ void GlobalVariableDesc::dump() { << "Name(\"" << getName() << "\"), " << "File(" << getFile() << ")," << "Line(" << getLine() << ")," - << "Type(\"" << getTypeDesc() << "\"), " + << "Type(\"" << getType() << "\"), " << "IsStatic(" << (isStatic() ? "true" : "false") << "), " << "IsDefinition(" << (isDefinition() ? "true" : "false") << "), " << "Global(" << Global << ")\n"; @@ -1037,8 +1099,6 @@ bool SubprogramDesc::classof(const DebugInfoDesc *D) { /// SubprogramDesc. void SubprogramDesc::ApplyToFields(DIVisitor *Visitor) { GlobalDesc::ApplyToFields(Visitor); - - Visitor->Apply(Elements); } /// getDescString - Return a string used to compose global names and labels. @@ -1068,7 +1128,7 @@ void SubprogramDesc::dump() { << "Name(\"" << getName() << "\"), " << "File(" << getFile() << ")," << "Line(" << getLine() << ")," - << "Type(\"" << getTypeDesc() << "\"), " + << "Type(\"" << getType() << "\"), " << "IsStatic(" << (isStatic() ? "true" : "false") << "), " << "IsDefinition(" << (isDefinition() ? "true" : "false") << ")\n"; } @@ -1078,6 +1138,7 @@ void SubprogramDesc::dump() { BlockDesc::BlockDesc() : DebugInfoDesc(DW_TAG_lexical_block) +, Context(NULL) {} // Implement isa/cast/dyncast. @@ -1090,7 +1151,7 @@ bool BlockDesc::classof(const DebugInfoDesc *D) { void BlockDesc::ApplyToFields(DIVisitor *Visitor) { DebugInfoDesc::ApplyToFields(Visitor); - Visitor->Apply(Elements); + Visitor->Apply(Context); } /// getDescString - Return a string used to compose global names and labels. @@ -1108,7 +1169,8 @@ const char *BlockDesc::getTypeString() const { #ifndef NDEBUG void BlockDesc::dump() { std::cerr << getDescString() << " " - << "Tag(" << getTag() << ")\n"; + << "Tag(" << getTag() << ")," + << "Context(" << Context << ")\n"; } #endif @@ -1284,14 +1346,17 @@ bool DIVerifier::Verify(GlobalVariable *GV) { // Get the Tag unsigned Tag = DebugInfoDesc::TagFromGlobal(GV); - if (Tag == DW_TAG_invalid) return false; + + // Check for user defined descriptors. + if (Tag == DW_TAG_invalid) return true; // If a compile unit we need the debug version. if (Tag == DW_TAG_compile_unit) { DebugVersion = CompileUnitDesc::DebugVersionFromGlobal(GV); - if (DebugVersion == DW_TAG_invalid) return false; + // FIXME - In the short term, changes are too drastic to continue. + if (DebugVersion != LLVMDebugVersion) return false; } - + // Construct an empty DebugInfoDesc. DebugInfoDesc *DD = DebugInfoDesc::DescFactory(Tag); @@ -1332,13 +1397,23 @@ bool DIVerifier::Verify(GlobalVariable *GV) { //===----------------------------------------------------------------------===// +DebugScope::~DebugScope() { + for (unsigned i = 0, N = Scopes.size(); i < N; ++i) delete Scopes[i]; + for (unsigned j = 0, M = Variables.size(); j < M; ++j) delete Variables[j]; +} + +//===----------------------------------------------------------------------===// MachineDebugInfo::MachineDebugInfo() : DR() +, VR() , CompileUnits() , Directories() , SourceFiles() , Lines() +, LabelID(0) +, ScopeMap() +, RootScope(NULL) { } @@ -1368,7 +1443,6 @@ DebugInfoDesc *MachineDebugInfo::getDescFor(Value *V) { /// Verify - Verify that a Value is debug information descriptor. /// bool MachineDebugInfo::Verify(Value *V) { - DIVerifier VR; return VR.Verify(V); } @@ -1401,3 +1475,94 @@ MachineDebugInfo::getGlobalVariablesUsing(Module &M, const std::string &RootName) { return ::getGlobalVariablesUsing(M, RootName); } + +/// RecordLabel - Records location information and associates it with a +/// debug label. Returns a unique label ID used to generate a label and +/// provide correspondence to the source line list. +unsigned MachineDebugInfo::RecordLabel(unsigned Line, unsigned Column, + unsigned Source) { + unsigned ID = NextLabelID(); + Lines.push_back(new SourceLineInfo(Line, Column, Source, ID)); + return ID; +} + +/// RecordSource - Register a source file with debug info. Returns an source +/// ID. +unsigned MachineDebugInfo::RecordSource(const std::string &Directory, + const std::string &Source) { + unsigned DirectoryID = Directories.insert(Directory); + return SourceFiles.insert(SourceFileInfo(DirectoryID, Source)); +} +unsigned MachineDebugInfo::RecordSource(const CompileUnitDesc *CompileUnit) { + return RecordSource(CompileUnit->getDirectory(), + CompileUnit->getFileName()); +} + +/// RecordRegionStart - Indicate the start of a region. +/// +unsigned MachineDebugInfo::RecordRegionStart(Value *V) { + // FIXME - need to be able to handle split scopes because of bb cloning. + DebugInfoDesc *ScopeDesc = DR.Deserialize(V); + DebugScope *Scope = getOrCreateScope(ScopeDesc); + unsigned ID = NextLabelID(); + if (!Scope->getStartLabelID()) Scope->setStartLabelID(ID); + return ID; +} + +/// RecordRegionEnd - Indicate the end of a region. +/// +unsigned MachineDebugInfo::RecordRegionEnd(Value *V) { + // FIXME - need to be able to handle split scopes because of bb cloning. + DebugInfoDesc *ScopeDesc = DR.Deserialize(V); + DebugScope *Scope = getOrCreateScope(ScopeDesc); + unsigned ID = NextLabelID(); + Scope->setEndLabelID(ID); + return ID; +} + +/// RecordVariable - Indicate the declaration of a local variable. +/// +void MachineDebugInfo::RecordVariable(Value *V, unsigned FrameIndex) { + VariableDesc *VD = cast<VariableDesc>(DR.Deserialize(V)); + DebugScope *Scope = getOrCreateScope(VD->getContext()); + DebugVariable *DV = new DebugVariable(VD, FrameIndex); + Scope->AddVariable(DV); +} + +/// getOrCreateScope - Returns the scope associated with the given descriptor. +/// +DebugScope *MachineDebugInfo::getOrCreateScope(DebugInfoDesc *ScopeDesc) { + DebugScope *&Slot = ScopeMap[ScopeDesc]; + if (!Slot) { + // FIXME - breaks down when the context is an inlined function. + DebugInfoDesc *ParentDesc = NULL; + if (BlockDesc *Block = dyn_cast<BlockDesc>(ScopeDesc)) { + ParentDesc = Block->getContext(); + } + DebugScope *Parent = ParentDesc ? getOrCreateScope(ParentDesc) : NULL; + Slot = new DebugScope(Parent, ScopeDesc); + if (Parent) { + Parent->AddScope(Slot); + } else if (RootScope) { + // FIXME - Add inlined function scopes to the root so we can delete + // them later. Long term, handle inlined functions properly. + RootScope->AddScope(Slot); + } else { + // First function is top level function. + RootScope = Slot; + } + } + return Slot; +} + +/// ClearScopes - Delete the scope and variable info after a function is +/// completed. +void MachineDebugInfo::ClearScopes() { + if (RootScope) { + delete RootScope; + ScopeMap.clear(); + RootScope = NULL; + } +} + + |