ldc/gen/todebug.cpp
2011-04-20 09:28:37 -06:00

557 lines
16 KiB
C++

#include "gen/llvm.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/PathV2.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
//////////////////////////////////////////////////////////////////////////////////////////////////
// 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, const char* c_name);
static llvm::DIType dwarfTypeDescription(Type* type, const char* c_name);
//////////////////////////////////////////////////////////////////////////////////////////////////
llvm::DIFile DtoDwarfFile(Loc loc)
{
llvm::SmallString<128> path(loc.filename);
llvm::sys::fs::make_absolute(path);
return gIR->dibuilder.createFile(
llvm::sys::path::filename(path),
llvm::sys::path::parent_path(path)
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIType dwarfBasicType(Type* type)
{
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->dibuilder.createBasicType(
type->toChars(), // name
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
id
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIType dwarfPointerType(Type* type)
{
const LLType* T = DtoType(type);
Type* t = type->toBasetype();
assert(t->ty == Tpointer && "only pointers allowed for debug info in dwarfPointerType");
// find base type
llvm::DIType basetype;
Type* nt = t->nextOf();
basetype = dwarfTypeDescription_impl(nt, NULL);
if (nt->ty == Tvoid)
basetype = llvm::DIType(NULL);
return gIR->dibuilder.createPointerType(
basetype,
getTypeBitSize(T), // size (bits)
getABITypeAlign(T)*8, // align (bits)
type->toChars() // name
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIType dwarfMemberType(unsigned linnum, Type* type, llvm::DIFile file, const char* c_name, unsigned offset)
{
const LLType* T = DtoType(type);
Type* t = type->toBasetype();
// find base type
llvm::DIType basetype;
basetype = dwarfTypeDescription(t, NULL);
if (t->ty == Tvoid)
basetype = llvm::DIType(NULL);
return gIR->dibuilder.createMemberType(
c_name, // name
file, // file
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::DIFile file,
std::vector<llvm::Value*>& elems)
{
if (sd->baseClass)
{
add_base_fields(sd->baseClass, file, elems);
}
ArrayIter<VarDeclaration> it(sd->fields);
size_t narr = sd->fields.dim;
elems.reserve(narr);
for (; !it.done(); it.next())
{
VarDeclaration* vd = it.get();
elems.push_back(dwarfMemberType(vd->loc.linnum, vd->type, file, vd->toChars(), vd->offset));
}
}
static llvm::DIType dwarfCompositeType(Type* type)
{
const LLType* T = DtoType(type);
Type* t = type->toBasetype();
// defaults
llvm::StringRef name;
unsigned linnum = 0;
llvm::DIFile file;
// elements
std::vector<llvm::Value*> elems;
// pointer to ir->diCompositeType
llvm::DIType *diCompositeType = 0;
llvm::DIType derivedFrom;
assert((t->ty == Tstruct || t->ty == Tclass) &&
"unsupported type for dwarfCompositeType");
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 ((llvm::MDNode*)ir->diCompositeType != 0)
return ir->diCompositeType;
diCompositeType = &ir->diCompositeType;
name = sd->toChars();
linnum = sd->loc.linnum;
file = DtoDwarfFile(sd->loc);
// set diCompositeType to handle recursive types properly
if (t->ty == Tclass) {
ir->diCompositeType = gIR->dibuilder.createClassType(
llvm::DIDescriptor(file),
name, // name
file, // compile unit where defined
linnum, // line number where defined
getTypeBitSize(T), // size in bits
getABITypeAlign(T)*8, // alignment in bits
0, // offset in bits,
llvm::DIType::FlagFwdDecl, // flags
derivedFrom, // DerivedFrom
llvm::DIArray(0)
);
} else {
ir->diCompositeType = gIR->dibuilder.createStructType(
llvm::DIDescriptor(file),
name, // name
file, // compile unit where defined
linnum, // line number where defined
getTypeBitSize(T), // size in bits
getABITypeAlign(T)*8, // alignment in bits
llvm::DIType::FlagFwdDecl, // flags
llvm::DIArray(0)
);
}
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();
llvm::DIType dt = dwarfMemberType(vd->loc.linnum, vd->type, file, vd->toChars(), vd->offset);
elems.push_back(dt);
}
}
else
{
ClassDeclaration *classDecl = ir->aggrdecl->isClassDeclaration();
add_base_fields(classDecl, file, elems);
if (classDecl->baseClass)
derivedFrom = dwarfCompositeType(classDecl->baseClass->getType());
}
}
llvm::DIArray elemsArray =
gIR->dibuilder.getOrCreateArray(elems.data(), elems.size());
llvm::DIType ret;
if (t->ty == Tclass) {
ret = gIR->dibuilder.createClassType(
llvm::DIDescriptor(file),
name, // name
file, // compile unit where defined
linnum, // line number where defined
getTypeBitSize(T), // size in bits
getABITypeAlign(T)*8, // alignment in bits
0, // offset in bits,
llvm::DIType::FlagFwdDecl, // flags
derivedFrom, // DerivedFrom
elemsArray
);
} else {
ret = gIR->dibuilder.createStructType(
llvm::DIDescriptor(file),
name, // name
file, // compile unit where defined
linnum, // line number where defined
getTypeBitSize(T), // size in bits
getABITypeAlign(T)*8, // alignment in bits
llvm::DIType::FlagFwdDecl, // flags
elemsArray
);
}
if (diCompositeType)
*diCompositeType = ret;
return ret;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
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
return gIR->dibuilder.createGlobalVariable(
vd->toChars(), // name TODO: mangle() or toPrettyChars() instead?
DtoDwarfFile(vd->loc), // file
vd->loc.linnum, // line num
dwarfTypeDescription_impl(vd->type, NULL), // type
vd->protection == PROTprivate, // is local to unit
ll // value
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static void dwarfDeclare(LLValue* var, llvm::DIVariable divar)
{
llvm::Instruction *instr = gIR->dibuilder.insertDeclare(var, divar, gIR->scopebb());
instr->setDebugLoc(gIR->ir->getCurrentDebugLocation());
}
//////////////////////////////////////////////////////////////////////////////////////////////////
llvm::DIType dwarfArrayType(Type* type) {
const LLType* T = DtoType(type);
Type* t = type->toBasetype();
llvm::DIFile file = DtoDwarfFile(Loc(gIR->dmodule, 0));
std::vector<llvm::Value*> elems;
elems.push_back(dwarfMemberType(0, Type::tsize_t, file, "length", 0));
elems.push_back(dwarfMemberType(0, t->nextOf()->pointerTo(), file, "ptr", global.params.is64bit?8:4));
return gIR->dibuilder.createStructType
(
llvm::DIDescriptor(file),
llvm::StringRef(), // Name TODO: Really no name for arrays?
file, // File
0, // LineNo
getTypeBitSize(T), // size in bits
getABITypeAlign(T)*8, // alignment in bits
0, // What here?
gIR->dibuilder.getOrCreateArray(elems.data(), elems.size())
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static llvm::DIType dwarfTypeDescription_impl(Type* type, 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);
else if (t->ty == Tpointer)
return dwarfPointerType(type);
else if (t->ty == Tarray)
return dwarfArrayType(type);
else if (t->ty == Tstruct || t->ty == Tclass)
return dwarfCompositeType(type);
return llvm::DIType(NULL);
}
static llvm::DIType dwarfTypeDescription(Type* type, const char* c_name)
{
Type* t = type->toBasetype();
if (t->ty == Tclass)
return dwarfTypeDescription_impl(type->pointerTo(), c_name);
else
return dwarfTypeDescription_impl(type, c_name);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd)
{
Logger::println("D to dwarf local variable");
LOG_SCOPE;
// get type description
llvm::DIType TD = dwarfTypeDescription(vd->type, NULL);
if ((llvm::MDNode*)TD == 0)
return; // unsupported
// get variable description
assert(!vd->isDataseg() && "static variable");
unsigned tag;
if (vd->isParameter())
tag = DW_TAG_arg_variable;
else
tag = DW_TAG_auto_variable;
vd->debugVariable = gIR->dibuilder.createLocalVariable(
tag, // tag
gIR->func()->diSubprogram, // context
vd->toChars(), // name
DtoDwarfFile(vd->loc), // file
vd->loc.linnum, // line num
TD, // type
true // preserve
);
// declare
dwarfDeclare(ll, vd->debugVariable);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void DtoDwarfCompileUnit(Module* m)
{
Logger::println("D to dwarf compile_unit");
LOG_SCOPE;
// 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.str();
if (!srcpath.empty() && *srcpath.rbegin() != '/' && *srcpath.rbegin() != '\\')
srcpath = srcpath + '/';
}
gIR->dibuilder.createCompileUnit(
global.params.symdebug == 2 ? DW_LANG_C : DW_LANG_D,
m->srcfile->name->toChars(),
srcpath,
"LDC (http://www.dsource.org/projects/ldc)",
false, // isOptimized TODO
llvm::StringRef(), // Flags TODO
1 // Runtime Version TODO
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
llvm::DISubprogram DtoDwarfSubProgram(FuncDeclaration* fd)
{
Logger::println("D to dwarf subprogram");
LOG_SCOPE;
llvm::DIFile file = DtoDwarfFile(fd->loc);
Type *retType = ((TypeFunction*)fd->type)->next;
// FIXME: duplicates ?
return gIR->dibuilder.createFunction(
llvm::DICompileUnit(file), // context
fd->toPrettyChars(), // name
fd->mangle(), // linkage name
file, // file
fd->loc.linnum, // line no
dwarfTypeDescription(retType, NULL), // type
fd->protection == PROTprivate, // is local to unit
gIR->dmodule == getDefinedModule(fd), // isdefinition
0, // Flags
false, // isOptimized
fd->ir.irFunc->func
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
llvm::DISubprogram DtoDwarfSubProgramInternal(const char* prettyname, const char* mangledname)
{
Logger::println("D to dwarf subprogram");
LOG_SCOPE;
llvm::DIFile file(DtoDwarfFile(Loc(gIR->dmodule, 0)));
// FIXME: duplicates ?
return gIR->dibuilder.createFunction(
llvm::DIDescriptor(file), // context
prettyname, // name
mangledname, // linkage name
file, // file
0, // line no
llvm::DIType(NULL), // return type. TODO: fill it up
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((llvm::MDNode*)fd->ir.irFunc->diSubprogram != 0);
DtoDwarfStopPoint(fd->loc.linnum);
/* fd->ir.irFunc->diLexicalBlock = gIR->difactory.CreateLexicalBlock(
fd->ir.irFunc->diSubprogram, // context
DtoDwarfFile(fd->loc, DtoDwarfCompileUnit(getDefinedModule(fd))), // file
fd->loc.linnum
);*/
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void DtoDwarfFuncEnd(FuncDeclaration* fd)
{
Logger::println("D to dwarf funcend");
LOG_SCOPE;
assert((llvm::MDNode*)fd->ir.irFunc->diSubprogram != 0);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void DtoDwarfStopPoint(unsigned ln)
{
Logger::println("D to dwarf stoppoint at line %u", ln);
LOG_SCOPE;
llvm::DebugLoc loc = llvm::DebugLoc::get(ln, 0, gIR->func()->diSubprogram);
gIR->ir->SetCurrentDebugLocation(loc);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void DtoDwarfValue(LLValue* var, VarDeclaration* vd)
{
if (llvm::isa<llvm::AllocaInst>(vd->ir.irLocal->value) == 0)
return;
llvm::Instruction *instr = gIR->dibuilder.insertDbgValueIntrinsic(vd->ir.irLocal->value, 0, vd->debugVariable, gIR->scopebb());
instr->setDebugLoc(gIR->ir->getCurrentDebugLocation());
}
#endif