// DIDescriptor
//===----------------------------------------------------------------------===//
-DIDescriptor::DIDescriptor(const DIFile F) : DbgNode(F.DbgNode) {
-}
-
-DIDescriptor::DIDescriptor(const DISubprogram F) : DbgNode(F.DbgNode) {
-}
-
-DIDescriptor::DIDescriptor(const DILexicalBlockFile F) : DbgNode(F.DbgNode) {
-}
-
-DIDescriptor::DIDescriptor(const DILexicalBlock F) : DbgNode(F.DbgNode) {
-}
-
-DIDescriptor::DIDescriptor(const DIVariable F) : DbgNode(F.DbgNode) {
-}
-
-DIDescriptor::DIDescriptor(const DIType F) : DbgNode(F.DbgNode) {
-}
-
bool DIDescriptor::Verify() const {
return DbgNode &&
(DIDerivedType(DbgNode).Verify() ||
getTag() == dwarf::DW_TAG_constant);
}
-/// isGlobal - Return true if the specified tag is legal for DIGlobal.
-bool DIDescriptor::isGlobal() const {
- return isGlobalVariable();
-}
-
/// isUnspecifiedParmeter - Return true if the specified tag is
/// DW_TAG_unspecified_parameters.
bool DIDescriptor::isUnspecifiedParameter() const {
case dwarf::DW_TAG_lexical_block:
case dwarf::DW_TAG_subprogram:
case dwarf::DW_TAG_namespace:
+ case dwarf::DW_TAG_file_type:
return true;
default:
break;
}
- return false;
+ return isType();
}
/// isTemplateTypeParameter - Return true if the specified tag is
// Simple Descriptor Constructors and other Methods
//===----------------------------------------------------------------------===//
-DIType::DIType(const MDNode *N) : DIScope(N) {
- if (!N) return;
- if (!isType())
- DbgNode = 0;
-}
-
unsigned DIArray::getNumElements() const {
if (!DbgNode)
return 0;
return DbgNode->getNumOperands();
}
-/// replaceAllUsesWith - Replace all uses of debug info referenced by
-/// this descriptor.
+/// replaceAllUsesWith - Replace all uses of the MDNode used by this
+/// type with the one in the passed descriptor.
void DIType::replaceAllUsesWith(DIDescriptor &D) {
- if (!DbgNode)
- return;
+
+ assert(DbgNode && "Trying to replace an unverified type!");
// Since we use a TrackingVH for the node, its easy for clients to manufacture
// legitimate situations where they want to replaceAllUsesWith() on something
}
}
-/// replaceAllUsesWith - Replace all uses of debug info referenced by
-/// this descriptor.
+/// replaceAllUsesWith - Replace all uses of the MDNode used by this
+/// type with the one in D.
void DIType::replaceAllUsesWith(MDNode *D) {
- if (!DbgNode)
- return;
+
+ assert(DbgNode && "Trying to replace an unverified type!");
// Since we use a TrackingVH for the node, its easy for clients to manufacture
// legitimate situations where they want to replaceAllUsesWith() on something
return DbgNode->getNumOperands() == 8;
}
+/// Check if a field at position Elt of a MDNode is a MDNode.
+/// We currently allow an empty string and an integer.
+/// But we don't allow a non-empty string in a MDNode field.
+static bool fieldIsMDNode(const MDNode *DbgNode, unsigned Elt) {
+ // FIXME: This function should return true, if the field is null or the field
+ // is indeed a MDNode: return !Fld || isa<MDNode>(Fld).
+ Value *Fld = getField(DbgNode, Elt);
+ if (Fld && isa<MDString>(Fld) &&
+ !cast<MDString>(Fld)->getString().empty())
+ return false;
+ return true;
+}
+
+/// Check if a field at position Elt of a MDNode is a MDString.
+static bool fieldIsMDString(const MDNode *DbgNode, unsigned Elt) {
+ Value *Fld = getField(DbgNode, Elt);
+ return !Fld || isa<MDString>(Fld);
+}
+
+/// Check if a value can be a reference to a type.
+static bool isTypeRef(const Value *Val) {
+ return !Val ||
+ (isa<MDString>(Val) && !cast<MDString>(Val)->getString().empty()) ||
+ (isa<MDNode>(Val) && DIType(cast<MDNode>(Val)).isType());
+}
+
+/// Check if a field at position Elt of a MDNode can be a reference to a type.
+static bool fieldIsTypeRef(const MDNode *DbgNode, unsigned Elt) {
+ Value *Fld = getField(DbgNode, Elt);
+ return isTypeRef(Fld);
+}
+
+/// Check if a value can be a ScopeRef.
+static bool isScopeRef(const Value *Val) {
+ return !Val ||
+ (isa<MDString>(Val) && !cast<MDString>(Val)->getString().empty()) ||
+ (isa<MDNode>(Val) && DIScope(cast<MDNode>(Val)).isScope());
+}
+
+/// Check if a field at position Elt of a MDNode can be a ScopeRef.
+static bool fieldIsScopeRef(const MDNode *DbgNode, unsigned Elt) {
+ Value *Fld = getField(DbgNode, Elt);
+ return isScopeRef(Fld);
+}
+
/// Verify - Verify that a type descriptor is well formed.
bool DIType::Verify() const {
if (!isType())
return false;
+ // Make sure Context @ field 2 is MDNode.
+ if (!fieldIsScopeRef(DbgNode, 2))
+ return false;
+
// FIXME: Sink this into the various subclass verifies.
- unsigned Tag = getTag();
+ uint16_t Tag = getTag();
if (!isBasicType() && Tag != dwarf::DW_TAG_const_type &&
Tag != dwarf::DW_TAG_volatile_type && Tag != dwarf::DW_TAG_pointer_type &&
Tag != dwarf::DW_TAG_ptr_to_member_type &&
/// Verify - Verify that a derived type descriptor is well formed.
bool DIDerivedType::Verify() const {
+ // Make sure DerivedFrom @ field 9 is MDNode.
+ if (!fieldIsMDNode(DbgNode, 9))
+ return false;
+ if (getTag() == dwarf::DW_TAG_ptr_to_member_type)
+ // Make sure ClassType @ field 10 is a TypeRef.
+ if (!fieldIsTypeRef(DbgNode, 10))
+ return false;
+
return isDerivedType() && DbgNode->getNumOperands() >= 10 &&
DbgNode->getNumOperands() <= 14;
}
if (!isCompositeType())
return false;
- return DbgNode->getNumOperands() >= 10 && DbgNode->getNumOperands() <= 14;
+ // Make sure DerivedFrom @ field 9 and ContainingType @ field 12 are MDNodes.
+ if (!fieldIsMDNode(DbgNode, 9))
+ return false;
+ if (!fieldIsTypeRef(DbgNode, 12))
+ return false;
+
+ // Make sure the type identifier at field 14 is MDString, it can be null.
+ if (!fieldIsMDString(DbgNode, 14))
+ return false;
+
+ // If this is an array type verify that we have a DIType in the derived type
+ // field as that's the type of our element.
+ if (getTag() == dwarf::DW_TAG_array_type)
+ if (!DIType(getTypeDerivedFrom()))
+ return false;
+
+ return DbgNode->getNumOperands() == 15;
}
/// Verify - Verify that a subprogram descriptor is well formed.
if (!isSubprogram())
return false;
+ // Make sure context @ field 2 and type @ field 7 are MDNodes.
+ if (!fieldIsMDNode(DbgNode, 2))
+ return false;
+ if (!fieldIsMDNode(DbgNode, 7))
+ return false;
+ // Containing type @ field 12.
+ if (!fieldIsTypeRef(DbgNode, 12))
+ return false;
return DbgNode->getNumOperands() == 20;
}
if (getDisplayName().empty())
return false;
+ // Make sure context @ field 2 and type @ field 8 are MDNodes.
+ if (!fieldIsMDNode(DbgNode, 2))
+ return false;
+ if (!fieldIsMDNode(DbgNode, 8))
+ return false;
+ // Make sure StaticDataMemberDeclaration @ field 12 is MDNode.
+ if (!fieldIsMDNode(DbgNode, 12))
+ return false;
return DbgNode->getNumOperands() == 13;
}
if (!isVariable())
return false;
+ // Make sure context @ field 1 and type @ field 5 are MDNodes.
+ if (!fieldIsMDNode(DbgNode, 1))
+ return false;
+ if (!fieldIsMDNode(DbgNode, 5))
+ return false;
return DbgNode->getNumOperands() >= 8;
}
/// getOriginalTypeSize - If this type is derived from a base type then
/// return base type size.
uint64_t DIDerivedType::getOriginalTypeSize() const {
- unsigned Tag = getTag();
+ uint16_t Tag = getTag();
if (Tag != dwarf::DW_TAG_member && Tag != dwarf::DW_TAG_typedef &&
Tag != dwarf::DW_TAG_const_type && Tag != dwarf::DW_TAG_volatile_type &&
return getNodeField(DbgNode, 10);
}
+MDString *DICompositeType::getIdentifier() const {
+ return cast_or_null<MDString>(getField(DbgNode, 14));
+}
+
+#ifndef NDEBUG
+static void VerifySubsetOf(const MDNode *LHS, const MDNode *RHS) {
+ for (unsigned i = 0; i != LHS->getNumOperands(); ++i) {
+ // Skip the 'empty' list (that's a single i32 0, rather than truly empty).
+ if (i == 0 && isa<ConstantInt>(LHS->getOperand(i)))
+ continue;
+ const MDNode *E = cast<MDNode>(LHS->getOperand(i));
+ bool found = false;
+ for (unsigned j = 0; !found && j != RHS->getNumOperands(); ++j)
+ found = E == RHS->getOperand(j);
+ assert(found && "Losing a member during member list replacement");
+ }
+}
+#endif
+
/// \brief Set the array of member DITypes.
void DICompositeType::setTypeArray(DIArray Elements, DIArray TParams) {
- assert((!TParams || DbgNode->getNumOperands() == 14) &&
+ assert((!TParams || DbgNode->getNumOperands() == 15) &&
"If you're setting the template parameters this should include a slot "
"for that!");
TrackingVH<MDNode> N(*this);
- N->replaceOperandWith(10, Elements);
+ if (Elements) {
+#ifndef NDEBUG
+ // Check that the new list of members contains all the old members as well.
+ if (const MDNode *El = cast_or_null<MDNode>(N->getOperand(10)))
+ VerifySubsetOf(El, Elements);
+#endif
+ N->replaceOperandWith(10, Elements);
+ }
if (TParams)
N->replaceOperandWith(13, TParams);
DbgNode = N;
}
+void DICompositeType::addMember(DIDescriptor D) {
+ SmallVector<llvm::Value *, 16> M;
+ DIArray OrigM = getTypeArray();
+ unsigned Elements = OrigM.getNumElements();
+ if (Elements == 1 && !OrigM.getElement(0))
+ Elements = 0;
+ M.reserve(Elements + 1);
+ for (unsigned i = 0; i != Elements; ++i)
+ M.push_back(OrigM.getElement(i));
+ M.push_back(D);
+ setTypeArray(DIArray(MDNode::get(DbgNode->getContext(), M)));
+}
+
+/// Generate a reference to this DIType. Uses the type identifier instead
+/// of the actual MDNode if possible, to help type uniquing.
+DIScopeRef DIScope::generateRef() {
+ if (!isCompositeType())
+ return DIScopeRef(*this);
+ DICompositeType DTy(DbgNode);
+ if (!DTy.getIdentifier())
+ return DIScopeRef(*this);
+ return DIScopeRef(DTy.getIdentifier());
+}
+
/// \brief Set the containing type.
void DICompositeType::setContainingType(DICompositeType ContainingType) {
TrackingVH<MDNode> N(*this);
- N->replaceOperandWith(12, ContainingType);
+ N->replaceOperandWith(12, ContainingType.generateRef());
DbgNode = N;
}
return getField(DbgNode, 4);
}
+// If the current node has a parent scope then return that,
+// else return an empty scope.
+DIScopeRef DIScope::getContext() const {
+
+ if (isType())
+ return DIType(DbgNode).getContext();
+
+ if (isSubprogram())
+ return DIScopeRef(DISubprogram(DbgNode).getContext());
+
+ if (isLexicalBlock())
+ return DIScopeRef(DILexicalBlock(DbgNode).getContext());
+
+ if (isLexicalBlockFile())
+ return DIScopeRef(DILexicalBlockFile(DbgNode).getContext());
+
+ if (isNameSpace())
+ return DIScopeRef(DINameSpace(DbgNode).getContext());
+
+ assert((isFile() || isCompileUnit()) && "Unhandled type of scope.");
+ return DIScopeRef(NULL);
+}
+
StringRef DIScope::getFilename() const {
if (!DbgNode)
return StringRef();
return DICompositeType();
}
-/// isSubprogramContext - Return true if Context is either a subprogram
-/// or another context nested inside a subprogram.
-bool llvm::isSubprogramContext(const MDNode *Context) {
- if (!Context)
- return false;
- DIDescriptor D(Context);
- if (D.isSubprogram())
- return true;
- if (D.isType())
- return isSubprogramContext(DIType(Context).getContext());
- return false;
+/// Update DITypeIdentifierMap by going through retained types of each CU.
+DITypeIdentifierMap llvm::generateDITypeIdentifierMap(
+ const NamedMDNode *CU_Nodes) {
+ DITypeIdentifierMap Map;
+ for (unsigned CUi = 0, CUe = CU_Nodes->getNumOperands(); CUi != CUe; ++CUi) {
+ DICompileUnit CU(CU_Nodes->getOperand(CUi));
+ DIArray Retain = CU.getRetainedTypes();
+ for (unsigned Ti = 0, Te = Retain.getNumElements(); Ti != Te; ++Ti) {
+ if (!Retain.getElement(Ti).isCompositeType())
+ continue;
+ DICompositeType Ty(Retain.getElement(Ti));
+ if (MDString *TypeId = Ty.getIdentifier()) {
+ // Definition has priority over declaration.
+ // Try to insert (TypeId, Ty) to Map.
+ std::pair<DITypeIdentifierMap::iterator, bool> P =
+ Map.insert(std::make_pair(TypeId, Ty));
+ // If TypeId already exists in Map and this is a definition, replace
+ // whatever we had (declaration or definition) with the definition.
+ if (!P.second && !Ty.isForwardDecl())
+ P.first->second = Ty;
+ }
+ }
+ }
+ return Map;
}
//===----------------------------------------------------------------------===//
TYs.clear();
Scopes.clear();
NodesSeen.clear();
+ TypeIdentifierMap.clear();
}
/// processModule - Process entire module and collect debug info.
void DebugInfoFinder::processModule(const Module &M) {
if (NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu")) {
+ TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes);
for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) {
DICompileUnit CU(CU_Nodes->getOperand(i));
addCompileUnit(CU);
DIArray RetainedTypes = CU.getRetainedTypes();
for (unsigned i = 0, e = RetainedTypes.getNumElements(); i != e; ++i)
processType(DIType(RetainedTypes.getElement(i)));
+ DIArray Imports = CU.getImportedEntities();
+ for (unsigned i = 0, e = Imports.getNumElements(); i != e; ++i) {
+ DIImportedEntity Import = DIImportedEntity(
+ Imports.getElement(i));
+ DIDescriptor Entity = Import.getEntity();
+ if (Entity.isType())
+ processType(DIType(Entity));
+ else if (Entity.isSubprogram())
+ processSubprogram(DISubprogram(Entity));
+ else if (Entity.isNameSpace())
+ processScope(DINameSpace(Entity).getContext());
+ }
// FIXME: We really shouldn't be bailing out after visiting just one CU
return;
}
/// processLocation - Process DILocation.
void DebugInfoFinder::processLocation(DILocation Loc) {
- if (!Loc.Verify()) return;
- DIDescriptor S(Loc.getScope());
- if (S.isCompileUnit())
- addCompileUnit(DICompileUnit(S));
- else if (S.isSubprogram())
- processSubprogram(DISubprogram(S));
- else if (S.isLexicalBlock())
- processLexicalBlock(DILexicalBlock(S));
- else if (S.isLexicalBlockFile()) {
- DILexicalBlockFile DBF = DILexicalBlockFile(S);
- processLexicalBlock(DILexicalBlock(DBF.getScope()));
- }
+ if (!Loc) return;
+ processScope(Loc.getScope());
processLocation(Loc.getOrigLocation());
}
void DebugInfoFinder::processType(DIType DT) {
if (!addType(DT))
return;
- processScope(DT.getContext());
+ processScope(DT.getContext().resolve(TypeIdentifierMap));
if (DT.isCompositeType()) {
DICompositeType DCT(DT);
processType(DCT.getTypeDerivedFrom());
return;
processScope(SP.getContext());
processType(SP.getType());
+ DIArray TParams = SP.getTemplateParams();
+ for (unsigned I = 0, E = TParams.getNumElements(); I != E; ++I) {
+ DIDescriptor Element = TParams.getElement(I);
+ if (Element.isTemplateTypeParameter()) {
+ DITemplateTypeParameter TType(Element);
+ processScope(TType.getContext());
+ processType(TType.getType());
+ } else if (Element.isTemplateValueParameter()) {
+ DITemplateValueParameter TVal(Element);
+ processScope(TVal.getContext());
+ processType(TVal.getType());
+ }
+ }
}
/// processDeclare - Process DbgDeclareInst.
if (!NodesSeen.insert(DV))
return;
+ processScope(DIVariable(N).getContext());
processType(DIVariable(N).getType());
}
/// addType - Add type into Tys.
bool DebugInfoFinder::addType(DIType DT) {
- if (!DT.isValid())
+ if (!DT)
return false;
if (!NodesSeen.insert(DT))
/// addCompileUnit - Add compile unit into CUs.
bool DebugInfoFinder::addCompileUnit(DICompileUnit CU) {
- if (!CU.Verify())
+ if (!CU)
return false;
-
if (!NodesSeen.insert(CU))
return false;
/// addGlobalVariable - Add global variable into GVs.
bool DebugInfoFinder::addGlobalVariable(DIGlobalVariable DIG) {
- if (!DIDescriptor(DIG).isGlobalVariable())
+ if (!DIG)
return false;
if (!NodesSeen.insert(DIG))
// addSubprogram - Add subprgoram into SPs.
bool DebugInfoFinder::addSubprogram(DISubprogram SP) {
- if (!DIDescriptor(SP).isSubprogram())
+ if (!SP)
return false;
if (!NodesSeen.insert(SP))
bool DebugInfoFinder::addScope(DIScope Scope) {
if (!Scope)
return false;
+ // FIXME: Ocaml binding generates a scope with no content, we treat it
+ // as null for now.
+ if (Scope->getNumOperands() == 0)
+ return false;
if (!NodesSeen.insert(Scope))
return false;
Scopes.push_back(Scope);
}
}
}
+
+/// Specialize constructor to make sure it has the correct type.
+template <>
+DIRef<DIScope>::DIRef(const Value *V) : Val(V) {
+ assert(isScopeRef(V) && "DIScopeRef should be a MDString or MDNode");
+}
+template <>
+DIRef<DIType>::DIRef(const Value *V) : Val(V) {
+ assert(isTypeRef(V) && "DITypeRef should be a MDString or MDNode");
+}
+
+/// Specialize getFieldAs to handle fields that are references to DIScopes.
+template <>
+DIScopeRef DIDescriptor::getFieldAs<DIScopeRef>(unsigned Elt) const {
+ return DIScopeRef(getField(DbgNode, Elt));
+}
+/// Specialize getFieldAs to handle fields that are references to DITypes.
+template <>
+DITypeRef DIDescriptor::getFieldAs<DITypeRef>(unsigned Elt) const {
+ return DITypeRef(getField(DbgNode, Elt));
+}
+
+DIScopeRef DIType::getContext() const {
+ return getFieldAs<DIScopeRef>(2);
+}