From b8509c5752d58280178f611e0c3f8b89ed076598 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Thu, 23 Mar 2006 18:07:55 +0000 Subject: [PATCH] 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 --- include/llvm/CodeGen/DwarfWriter.h | 49 +++- include/llvm/CodeGen/MachineDebugInfo.h | 200 +++++++++++++-- include/llvm/Support/Dwarf.h | 12 +- lib/CodeGen/DwarfWriter.cpp | 324 +++++++++++++++++++----- lib/CodeGen/MachineDebugInfo.cpp | 189 +++++++++++++- 5 files changed, 660 insertions(+), 114 deletions(-) diff --git a/include/llvm/CodeGen/DwarfWriter.h b/include/llvm/CodeGen/DwarfWriter.h index 6c4aac758c4..7733c48c2da 100644 --- a/include/llvm/CodeGen/DwarfWriter.h +++ b/include/llvm/CodeGen/DwarfWriter.h @@ -35,6 +35,8 @@ class AsmPrinter; class CompileUnit; class CompileUnitDesc; class DebugInfoDesc; +class DebugVariable; +class DebugScope; class DIE; class DIEAbbrev; class GlobalVariableDesc; @@ -78,6 +80,14 @@ protected: /// AsmPrinter *Asm; + /// M - Current module. + /// + Module *M; + + /// MF - Current machine function. + /// + MachineFunction *MF; + /// DebugInfo - Collected debug information. /// MachineDebugInfo *DebugInfo; @@ -86,6 +96,10 @@ protected: /// bool didInitial; + /// SubprogramCount - The running count of functions being compiled. + /// + unsigned SubprogramCount; + //===--------------------------------------------------------------------===// // Attributes used to construct specific Dwarf sections. // @@ -209,6 +223,10 @@ public: /// EOL - Print a newline character to asm stream. If a comment is present /// then it will be printed first. Comments should not contain '\n'. void EOL(const std::string &Comment) const; + + /// EmitAlign - Print a align directive. + /// + void EmitAlign(unsigned Alignment) const; /// EmitULEB128Bytes - Emit an assembler byte data directive to compose an /// unsigned leb128 value. @@ -300,6 +318,10 @@ public: private: + /// AddSourceLine - Add location information to specified debug information + /// entry. + void AddSourceLine(DIE *Die, CompileUnitDesc *File, unsigned Line); + /// NewType - Create a new type DIE. /// DIE *NewType(DIE *Context, TypeDesc *TyDesc); @@ -320,6 +342,19 @@ private: /// DIE *NewSubprogram(SubprogramDesc *SPD); + /// NewScopeVariable - Create a new scope variable. + /// + DIE *NewScopeVariable(DebugVariable *DV, CompileUnit *Unit); + + /// ConstructScope - Construct the components of a scope. + /// + void ConstructScope(DebugScope *ParentScope, DIE *ParentDie, + CompileUnit *Unit); + + /// ConstructRootScope - Construct the scope for the subprogram. + /// + void ConstructRootScope(DebugScope *RootScope); + /// EmitInitial - Emit initial Dwarf declarations. /// void EmitInitial() const; @@ -330,7 +365,7 @@ private: /// SizeAndOffsetDie - Compute the size and offset of a DIE. /// - unsigned SizeAndOffsetDie(DIE *Die, unsigned Offset); + unsigned SizeAndOffsetDie(DIE *Die, unsigned Offset, bool Last); /// SizeAndOffsets - Compute the size and offset of all the DIEs. /// @@ -382,11 +417,11 @@ private: /// ConstructGlobalDIEs - Create DIEs for each of the externally visible /// global variables. - void ConstructGlobalDIEs(Module &M); + void ConstructGlobalDIEs(); /// ConstructSubprogramDIEs - Create DIEs for each of the externally visible /// subprograms. - void ConstructSubprogramDIEs(Module &M); + void ConstructSubprogramDIEs(); /// ShouldEmitDwarf - Returns true if Dwarf declarations should be made. /// When called it also checks to see if debug info is newly available. if @@ -408,19 +443,19 @@ public: /// BeginModule - Emit all Dwarf sections that should come prior to the /// content. - void BeginModule(Module &M); + void BeginModule(Module *M); /// EndModule - Emit all Dwarf sections that should come after the content. /// - void EndModule(Module &M); + void EndModule(); /// BeginFunction - Gather pre-function debug information. /// - void BeginFunction(MachineFunction &MF); + void BeginFunction(MachineFunction *MF); /// EndFunction - Gather and emit post-function debug information. /// - void EndFunction(MachineFunction &MF); + void EndFunction(); }; } // end llvm namespace diff --git a/include/llvm/CodeGen/MachineDebugInfo.h b/include/llvm/CodeGen/MachineDebugInfo.h index 622d17b5411..e63fae3eea0 100644 --- a/include/llvm/CodeGen/MachineDebugInfo.h +++ b/include/llvm/CodeGen/MachineDebugInfo.h @@ -55,7 +55,7 @@ class StructType; // Debug info constants. enum { - LLVMDebugVersion = 2 // Current version of debug information. + LLVMDebugVersion = 3 // Current version of debug information. }; //===----------------------------------------------------------------------===// @@ -299,7 +299,7 @@ public: void setAlign(uint64_t A) { Align = A; } void setOffset(uint64_t O) { Offset = O; } - /// ApplyToFields - Target the visitor to the fields of the TypeDesc. + /// ApplyToFields - Target the visitor to the fields of the TypeDesc. /// virtual void ApplyToFields(DIVisitor *Visitor); @@ -334,7 +334,7 @@ public: static bool classof(const BasicTypeDesc *) { return true; } static bool classof(const DebugInfoDesc *D); - /// ApplyToFields - Target the visitor to the fields of the BasicTypeDesc. + /// ApplyToFields - Target the visitor to the fields of the BasicTypeDesc. /// virtual void ApplyToFields(DIVisitor *Visitor); @@ -370,7 +370,7 @@ public: static bool classof(const DerivedTypeDesc *) { return true; } static bool classof(const DebugInfoDesc *D); - /// ApplyToFields - Target the visitor to the fields of the DerivedTypeDesc. + /// ApplyToFields - Target the visitor to the fields of the DerivedTypeDesc. /// virtual void ApplyToFields(DIVisitor *Visitor); @@ -497,6 +497,54 @@ public: #endif }; +//===----------------------------------------------------------------------===// +/// VariableDesc - This class packages debug information associated with a +/// subprogram variable. +/// +class VariableDesc : public DebugInfoDesc { +private: + DebugInfoDesc *Context; // Context debug descriptor. + std::string Name; // Type name (may be empty.) + CompileUnitDesc *File; // Defined compile unit (may be NULL.) + unsigned Line; // Defined line# (may be zero.) + TypeDesc *TyDesc; // Type of variable. + +public: + VariableDesc(unsigned T); + + // Accessors + DebugInfoDesc *getContext() const { return Context; } + const std::string &getName() const { return Name; } + CompileUnitDesc *getFile() const { return File; } + unsigned getLine() const { return Line; } + TypeDesc *getType() const { return TyDesc; } + void setContext(DebugInfoDesc *C) { Context = C; } + void setName(const std::string &N) { Name = N; } + void setFile(CompileUnitDesc *U) { File = U; } + void setLine(unsigned L) { Line = L; } + void setType(TypeDesc *T) { TyDesc = T; } + + // Implement isa/cast/dyncast. + static bool classof(const VariableDesc *) { return true; } + static bool classof(const DebugInfoDesc *D); + + /// ApplyToFields - Target the visitor to the fields of the VariableDesc. + /// + virtual void ApplyToFields(DIVisitor *Visitor); + + /// getDescString - Return a string used to compose global names and labels. + /// + virtual const char *getDescString() const; + + /// getTypeString - Return a string used to label this descriptor's type. + /// + virtual const char *getTypeString() const; + +#ifndef NDEBUG + virtual void dump(); +#endif +}; + //===----------------------------------------------------------------------===// /// GlobalDesc - This class is the base descriptor for global functions and /// variables. @@ -519,7 +567,7 @@ public: const std::string &getName() const { return Name; } CompileUnitDesc *getFile() const { return File; } unsigned getLine() const { return Line; } - TypeDesc *getTypeDesc() const { return TyDesc; } + TypeDesc *getType() const { return TyDesc; } bool isStatic() const { return IsStatic; } bool isDefinition() const { return IsDefinition; } void setContext(DebugInfoDesc *C) { Context = C; } @@ -580,14 +628,11 @@ public: /// subprogram/function. class SubprogramDesc : public GlobalDesc { private: - std::vector Elements;// Information about args, variables - // and blocks. public: SubprogramDesc(); // Accessors - std::vector &getElements() { return Elements; } // Implement isa/cast/dyncast. static bool classof(const SubprogramDesc *) { return true; } @@ -620,13 +665,14 @@ public: /// class BlockDesc : public DebugInfoDesc { private: - std::vector Elements;// Information about nested variables - // and blocks. + DebugInfoDesc *Context; // Context debug descriptor. + public: BlockDesc(); // Accessors - std::vector &getElements() { return Elements; } + DebugInfoDesc *getContext() const { return Context; } + void setContext(DebugInfoDesc *C) { Context = C; } // Implement isa/cast/dyncast. static bool classof(const BlockDesc *) { return true; } @@ -753,15 +799,17 @@ private: unsigned Line; // Source line number. unsigned Column; // Source column. unsigned SourceID; // Source ID number. + unsigned LabelID; // Label in code ID number. public: - SourceLineInfo(unsigned L, unsigned C, unsigned S) - : Line(L), Column(C), SourceID(S) {} + SourceLineInfo(unsigned L, unsigned C, unsigned S, unsigned I) + : Line(L), Column(C), SourceID(S), LabelID(I) {} // Accessors unsigned getLine() const { return Line; } unsigned getColumn() const { return Column; } unsigned getSourceID() const { return SourceID; } + unsigned getLabelID() const { return LabelID; } }; //===----------------------------------------------------------------------===// @@ -793,6 +841,68 @@ public: } }; +//===----------------------------------------------------------------------===// +/// DebugVariable - This class is used to track local variable information. +/// +class DebugVariable { +private: + VariableDesc *Desc; // Variable Descriptor. + unsigned FrameIndex; // Variable frame index. + +public: + DebugVariable(VariableDesc *D, unsigned I) + : Desc(D) + , FrameIndex(I) + {} + + // Accessors. + VariableDesc *getDesc() const { return Desc; } + unsigned getFrameIndex() const { return FrameIndex; } +}; + +//===----------------------------------------------------------------------===// +/// DebugScope - This class is used to track scope information. +/// +class DebugScope { +private: + DebugScope *Parent; // Parent to this scope. + DebugInfoDesc *Desc; // Debug info descriptor for scope. + // Either subprogram or block. + unsigned StartLabelID; // Label ID of the beginning of scope. + unsigned EndLabelID; // Label ID of the end of scope. + std::vector Scopes; // Scopes defined in scope. + std::vector Variables;// Variables declared in scope. + +public: + DebugScope(DebugScope *P, DebugInfoDesc *D) + : Parent(P) + , Desc(D) + , StartLabelID(0) + , EndLabelID(0) + , Scopes() + , Variables() + {} + ~DebugScope(); + + // Accessors. + DebugScope *getParent() const { return Parent; } + DebugInfoDesc *getDesc() const { return Desc; } + unsigned getStartLabelID() const { return StartLabelID; } + unsigned getEndLabelID() const { return EndLabelID; } + std::vector &getScopes() { return Scopes; } + std::vector &getVariables() { return Variables; } + void setStartLabelID(unsigned S) { StartLabelID = S; } + void setEndLabelID(unsigned E) { EndLabelID = E; } + + /// AddScope - Add a scope to the scope. + /// + void AddScope(DebugScope *S) { Scopes.push_back(S); } + + /// AddVariable - Add a variable to the scope. + /// + void AddVariable(DebugVariable *V) { Variables.push_back(V); } +}; + //===----------------------------------------------------------------------===// /// MachineDebugInfo - This class contains debug information specific to a /// module. Queries can be made by different debugging schemes and reformated @@ -800,8 +910,9 @@ public: /// class MachineDebugInfo : public ImmutablePass { private: - // Use the same serializer/deserializer/verifier for the module. + // Use the same deserializer/verifier for the module. DIDeserializer DR; + DIVerifier VR; // CompileUnits - Uniquing vector for compile units. UniqueVector CompileUnits; @@ -814,6 +925,16 @@ private: // Lines - List of of source line correspondence. std::vector Lines; + + // LabelID - Current number assigned to unique label numbers. + unsigned LabelID; + + // ScopeMap - Tracks the scopes in the current function. + std::map ScopeMap; + + // RootScope - Top level scope for the current function. + // + DebugScope *RootScope; public: MachineDebugInfo(); @@ -844,25 +965,20 @@ public: /// bool hasInfo() const { return !CompileUnits.empty(); } + /// NextLabelID - Return the next unique label id. + /// + unsigned NextLabelID() { return ++LabelID; } + /// 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 RecordLabel(unsigned Line, unsigned Column, unsigned Source) { - Lines.push_back(new SourceLineInfo(Line, Column, Source)); - return Lines.size(); - } + unsigned RecordLabel(unsigned Line, unsigned Column, unsigned Source); /// RecordSource - Register a source file with debug info. Returns an source /// ID. unsigned RecordSource(const std::string &Directory, - const std::string &Source) { - unsigned DirectoryID = Directories.insert(Directory); - return SourceFiles.insert(SourceFileInfo(DirectoryID, Source)); - } - unsigned RecordSource(const CompileUnitDesc *CompileUnit) { - return RecordSource(CompileUnit->getDirectory(), - CompileUnit->getFileName()); - } + const std::string &Source); + unsigned RecordSource(const CompileUnitDesc *CompileUnit); /// getDirectories - Return the UniqueVector of std::string representing /// directories. @@ -904,8 +1020,14 @@ public: std::vector AnchoredDescs; for (unsigned i = 0, N = Globals.size(); i < N; ++i) { GlobalVariable *GV = Globals[i]; - // FIXME - Tag check only necessary for bring up (changed tag values.) unsigned Tag = DebugInfoDesc::TagFromGlobal(GV); + + if (isa(&Desc)) { + unsigned DebugVersion = CompileUnitDesc::DebugVersionFromGlobal(GV); + // FIXME - In the short term, changes are too drastic to continue. + if (DebugVersion != LLVMDebugVersion) break; + } + if (Tag == Desc.getTag()) { AnchoredDescs.push_back(cast(DR.Deserialize(GV))); } @@ -913,6 +1035,30 @@ public: return AnchoredDescs; } + + /// RecordRegionStart - Indicate the start of a region. + /// + unsigned RecordRegionStart(Value *V); + + /// RecordRegionEnd - Indicate the end of a region. + /// + unsigned RecordRegionEnd(Value *V); + + /// RecordVariable - Indicate the declaration of a local variable. + /// + void RecordVariable(Value *V, unsigned FrameIndex); + + /// getRootScope - Return current functions root scope. + /// + DebugScope *getRootScope() { return RootScope; } + + /// getOrCreateScope - Returns the scope associated with the given descriptor. + /// + DebugScope *getOrCreateScope(DebugInfoDesc *ScopeDesc); + + /// ClearScopes - Delete the scope and variable info after a function is + /// completed. + void ClearScopes(); }; // End class MachineDebugInfo diff --git a/include/llvm/Support/Dwarf.h b/include/llvm/Support/Dwarf.h index 090fc6033ae..fb434f64652 100644 --- a/include/llvm/Support/Dwarf.h +++ b/include/llvm/Support/Dwarf.h @@ -31,7 +31,16 @@ namespace dwarf { enum llvm_dwarf_constants { // llvm mock tags DW_TAG_invalid = ~0U, // Tag for invalid results. - DW_TAG_anchor = 0 // Tag for descriptor anchors. + + DW_TAG_anchor = 0, // Tag for descriptor anchors. + DW_TAG_auto_variable = 0x100, // Tag for local (auto) variables. + DW_TAG_arg_variable = 0x101, // Tag for argument variables. + DW_TAG_return_variable = 0x102, // Tag for return variables. + + DW_TAG_user_base = 0x1000, // Recommended base for user tags. + + DW_CIE_VERSION = 1, // Common frame information version. + DW_CIE_ID = 0xffffffff // Common frame information mark. }; enum dwarf_constants { @@ -410,6 +419,7 @@ enum dwarf_constants { DW_MACINFO_vendor_ext = 0xff, // Call frame instruction encodings + DW_CFA_extended = 0x00, DW_CFA_advance_loc = 0x40, DW_CFA_offset = 0x80, DW_CFA_restore = 0xc0, diff --git a/lib/CodeGen/DwarfWriter.cpp b/lib/CodeGen/DwarfWriter.cpp index b77721dd0c6..9896faacc16 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 @@ -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 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(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 &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 &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(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(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 &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 &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 &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 GlobalVariables = - DebugInfo->getAnchoredDescriptors(M); + DebugInfo->getAnchoredDescriptors(*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 Subprograms = - DebugInfo->getAnchoredDescriptors(M); + DebugInfo->getAnchoredDescriptors(*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 e867c889482..d2b7f41cf92 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(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(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; + } +} + +