From 0db006ea38de2ccd738363a7b4f8f2d95128540a Mon Sep 17 00:00:00 2001 From: Devang Patel Date: Thu, 8 Jan 2009 02:33:41 +0000 Subject: [PATCH] Add APIs to manage scope using DebugInfo interface. This is a shameless copy of similar APIs from MachineModuleInfo. The copy from MMI will be deleted in near future. llvm-svn: 61908 --- lib/CodeGen/AsmPrinter/DwarfWriter.cpp | 297 +++++++++++++++++++++++++ 1 file changed, 297 insertions(+) diff --git a/lib/CodeGen/AsmPrinter/DwarfWriter.cpp b/lib/CodeGen/AsmPrinter/DwarfWriter.cpp index 6e2011ea280..a53874dcd3f 100644 --- a/lib/CodeGen/AsmPrinter/DwarfWriter.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfWriter.cpp @@ -1192,6 +1192,60 @@ public: } }; +//===----------------------------------------------------------------------===// +/// DbgVariable - This class is used to track local variable information. +/// +class DbgVariable { +private: + DIVariable *Var; // Variable Descriptor. + unsigned FrameIndex; // Variable frame index. + +public: + DbgVariable(DIVariable *V, unsigned I) : Var(V), FrameIndex(I) {} + + // Accessors. + DIVariable *getVariable() const { return Var; } + unsigned getFrameIndex() const { return FrameIndex; } +}; + +//===----------------------------------------------------------------------===// +/// DbgScope - This class is used to track scope information. +/// +class DbgScope { +private: + DbgScope *Parent; // Parent to this scope. + DIDescriptor *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. + SmallVector Scopes; // Scopes defined in scope. + SmallVector Variables;// Variables declared in scope. + +public: + DbgScope(DbgScope *P, DIDescriptor *D) + : Parent(P), Desc(D), StartLabelID(0), EndLabelID(0), Scopes(), Variables() + {} + ~DbgScope(); + + // Accessors. + DbgScope *getParent() const { return Parent; } + DIDescriptor *getDesc() const { return Desc; } + unsigned getStartLabelID() const { return StartLabelID; } + unsigned getEndLabelID() const { return EndLabelID; } + SmallVector &getScopes() { return Scopes; } + SmallVector &getVariables() { return Variables; } + void setStartLabelID(unsigned S) { StartLabelID = S; } + void setEndLabelID(unsigned E) { EndLabelID = E; } + + /// AddScope - Add a scope to the scope. + /// + void AddScope(DbgScope *S) { Scopes.push_back(S); } + + /// AddVariable - Add a variable to the scope. + /// + void AddVariable(DbgVariable *V) { Variables.push_back(V); } +}; + //===----------------------------------------------------------------------===// /// DwarfDebug - Emits Dwarf debug directives. /// @@ -1253,6 +1307,44 @@ private: /// bool shouldEmit; + // RootScope - Top level scope for the current function. + // + DbgScope *RootDbgScope; + + // DbgScopeMap - Tracks the scopes in the current function. + DenseMap DbgScopeMap; + + // DbgLabelIDList - One entry per assigned label. Normally the entry is equal to + // the list index(+1). If the entry is zero then the label has been deleted. + // Any other value indicates the label has been deleted by is mapped to + // another label. + SmallVector DbgLabelIDList; + + /// NextLabelID - Return the next unique label id. + /// + unsigned NextLabelID() { + unsigned ID = (unsigned)DbgLabelIDList.size() + 1; + DbgLabelIDList.push_back(ID); + return ID; + } + + /// RemapLabel - Indicate that a label has been merged into another. + /// + void RemapLabel(unsigned OldLabelID, unsigned NewLabelID) { + assert(0 < OldLabelID && OldLabelID <= DbgLabelIDList.size() && + "Old label ID out of range."); + assert(NewLabelID <= DbgLabelIDList.size() && + "New label ID out of range."); + DbgLabelIDList[OldLabelID - 1] = NewLabelID; + } + + /// MappedLabel - Find out the label's final ID. Zero indicates deletion. + /// ID != Mapped ID indicates that the label was folded into another label. + unsigned MappedLabel(unsigned LabelID) const { + assert(LabelID <= DbgLabelIDList.size() && "Debug label ID out of range."); + return LabelID ? DbgLabelIDList[LabelID - 1] : 0; + } + struct FunctionDebugFrameInfo { unsigned Number; std::vector Moves; @@ -1492,6 +1584,25 @@ private: } } + /// AddSourceLine - Add location information to specified debug information + /// entry. + void AddSourceLine(DIE *Die, DIVariable *V) { + unsigned FileID = 0; + unsigned Line = V->getLineNumber(); + if (V->getVersion() < DIDescriptor::Version7) { + // Version6 or earlier. Use compile unit info to get file id. + CompileUnit *Unit = FindCompileUnit(V->getCompileUnit()); + FileID = Unit->getID(); + } else { + // Version7 or newer, use filename and directory info from DIVariable + // directly. + unsigned DID = Directories.idFor(V->getDirectory()); + FileID = SrcFiles.idFor(SrcFileInfo(DID, V->getFilename())); + } + AddUInt(Die, DW_AT_decl_file, 0, FileID); + AddUInt(Die, DW_AT_decl_line, 0, Line); + } + /// AddSourceLine - Add location information to specified debug information /// entry. void AddSourceLine(DIE *Die, DIGlobal *G) { @@ -2393,6 +2504,191 @@ private: return VariableDie; } + /// NewScopeVariable - Create a new scope variable. + /// + DIE *NewDbgScopeVariable(DbgVariable *DV, CompileUnit *Unit) { + // Get the descriptor. + DIVariable *VD = DV->getVariable(); + + // 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); + AddString(VariableDie, DW_AT_name, DW_FORM_string, VD->getName()); + + // Add source line info if available. + AddSourceLine(VariableDie, VD); + + // Add variable type. + AddType(Unit, VariableDie, VD->getType()); + + // Add variable address. + MachineLocation Location; + Location.set(RI->getFrameRegister(*MF), + RI->getFrameIndexOffset(*MF, DV->getFrameIndex())); + AddAddress(VariableDie, DW_AT_location, Location); + + return VariableDie; + } + + + /// getOrCreateScope - Returns the scope associated with the given descriptor. + /// + DbgScope *getOrCreateScope(GlobalVariable *V) { + DbgScope *&Slot = DbgScopeMap[V]; + if (!Slot) { + // FIXME - breaks down when the context is an inlined function. + DIDescriptor ParentDesc; + DIBlock *DB = new DIBlock(V); + if (DIBlock *Block = dyn_cast(DB)) { + ParentDesc = Block->getContext(); + } + DbgScope *Parent = ParentDesc.isNull() ? + getOrCreateScope(ParentDesc.getGV()) : NULL; + Slot = new DbgScope(Parent, DB); + if (Parent) { + Parent->AddScope(Slot); + } else if (RootDbgScope) { + // FIXME - Add inlined function scopes to the root so we can delete + // them later. Long term, handle inlined functions properly. + RootDbgScope->AddScope(Slot); + } else { + // First function is top level function. + RootDbgScope = Slot; + } + } + return Slot; + } + + /// ConstructDbgScope - Construct the components of a scope. + /// + void ConstructDbgScope(DbgScope *ParentScope, + unsigned ParentStartID, unsigned ParentEndID, + DIE *ParentDie, CompileUnit *Unit) { + // Add variables to scope. + SmallVector &Variables = ParentScope->getVariables(); + for (unsigned i = 0, N = Variables.size(); i < N; ++i) { + DIE *VariableDie = NewDbgScopeVariable(Variables[i], Unit); + if (VariableDie) ParentDie->AddChild(VariableDie); + } + + // Add nested scopes. + SmallVector &Scopes = ParentScope->getScopes(); + for (unsigned j = 0, M = Scopes.size(); j < M; ++j) { + // Define the Scope debug information entry. + DbgScope *Scope = Scopes[j]; + // FIXME - Ignore inlined functions for the time being. + if (!Scope->getParent()) continue; + + unsigned StartID = MappedLabel(Scope->getStartLabelID()); + unsigned EndID = MappedLabel(Scope->getEndLabelID()); + + // Ignore empty scopes. + if (StartID == EndID && StartID != 0) continue; + if (Scope->getScopes().empty() && Scope->getVariables().empty()) continue; + + if (StartID == ParentStartID && EndID == ParentEndID) { + // Just add stuff to the parent scope. + ConstructDbgScope(Scope, ParentStartID, ParentEndID, ParentDie, Unit); + } else { + DIE *ScopeDie = new DIE(DW_TAG_lexical_block); + + // Add the scope bounds. + if (StartID) { + AddLabel(ScopeDie, DW_AT_low_pc, DW_FORM_addr, + DWLabel("label", StartID)); + } else { + AddLabel(ScopeDie, DW_AT_low_pc, DW_FORM_addr, + DWLabel("func_begin", SubprogramCount)); + } + if (EndID) { + AddLabel(ScopeDie, DW_AT_high_pc, DW_FORM_addr, + DWLabel("label", EndID)); + } else { + AddLabel(ScopeDie, DW_AT_high_pc, DW_FORM_addr, + DWLabel("func_end", SubprogramCount)); + } + + // Add the scope contents. + ConstructDbgScope(Scope, StartID, EndID, ScopeDie, Unit); + ParentDie->AddChild(ScopeDie); + } + } + } + + /// ConstructRootDbgScope - Construct the scope for the subprogram. + /// + void ConstructRootDbgScope(DbgScope *RootScope) { + // Exit if there is no root scope. + if (!RootScope) return; + + // Get the subprogram debug information entry. + DISubprogram *SPD = cast(RootScope->getDesc()); + + // Get the compile unit context. + CompileUnit *Unit = FindCompileUnit(SPD->getCompileUnit()); + + // Get the subprogram die. + DIE *SPDie = Unit->getDieMapSlotFor(SPD->getGV()); + assert(SPDie && "Missing subprogram descriptor"); + + // Add the function bounds. + AddLabel(SPDie, DW_AT_low_pc, DW_FORM_addr, + DWLabel("func_begin", SubprogramCount)); + AddLabel(SPDie, DW_AT_high_pc, DW_FORM_addr, + DWLabel("func_end", SubprogramCount)); + MachineLocation Location(RI->getFrameRegister(*MF)); + AddAddress(SPDie, DW_AT_frame_base, Location); + + ConstructDbgScope(RootScope, 0, 0, SPDie, Unit); + } + + /// ConstructDefaultDbgScope - Construct a default scope for the subprogram. + /// + void ConstructDefaultDbgScope(MachineFunction *MF) { + // Find the correct subprogram descriptor. + std::string SPName = "llvm.dbg.subprograms"; + std::vector Result; + getGlobalVariablesUsing(*M, SPName, Result); + for (std::vector::iterator I = Result.begin(), + E = Result.end(); I != E; ++I) { + + DISubprogram *SPD = new DISubprogram(*I); + + if (SPD->getName() == MF->getFunction()->getName()) { + // Get the compile unit context. + CompileUnit *Unit = FindCompileUnit(SPD->getCompileUnit()); + + // Get the subprogram die. + DIE *SPDie = Unit->getDieMapSlotFor(SPD->getGV()); + assert(SPDie && "Missing subprogram descriptor"); + + // Add the function bounds. + AddLabel(SPDie, DW_AT_low_pc, DW_FORM_addr, + DWLabel("func_begin", SubprogramCount)); + AddLabel(SPDie, DW_AT_high_pc, DW_FORM_addr, + DWLabel("func_end", SubprogramCount)); + + MachineLocation Location(RI->getFrameRegister(*MF)); + AddAddress(SPDie, DW_AT_frame_base, Location); + return; + } + } +#if 0 + // FIXME: This is causing an abort because C++ mangled names are compared + // with their unmangled counterparts. See PR2885. Don't do this assert. + assert(0 && "Couldn't find DIE for machine function!"); +#endif + } + /// ConstructScope - Construct the components of a scope. /// void ConstructScope(DebugScope *ParentScope, @@ -3282,6 +3578,7 @@ public: , SectionSourceLines() , didInitial(false) , shouldEmit(false) + , RootDbgScope(NULL) { } virtual ~DwarfDebug() {