#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"
#include "llvm/Target/TargetRegisterInfo.h"
using namespace llvm;
-static cl::opt<bool> DisableDebugInfoPrinting("disable-debug-info-print",
- cl::Hidden,
- cl::desc("Disable debug info printing"));
+static cl::opt<bool>
+DisableDebugInfoPrinting("disable-debug-info-print", cl::Hidden,
+ cl::desc("Disable debug info printing"));
-static cl::opt<bool> UnknownLocations("use-unknown-locations", cl::Hidden,
- cl::desc("Make an absence of debug location information explicit."),
- cl::init(false));
+static cl::opt<bool> UnknownLocations(
+ "use-unknown-locations", cl::Hidden,
+ cl::desc("Make an absence of debug location information explicit."),
+ cl::init(false));
-static cl::opt<bool> GenerateDwarfPubNamesSection("generate-dwarf-pubnames",
- cl::Hidden, cl::init(false),
- cl::desc("Generate DWARF pubnames section"));
+static cl::opt<bool>
+GenerateDwarfPubNamesSection("generate-dwarf-pubnames", cl::Hidden,
+ cl::init(false),
+ cl::desc("Generate DWARF pubnames section"));
-namespace {
- enum DefaultOnOff {
- Default, Enable, Disable
- };
-}
+static cl::opt<bool>
+GenerateODRHash("generate-odr-hash", cl::Hidden,
+ cl::desc("Add an ODR hash to external type DIEs."),
+ cl::init(false));
-static cl::opt<DefaultOnOff> 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<DefaultOnOff> 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<DefaultOnOff> 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<DefaultOnOff>
+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<DefaultOnOff>
+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<DefaultOnOff>
+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 <typename T> bool operator()(const T &lhs, const T &rhs) const {
/// Return Dwarf Version by checking module flags.
static unsigned getDwarfVersionFromModule(const Module *M) {
- SmallVector<Module::ModuleFlagEntry, 8> 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<ConstantInt>(Val)->getZExtValue();
- }
- return dwarf::DWARF_VERSION;
+ Value *Val = M->getModuleFlag("Dwarf Version");
+ if (!Val)
+ return dwarf::DWARF_VERSION;
+ return cast<ConstantInt>(Val)->getZExtValue();
}
DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M)
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;
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);
}
}
DeleteContainerSeconds(DeadFnScopeMap);
}
+// Type Signature computation code.
+typedef ArrayRef<uint8_t> 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<DIEValue *> &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<DIEString>(V) && "String requested. Not a string.");
+ DIEString *S = cast<DIEString>(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<support::ulittle64_t *>(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();
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())
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.
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());
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));
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)
// 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;
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.
// 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.
- SmallVector<std::pair<unsigned, const MCExpr *>, 64> Entries;
+ // Order the address pool entries by ID
+ SmallVector<const MCExpr *, 64> Entries(AddressPool.size());
- for (DenseMap<const MCExpr *, unsigned>::iterator
- I = AddressPool.begin(),
- E = AddressPool.end();
+ for (DenseMap<const MCExpr *, unsigned>::iterator I = AddressPool.begin(),
+ E = AddressPool.end();
I != E; ++I)
- Entries.push_back(std::make_pair(I->second, I->first));
-
- array_pod_sort(Entries.begin(), Entries.end());
+ Entries[I->second] = I->first;
for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
// Emit an expression for reference from debug information entries.
- if (const MCExpr *Expr = Entries[i].second)
+ if (const MCExpr *Expr = Entries[i])
Asm->OutStreamer.EmitValue(Expr, Asm->getDataLayout().getPointerSize());
else
Asm->OutStreamer.EmitIntValue(0, Asm->getDataLayout().getPointerSize());