Files
ldc/gen/todebug.cpp
Tomas Lindquist Olsen 1fac40d2bd Update to work with LLVM 2.7.
Removed use of dyn_cast, llvm no compiles
without exceptions and rtti by
default. We do need exceptions for the libconfig stuff, but rtti isn't
necessary (anymore).

Debug info needs to be rewritten, as in LLVM 2.7 the format has
completely changed. To have something to look at while rewriting, the
old code has been wrapped inside #ifndef DISABLE_DEBUG_INFO , this means
that you have to define this to compile at the moment.

Updated tango 0.99.9 patch to include updated EH runtime code, which is
needed for LLVM 2.7 as well.
2010-05-19 12:42:32 +02:00

643 lines
20 KiB
C++

#include "gen/llvm.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/System/Path.h"
#include "declaration.h"
#include "module.h"
#include "mars.h"
#include "gen/todebug.h"
#include "gen/irstate.h"
#include "gen/tollvm.h"
#include "gen/logger.h"
#include "gen/llvmhelpers.h"
#include "gen/linkage.h"
#include "gen/utils.h"
#include "ir/irmodule.h"
using namespace llvm::dwarf;
#ifndef DISABLE_DEBUG_INFO
#define DBG_NULL ( LLConstant::getNullValue(DBG_TYPE) )
#define DBG_TYPE ( getPtrToType(llvm::StructType::get(gIR->context(),NULL,NULL)) )
#define DBG_CAST(X) ( llvm::ConstantExpr::getBitCast(X, DBG_TYPE) )
#define DBG_TAG(X) ( llvm::ConstantExpr::getAdd( DtoConstUint( X ), DtoConstUint( llvm::LLVMDebugVersion ) ) )
//////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Emits a global variable, LLVM Dwarf style, only declares.
* @param type Type of variable.
* @param name Name.
* @return The global variable.
*/
static LLGlobalVariable* emitDwarfGlobalDecl(const LLStructType* type, const char* name, bool linkonce=false)
{
LLGlobalValue::LinkageTypes linkage = linkonce
? DEBUGINFO_LINKONCE_LINKAGE_TYPE
: LLGlobalValue::InternalLinkage;
LLGlobalVariable* gv = new LLGlobalVariable(*gIR->module, type, true, linkage, NULL, name);
gv->setSection("llvm.metadata");
return gv;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static const llvm::StructType* getDwarfCompileUnitType() {
return isaStruct(gIR->module->getTypeByName("llvm.dbg.compile_unit.type"));
}
static const llvm::StructType* getDwarfSubProgramType() {
return isaStruct(gIR->module->getTypeByName("llvm.dbg.subprogram.type"));
}
static const llvm::StructType* getDwarfVariableType() {
return isaStruct(gIR->module->getTypeByName("llvm.dbg.variable.type"));
}
static const llvm::StructType* getDwarfDerivedTypeType() {
return isaStruct(gIR->module->getTypeByName("llvm.dbg.derivedtype.type"));
}
static const llvm::StructType* getDwarfBasicTypeType() {
return isaStruct(gIR->module->getTypeByName("llvm.dbg.basictype.type"));
}
static const llvm::StructType* getDwarfCompositeTypeType() {
return isaStruct(gIR->module->getTypeByName("llvm.dbg.compositetype.type"));
}
static const llvm::StructType* getDwarfGlobalVariableType() {
return isaStruct(gIR->module->getTypeByName("llvm.dbg.global_variable.type"));
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// get the module the symbol is in, or - for template instances - the current module
static Module* getDefinedModule(Dsymbol* s)
{
// templates are defined in current module
if (DtoIsTemplateInstance(s))
{
return gIR->dmodule;
}
// array operations as well
else if (FuncDeclaration* fd = s->isFuncDeclaration())
{
if (fd->isArrayOp)
return gIR->dmodule;
}
// otherwise use the symbol's module
return s->getModule();
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIType dwarfTypeDescription_impl(Type* type, llvm::DICompileUnit cu, const char* c_name);
static llvm::DIType dwarfTypeDescription(Type* type, llvm::DICompileUnit cu, const char* c_name);
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIBasicType dwarfBasicType(Type* type, llvm::DICompileUnit compileUnit)
{
Type* t = type->toBasetype();
const LLType* T = DtoType(type);
// find encoding
unsigned id;
if (t->isintegral())
{
if (type->isunsigned())
id = DW_ATE_unsigned;
else
id = DW_ATE_signed;
}
else if (t->isfloating())
{
id = DW_ATE_float;
}
else
{
assert(0 && "unsupported basictype for debug info");
}
return gIR->difactory.CreateBasicType(
compileUnit, // context
type->toChars(), // name
llvm::DICompileUnit(NULL), // compile unit
0, // line number
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
0, // offset (bits)
//FIXME: need flags?
0, // flags
id // encoding
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIDerivedType dwarfDerivedType(Type* type, llvm::DICompileUnit compileUnit)
{
const LLType* T = DtoType(type);
Type* t = type->toBasetype();
assert(t->ty == Tpointer && "unsupported derivedtype for debug info, only pointers allowed");
// find base type
llvm::DIType basetype;
Type* nt = t->nextOf();
basetype = dwarfTypeDescription_impl(nt, compileUnit, NULL);
if (nt->ty == Tvoid)
basetype = llvm::DIType(NULL);
return gIR->difactory.CreateDerivedType(
DW_TAG_pointer_type, // tag
compileUnit, // context
"", // name
llvm::DICompileUnit(NULL), // compile unit
0, // line number
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
0, // offset (bits)
//FIXME: need flags?
0, // flags
basetype // derived from
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIDerivedType dwarfMemberType(unsigned linnum, Type* type, llvm::DICompileUnit compileUnit, llvm::DICompileUnit definedCU, const char* c_name, unsigned offset)
{
const LLType* T = DtoType(type);
Type* t = type->toBasetype();
// find base type
llvm::DIType basetype;
basetype = dwarfTypeDescription(t, compileUnit, NULL);
if (t->ty == Tvoid)
basetype = llvm::DIType(NULL);
return gIR->difactory.CreateDerivedType(
DW_TAG_member, // tag
compileUnit, // context
c_name, // name
definedCU, // compile unit
linnum, // line number
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
offset*8, // offset (bits)
//FIXME: need flags?
0, // flags
basetype // derived from
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static void add_base_fields(
ClassDeclaration* sd,
llvm::DICompileUnit compileUnit,
llvm::DICompileUnit definedCU,
std::vector<LLConstant*>& elems)
{
if (sd->baseClass)
{
add_base_fields(sd->baseClass, compileUnit, definedCU, elems);
}
ArrayIter<VarDeclaration> it(sd->fields);
size_t narr = sd->fields.dim;
elems.reserve(narr);
for (; !it.done(); it.next())
{
VarDeclaration* vd = it.get();
LLGlobalVariable* ptr = dwarfMemberType(vd->loc.linnum, vd->type, compileUnit, definedCU, vd->toChars(), vd->offset).getGV();
elems.push_back(DBG_CAST(ptr));
}
}
//FIXME: This does not use llvm's DIFactory as it can't
// handle recursive types properly.
static llvm::DICompositeType dwarfCompositeType(Type* type, llvm::DICompileUnit compileUnit)
{
const LLType* T = DtoType(type);
Type* t = type->toBasetype();
// defaults
LLConstant* name = getNullPtr(getVoidPtrType());
LLGlobalVariable* members = NULL;
unsigned linnum = 0;
llvm::DICompileUnit definedCU;
// prepare tag and members
unsigned tag;
// declare final global variable
LLGlobalVariable* gv = NULL;
// dynamic array
if (t->ty == Tarray)
{
tag = DW_TAG_structure_type;
LLGlobalVariable* len = dwarfMemberType(0, Type::tsize_t, compileUnit, llvm::DICompileUnit(NULL), "length", 0).getGV();
assert(len);
LLGlobalVariable* ptr = dwarfMemberType(0, t->nextOf()->pointerTo(), compileUnit, llvm::DICompileUnit(NULL), "ptr", global.params.is64bit?8:4).getGV();
assert(ptr);
const LLArrayType* at = LLArrayType::get(DBG_TYPE, 2);
std::vector<LLConstant*> elems(2);
elems[0] = DBG_CAST(len);
elems[1] = DBG_CAST(ptr);
LLConstant* ca = LLConstantArray::get(at, elems);
members = new LLGlobalVariable(*gIR->module, ca->getType(), true, LLGlobalValue::InternalLinkage, ca, ".array");
members->setSection("llvm.metadata");
name = DtoConstStringPtr(t->toChars(), "llvm.metadata");
}
// struct/class
else if (t->ty == Tstruct || t->ty == Tclass)
{
AggregateDeclaration* sd;
if (t->ty == Tstruct)
{
TypeStruct* ts = (TypeStruct*)t;
sd = ts->sym;
}
else
{
TypeClass* tc = (TypeClass*)t;
sd = tc->sym;
}
assert(sd);
// make sure it's resolved
sd->codegen(Type::sir);
// if we don't know the aggregate's size, we don't know enough about it
// to provide debug info. probably a forward-declared struct?
if (sd->sizeok == 0)
return llvm::DICompositeType(NULL);
IrStruct* ir = sd->ir.irStruct;
assert(ir);
if (!ir->diCompositeType.isNull())
return ir->diCompositeType;
// set to handle recursive types properly
gv = emitDwarfGlobalDecl(getDwarfCompositeTypeType(), "llvm.dbg.compositetype");
// set bogus initializer to satisfy asserts in DICompositeType constructor
std::vector<LLConstant*> initvals(11);
initvals[0] = DBG_TAG(DW_TAG_structure_type);
for (int i = 1; i < initvals.size(); ++i)
initvals[i] = LLConstant::getNullValue(getDwarfCompositeTypeType()->getContainedType(i));
gv->setInitializer(LLConstantStruct::get(getDwarfCompositeTypeType(), initvals));
ir->diCompositeType = llvm::DICompositeType(gv);
tag = DW_TAG_structure_type;
name = DtoConstStringPtr(sd->toChars(), "llvm.metadata");
linnum = sd->loc.linnum;
definedCU = DtoDwarfCompileUnit(getDefinedModule(sd));
std::vector<LLConstant*> elems;
if (!ir->aggrdecl->isInterfaceDeclaration()) // plain interfaces don't have one
{
if (t->ty == Tstruct)
{
ArrayIter<VarDeclaration> it(sd->fields);
size_t narr = sd->fields.dim;
elems.reserve(narr);
for (; !it.done(); it.next())
{
VarDeclaration* vd = it.get();
LLGlobalVariable* ptr = dwarfMemberType(vd->loc.linnum, vd->type, compileUnit, definedCU, vd->toChars(), vd->offset).getGV();
elems.push_back(DBG_CAST(ptr));
}
}
else
{
add_base_fields(ir->aggrdecl->isClassDeclaration(), compileUnit, definedCU, elems);
}
}
const LLArrayType* at = LLArrayType::get(DBG_TYPE, elems.size());
LLConstant* ca = LLConstantArray::get(at, elems);
members = new LLGlobalVariable(*gIR->module, ca->getType(), true, LLGlobalValue::InternalLinkage, ca, ".array");
members->setSection("llvm.metadata");
}
// unsupported composite type
else
{
assert(0 && "unsupported compositetype for debug info");
}
std::vector<LLConstant*> vals(11);
// tag
vals[0] = DBG_TAG(tag);
// context
vals[1] = DBG_CAST(compileUnit.getGV());
// name
vals[2] = name;
// compile unit where defined
if (definedCU.getGV())
vals[3] = DBG_CAST(definedCU.getGV());
else
vals[3] = DBG_NULL;
// line number where defined
vals[4] = DtoConstInt(linnum);
// size in bits
vals[5] = LLConstantInt::get(LLType::getInt64Ty(gIR->context()), getTypeBitSize(T), false);
// alignment in bits
vals[6] = LLConstantInt::get(LLType::getInt64Ty(gIR->context()), getABITypeAlign(T)*8, false);
// offset in bits
vals[7] = LLConstantInt::get(LLType::getInt64Ty(gIR->context()), 0, false);
// FIXME: dont know what this is
vals[8] = DtoConstUint(0);
// FIXME: ditto
vals[9] = DBG_NULL;
// members array
if (members)
vals[10] = DBG_CAST(members);
else
vals[10] = DBG_NULL;
// set initializer
if (!gv)
gv = emitDwarfGlobalDecl(getDwarfCompositeTypeType(), "llvm.dbg.compositetype");
LLConstant* initia = LLConstantStruct::get(getDwarfCompositeTypeType(), vals);
gv->setInitializer(initia);
return llvm::DICompositeType(gv);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIGlobalVariable dwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd)
{
#if DMDV2
assert(vd->isDataseg() || (vd->storage_class & (STCconst | STCimmutable) && vd->init));
#else
assert(vd->isDataseg());
#endif
llvm::DICompileUnit compileUnit = DtoDwarfCompileUnit(gIR->dmodule);
return gIR->difactory.CreateGlobalVariable(
compileUnit, // context
vd->mangle(), // name
vd->toPrettyChars(), // displayname
vd->toChars(), // linkage name
DtoDwarfCompileUnit(getDefinedModule(vd)), // compile unit
vd->loc.linnum, // line num
dwarfTypeDescription_impl(vd->type, compileUnit, NULL), // type
vd->protection == PROTprivate, // is local to unit
getDefinedModule(vd) == gIR->dmodule, // is definition
ll // value
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIVariable dwarfVariable(VarDeclaration* vd, llvm::DIType type)
{
assert(!vd->isDataseg() && "static variable");
unsigned tag;
if (vd->isParameter())
tag = DW_TAG_arg_variable;
else
tag = DW_TAG_auto_variable;
return gIR->difactory.CreateVariable(
tag, // tag
gIR->func()->diSubprogram, // context
vd->toChars(), // name
DtoDwarfCompileUnit(getDefinedModule(vd)), // compile unit
vd->loc.linnum, // line num
type // type
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static void dwarfDeclare(LLValue* var, llvm::DIVariable divar)
{
gIR->difactory.InsertDeclare(var, divar, gIR->scopebb());
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIType dwarfTypeDescription_impl(Type* type, llvm::DICompileUnit cu, const char* c_name)
{
Type* t = type->toBasetype();
if (t->ty == Tvoid)
return llvm::DIType(NULL);
else if (t->isintegral() || t->isfloating())
return dwarfBasicType(type, cu);
else if (t->ty == Tpointer)
return dwarfDerivedType(type, cu);
else if (t->ty == Tarray || t->ty == Tstruct || t->ty == Tclass)
return dwarfCompositeType(type, cu);
return llvm::DIType(NULL);
}
static llvm::DIType dwarfTypeDescription(Type* type, llvm::DICompileUnit cu, const char* c_name)
{
Type* t = type->toBasetype();
if (t->ty == Tclass)
return dwarfTypeDescription_impl(type->pointerTo(), cu, c_name);
else
return dwarfTypeDescription_impl(type, cu, c_name);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd)
{
Logger::println("D to dwarf local variable");
LOG_SCOPE;
// get compile units
llvm::DICompileUnit thisCU = DtoDwarfCompileUnit(gIR->dmodule);
llvm::DICompileUnit varCU = DtoDwarfCompileUnit(getDefinedModule(vd));
// get type description
llvm::DIType TD = dwarfTypeDescription(vd->type, thisCU, NULL);
if (TD.isNull())
return; // unsupported
// get variable description
llvm::DIVariable VD = dwarfVariable(vd, TD);
// declare
dwarfDeclare(ll, VD);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
llvm::DICompileUnit DtoDwarfCompileUnit(Module* m)
{
Logger::println("D to dwarf compile_unit");
LOG_SCOPE;
// we might be generating for an import
IrModule* irmod = getIrModule(m);
if (!irmod->diCompileUnit.isNull())
{
assert (irmod->diCompileUnit.getGV()->getParent() == gIR->module
&& "debug info compile unit belongs to incorrect llvm module!");
return irmod->diCompileUnit;
}
// prepare srcpath
std::string srcpath(FileName::path(m->srcfile->name->toChars()));
if (!FileName::absolute(srcpath.c_str())) {
llvm::sys::Path tmp = llvm::sys::Path::GetCurrentDirectory();
tmp.appendComponent(srcpath);
srcpath = tmp.toString();
if (!srcpath.empty() && *srcpath.rbegin() != '/' && *srcpath.rbegin() != '\\')
srcpath = srcpath + '/';
}
// make compile unit
irmod->diCompileUnit = gIR->difactory.CreateCompileUnit(
global.params.symdebug == 2 ? DW_LANG_C : DW_LANG_D,
m->srcfile->name->toChars(),
srcpath,
"LDC (http://www.dsource.org/projects/ldc)",
//FIXME: What do these two mean?
false, // isMain,
false // isOptimized
);
// if the linkage stays internal, we can't llvm-link the generated modules together:
// llvm's DwarfWriter uses path and filename to determine the symbol name and we'd
// end up with duplicate symbols
irmod->diCompileUnit.getGV()->setLinkage(DEBUGINFO_LINKONCE_LINKAGE_TYPE);
irmod->diCompileUnit.getGV()->setName(std::string("llvm.dbg.compile_unit_") + srcpath + m->srcfile->name->toChars());
return irmod->diCompileUnit;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
llvm::DISubprogram DtoDwarfSubProgram(FuncDeclaration* fd)
{
Logger::println("D to dwarf subprogram");
LOG_SCOPE;
llvm::DICompileUnit context = DtoDwarfCompileUnit(gIR->dmodule);
llvm::DICompileUnit definition = DtoDwarfCompileUnit(getDefinedModule(fd));
// FIXME: duplicates ?
return gIR->difactory.CreateSubprogram(
context, // context
fd->toPrettyChars(), // name
fd->toPrettyChars(), // display name
fd->mangle(), // linkage name
definition, // compile unit
fd->loc.linnum, // line no
//FIXME: what's this type for?
llvm::DIType(NULL), // type
fd->protection == PROTprivate, // is local to unit
context.getGV() == definition.getGV() // isdefinition
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
llvm::DISubprogram DtoDwarfSubProgramInternal(const char* prettyname, const char* mangledname)
{
Logger::println("D to dwarf subprogram");
LOG_SCOPE;
llvm::DICompileUnit context = DtoDwarfCompileUnit(gIR->dmodule);
// FIXME: duplicates ?
return gIR->difactory.CreateSubprogram(
context, // context
prettyname, // name
prettyname, // display name
mangledname, // linkage name
context, // compile unit
0, // line no
//FIXME: what's this type for?
llvm::DIType(NULL), // type
true, // is local to unit
true // isdefinition
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
llvm::DIGlobalVariable DtoDwarfGlobalVariable(LLGlobalVariable* ll, VarDeclaration* vd)
{
Logger::println("D to dwarf global_variable");
LOG_SCOPE;
// FIXME: duplicates ?
return dwarfGlobalVariable(ll, vd);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void DtoDwarfFuncStart(FuncDeclaration* fd)
{
Logger::println("D to dwarf funcstart");
LOG_SCOPE;
assert(!fd->ir.irFunc->diSubprogram.isNull());
gIR->difactory.InsertSubprogramStart(fd->ir.irFunc->diSubprogram, gIR->scopebb());
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void DtoDwarfFuncEnd(FuncDeclaration* fd)
{
Logger::println("D to dwarf funcend");
LOG_SCOPE;
assert(!fd->ir.irFunc->diSubprogram.isNull());
gIR->difactory.InsertRegionEnd(fd->ir.irFunc->diSubprogram, gIR->scopebb());
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void DtoDwarfStopPoint(unsigned ln)
{
Logger::println("D to dwarf stoppoint at line %u", ln);
LOG_SCOPE;
gIR->difactory.InsertStopPoint(
DtoDwarfCompileUnit(getDefinedModule(gIR->func()->decl)), // compile unit
ln, // line no
0, // col no
gIR->scopebb()
);
}
#endif