There are several bugfixes in this update, but the most important one is to ensure __start_ and __stop_ symbols for linker sets and kernel module metadata are always emitted in object files: http://llvm.org/bugs/show_bug.cgi?id=9292 Before this fix, if you compiled kernel modules with clang, they would not be properly processed by kldxref, and if they had any dependencies, the kernel would fail to load those. Another problem occurred when attempting to mount a tmpfs filesystem, which would result in 'operation not supported by device'.
382 lines
11 KiB
C++
382 lines
11 KiB
C++
//===--- DocumentXML.cpp - XML document for ASTs --------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the XML document class, which provides the means to
|
|
// dump out the AST in a XML form that exposes type details and other fields.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Frontend/DocumentXML.h"
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/AST/DeclCXX.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/Basic/SourceManager.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Config/config.h"
|
|
#include <cstdio>
|
|
|
|
namespace clang {
|
|
|
|
//---------------------------------------------------------
|
|
DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
|
|
Out(out),
|
|
Ctx(0),
|
|
HasCurrentNodeSubNodes(false) {
|
|
NodeStack.push(rootName);
|
|
Out << "<?xml version=\"1.0\"?>\n<" << rootName;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
DocumentXML& DocumentXML::addSubNode(const std::string& name) {
|
|
if (!HasCurrentNodeSubNodes)
|
|
Out << ">\n";
|
|
NodeStack.push(name);
|
|
HasCurrentNodeSubNodes = false;
|
|
Indent();
|
|
Out << "<" << NodeStack.top();
|
|
return *this;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::Indent() {
|
|
for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i)
|
|
Out << ' ';
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
DocumentXML& DocumentXML::toParent() {
|
|
assert(NodeStack.size() > 1 && "too much backtracking");
|
|
|
|
if (HasCurrentNodeSubNodes) {
|
|
Indent();
|
|
Out << "</" << NodeStack.top() << ">\n";
|
|
} else
|
|
Out << "/>\n";
|
|
NodeStack.pop();
|
|
HasCurrentNodeSubNodes = true;
|
|
return *this;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
namespace {
|
|
|
|
enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST };
|
|
|
|
unsigned getNewId(tIdType idType) {
|
|
static unsigned int idCounts[ID_LAST] = { 0 };
|
|
return ++idCounts[idType];
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
inline std::string getPrefixedId(unsigned uId, tIdType idType) {
|
|
static const char idPrefix[ID_LAST] = { '_', 'f', 'l' };
|
|
char buffer[20];
|
|
char* BufPtr = llvm::utohex_buffer(uId, buffer + 20);
|
|
*--BufPtr = idPrefix[idType];
|
|
return BufPtr;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
template<class T, class V>
|
|
bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL) {
|
|
typename T::iterator i = idMap.find(value);
|
|
bool toAdd = i == idMap.end();
|
|
if (toAdd)
|
|
idMap.insert(typename T::value_type(value, getNewId(idType)));
|
|
return toAdd;
|
|
}
|
|
|
|
} // anon NS
|
|
|
|
|
|
//---------------------------------------------------------
|
|
std::string DocumentXML::escapeString(const char* pStr,
|
|
std::string::size_type len) {
|
|
std::string value;
|
|
value.reserve(len + 1);
|
|
char buffer[16];
|
|
for (unsigned i = 0; i < len; ++i) {
|
|
switch (char C = pStr[i]) {
|
|
default:
|
|
if (isprint(C))
|
|
value += C;
|
|
else {
|
|
#ifdef LLVM_ON_WIN32
|
|
sprintf(buffer, "\\%03o", C);
|
|
#else
|
|
snprintf(buffer, sizeof(buffer), "\\%03o", C);
|
|
#endif
|
|
value += buffer;
|
|
}
|
|
break;
|
|
|
|
case '\n': value += "\\n"; break;
|
|
case '\t': value += "\\t"; break;
|
|
case '\a': value += "\\a"; break;
|
|
case '\b': value += "\\b"; break;
|
|
case '\r': value += "\\r"; break;
|
|
|
|
case '&': value += "&"; break;
|
|
case '<': value += "<"; break;
|
|
case '>': value += ">"; break;
|
|
case '"': value += """; break;
|
|
case '\'': value += "'"; break;
|
|
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::finalize() {
|
|
assert(NodeStack.size() == 1 && "not completely backtracked");
|
|
|
|
addSubNode("ReferenceSection");
|
|
addSubNode("Types");
|
|
|
|
for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
|
|
i != e; ++i) {
|
|
if (i->first.hasLocalQualifiers()) {
|
|
writeTypeToXML(i->first);
|
|
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
|
|
toParent();
|
|
}
|
|
}
|
|
|
|
for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(),
|
|
e = BasicTypes.end(); i != e; ++i) {
|
|
writeTypeToXML(i->first);
|
|
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
|
|
toParent();
|
|
}
|
|
|
|
|
|
toParent().addSubNode("Contexts");
|
|
|
|
for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(),
|
|
e = Contexts.end(); i != e; ++i) {
|
|
addSubNode(i->first->getDeclKindName());
|
|
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
|
|
if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first))
|
|
addAttribute("name", ND->getNameAsString());
|
|
if (const TagDecl *TD = dyn_cast<TagDecl>(i->first))
|
|
addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL));
|
|
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first))
|
|
addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAs<FunctionType>()], ID_NORMAL));
|
|
|
|
if (const DeclContext* parent = i->first->getParent())
|
|
addAttribute("context", parent);
|
|
toParent();
|
|
}
|
|
|
|
toParent().addSubNode("Files");
|
|
|
|
for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(),
|
|
e = SourceFiles.end(); i != e; ++i) {
|
|
addSubNode("File");
|
|
addAttribute("id", getPrefixedId(i->second, ID_FILE));
|
|
addAttribute("name", escapeString(i->first.c_str(), i->first.size()));
|
|
toParent();
|
|
}
|
|
|
|
toParent().toParent();
|
|
|
|
// write the root closing node (which has always subnodes)
|
|
Out << "</" << NodeStack.top() << ">\n";
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addAttribute(const char* pAttributeName,
|
|
const QualType& pType) {
|
|
addTypeRecursively(pType);
|
|
addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addPtrAttribute(const char* pAttributeName,
|
|
const Type* pType) {
|
|
addTypeRecursively(pType);
|
|
addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addPtrAttribute(const char* pAttributeName,
|
|
const NestedNameSpecifier* pNNS) {
|
|
switch (pNNS->getKind()) {
|
|
case NestedNameSpecifier::Identifier: {
|
|
IdentifierInfo *ii = pNNS->getAsIdentifier();
|
|
// FIXME how should we handle those ?
|
|
addPtrAttribute(pAttributeName, ii->getName().data());
|
|
break;
|
|
}
|
|
case NestedNameSpecifier::Namespace: {
|
|
addPtrAttribute(pAttributeName, pNNS->getAsNamespace());
|
|
break;
|
|
}
|
|
case NestedNameSpecifier::NamespaceAlias: {
|
|
addPtrAttribute(pAttributeName, pNNS->getAsNamespaceAlias());
|
|
break;
|
|
}
|
|
case NestedNameSpecifier::TypeSpec: {
|
|
addPtrAttribute(pAttributeName, pNNS->getAsType());
|
|
break;
|
|
}
|
|
case NestedNameSpecifier::TypeSpecWithTemplate: {
|
|
addPtrAttribute(pAttributeName, pNNS->getAsType());
|
|
break;
|
|
}
|
|
case NestedNameSpecifier::Global: {
|
|
addPtrAttribute(pAttributeName, "::");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addTypeRecursively(const QualType& pType)
|
|
{
|
|
if (addToMap(Types, pType))
|
|
{
|
|
addTypeRecursively(pType.getTypePtr());
|
|
// beautifier: a non-qualified type shall be transparent
|
|
if (!pType.hasLocalQualifiers())
|
|
{
|
|
Types[pType] = BasicTypes[pType.getTypePtr()];
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addTypeRecursively(const Type* pType)
|
|
{
|
|
if (addToMap(BasicTypes, pType))
|
|
{
|
|
addParentTypes(pType);
|
|
/*
|
|
// FIXME: doesn't work in the immediate streaming approach
|
|
if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType))
|
|
{
|
|
addSubNode("VariableArraySizeExpression");
|
|
PrintStmt(VAT->getSizeExpr());
|
|
toParent();
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC)
|
|
{
|
|
addContextsRecursively(DC);
|
|
addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D)
|
|
{
|
|
if (const DeclContext* DC = dyn_cast<DeclContext>(D))
|
|
{
|
|
addContextsRecursively(DC);
|
|
addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL));
|
|
}
|
|
else
|
|
{
|
|
addToMap(Decls, D);
|
|
addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL));
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D)
|
|
{
|
|
addPtrAttribute(pName, static_cast<const DeclContext*>(D));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addContextsRecursively(const DeclContext *DC)
|
|
{
|
|
if (DC != 0 && addToMap(Contexts, DC))
|
|
{
|
|
addContextsRecursively(DC->getParent());
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addSourceFileAttribute(const std::string& fileName)
|
|
{
|
|
addToMap(SourceFiles, fileName, ID_FILE);
|
|
addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE));
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L)
|
|
{
|
|
addToMap(Labels, L, ID_LABEL);
|
|
addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL));
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc)
|
|
{
|
|
SourceManager& SM = Ctx->getSourceManager();
|
|
SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
|
|
PresumedLoc PLoc;
|
|
if (!SpellingLoc.isInvalid())
|
|
{
|
|
PLoc = SM.getPresumedLoc(SpellingLoc);
|
|
if (PLoc.isValid()) {
|
|
addSourceFileAttribute(PLoc.getFilename());
|
|
addAttribute("line", PLoc.getLine());
|
|
addAttribute("col", PLoc.getColumn());
|
|
}
|
|
}
|
|
// else there is no error in some cases (eg. CXXThisExpr)
|
|
return PLoc;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::addLocationRange(const SourceRange& R)
|
|
{
|
|
PresumedLoc PStartLoc = addLocation(R.getBegin());
|
|
if (R.getBegin() != R.getEnd())
|
|
{
|
|
SourceManager& SM = Ctx->getSourceManager();
|
|
SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd());
|
|
if (!SpellingLoc.isInvalid())
|
|
{
|
|
PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
|
|
if (PLoc.isInvalid()) {
|
|
} else if (PStartLoc.isInvalid() ||
|
|
strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) {
|
|
addToMap(SourceFiles, PLoc.getFilename(), ID_FILE);
|
|
addAttribute("endfile", PLoc.getFilename());
|
|
addAttribute("endline", PLoc.getLine());
|
|
addAttribute("endcol", PLoc.getColumn());
|
|
} else if (PLoc.getLine() != PStartLoc.getLine()) {
|
|
addAttribute("endline", PLoc.getLine());
|
|
addAttribute("endcol", PLoc.getColumn());
|
|
} else {
|
|
addAttribute("endcol", PLoc.getColumn());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
void DocumentXML::PrintDecl(Decl *D)
|
|
{
|
|
writeDeclToXML(D);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
} // NS clang
|
|
|