blob: 53ec507714dcccfca74c9a6314fb7b57aa59be6c [file] [log] [blame]
//===-------------- Debug.cpp - Debug information gathering ---------------===//
//
// Copyright (C) 2005 to 2013 Jim Laskey, Duncan Sands et al.
//
// This file is part of DragonEgg.
//
// DragonEgg is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later version.
//
// DragonEgg is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// DragonEgg; see the file COPYING. If not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
//
//===----------------------------------------------------------------------===//
// This file implements debug information gathering.
//===----------------------------------------------------------------------===//
// Plugin headers
#include "dragonegg/Debug.h"
// LLVM headers
#include "llvm/IR/Module.h"
// System headers
#include <gmp.h>
// GCC headers
#include "auto-host.h"
#ifndef ENABLE_BUILD_WITH_CXX
#include <cstring> // Otherwise included by system.h with C linkage.
extern "C" {
#endif
#include "config.h"
// Stop GCC declaring 'getopt' as it can clash with the system's declaration.
#undef HAVE_DECL_GETOPT
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "flags.h"
#include "langhooks.h"
#include "toplev.h"
#include "version.h"
#ifndef ENABLE_BUILD_WITH_CXX
} // extern "C"
#endif
// Trees header.
#include "dragonegg/Trees.h"
using namespace llvm;
using namespace llvm::dwarf;
/// DirectoryAndFile - Extract the directory and file name from a path. If no
/// directory is specified, then use the source working directory.
static void DirectoryAndFile(const std::string &FullPath,
std::string &Directory, std::string &FileName) {
// Look for the directory slash.
size_t Slash = FullPath.rfind('/');
// If no slash
if (Slash == std::string::npos) {
// The entire path is the file name.
Directory = "";
FileName = FullPath;
} else {
// Separate the directory from the file name.
Directory = FullPath.substr(0, Slash);
FileName = FullPath.substr(Slash + 1);
}
// If no directory present then use source working directory.
if (Directory.empty() || Directory[0] != '/') {
Directory = std::string(get_src_pwd()) + "/" + Directory;
}
}
/// NodeSizeInBits - Returns the size in bits stored in a tree node regardless
/// of whether the node is a TYPE or DECL.
static uint64_t NodeSizeInBits(tree Node) {
if (isa<ERROR_MARK>(Node)) {
return BITS_PER_WORD;
} else if (isa<TYPE>(Node)) {
if (TYPE_SIZE(Node) == NULL_TREE)
return 0;
else if (isInt64(TYPE_SIZE(Node), true))
return getInt64(TYPE_SIZE(Node), true);
else
return TYPE_ALIGN(Node);
} else if (DECL_P(Node)) {
if (DECL_SIZE(Node) == NULL_TREE)
return 0;
else if (isInt64(DECL_SIZE(Node), 1))
return getInt64(DECL_SIZE(Node), 1);
else
return DECL_ALIGN(Node);
}
return 0;
}
/// NodeAlignInBits - Returns the alignment in bits stored in a tree node
/// regardless of whether the node is a TYPE or DECL.
static uint64_t NodeAlignInBits(tree Node) {
if (isa<ERROR_MARK>(Node))
return BITS_PER_WORD;
if (isa<TYPE>(Node))
return TYPE_ALIGN(Node);
if (DECL_P(Node))
return DECL_ALIGN(Node);
return BITS_PER_WORD;
}
/// FieldType - Returns the type node of a structure member field.
///
static tree FieldType(tree Field) {
if (isa<ERROR_MARK>(Field))
return integer_type_node;
return DECL_BIT_FIELD_TYPE(Field) ? DECL_BIT_FIELD_TYPE(Field)
: TREE_TYPE(Field);
}
/// GetNodeName - Returns the name stored in a node regardless of whether the
/// node is a TYPE or DECL.
static StringRef GetNodeName(tree Node) {
tree Name = NULL;
if (DECL_P(Node)) {
Name = DECL_NAME(Node);
} else if (isa<TYPE>(Node)) {
Name = TYPE_NAME(Node);
}
if (Name) {
if (isa<IDENTIFIER_NODE>(Name)) {
return IDENTIFIER_POINTER(Name);
} else if (isa<TYPE_DECL>(Name) && DECL_NAME(Name) &&
!DECL_IGNORED_P(Name)) {
return StringRef(IDENTIFIER_POINTER(DECL_NAME(Name)));
}
}
return StringRef();
}
/// GetNodeLocation - Returns the location stored in a node regardless of
/// whether the node is a TYPE or DECL. UseStub is true if we should consider
/// the type stub as the actually location (ignored in struct/unions/enums.)
static expanded_location GetNodeLocation(tree Node, bool UseStub = true) {
expanded_location Location = {};
if (Node == NULL_TREE)
return Location;
tree Name = NULL;
if (DECL_P(Node)) {
Name = DECL_NAME(Node);
} else if (isa<TYPE>(Node)) {
Name = TYPE_NAME(Node);
}
if (Name) {
if (isa<TYPE>(Name) && TYPE_STUB_DECL(Name)) {
tree Stub = TYPE_STUB_DECL(Name);
Location = expand_location(DECL_SOURCE_LOCATION(Stub));
} else if (DECL_P(Name)) {
Location = expand_location(DECL_SOURCE_LOCATION(Name));
}
}
if (!Location.line) {
if (UseStub && isa<TYPE>(Node) && TYPE_STUB_DECL(Node)) {
tree Stub = TYPE_STUB_DECL(Node);
Location = expand_location(DECL_SOURCE_LOCATION(Stub));
} else if (DECL_P(Node)) {
Location = expand_location(DECL_SOURCE_LOCATION(Node));
}
}
return Location;
}
static StringRef getLinkageName(tree Node) {
// Use llvm value name as linkage name if it is available.
if (DECL_LLVM_SET_P(Node)) {
Value *V = DECL_LLVM(Node);
return V->getName();
}
tree decl_name = DECL_NAME(Node);
if (decl_name != NULL && IDENTIFIER_POINTER(decl_name) != NULL) {
if (TREE_PUBLIC(Node) && DECL_ASSEMBLER_NAME(Node) != DECL_NAME(Node) &&
!DECL_ABSTRACT(Node)) {
return StringRef(IDENTIFIER_POINTER(DECL_ASSEMBLER_NAME(Node)));
}
}
return StringRef();
}
DebugInfo::DebugInfo(Module *m)
: M(*m), VMContext(M.getContext()), Builder(M), DeclareFn(0),
ValueFn(0), CurFullPath(""), PrevFullPath(""), CurLineNo(0), PrevLineNo(0),
PrevBB(NULL) {}
/// getFunctionName - Get function name for the given FnDecl. If the
/// name is constructred on demand (e.g. C++ destructor) then the name
/// is stored on the side.
StringRef DebugInfo::getFunctionName(tree FnDecl) {
StringRef FnNodeName = GetNodeName(FnDecl);
// Use dwarf_name to construct function names. In C++ this is used to
// create human readable destructor names.
StringRef FnName = lang_hooks.dwarf_name(FnDecl, 0);
if (FnNodeName.equals(FnName))
return FnNodeName;
// Use name returned by dwarf_name. It is in a temp. storage so make a
// copy first.
char *StrPtr = FunctionNames.Allocate<char>(FnName.size() + 1);
strncpy(StrPtr, FnName.data(), FnName.size());
StrPtr[FnName.size()] = 0;
return StringRef(StrPtr);
}
/// EmitFunctionStart - Constructs the debug code for entering a function.
void DebugInfo::EmitFunctionStart(tree FnDecl, Function *Fn) {
DIType FNType = getOrCreateType(TREE_TYPE(FnDecl));
unsigned lineno = CurLineNo;
std::map<tree_node *, WeakVH>::iterator I = SPCache.find(FnDecl);
if (I != SPCache.end()) {
DISubprogram SPDecl(cast<MDNode>(I->second));
DISubprogram SP = CreateSubprogramDefinition(SPDecl, lineno, Fn);
SPDecl->replaceAllUsesWith(SP);
// Push function on region stack.
RegionStack.push_back(WeakVH(SP));
RegionMap[FnDecl] = WeakVH(SP);
return;
}
bool ArtificialFnWithAbstractOrigin = false;
// If this artificial function has abstract origin then put this function
// at module scope. The abstract copy will be placed in appropriate region.
if (DECL_ARTIFICIAL(FnDecl) && DECL_ABSTRACT_ORIGIN(FnDecl) &&
DECL_ABSTRACT_ORIGIN(FnDecl) != FnDecl)
ArtificialFnWithAbstractOrigin = true;
DIDescriptor SPContext =
ArtificialFnWithAbstractOrigin ? getOrCreateFile(main_input_filename)
: findRegion(DECL_CONTEXT(FnDecl));
// Creating context may have triggered creation of this SP descriptor. So
// check the cache again.
I = SPCache.find(FnDecl);
if (I != SPCache.end()) {
DISubprogram SPDecl(cast<MDNode>(I->second));
DISubprogram SP = CreateSubprogramDefinition(SPDecl, lineno, Fn);
SPDecl->replaceAllUsesWith(SP);
// Push function on region stack.
RegionStack.push_back(WeakVH(SP));
RegionMap[FnDecl] = WeakVH(SP);
return;
}
// Gather location information.
expanded_location Loc = GetNodeLocation(FnDecl, false);
StringRef LinkageName = getLinkageName(FnDecl);
unsigned Virtuality = 0;
unsigned VIndex = 0;
DIType ContainingType;
if (DECL_VINDEX(FnDecl) && DECL_CONTEXT(FnDecl) &&
isa<TYPE>((DECL_CONTEXT(FnDecl)))) { // Workaround GCC PR42653
if (host_integerp(DECL_VINDEX(FnDecl), 0))
VIndex = tree_low_cst(DECL_VINDEX(FnDecl), 0);
Virtuality = dwarf::DW_VIRTUALITY_virtual;
ContainingType = getOrCreateType(DECL_CONTEXT(FnDecl));
}
StringRef FnName = getFunctionName(FnDecl);
DISubprogram SP = CreateSubprogram(
SPContext, FnName, FnName, LinkageName, getOrCreateFile(Loc.file), lineno,
FNType, Fn->hasInternalLinkage(), true /*definition*/, Virtuality, VIndex,
ContainingType, DECL_ARTIFICIAL(FnDecl), optimize, Fn);
SPCache[FnDecl] = WeakVH(SP);
// Push function on region stack.
RegionStack.push_back(WeakVH(SP));
RegionMap[FnDecl] = WeakVH(SP);
}
/// getOrCreateNameSpace - Get name space descriptor for the tree node.
DINameSpace DebugInfo::getOrCreateNameSpace(tree Node, DIDescriptor Context) {
std::map<tree_node *, WeakVH>::iterator I = NameSpaceCache.find(Node);
if (I != NameSpaceCache.end())
return DINameSpace(cast<MDNode>(I->second));
expanded_location Loc = GetNodeLocation(Node, false);
DINameSpace DNS = Builder.createNameSpace(
Context, GetNodeName(Node), getOrCreateFile(Loc.file), Loc.line);
NameSpaceCache[Node] = WeakVH(DNS);
return DNS;
}
/// findRegion - Find tree_node N's region.
DIDescriptor DebugInfo::findRegion(tree Node) {
if (Node == NULL_TREE)
return getOrCreateFile(main_input_filename);
std::map<tree_node *, WeakVH>::iterator I = RegionMap.find(Node);
if (I != RegionMap.end())
if (MDNode *R = dyn_cast_or_null<MDNode>(&*I->second))
return DIDescriptor(R);
if (isa<TYPE>(Node)) {
DIType Ty = getOrCreateType(Node);
return DIDescriptor(Ty);
} else if (DECL_P(Node)) {
if (isa<NAMESPACE_DECL>(Node)) {
DIDescriptor NSContext = findRegion(DECL_CONTEXT(Node));
DINameSpace NS = getOrCreateNameSpace(Node, NSContext);
return DIDescriptor(NS);
}
return findRegion(DECL_CONTEXT(Node));
}
// Otherwise main compile unit covers everything.
return getOrCreateFile(main_input_filename);
}
/// EmitFunctionEnd - Pop the region stack and reset current lexical block.
void DebugInfo::EmitFunctionEnd(bool EndFunction) {
assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
RegionStack.pop_back();
// Blocks get erased; clearing these is needed for determinism, and also
// a good idea if the next function gets inlined.
if (EndFunction) {
PrevBB = NULL;
PrevLineNo = 0;
PrevFullPath = NULL;
}
}
/// EmitDeclare - Constructs the debug code for allocation of a new variable.
void DebugInfo::EmitDeclare(tree decl, unsigned Tag, StringRef Name, tree type,
Value *AI, LLVMBuilder &IRBuilder) {
// Ignore compiler generated temporaries.
if (DECL_IGNORED_P(decl))
return;
assert(!RegionStack.empty() && "Region stack mismatch, stack empty!");
expanded_location Loc = GetNodeLocation(decl, false);
// Construct variable.
DIScope VarScope = DIScope(cast<MDNode>(RegionStack.back()));
DIType Ty = getOrCreateType(type);
if (Ty && DECL_ARTIFICIAL(decl))
Ty = Builder.createArtificialType(Ty);
// If type info is not available then do not emit debug info for this var.
if (!Ty)
return;
llvm::DIVariable D = Builder.createLocalVariable(
Tag, VarScope, Name, getOrCreateFile(Loc.file), Loc.line, Ty, optimize);
Instruction *Call = InsertDeclare(AI, D, IRBuilder.GetInsertBlock());
Call->setDebugLoc(DebugLoc::get(Loc.line, 0, VarScope));
}
/// EmitStopPoint - Set current source location.
void DebugInfo::EmitStopPoint(BasicBlock *CurBB, LLVMBuilder &Builder) {
// Don't bother if things are the same as last time.
if (PrevLineNo == CurLineNo && PrevBB == CurBB &&
(PrevFullPath == CurFullPath || !strcmp(PrevFullPath, CurFullPath)))
return;
if (!CurFullPath[0] || CurLineNo == 0)
return;
// Update last state.
PrevFullPath = CurFullPath;
PrevLineNo = CurLineNo;
PrevBB = CurBB;
if (RegionStack.empty())
return;
MDNode *Scope = cast<MDNode>(RegionStack.back());
Builder.SetCurrentDebugLocation(DebugLoc::get(CurLineNo, 0 /*col*/, Scope));
}
/// EmitGlobalVariable - Emit information about a global variable.
///
void DebugInfo::EmitGlobalVariable(GlobalVariable *GV, tree decl) {
if (DECL_ARTIFICIAL(decl) || DECL_IGNORED_P(decl))
return;
// Gather location information.
expanded_location Loc = expand_location(DECL_SOURCE_LOCATION(decl));
DIType TyD = getOrCreateType(TREE_TYPE(decl));
StringRef DispName = GV->getName();
if (DispName.empty())
DispName = "__unknown__";
if (DECL_NAME(decl)) {
if (IDENTIFIER_POINTER(DECL_NAME(decl)))
DispName = IDENTIFIER_POINTER(DECL_NAME(decl));
}
StringRef LinkageName;
// The gdb does not expect linkage names for function local statics.
if (DECL_CONTEXT(decl))
if (!isa<FUNCTION_DECL>(DECL_CONTEXT(decl)))
LinkageName = GV->getName();
Builder.createStaticVariable(
findRegion(DECL_CONTEXT(decl)), DispName, LinkageName,
getOrCreateFile(Loc.file), Loc.line, TyD, GV->hasInternalLinkage(), GV);
}
/// createBasicType - Create BasicType.
DIType DebugInfo::createBasicType(tree type) {
StringRef TypeName = GetNodeName(type);
if (TypeName.empty())
TypeName = "__unknown__";
uint64_t Size = NodeSizeInBits(type);
uint64_t Align = NodeAlignInBits(type);
unsigned Encoding = 0;
switch (TREE_CODE(type)) {
case INTEGER_TYPE:
if (TYPE_STRING_FLAG(type)) {
if (TYPE_UNSIGNED(type))
Encoding = DW_ATE_unsigned_char;
else
Encoding = DW_ATE_signed_char;
} else if (TYPE_UNSIGNED(type))
Encoding = DW_ATE_unsigned;
else
Encoding = DW_ATE_signed;
break;
case REAL_TYPE:
Encoding = DW_ATE_float;
break;
case COMPLEX_TYPE:
Encoding =
isa<REAL_TYPE>(TREE_TYPE(type)) ? DW_ATE_complex_float : DW_ATE_lo_user;
break;
case BOOLEAN_TYPE:
Encoding = DW_ATE_boolean;
break;
default:
llvm_unreachable("Basic type case missing");
}
return Builder.createBasicType(TypeName, Size, Align, Encoding);
}
/// isArtificialArgumentType - Return true if arg_type represents artificial,
/// i.e. "this" in c++, argument.
static bool isArtificialArgumentType(tree arg_type, tree method_type) {
if (!isa<METHOD_TYPE>(method_type))
return false;
if (!isa<POINTER_TYPE>(arg_type))
return false;
if (TREE_TYPE(arg_type) == TYPE_METHOD_BASETYPE(method_type))
return true;
if (main_type(arg_type) && main_type(arg_type) != TREE_TYPE(arg_type) &&
(main_type(arg_type) == TYPE_METHOD_BASETYPE(method_type)))
return true;
return false;
}
/// createMethodType - Create MethodType.
DIType DebugInfo::createMethodType(tree type) {
// Create a place holder type first. The may be used as a context
// for the argument types.
llvm::DIType FwdType = Builder.createReplaceableForwardDecl(
llvm::dwarf::DW_TAG_subroutine_type, StringRef(),
findRegion(TYPE_CONTEXT(type)), getOrCreateFile(main_input_filename),
0, 0, 0, 0);
llvm::MDNode *FTN = FwdType;
llvm::TrackingVH<llvm::MDNode> FwdTypeNode = FTN;
TypeCache[type] = WeakVH(FwdType);
// Push the struct on region stack.
RegionStack.push_back(WeakVH(FwdType));
RegionMap[type] = WeakVH(FwdType);
llvm::SmallVector<Value*, 16> EltTys;
// Add the result type at least.
EltTys.push_back(getOrCreateType(TREE_TYPE(type)));
// Set up remainder of arguments.
bool ProcessedFirstArg = false;
for (tree arg = TYPE_ARG_TYPES(type); arg; arg = TREE_CHAIN(arg)) {
tree formal_type = TREE_VALUE(arg);
if (formal_type == void_type_node)
break;
llvm::DIType FormalType = getOrCreateType(formal_type);
if (!ProcessedFirstArg && isArtificialArgumentType(formal_type, type)) {
DIType AFormalType = Builder.createArtificialType(FormalType);
EltTys.push_back(AFormalType);
} else
EltTys.push_back(FormalType);
if (!ProcessedFirstArg)
ProcessedFirstArg = true;
}
llvm::DIArray EltTypeArray = Builder.getOrCreateArray(EltTys);
RegionStack.pop_back();
std::map<tree_node *, WeakVH>::iterator RI = RegionMap.find(type);
if (RI != RegionMap.end())
RegionMap.erase(RI);
llvm::DIType RealType = CreateCompositeType(
llvm::dwarf::DW_TAG_subroutine_type, findRegion(TYPE_CONTEXT(type)),
StringRef(), getOrCreateFile(main_input_filename), 0, 0, 0, 0, 0,
llvm::DIType(), EltTypeArray);
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
llvm::DIType(FwdTypeNode).replaceAllUsesWith(RealType);
return RealType;
}
/// createPointerType - Create PointerType.
DIType DebugInfo::createPointerType(tree type) {
DIType FromTy = getOrCreateType(TREE_TYPE(type));
// type* and type&
// FIXME: Should BLOCK_POINTER_TYP have its own DW_TAG?
unsigned Tag =
isa<REFERENCE_TYPE>(type) ? DW_TAG_reference_type : DW_TAG_pointer_type;
unsigned Flags = 0;
// Check if this pointer type has a name.
if (tree TyName = TYPE_NAME(type))
if (isa<TYPE_DECL>(TyName) && !DECL_ORIGINAL_TYPE(TyName)) {
expanded_location TypeNameLoc = GetNodeLocation(TyName);
DIType Ty = CreateDerivedType(
Tag, findRegion(DECL_CONTEXT(TyName)), GetNodeName(TyName),
getOrCreateFile(TypeNameLoc.file), TypeNameLoc.line, 0 /*size*/,
0 /*align*/, 0 /*offset */, 0 /*flags*/, FromTy);
TypeCache[TyName] = WeakVH(Ty);
return Ty;
}
StringRef PName = FromTy.getName();
DIType PTy = CreateDerivedType(
Tag, findRegion(TYPE_CONTEXT(type)),
Tag == DW_TAG_pointer_type ? StringRef() : PName,
getOrCreateFile(main_input_filename), 0 /*line no*/, NodeSizeInBits(type),
NodeAlignInBits(type), 0 /*offset */, Flags, FromTy);
return PTy;
}
/// createArrayType - Create ArrayType.
DIType DebugInfo::createArrayType(tree type) {
// Add the dimensions of the array. FIXME: This loses CV qualifiers from
// interior arrays, do we care? Why aren't nested arrays represented the
// obvious/recursive way?
llvm::SmallVector<Value*, 8> Subscripts;
// There will be ARRAY_TYPE nodes for each rank. Followed by the derived
// type.
tree EltTy = TREE_TYPE(type);
if (isa<ARRAY_TYPE>(type)) {
tree atype = type;
for (; isa<ARRAY_TYPE>(atype); atype = TREE_TYPE(atype)) {
tree Domain = TYPE_DOMAIN(atype);
if (Domain) {
// FIXME - handle dynamic ranges
tree MinValue = TYPE_MIN_VALUE(Domain);
tree MaxValue = TYPE_MAX_VALUE(Domain);
int64_t Low = 0;
int64_t Hi = 0;
if (isInt64(MinValue, false))
Low = getInt64(MinValue, false);
if (isInt64(MaxValue, false))
Hi = getInt64(MaxValue, false);
Subscripts.push_back(Builder.getOrCreateSubrange(Low, Hi));
}
EltTy = TREE_TYPE(atype);
}
} else {
assert(isa<VECTOR_TYPE>(type) && "Not an array or vector type!");
unsigned Length = TYPE_VECTOR_SUBPARTS(type);
Subscripts.push_back(Builder.getOrCreateSubrange(0, Length));
}
llvm::DIArray SubscriptArray = Builder.getOrCreateArray(Subscripts);
expanded_location Loc = GetNodeLocation(type);
return CreateCompositeType(
llvm::dwarf::DW_TAG_array_type, findRegion(TYPE_CONTEXT(type)),
StringRef(), getOrCreateFile(Loc.file), 0, NodeSizeInBits(type),
NodeAlignInBits(type), 0, 0, getOrCreateType(EltTy), SubscriptArray);
}
/// createEnumType - Create EnumType.
DIType DebugInfo::createEnumType(tree type) {
// enum { a, b, ..., z };
llvm::SmallVector<Value*, 32> Elements;
if (TYPE_SIZE(type)) {
for (tree Link = TYPE_VALUES(type); Link; Link = TREE_CHAIN(Link)) {
tree EnumValue = TREE_VALUE(Link);
if (isa<CONST_DECL>(EnumValue))
EnumValue = DECL_INITIAL(EnumValue);
uint64_t Value = getAPIntValue(EnumValue, 64).getZExtValue();
const char *EnumName = IDENTIFIER_POINTER(TREE_PURPOSE(Link));
Elements.push_back(Builder.createEnumerator(EnumName, Value));
}
}
llvm::DIArray EltArray = Builder.getOrCreateArray(Elements);
expanded_location Loc = {};
if (TYPE_SIZE(type))
// Incomplete enums do not have any location info.
Loc = GetNodeLocation(TREE_CHAIN(type), false);
return CreateCompositeType(
llvm::dwarf::DW_TAG_enumeration_type, findRegion(TYPE_CONTEXT(type)),
GetNodeName(type), getOrCreateFile(Loc.file), Loc.line,
NodeSizeInBits(type), NodeAlignInBits(type), 0, 0, llvm::DIType(),
EltArray);
}
/// createStructType - Create StructType for struct or union or class.
DIType DebugInfo::createStructType(tree type) {
// struct { a; b; ... z; }; | union { a; b; ... z; };
unsigned Tag =
isa<RECORD_TYPE>(type) ? DW_TAG_structure_type : DW_TAG_union_type;
unsigned RunTimeLang = 0;
//TODO if (TYPE_LANG_SPECIFIC (type)
//TODO && lang_hooks.types.is_runtime_specific_type (type))
//TODO {
//TODO unsigned CULang = TheCU.getLanguage();
//TODO switch (CULang) {
//TODO case DW_LANG_ObjC_plus_plus :
//TODO RunTimeLang = DW_LANG_ObjC_plus_plus;
//TODO break;
//TODO case DW_LANG_ObjC :
//TODO RunTimeLang = DW_LANG_ObjC;
//TODO break;
//TODO case DW_LANG_C_plus_plus :
//TODO RunTimeLang = DW_LANG_C_plus_plus;
//TODO break;
//TODO default:
//TODO break;
//TODO }
//TODO }
// Records and classes and unions can all be recursive. To handle them,
// we first generate a debug descriptor for the struct as a forward
// declaration. Then (if it is a definition) we go through and get debug
// info for all of its members. Finally, we create a descriptor for the
// complete type (which may refer to the forward decl if the struct is
// recursive) and replace all uses of the forward declaration with the
// final definition.
expanded_location Loc = GetNodeLocation(TREE_CHAIN(type), false);
unsigned SFlags = 0;
DIDescriptor TyContext = findRegion(TYPE_CONTEXT(type));
// Check if this type is created while creating context information
// descriptor.
{
std::map<tree_node *, WeakVH>::iterator I = TypeCache.find(type);
if (I != TypeCache.end())
if (MDNode *TN = dyn_cast_or_null<MDNode>(&*I->second))
return DIType(TN);
}
llvm::DIType FwdDecl = Builder.createReplaceableForwardDecl(
Tag, GetNodeName(type), TyContext, getOrCreateFile(Loc.file), Loc.line,
0, 0, 0);
if (TYPE_SIZE(type) == 0)
// forward declaration,
return FwdDecl;
// Insert into the TypeCache so that recursive uses will find it.
llvm::MDNode *FDN = FwdDecl;
llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FDN;
TypeCache[type] = WeakVH(FwdDecl);
// Push the struct on region stack.
RegionStack.push_back(WeakVH(FwdDecl));
RegionMap[type] = WeakVH(FwdDecl);
// Convert all the elements.
llvm::SmallVector<Value*, 16> EltTys;
if (tree binfo = TYPE_BINFO(type)) {
for (unsigned i = 0, e = BINFO_N_BASE_BINFOS(binfo); i != e; ++i) {
tree BInfo = BINFO_BASE_BINFO(binfo, i);
tree BInfoType = BINFO_TYPE(BInfo);
DIType BaseClass = getOrCreateType(BInfoType);
unsigned BFlags = 0;
if (BINFO_VIRTUAL_P(BInfo))
BFlags = llvm::DIType::FlagVirtual;
if (BINFO_BASE_ACCESSES(binfo)) {
tree access = BINFO_BASE_ACCESS(binfo, i);
if (access == access_protected_node)
BFlags |= llvm::DIType::FlagProtected;
else if (access == access_private_node)
BFlags |= llvm::DIType::FlagPrivate;
}
// Check for zero BINFO_OFFSET.
// FIXME : Is this correct ?
unsigned Offset =
BINFO_OFFSET(BInfo) ? getInt64(BINFO_OFFSET(BInfo), true) * 8 : 0;
if (BINFO_VIRTUAL_P(BInfo))
Offset = 0 - getInt64(BINFO_VPTR_FIELD(BInfo), false);
// FIXME : name, size, align etc...
DIType DTy = CreateDerivedType(
DW_TAG_inheritance, findRegion(type), StringRef(), llvm::DIFile(), 0,
0, 0, Offset, BFlags, BaseClass);
EltTys.push_back(DTy);
}
}
// Now add members of this class.
for (tree Member = TYPE_FIELDS(type); Member; Member = TREE_CHAIN(Member)) {
// Should we skip.
if (DECL_P(Member) && DECL_IGNORED_P(Member))
continue;
// Get the location of the member.
expanded_location MemLoc = GetNodeLocation(Member, false);
if (!isa<FIELD_DECL>(Member))
// otherwise is a static variable, whose debug info is emitted
// when through EmitGlobalVariable().
continue;
if (!OffsetIsLLVMCompatible(Member))
// FIXME: field with variable or humongous offset.
// Skip it for now.
continue;
/* Ignore nameless fields. */
if (DECL_NAME(Member) == NULL_TREE &&
!isa<RECORD_OR_UNION_TYPE>(TREE_TYPE(Member)))
continue;
// Field type is the declared type of the field.
tree FieldNodeType = FieldType(Member);
DIType MemberType = getOrCreateType(FieldNodeType);
StringRef MemberName = GetNodeName(Member);
unsigned MFlags = 0;
if (TREE_PROTECTED(Member))
MFlags = llvm::DIType::FlagProtected;
else if (TREE_PRIVATE(Member))
MFlags = llvm::DIType::FlagPrivate;
DIType DTy = CreateDerivedType(
DW_TAG_member, findRegion(DECL_CONTEXT(Member)), MemberName,
getOrCreateFile(MemLoc.file), MemLoc.line, NodeSizeInBits(Member),
NodeAlignInBits(FieldNodeType), int_bit_position(Member), MFlags,
MemberType);
EltTys.push_back(DTy);
}
for (tree Member = TYPE_METHODS(type); Member; Member = TREE_CHAIN(Member)) {
if (DECL_ABSTRACT_ORIGIN(Member))
continue;
// Ignore unused aritificial members.
if (DECL_ARTIFICIAL(Member) && !TREE_USED(Member))
continue;
// In C++, TEMPLATE_DECLs are marked Ignored, and should be.
if (DECL_P(Member) && DECL_IGNORED_P(Member))
continue;
std::map<tree_node *, WeakVH>::iterator I = SPCache.find(Member);
if (I != SPCache.end())
EltTys.push_back(DISubprogram(cast<MDNode>(I->second)));
else {
// Get the location of the member.
expanded_location MemLoc = GetNodeLocation(Member, false);
StringRef MemberName = getFunctionName(Member);
StringRef LinkageName = getLinkageName(Member);
DIType SPTy = getOrCreateType(TREE_TYPE(Member));
unsigned Virtuality = 0;
unsigned VIndex = 0;
DIType ContainingType;
if (DECL_VINDEX(Member)) {
if (host_integerp(DECL_VINDEX(Member), 0))
VIndex = tree_low_cst(DECL_VINDEX(Member), 0);
Virtuality = dwarf::DW_VIRTUALITY_virtual;
ContainingType = getOrCreateType(DECL_CONTEXT(Member));
}
DISubprogram SP = CreateSubprogram(
findRegion(DECL_CONTEXT(Member)), MemberName, MemberName, LinkageName,
getOrCreateFile(MemLoc.file), MemLoc.line, SPTy, false, false,
Virtuality, VIndex, ContainingType, DECL_ARTIFICIAL(Member),
optimize);
EltTys.push_back(SP);
SPCache[Member] = WeakVH(SP);
}
}
llvm::DIArray Elements = Builder.getOrCreateArray(EltTys);
RegionStack.pop_back();
std::map<tree_node *, WeakVH>::iterator RI = RegionMap.find(type);
if (RI != RegionMap.end())
RegionMap.erase(RI);
llvm::DIType ContainingType;
if (TYPE_VFIELD(type)) {
tree vtype = DECL_FCONTEXT(TYPE_VFIELD(type));
ContainingType = getOrCreateType(vtype);
}
llvm::DICompositeType RealDecl = CreateCompositeType(
Tag, findRegion(TYPE_CONTEXT(type)), GetNodeName(type),
getOrCreateFile(Loc.file), Loc.line, NodeSizeInBits(type),
NodeAlignInBits(type), 0, SFlags, llvm::DIType(), Elements, RunTimeLang,
ContainingType);
RegionMap[type] = WeakVH(RealDecl);
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
llvm::DIType(FwdDeclNode).replaceAllUsesWith(RealDecl);
return RealDecl;
}
/// createVariantType - Create variant type or return MainTy.
DIType DebugInfo::createVariantType(tree type, DIType MainTy) {
DIType Ty;
if (tree TyDef = TYPE_NAME(type)) {
std::map<tree_node *, WeakVH>::iterator I = TypeCache.find(TyDef);
if (I != TypeCache.end())
if (I->second)
return DIType(cast<MDNode>(I->second));
if (isa<TYPE_DECL>(TyDef) && DECL_ORIGINAL_TYPE(TyDef)) {
expanded_location TypeDefLoc = GetNodeLocation(TyDef);
Ty = CreateDerivedType(
DW_TAG_typedef, findRegion(DECL_CONTEXT(TyDef)), GetNodeName(TyDef),
getOrCreateFile(TypeDefLoc.file), TypeDefLoc.line, 0 /*size*/,
0 /*align*/, 0 /*offset */, 0 /*flags*/, MainTy);
TypeCache[TyDef] = WeakVH(Ty);
return Ty;
}
}
if (TYPE_VOLATILE(type)) {
Ty = CreateDerivedType(
DW_TAG_volatile_type, findRegion(TYPE_CONTEXT(type)), StringRef(),
getOrCreateFile(main_input_filename), 0 /*line no*/,
NodeSizeInBits(type), NodeAlignInBits(type), 0 /*offset */,
0 /* flags */, MainTy);
MainTy = Ty;
}
if (TYPE_READONLY(type))
Ty = CreateDerivedType(
DW_TAG_const_type, findRegion(TYPE_CONTEXT(type)), StringRef(),
getOrCreateFile(main_input_filename), 0 /*line no*/,
NodeSizeInBits(type), NodeAlignInBits(type), 0 /*offset */,
0 /* flags */, MainTy);
if (TYPE_VOLATILE(type) || TYPE_READONLY(type)) {
TypeCache[type] = WeakVH(Ty);
return Ty;
}
// If, for some reason, main type variant type is seen then use it.
return MainTy;
}
/// getOrCreateType - Get the type from the cache or create a new type if
/// necessary.
DIType DebugInfo::getOrCreateType(tree type) {
if (type == NULL_TREE || type == error_mark_node)
llvm_unreachable("Not a type.");
// Should only be void if a pointer/reference/return type. Returning NULL
// allows the caller to produce a non-derived type.
if (isa<VOID_TYPE>(type))
return DIType();
// Check to see if the compile unit already has created this type.
std::map<tree_node *, WeakVH>::iterator I = TypeCache.find(type);
if (I != TypeCache.end())
if (I->second)
return DIType(cast<MDNode>(I->second));
if (type != TYPE_MAIN_VARIANT(type) && TYPE_MAIN_VARIANT(type)) {
DIType MainTy = getOrCreateType(TYPE_MAIN_VARIANT(type));
DIType Ty = createVariantType(type, MainTy);
if (Ty.isValid())
return Ty;
}
// Work out details of type.
DIType Ty;
switch (TREE_CODE(type)) {
case ERROR_MARK:
case TRANSLATION_UNIT_DECL:
default:
llvm_unreachable("Unsupported type");
#if (GCC_MINOR > 5)
case NULLPTR_TYPE:
#endif
case LANG_TYPE: {
tree name = TYPE_NAME(type);
if (TREE_CODE(name) == TYPE_DECL)
name = DECL_NAME(name);
return Builder.createUnspecifiedType(IDENTIFIER_POINTER(name));
}
case OFFSET_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
// Do not cache pointer type. The pointer may point to forward declared
// struct.
return createPointerType(type);
case FUNCTION_TYPE:
case METHOD_TYPE:
Ty = createMethodType(type);
break;
case VECTOR_TYPE:
case ARRAY_TYPE:
Ty = createArrayType(type);
break;
case ENUMERAL_TYPE:
Ty = createEnumType(type);
break;
case RECORD_TYPE:
case QUAL_UNION_TYPE:
case UNION_TYPE:
return createStructType(type);
case INTEGER_TYPE:
case REAL_TYPE:
case COMPLEX_TYPE:
case BOOLEAN_TYPE:
Ty = createBasicType(type);
break;
}
TypeCache[type] = WeakVH(Ty);
return Ty;
}
/// Initialize - Initialize debug info by creating compile unit for
/// main_input_filename. This must be invoked after language dependent
/// initialization is done.
void DebugInfo::Initialize() {
// Debug info metadata without a version or with an outdated version will be
// dropped. Add a version here to avoid that.
M.addModuleFlag(llvm::Module::Error, "Debug Info Version",
llvm::DEBUG_METADATA_VERSION);
// Each input file is encoded as a separate compile unit in LLVM
// debugging information output. However, many target specific tool chains
// prefer to encode only one compile unit in an object file. In this
// situation, the LLVM code generator will include debugging information
// entities in the compile unit that is marked as main compile unit. The
// code generator accepts maximum one main compile unit per module. If a
// module does not contain any main compile unit then the code generator
// will emit multiple compile units in the output object file.
getOrCreateCompileUnit(main_input_filename, true);
}
/// getOrCreateCompileUnit - Get the compile unit from the cache or
/// create a new one if necessary.
void DebugInfo::getOrCreateCompileUnit(const char *FullPath, bool isMain) {
if (!FullPath)
FullPath = main_input_filename;
if (!strcmp(FullPath, ""))
FullPath = "<stdin>";
// Get source file information.
std::string Directory;
std::string FileName;
DirectoryAndFile(FullPath, Directory, FileName);
// Set up Language number.
unsigned LangTag;
const std::string LanguageName(lang_hooks.name);
if (LanguageName == "GNU C")
LangTag = DW_LANG_C89;
else if (LanguageName == "GNU C++")
LangTag = DW_LANG_C_plus_plus;
else if (LanguageName == "GNU Ada")
LangTag = DW_LANG_Ada95;
else if (LanguageName == "GNU F77")
LangTag = DW_LANG_Fortran77;
else if (LanguageName == "GNU Pascal")
LangTag = DW_LANG_Pascal83;
else if (LanguageName == "GNU Java")
LangTag = DW_LANG_Java;
else if (LanguageName == "GNU Objective-C")
LangTag = DW_LANG_ObjC;
else if (LanguageName == "GNU Objective-C++")
LangTag = DW_LANG_ObjC_plus_plus;
else
LangTag = DW_LANG_C89;
StringRef Flags;
// flag_objc_abi represents Objective-C runtime version number. It is zero
// for all other language.
unsigned ObjcRunTimeVer = 0;
// if (flag_objc_abi != 0 && flag_objc_abi != -1)
// ObjcRunTimeVer = flag_objc_abi;
Builder.createCompileUnit(LangTag, FileName, Directory, version_string,
optimize, Flags, ObjcRunTimeVer);
}
/// getOrCreateFile - Get DIFile descriptor.
DIFile DebugInfo::getOrCreateFile(const char *FullPath) {
if (!FullPath)
FullPath = main_input_filename;
if (!strcmp(FullPath, ""))
FullPath = "<stdin>";
// Get source file information.
std::string Directory;
std::string FileName;
DirectoryAndFile(FullPath, Directory, FileName);
return Builder.createFile(FileName, Directory);
}
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Primary Constructors
//===----------------------------------------------------------------------===//
/// CreateDerivedType - Create a derived type like const qualified type,
/// pointer, typedef, etc.
DIDerivedType DebugInfo::CreateDerivedType(
unsigned Tag, DIDescriptor Context, StringRef Name, DIFile F,
unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits,
uint64_t OffsetInBits, unsigned Flags, DIType DerivedFrom) {
switch (Tag) {
case dwarf::DW_TAG_typedef:
return Builder.createTypedef(DerivedFrom, Name, F, LineNumber, Context);
case dwarf::DW_TAG_pointer_type:
return Builder.createPointerType(DerivedFrom, SizeInBits, AlignInBits,
Name);
case dwarf::DW_TAG_reference_type:
case dwarf::DW_TAG_rvalue_reference_type:
return Builder.createReferenceType(Tag, DerivedFrom);
case dwarf::DW_TAG_const_type:
case dwarf::DW_TAG_volatile_type:
case dwarf::DW_TAG_restrict_type:
return Builder.createQualifiedType(Tag, DerivedFrom);
case dwarf::DW_TAG_member:
return Builder.createMemberType(Context, Name, F, LineNumber, SizeInBits,
AlignInBits, OffsetInBits, Flags,
DerivedFrom);
case dwarf::DW_TAG_inheritance:
return Builder.createInheritance(DIType(Context), DerivedFrom, OffsetInBits,
Flags);
case dwarf::DW_TAG_friend:
case dwarf::DW_TAG_ptr_to_member_type:
break;
}
llvm_unreachable("Unimplemented derived type tag");
}
/// CreateCompositeType - Create a composite type like array, struct, etc.
DICompositeType DebugInfo::CreateCompositeType(
unsigned Tag, DIDescriptor Context, StringRef Name, DIFile F,
unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits,
uint64_t OffsetInBits, unsigned Flags, DIType DerivedFrom, DIArray Elements,
unsigned RuntimeLang, MDNode *ContainingType) {
switch (Tag) {
case dwarf::DW_TAG_array_type:
return Builder.createArrayType(SizeInBits, AlignInBits, DerivedFrom,
Elements);
case dwarf::DW_TAG_structure_type:
return Builder.createStructType(Context, Name, F, LineNumber, SizeInBits,
AlignInBits, Flags, DerivedFrom, Elements,
0, DIType(ContainingType));
case dwarf::DW_TAG_union_type:
return Builder.createUnionType(Context, Name, F, LineNumber, SizeInBits,
AlignInBits, Flags, Elements, RuntimeLang);
case dwarf::DW_TAG_enumeration_type:
return Builder.createEnumerationType(Context, Name, F, LineNumber,
SizeInBits, AlignInBits, Elements,
DerivedFrom);
case dwarf::DW_TAG_subroutine_type:
return Builder.createSubroutineType(F, Elements);
case dwarf::DW_TAG_class_type:
break;
}
llvm_unreachable("Unimplemented composite type tag");
}
/// CreateSubprogram - Create a new descriptor for the specified subprogram.
/// See comments in DISubprogram for descriptions of these fields. This
/// method does not unique the generated descriptors.
DISubprogram DebugInfo::CreateSubprogram(
DIDescriptor Context, StringRef Name, StringRef DisplayName,
StringRef LinkageName, DIFile F, unsigned LineNo, DIType Ty,
bool isLocalToUnit, bool isDefinition, unsigned VK, unsigned VIndex,
DIType ContainingType, unsigned Flags, bool isOptimized, Function *Fn) {
DICompositeType CTy = getDICompositeType(Ty);
assert(CTy.Verify() && "Expected a composite type!");
if (ContainingType.isValid() || VK || VIndex)
return Builder.createMethod(Context, Name, LinkageName, F, LineNo, CTy,
isLocalToUnit, isDefinition, VK, VIndex,
DIType(),
Flags, isOptimized, Fn, NULL);
return Builder.createFunction(Context, Name, LinkageName, F, LineNo, CTy,
isLocalToUnit, isDefinition, LineNo, Flags,
isOptimized, Fn, NULL, NULL);
}
/// CreateSubprogramDefinition - Create new subprogram descriptor for the
/// given declaration.
DISubprogram DebugInfo::CreateSubprogramDefinition(
DISubprogram &SP, unsigned LineNo, Function *Fn) {
if (SP.isDefinition())
return DISubprogram(SP);
DIFile File = Builder.createFile(SP.getFilename(), SP.getDirectory());
return Builder.createFunction(
SP.getContext(), SP.getName(), SP.getLinkageName(), File,
SP.getLineNumber(), SP.getType(), SP.isLocalToUnit(), true, LineNo,
SP.getFlags(), SP.isOptimized(), Fn, SP.getTemplateParams(), SP);
}
//===----------------------------------------------------------------------===//
// Routines for inserting code into a function
//===----------------------------------------------------------------------===//
/// InsertDeclare - Insert a new llvm.dbg.declare intrinsic call.
Instruction *DebugInfo::InsertDeclare(Value *Storage, DIVariable D,
Instruction *InsertBefore) {
assert(Storage && "no storage passed to dbg.declare");
assert(D.Verify() && "empty DIVariable passed to dbg.declare");
if (!DeclareFn)
DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare);
Value *Args[] = { MDNode::get(Storage->getContext(), Storage), D };
return CallInst::Create(DeclareFn, Args, "", InsertBefore);
}
/// InsertDeclare - Insert a new llvm.dbg.declare intrinsic call.
Instruction *DebugInfo::InsertDeclare(Value *Storage, DIVariable D,
BasicBlock *InsertAtEnd) {
assert(Storage && "no storage passed to dbg.declare");
assert(D.Verify() && "invalid DIVariable passed to dbg.declare");
if (!DeclareFn)
DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare);
Value *Args[] = { MDNode::get(Storage->getContext(), Storage), D };
// If this block already has a terminator then insert this intrinsic
// before the terminator.
if (TerminatorInst *T = InsertAtEnd->getTerminator())
return CallInst::Create(DeclareFn, Args, "", T);
else
return CallInst::Create(DeclareFn, Args, "", InsertAtEnd);
}
/// InsertDbgValueIntrinsic - Insert a new llvm.dbg.value intrinsic call.
Instruction *DebugInfo::InsertDbgValueIntrinsic(
Value *V, uint64_t Offset, DIVariable D, Instruction *InsertBefore) {
assert(V && "no value passed to dbg.value");
assert(D.Verify() && "invalid DIVariable passed to dbg.value");
if (!ValueFn)
ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value);
Value *Args[] = { MDNode::get(V->getContext(), V),
ConstantInt::get(Type::getInt64Ty(V->getContext()), Offset),
D };
return CallInst::Create(ValueFn, Args, "", InsertBefore);
}
/// InsertDbgValueIntrinsic - Insert a new llvm.dbg.value intrinsic call.
Instruction *DebugInfo::InsertDbgValueIntrinsic(
Value *V, uint64_t Offset, DIVariable D, BasicBlock *InsertAtEnd) {
assert(V && "no value passed to dbg.value");
assert(D.Verify() && "invalid DIVariable passed to dbg.value");
if (!ValueFn)
ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value);
Value *Args[] = { MDNode::get(V->getContext(), V),
ConstantInt::get(Type::getInt64Ty(V->getContext()), Offset),
D };
return CallInst::Create(ValueFn, Args, "", InsertAtEnd);
}