X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FCodeGen%2FAsmPrinter%2FDwarfDebug.cpp;h=7ba1fc187da1cc29e0122924707a722e22fee56c;hb=1faea8f0869a173c5952b59fd17718cf42111416;hp=6b06d8b99b3d72a17eafbc9c327e07c0a515ef31;hpb=5ce4091a68936b94c1f8858a101e61e65f71a23b;p=oota-llvm.git diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 6b06d8b99b3..7ba1fc187da 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -36,6 +36,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/MD5.h" #include "llvm/Support/Path.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ValueHandle.h" @@ -46,54 +47,60 @@ #include "llvm/Target/TargetRegisterInfo.h" using namespace llvm; -static cl::opt DisableDebugInfoPrinting("disable-debug-info-print", - cl::Hidden, - cl::desc("Disable debug info printing")); +static cl::opt +DisableDebugInfoPrinting("disable-debug-info-print", cl::Hidden, + cl::desc("Disable debug info printing")); -static cl::opt UnknownLocations("use-unknown-locations", cl::Hidden, - cl::desc("Make an absence of debug location information explicit."), - cl::init(false)); +static cl::opt UnknownLocations( + "use-unknown-locations", cl::Hidden, + cl::desc("Make an absence of debug location information explicit."), + cl::init(false)); -static cl::opt GenerateDwarfPubNamesSection("generate-dwarf-pubnames", - cl::Hidden, cl::init(false), - cl::desc("Generate DWARF pubnames section")); +static cl::opt +GenerateDwarfPubNamesSection("generate-dwarf-pubnames", cl::Hidden, + cl::init(false), + cl::desc("Generate DWARF pubnames section")); -namespace { - enum DefaultOnOff { - Default, Enable, Disable - }; -} +static cl::opt +GenerateODRHash("generate-odr-hash", cl::Hidden, + cl::desc("Add an ODR hash to external type DIEs."), + cl::init(false)); -static cl::opt DwarfAccelTables("dwarf-accel-tables", cl::Hidden, - cl::desc("Output prototype dwarf accelerator tables."), - cl::values( - clEnumVal(Default, "Default for platform"), - clEnumVal(Enable, "Enabled"), - clEnumVal(Disable, "Disabled"), - clEnumValEnd), - cl::init(Default)); - -static cl::opt DarwinGDBCompat("darwin-gdb-compat", cl::Hidden, - cl::desc("Compatibility with Darwin gdb."), - cl::values( - clEnumVal(Default, "Default for platform"), - clEnumVal(Enable, "Enabled"), - clEnumVal(Disable, "Disabled"), - clEnumValEnd), - cl::init(Default)); - -static cl::opt SplitDwarf("split-dwarf", cl::Hidden, - cl::desc("Output prototype dwarf split debug info."), - cl::values( - clEnumVal(Default, "Default for platform"), - clEnumVal(Enable, "Enabled"), - clEnumVal(Disable, "Disabled"), - clEnumValEnd), - cl::init(Default)); +namespace { +enum DefaultOnOff { + Default, + Enable, + Disable +}; +} + +static cl::opt +DwarfAccelTables("dwarf-accel-tables", cl::Hidden, + cl::desc("Output prototype dwarf accelerator tables."), + cl::values(clEnumVal(Default, "Default for platform"), + clEnumVal(Enable, "Enabled"), + clEnumVal(Disable, "Disabled"), clEnumValEnd), + cl::init(Default)); + +static cl::opt +DarwinGDBCompat("darwin-gdb-compat", cl::Hidden, + cl::desc("Compatibility with Darwin gdb."), + cl::values(clEnumVal(Default, "Default for platform"), + clEnumVal(Enable, "Enabled"), + clEnumVal(Disable, "Disabled"), clEnumValEnd), + cl::init(Default)); + +static cl::opt +SplitDwarf("split-dwarf", cl::Hidden, + cl::desc("Output prototype dwarf split debug info."), + cl::values(clEnumVal(Default, "Default for platform"), + clEnumVal(Enable, "Enabled"), + clEnumVal(Disable, "Disabled"), clEnumValEnd), + cl::init(Default)); namespace { - const char *DWARFGroupName = "DWARF Emission"; - const char *DbgTimerName = "DWARF Debug Writer"; + const char *const DWARFGroupName = "DWARF Emission"; + const char *const DbgTimerName = "DWARF Debug Writer"; struct CompareFirst { template bool operator()(const T &lhs, const T &rhs) const { @@ -164,17 +171,10 @@ DIType DbgVariable::getType() const { /// Return Dwarf Version by checking module flags. static unsigned getDwarfVersionFromModule(const Module *M) { - SmallVector ModuleFlags; - M->getModuleFlagsMetadata(ModuleFlags); - for (unsigned I = 0, E = ModuleFlags.size(); I < E; ++I) { - const Module::ModuleFlagEntry &MFE = ModuleFlags[I]; - StringRef Key = MFE.Key->getString(); - Value *Val = MFE.Val; - - if (Key == "Dwarf Version") - return cast(Val)->getZExtValue(); - } - return dwarf::DWARF_VERSION; + Value *Val = M->getModuleFlag("Dwarf Version"); + if (!Val) + return dwarf::DWARF_VERSION; + return cast(Val)->getZExtValue(); } DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) @@ -934,7 +934,7 @@ void DwarfDebug::collectDeadVariables() { for (unsigned i = 0, e = Subprograms.getNumElements(); i != e; ++i) { DISubprogram SP(Subprograms.getElement(i)); if (ProcessedSPNodes.count(SP) != 0) continue; - if (!SP.Verify()) continue; + if (!SP.isSubprogram()) continue; if (!SP.isDefinition()) continue; DIArray Variables = SP.getVariables(); if (Variables.getNumElements() == 0) continue; @@ -950,10 +950,10 @@ void DwarfDebug::collectDeadVariables() { DIE *ScopeDIE = SPCU->getDIE(SP); for (unsigned vi = 0, ve = Variables.getNumElements(); vi != ve; ++vi) { DIVariable DV(Variables.getElement(vi)); - if (!DV.Verify()) continue; - DbgVariable *NewVar = new DbgVariable(DV, NULL); + if (!DV.isVariable()) continue; + DbgVariable NewVar(DV, NULL); if (DIE *VariableDIE = - SPCU->constructVariableDIE(NewVar, Scope->isAbstractScope())) + SPCU->constructVariableDIE(&NewVar, Scope->isAbstractScope())) ScopeDIE->addChild(VariableDIE); } } @@ -962,6 +962,127 @@ void DwarfDebug::collectDeadVariables() { DeleteContainerSeconds(DeadFnScopeMap); } +// Type Signature computation code. +typedef ArrayRef HashValue; + +/// \brief Grabs the string in whichever attribute is passed in and returns +/// a reference to it. +static StringRef getDIEStringAttr(DIE *Die, unsigned Attr) { + const SmallVectorImpl &Values = Die->getValues(); + const DIEAbbrev &Abbrevs = Die->getAbbrev(); + + // Iterate through all the attributes until we find the one we're + // looking for, if we can't find it return an empty string. + for (size_t i = 0; i < Values.size(); ++i) { + if (Abbrevs.getData()[i].getAttribute() == Attr) { + DIEValue *V = Values[i]; + assert(isa(V) && "String requested. Not a string."); + DIEString *S = cast(V); + return S->getString(); + } + } + return StringRef(""); +} + +/// \brief Adds the string in \p Str to the hash in \p Hash. This also hashes +/// a trailing NULL with the string. +static void addStringToHash(MD5 &Hash, StringRef Str) { + DEBUG(dbgs() << "Adding string " << Str << " to hash.\n"); + HashValue SVal((const uint8_t *)Str.data(), Str.size()); + const uint8_t NB = '\0'; + HashValue NBVal((const uint8_t *)&NB, 1); + Hash.update(SVal); + Hash.update(NBVal); +} + +// FIXME: These are copied and only slightly modified out of LEB128.h. + +/// \brief Adds the unsigned in \p N to the hash in \p Hash. This also encodes +/// the unsigned as a ULEB128. +static void addULEB128ToHash(MD5 &Hash, uint64_t Value) { + DEBUG(dbgs() << "Adding ULEB128 " << Value << " to hash.\n"); + do { + uint8_t Byte = Value & 0x7f; + Value >>= 7; + if (Value != 0) + Byte |= 0x80; // Mark this byte to show that more bytes will follow. + Hash.update(Byte); + } while (Value != 0); +} + +/// \brief Including \p Parent adds the context of Parent to \p Hash. +static void addParentContextToHash(MD5 &Hash, DIE *Parent) { + unsigned Tag = Parent->getTag(); + + DEBUG(dbgs() << "Adding parent context to hash...\n"); + + // For each surrounding type or namespace... + if (Tag != dwarf::DW_TAG_namespace && Tag != dwarf::DW_TAG_class_type && + Tag != dwarf::DW_TAG_structure_type) + return; + + // ... beginning with the outermost such construct... + if (Parent->getParent() != NULL) + addParentContextToHash(Hash, Parent->getParent()); + + // Append the letter "C" to the sequence. + addULEB128ToHash(Hash, 'C'); + + // Followed by the DWARF tag of the construct. + addULEB128ToHash(Hash, Parent->getTag()); + + // Then the name, taken from the DW_AT_name attribute. + StringRef Name = getDIEStringAttr(Parent, dwarf::DW_AT_name); + if (!Name.empty()) + addStringToHash(Hash, Name); +} + +/// This is based on the type signature computation given in section 7.27 of the +/// DWARF4 standard. It is the md5 hash of a flattened description of the DIE. +static void addDIEODRSignature(MD5 &Hash, CompileUnit *CU, DIE *Die) { + + // Add the contexts to the hash. + DIE *Parent = Die->getParent(); + if (Parent) + addParentContextToHash(Hash, Parent); + + // Add the current DIE information. + + // Add the DWARF tag of the DIE. + addULEB128ToHash(Hash, Die->getTag()); + + // Add the name of the type to the hash. + addStringToHash(Hash, getDIEStringAttr(Die, dwarf::DW_AT_name)); + + // Now get the result. + MD5::MD5Result Result; + Hash.final(Result); + + // ... take the least significant 8 bytes and store those as the attribute. + // Our MD5 implementation always returns its results in little endian, swap + // bytes appropriately. + uint64_t Signature = *reinterpret_cast(Result + 8); + + // FIXME: This should be added onto the type unit, not the type, but this + // works as an intermediate stage. + CU->addUInt(Die, dwarf::DW_AT_GNU_odr_signature, dwarf::DW_FORM_data8, + Signature); +} + +/// Return true if the current DIE is contained within an anonymous namespace. +static bool isContainedInAnonNamespace(DIE *Die) { + DIE *Parent = Die->getParent(); + + while (Parent) { + if (Die->getTag() == dwarf::DW_TAG_namespace && + getDIEStringAttr(Die, dwarf::DW_AT_name) == "") + return true; + Parent = Parent->getParent(); + } + + return false; +} + void DwarfDebug::finalizeModuleInfo() { // Collect info for variables that were optimized out. collectDeadVariables(); @@ -977,6 +1098,20 @@ void DwarfDebug::finalizeModuleInfo() { TheCU->constructContainingTypeDIEs(); } + // For types that we'd like to move to type units or ODR check go ahead + // and either move the types out or add the ODR attribute now. + // FIXME: Do type splitting. + for (unsigned i = 0, e = TypeUnits.size(); i != e; ++i) { + MD5 Hash; + DIE *Die = TypeUnits[i]; + // If we're in C++ and we want to generate the hash then go ahead and do + // that now. + if (GenerateODRHash && + CUMap.begin()->second->getLanguage() == dwarf::DW_LANG_C_plus_plus && + !isContainedInAnonNamespace(Die)) + addDIEODRSignature(Hash, CUMap.begin()->second, Die); + } + // Compute DIE offsets and sizes. InfoHolder.computeSizeAndOffsets(); if (useSplitDwarf()) @@ -1184,7 +1319,8 @@ static bool isDbgValueInDefinedReg(const MachineInstr *MI) { assert(MI->isDebugValue() && "Invalid DBG_VALUE machine instruction!"); return MI->getNumOperands() == 3 && MI->getOperand(0).isReg() && MI->getOperand(0).getReg() && - MI->getOperand(1).isImm() && MI->getOperand(1).getImm() == 0; + (MI->getOperand(1).isImm() || + (MI->getOperand(1).isReg() && MI->getOperand(1).getReg() == 0U)); } // Get .debug_loc entry for the instruction range starting at MI. @@ -1195,12 +1331,11 @@ static DotDebugLocEntry getDebugLocEntry(AsmPrinter *Asm, const MDNode *Var = MI->getOperand(MI->getNumOperands() - 1).getMetadata(); assert(MI->getNumOperands() == 3); - if (MI->getOperand(0).isReg() && MI->getOperand(1).isImm()) { + if (MI->getOperand(0).isReg()) { MachineLocation MLoc; - // TODO: Currently an offset of 0 in a DBG_VALUE means - // we need to generate a direct register value. - // There is no way to specify an indirect value with offset 0. - if (MI->getOperand(1).getImm() == 0) + // If the second operand is an immediate, this is a + // register-indirect address. + if (!MI->getOperand(1).isImm()) MLoc.set(MI->getOperand(0).getReg()); else MLoc.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm()); @@ -1314,7 +1449,7 @@ DwarfDebug::collectVariableInfo(const MachineFunction *MF, DIArray Variables = DISubprogram(FnScope->getScopeNode()).getVariables(); for (unsigned i = 0, e = Variables.getNumElements(); i != e; ++i) { DIVariable DV(Variables.getElement(i)); - if (!DV || !DV.Verify() || !Processed.insert(DV)) + if (!DV || !DV.isVariable() || !Processed.insert(DV)) continue; if (LexicalScope *Scope = LScopes.findLexicalScope(DV.getContext())) addScopeVariable(Scope, new DbgVariable(DV, NULL)); @@ -1445,7 +1580,7 @@ static MDNode *getScopeNode(DebugLoc DL, const LLVMContext &Ctx) { static DebugLoc getFnDebugLoc(DebugLoc DL, const LLVMContext &Ctx) { const MDNode *Scope = getScopeNode(DL, Ctx); DISubprogram SP = getDISubprogram(Scope); - if (SP.Verify()) { + if (SP.isSubprogram()) { // Check for number of operands since the compatibility is // cheap here. if (SP->getNumOperands() > 19) @@ -1513,7 +1648,7 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { // The first mention of a function argument gets the FunctionBeginSym // label, so arguments are visible when breaking at function entry. DIVariable DV(Var); - if (DV.Verify() && DV.getTag() == dwarf::DW_TAG_arg_variable && + if (DV.isVariable() && DV.getTag() == dwarf::DW_TAG_arg_variable && DISubprogram(getDISubprogram(DV.getContext())) .describes(MF->getFunction())) LabelsBeforeInsn[MI] = FunctionBeginSym; @@ -1699,12 +1834,12 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { for (unsigned i = 0, e = AList.size(); i != e; ++i) { LexicalScope *AScope = AList[i]; DISubprogram SP(AScope->getScopeNode()); - if (SP.Verify()) { + if (SP.isSubprogram()) { // Collect info for variables that were optimized out. DIArray Variables = SP.getVariables(); for (unsigned i = 0, e = Variables.getNumElements(); i != e; ++i) { DIVariable DV(Variables.getElement(i)); - if (!DV || !DV.Verify() || !ProcessedVars.insert(DV)) + if (!DV || !DV.isVariable() || !ProcessedVars.insert(DV)) continue; // Check that DbgVariable for DV wasn't created earlier, when // findAbstractVariable() was called for inlined instance of DV. @@ -2383,13 +2518,11 @@ void DwarfUnits::emitAddresses(const MCSection *AddrSection) { // Start the dwarf addr section. Asm->OutStreamer.SwitchSection(AddrSection); - // Get all of the address pool entries and put them in an array by their ID so - // we can sort them. + // Order the address pool entries by ID SmallVector Entries(AddressPool.size()); - for (DenseMap::iterator - I = AddressPool.begin(), - E = AddressPool.end(); + for (DenseMap::iterator I = AddressPool.begin(), + E = AddressPool.end(); I != E; ++I) Entries[I->second] = I->first;