#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
-#include "llvm/IR/Metadata.h"
+#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/ErrorHandling.h"
typedef DenseMap<const MDString *, MDNode *> DITypeIdentifierMap;
class DIHeaderFieldIterator
- : public std::iterator<std::forward_iterator_tag, StringRef, std::ptrdiff_t,
+ : public std::iterator<std::input_iterator_tag, StringRef, std::ptrdiff_t,
const StringRef *, StringRef> {
StringRef Header;
StringRef Current;
explicit DIHeaderFieldIterator(StringRef Header)
: Header(Header), Current(Header.slice(0, Header.find('\0'))) {}
StringRef operator*() const { return Current; }
- const StringRef * operator->() const { return &Current; }
+ const StringRef *operator->() const { return &Current; }
DIHeaderFieldIterator &operator++() {
increment();
return *this;
// FIXME: This operator bool isn't actually protecting anything at the
// moment due to the conversion operator above making DIDescriptor nodes
// implicitly convertable to bool.
- LLVM_EXPLICIT operator bool() const { return DbgNode != nullptr; }
+ explicit operator bool() const { return DbgNode != nullptr; }
bool operator==(DIDescriptor Other) const { return DbgNode == Other.DbgNode; }
bool operator!=(DIDescriptor Other) const { return !operator==(Other); }
- StringRef getHeader() const {
- return getStringField(0);
- }
+ StringRef getHeader() const { return getStringField(0); }
size_t getNumHeaderFields() const {
return std::distance(DIHeaderFieldIterator(getHeader()),
unsigned getNumElements() const {
return DbgNode ? DbgNode->getNumOperands() : 0;
}
- T getElement(unsigned Idx) const {
- return getFieldAs<T>(Idx);
- }
+ T getElement(unsigned Idx) const { return getFieldAs<T>(Idx); }
};
typedef DITypedArray<DIDescriptor> DIArray;
};
template <typename T> class DIRef;
+typedef DIRef<DIDescriptor> DIDescriptorRef;
typedef DIRef<DIScope> DIScopeRef;
typedef DIRef<DIType> DITypeRef;
typedef DITypedArray<DITypeRef> DITypeArray;
return MS->getString();
}
+/// \brief Handle fields that are references to DIDescriptors.
+template <>
+DIDescriptorRef DIDescriptor::getFieldAs<DIDescriptorRef>(unsigned Elt) const;
+/// \brief Specialize DIRef constructor for DIDescriptorRef.
+template <> DIRef<DIDescriptor>::DIRef(const Metadata *V);
+
/// \brief Handle fields that are references to DIScopes.
template <> DIScopeRef DIDescriptor::getFieldAs<DIScopeRef>(unsigned Elt) const;
/// \brief Specialize DIRef constructor for DIScopeRef.
public:
explicit DIType(const MDNode *N = nullptr) : DIScope(N) {}
- operator DITypeRef () const {
+ operator DITypeRef() const {
assert(isType() &&
"constructing DITypeRef from an MDNode that is not a type");
return DITypeRef(&*getRef());
DIScopeRef getContext() const { return getFieldAs<DIScopeRef>(2); }
StringRef getName() const { return getHeaderField(1); }
- unsigned getLineNumber() const {
- return getHeaderFieldAs<unsigned>(2);
- }
- uint64_t getSizeInBits() const {
- return getHeaderFieldAs<unsigned>(3);
- }
- uint64_t getAlignInBits() const {
- return getHeaderFieldAs<unsigned>(4);
- }
+ unsigned getLineNumber() const { return getHeaderFieldAs<unsigned>(2); }
+ uint64_t getSizeInBits() const { return getHeaderFieldAs<unsigned>(3); }
+ uint64_t getAlignInBits() const { return getHeaderFieldAs<unsigned>(4); }
// FIXME: Offset is only used for DW_TAG_member nodes. Making every type
// carry this is just plain insane.
- uint64_t getOffsetInBits() const {
- return getHeaderFieldAs<unsigned>(5);
- }
+ uint64_t getOffsetInBits() const { return getHeaderFieldAs<unsigned>(5); }
unsigned getFlags() const { return getHeaderFieldAs<unsigned>(6); }
bool isPrivate() const {
return (getFlags() & FlagAccessibility) == FlagPrivate;
private:
template <typename T>
void setArrays(DITypedArray<T> Elements, DIArray TParams = DIArray()) {
- assert((!TParams || DbgNode->getNumOperands() == 8) &&
- "If you're setting the template parameters this should include a slot "
- "for that!");
+ assert(
+ (!TParams || DbgNode->getNumOperands() == 8) &&
+ "If you're setting the template parameters this should include a slot "
+ "for that!");
setArraysHelper(Elements, TParams);
}
public:
- unsigned getRunTimeLang() const {
- return getHeaderFieldAs<unsigned>(7);
- }
+ unsigned getRunTimeLang() const { return getHeaderFieldAs<unsigned>(7); }
DITypeRef getContainingType() const { return getFieldAs<DITypeRef>(5); }
private:
unsigned isRValueReference() const {
return (getFlags() & FlagRValueReference) != 0;
}
-
};
/// \brief This is a wrapper for a lexical block.
public:
explicit DILexicalBlock(const MDNode *N = nullptr) : DIScope(N) {}
DIScope getContext() const { return getFieldAs<DIScope>(2); }
- unsigned getLineNumber() const {
- return getHeaderFieldAs<unsigned>(1);
- }
- unsigned getColumnNumber() const {
- return getHeaderFieldAs<unsigned>(2);
- }
+ unsigned getLineNumber() const { return getHeaderFieldAs<unsigned>(1); }
+ unsigned getColumnNumber() const { return getHeaderFieldAs<unsigned>(2); }
bool Verify() const;
};
public:
explicit DILexicalBlockFile(const MDNode *N = nullptr) : DIScope(N) {}
DIScope getContext() const {
+ // FIXME: This logic is horrible. getScope() returns a DILexicalBlock, but
+ // then we check if it's a subprogram? WHAT?!?
if (getScope().isSubprogram())
return getScope();
return getScope().getContext();
class DITemplateTypeParameter : public DIDescriptor {
public:
explicit DITemplateTypeParameter(const MDNode *N = nullptr)
- : DIDescriptor(N) {}
+ : DIDescriptor(N) {}
StringRef getName() const { return getHeaderField(1); }
- unsigned getLineNumber() const { return getHeaderFieldAs<unsigned>(2); }
- unsigned getColumnNumber() const { return getHeaderFieldAs<unsigned>(3); }
DIScopeRef getContext() const { return getFieldAs<DIScopeRef>(1); }
DITypeRef getType() const { return getFieldAs<DITypeRef>(2); }
- StringRef getFilename() const { return getFieldAs<DIFile>(3).getFilename(); }
- StringRef getDirectory() const {
- return getFieldAs<DIFile>(3).getDirectory();
- }
bool Verify() const;
};
class DITemplateValueParameter : public DIDescriptor {
public:
explicit DITemplateValueParameter(const MDNode *N = nullptr)
- : DIDescriptor(N) {}
+ : DIDescriptor(N) {}
StringRef getName() const { return getHeaderField(1); }
- unsigned getLineNumber() const { return getHeaderFieldAs<unsigned>(2); }
- unsigned getColumnNumber() const { return getHeaderFieldAs<unsigned>(3); }
DIScopeRef getContext() const { return getFieldAs<DIScopeRef>(1); }
DITypeRef getType() const { return getFieldAs<DITypeRef>(2); }
Metadata *getValue() const;
- StringRef getFilename() const { return getFieldAs<DIFile>(4).getFilename(); }
- StringRef getDirectory() const {
- return getFieldAs<DIFile>(4).getDirectory();
- }
bool Verify() const;
};
void printExtendedName(raw_ostream &OS) const;
};
-/// \brief A complex location expression.
+/// \brief A complex location expression in postfix notation.
+///
+/// This is (almost) a DWARF expression that modifies the location of a
+/// variable or (or the location of a single piece of a variable).
+///
+/// FIXME: Instead of DW_OP_plus taking an argument, this should use DW_OP_const
+/// and have DW_OP_plus consume the topmost elements on the stack.
class DIExpression : public DIDescriptor {
friend class DIDescriptor;
void printInternal(raw_ostream &OS) const;
uint64_t getElement(unsigned Idx) const;
/// \brief Return whether this is a piece of an aggregate variable.
- bool isVariablePiece() const;
- /// \brief Return the offset of this piece in bytes.
- uint64_t getPieceOffset() const;
- /// \brief Return the size of this piece in bytes.
- uint64_t getPieceSize() const;
+ bool isBitPiece() const;
+ /// \brief Return the offset of this piece in bits.
+ uint64_t getBitPieceOffset() const;
+ /// \brief Return the size of this piece in bits.
+ uint64_t getBitPieceSize() const;
+
+ class iterator;
+ /// \brief A lightweight wrapper around an element of a DIExpression.
+ class Operand {
+ friend class iterator;
+ DIHeaderFieldIterator I;
+ Operand() {}
+ Operand(DIHeaderFieldIterator I) : I(I) {}
+ public:
+ /// \brief Operands such as DW_OP_piece have explicit (non-stack) arguments.
+ /// Argument 0 is the operand itself.
+ uint64_t getArg(unsigned N) const {
+ DIHeaderFieldIterator In = I;
+ std::advance(In, N);
+ return In.getNumber<uint64_t>();
+ }
+ operator uint64_t () const { return I.getNumber<uint64_t>(); }
+ /// \brief Returns underlying DIHeaderFieldIterator.
+ const DIHeaderFieldIterator &getBase() const { return I; }
+ /// \brief Returns the next operand.
+ Operand getNext() const;
+ };
/// \brief An iterator for DIExpression elements.
- class iterator
- : public std::iterator<std::forward_iterator_tag, StringRef, unsigned,
- const uint64_t *, uint64_t> {
+ class iterator : public std::iterator<std::input_iterator_tag, StringRef,
+ unsigned, const Operand*, Operand> {
+ friend class Operand;
DIHeaderFieldIterator I;
+ Operand Tmp;
iterator(DIHeaderFieldIterator I) : I(I) {}
public:
iterator() {}
iterator(const DIExpression &Expr) : I(++Expr.header_begin()) {}
- uint64_t operator*() const { return I.getNumber<uint64_t>(); }
+ const Operand &operator*() { return Tmp = Operand(I); }
+ const Operand *operator->() { return &(Tmp = Operand(I)); }
iterator &operator++() {
increment();
return *this;
increment();
return X;
}
- bool operator==(const iterator &X) const {
- return I == X.I;
- }
- bool operator!=(const iterator &X) const {
- return !(*this == X);
- }
-
- uint64_t getArg(unsigned N) const {
- auto In = I;
- std::advance(In, N);
- return In.getNumber<uint64_t>();
- }
-
- const DIHeaderFieldIterator& getBase() const { return I; }
-
+ bool operator==(const iterator &X) const { return I == X.I; }
+ bool operator!=(const iterator &X) const { return !(*this == X); }
+
private:
void increment() {
switch (**this) {
- case dwarf::DW_OP_piece: std::advance(I, 3); break;
- case dwarf::DW_OP_plus: std::advance(I, 2); break;
- case dwarf::DW_OP_deref: std::advance(I, 1); break;
+ case dwarf::DW_OP_bit_piece: std::advance(I, 3); break;
+ case dwarf::DW_OP_plus: std::advance(I, 2); break;
+ case dwarf::DW_OP_deref: std::advance(I, 1); break;
default:
- assert("unsupported operand");
+ llvm_unreachable("unsupported operand");
}
}
};
public:
explicit DIImportedEntity(const MDNode *N) : DIDescriptor(N) {}
DIScope getContext() const { return getFieldAs<DIScope>(1); }
- DIScopeRef getEntity() const { return getFieldAs<DIScopeRef>(2); }
+ DIDescriptorRef getEntity() const { return getFieldAs<DIDescriptorRef>(2); }
unsigned getLineNumber() const { return getHeaderFieldAs<unsigned>(1); }
StringRef getName() const { return getHeaderField(2); }
bool Verify() const;
public:
typedef SmallVectorImpl<DICompileUnit>::const_iterator compile_unit_iterator;
typedef SmallVectorImpl<DISubprogram>::const_iterator subprogram_iterator;
- typedef SmallVectorImpl<DIGlobalVariable>::const_iterator global_variable_iterator;
+ typedef SmallVectorImpl<DIGlobalVariable>::const_iterator
+ global_variable_iterator;
typedef SmallVectorImpl<DIType>::const_iterator type_iterator;
typedef SmallVectorImpl<DIScope>::const_iterator scope_iterator;