mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-03 00:20:40 +03:00
424 lines
14 KiB
C++
424 lines
14 KiB
C++
#include "gen/llvm.h"
|
|
#include "llvm/Support/Dwarf.h"
|
|
#include "llvm/CodeGen/MachineModuleInfo.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 "ir/irmodule.h"
|
|
|
|
using namespace llvm::dwarf;
|
|
|
|
static const llvm::PointerType* ptrTy(const LLType* t)
|
|
{
|
|
return llvm::PointerType::get(t, 0);
|
|
}
|
|
|
|
static const llvm::PointerType* dbgArrTy()
|
|
{
|
|
return ptrTy(llvm::StructType::get(NULL,NULL));
|
|
}
|
|
|
|
static LLConstant* dbgToArrTy(LLConstant* c)
|
|
{
|
|
return llvm::ConstantExpr::getBitCast(c, dbgArrTy());
|
|
}
|
|
|
|
#define Ty(X) LLType::X
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static llvm::GlobalVariable* dbg_compile_units = 0;
|
|
static llvm::GlobalVariable* dbg_global_variables = 0;
|
|
static llvm::GlobalVariable* dbg_subprograms = 0;
|
|
|
|
const llvm::StructType* GetDwarfAnchorType()
|
|
{
|
|
/*
|
|
%llvm.dbg.anchor.type = type {
|
|
uint, ;; Tag = 0 + LLVMDebugVersion
|
|
uint ;; Tag of descriptors grouped by the anchor
|
|
}
|
|
*/
|
|
|
|
const llvm::StructType* t = isaStruct(gIR->module->getTypeByName("llvm.dbg.anchor.type"));
|
|
|
|
/*
|
|
%llvm.dbg.compile_units = linkonce constant %llvm.dbg.anchor.type { uint 0, uint 17 } ;; DW_TAG_compile_unit
|
|
%llvm.dbg.global_variables = linkonce constant %llvm.dbg.anchor.type { uint 0, uint 52 } ;; DW_TAG_variable
|
|
%llvm.dbg.subprograms = linkonce constant %llvm.dbg.anchor.type { uint 0, uint 46 } ;; DW_TAG_subprogram
|
|
*/
|
|
if (!gIR->module->getNamedGlobal("llvm.dbg.compile_units")) {
|
|
std::vector<LLConstant*> vals;
|
|
vals.push_back(DtoConstUint(llvm::LLVMDebugVersion));
|
|
vals.push_back(DtoConstUint(DW_TAG_compile_unit));
|
|
LLConstant* i = llvm::ConstantStruct::get(t, vals);
|
|
dbg_compile_units = new llvm::GlobalVariable(t,true,llvm::GlobalValue::LinkOnceLinkage,i,"llvm.dbg.compile_units",gIR->module);
|
|
dbg_compile_units->setSection("llvm.metadata");
|
|
}
|
|
if (!gIR->module->getNamedGlobal("llvm.dbg.global_variables")) {
|
|
std::vector<LLConstant*> vals;
|
|
vals.push_back(DtoConstUint(llvm::LLVMDebugVersion));
|
|
vals.push_back(DtoConstUint(DW_TAG_variable));
|
|
LLConstant* i = llvm::ConstantStruct::get(t, vals);
|
|
dbg_global_variables = new llvm::GlobalVariable(t,true,llvm::GlobalValue::LinkOnceLinkage,i,"llvm.dbg.global_variables",gIR->module);
|
|
dbg_global_variables->setSection("llvm.metadata");
|
|
}
|
|
if (!gIR->module->getNamedGlobal("llvm.dbg.subprograms")) {
|
|
std::vector<LLConstant*> vals;
|
|
vals.push_back(DtoConstUint(llvm::LLVMDebugVersion));
|
|
vals.push_back(DtoConstUint(DW_TAG_subprogram));
|
|
LLConstant* i = llvm::ConstantStruct::get(t, vals);
|
|
dbg_subprograms = new llvm::GlobalVariable(t,true,llvm::GlobalValue::LinkOnceLinkage,i,"llvm.dbg.subprograms",gIR->module);
|
|
dbg_subprograms->setSection("llvm.metadata");
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
LLConstant* GetDwarfAnchor(llvm::dwarf::dwarf_constants c)
|
|
{
|
|
GetDwarfAnchorType();
|
|
switch (c)
|
|
{
|
|
case DW_TAG_compile_unit:
|
|
return dbg_compile_units;
|
|
case DW_TAG_variable:
|
|
return dbg_global_variables;
|
|
case DW_TAG_subprogram:
|
|
return dbg_subprograms;
|
|
}
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
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"));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLGlobalVariable* DtoDwarfCompileUnit(Module* m)
|
|
{
|
|
if (!m->ir.irModule)
|
|
m->ir.irModule = new IrModule(m);
|
|
else if (m->ir.irModule->dwarfCompileUnit)
|
|
{
|
|
if (m->ir.irModule->dwarfCompileUnit->getParent() == gIR->module)
|
|
return m->ir.irModule->dwarfCompileUnit;
|
|
}
|
|
|
|
// create a valid compile unit constant for the current module
|
|
|
|
LLConstant* c = NULL;
|
|
|
|
std::vector<LLConstant*> vals;
|
|
vals.push_back(llvm::ConstantExpr::getAdd(
|
|
DtoConstUint(DW_TAG_compile_unit),
|
|
DtoConstUint(llvm::LLVMDebugVersion)));
|
|
vals.push_back(dbgToArrTy(GetDwarfAnchor(DW_TAG_compile_unit)));
|
|
|
|
vals.push_back(DtoConstUint(DW_LANG_C));// _D)); // doesn't seem to work
|
|
vals.push_back(DtoConstStringPtr(m->srcfile->name->toChars(), "llvm.metadata"));
|
|
std::string srcpath(FileName::path(m->srcfile->name->toChars()));
|
|
if (srcpath.empty()) {
|
|
const char* str = get_current_dir_name();
|
|
assert(str != NULL);
|
|
srcpath = str;
|
|
}
|
|
vals.push_back(DtoConstStringPtr(srcpath.c_str(), "llvm.metadata"));
|
|
vals.push_back(DtoConstStringPtr("LLVMDC (http://www.dsource.org/projects/llvmdc)", "llvm.metadata"));
|
|
|
|
c = llvm::ConstantStruct::get(GetDwarfCompileUnitType(), vals);
|
|
|
|
llvm::GlobalVariable* gv = new llvm::GlobalVariable(GetDwarfCompileUnitType(), true, llvm::GlobalValue::InternalLinkage, c, "llvm.dbg.compile_unit", gIR->module);
|
|
gv->setSection("llvm.metadata");
|
|
|
|
m->ir.irModule->dwarfCompileUnit = gv;
|
|
return gv;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LLGlobalVariable* DtoDwarfSubProgram(FuncDeclaration* fd, llvm::GlobalVariable* compileUnit)
|
|
{
|
|
std::vector<LLConstant*> vals;
|
|
vals.push_back(llvm::ConstantExpr::getAdd(
|
|
DtoConstUint(DW_TAG_subprogram),
|
|
DtoConstUint(llvm::LLVMDebugVersion)));
|
|
vals.push_back(dbgToArrTy(GetDwarfAnchor(DW_TAG_subprogram)));
|
|
|
|
vals.push_back(dbgToArrTy(compileUnit));
|
|
vals.push_back(DtoConstStringPtr(fd->toPrettyChars(), "llvm.metadata"));
|
|
vals.push_back(vals.back());
|
|
vals.push_back(DtoConstStringPtr(fd->mangle(), "llvm.metadata"));
|
|
vals.push_back(dbgToArrTy(compileUnit));
|
|
vals.push_back(DtoConstUint(fd->loc.linnum));
|
|
vals.push_back(llvm::ConstantPointerNull::get(dbgArrTy()));
|
|
vals.push_back(DtoConstBool(fd->protection == PROTprivate));
|
|
vals.push_back(DtoConstBool(fd->getModule() == gIR->dmodule));
|
|
|
|
LLConstant* c = llvm::ConstantStruct::get(GetDwarfSubProgramType(), vals);
|
|
llvm::GlobalVariable* gv = new llvm::GlobalVariable(c->getType(), true, llvm::GlobalValue::InternalLinkage, c, "llvm.dbg.subprogram", gIR->module);
|
|
gv->setSection("llvm.metadata");
|
|
return gv;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DtoDwarfFuncStart(FuncDeclaration* fd)
|
|
{
|
|
assert(fd->ir.irFunc->dwarfSubProg);
|
|
gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.func.start"), dbgToArrTy(fd->ir.irFunc->dwarfSubProg));
|
|
}
|
|
|
|
void DtoDwarfFuncEnd(FuncDeclaration* fd)
|
|
{
|
|
assert(fd->ir.irFunc->dwarfSubProg);
|
|
gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.region.end"), dbgToArrTy(fd->ir.irFunc->dwarfSubProg));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void DtoDwarfStopPoint(unsigned ln)
|
|
{
|
|
LLSmallVector<LLValue*,3> args;
|
|
args.push_back(DtoConstUint(ln));
|
|
args.push_back(DtoConstUint(0));
|
|
FuncDeclaration* fd = gIR->func()->decl;
|
|
args.push_back(dbgToArrTy(DtoDwarfCompileUnit(fd->getModule())));
|
|
gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.stoppoint"), args.begin(), args.end());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static LLGlobalVariable* DtoDwarfTypeDescription(Loc loc, Type* type, LLGlobalVariable* cu);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static LLGlobalVariable* DtoDwarfBasicType(Type* type, llvm::GlobalVariable* compileUnit)
|
|
{
|
|
Type* t = type->toBasetype();
|
|
|
|
|
|
const LLType* T = DtoType(type);
|
|
|
|
std::vector<LLConstant*> vals;
|
|
// tag
|
|
vals.push_back(llvm::ConstantExpr::getAdd(
|
|
DtoConstUint(DW_TAG_base_type),
|
|
DtoConstUint(llvm::LLVMDebugVersion)));
|
|
// context
|
|
vals.push_back(dbgToArrTy(compileUnit));
|
|
// name
|
|
vals.push_back(DtoConstStringPtr(type->toChars(), "llvm.metadata"));
|
|
// compile unit where defined
|
|
vals.push_back(getNullPtr(dbgArrTy()));
|
|
// line number where defined
|
|
vals.push_back(DtoConstInt(0));
|
|
// size in bits
|
|
vals.push_back(LLConstantInt::get(LLType::Int64Ty, getTypeBitSize(T), false));
|
|
// alignment in bits
|
|
vals.push_back(LLConstantInt::get(LLType::Int64Ty, getABITypeAlign(T)*8, false));
|
|
// offset in bits
|
|
vals.push_back(LLConstantInt::get(LLType::Int64Ty, 0, false));
|
|
// FIXME: dont know what this is
|
|
vals.push_back(DtoConstUint(0));
|
|
// dwarf type
|
|
unsigned id;
|
|
if (t->isintegral())
|
|
{
|
|
if (type->isunsigned())
|
|
id = llvm::dwarf::DW_ATE_unsigned;
|
|
else
|
|
id = llvm::dwarf::DW_ATE_signed;
|
|
}
|
|
else if (t->isfloating())
|
|
{
|
|
id = llvm::dwarf::DW_ATE_float;
|
|
}
|
|
else
|
|
{
|
|
assert(0 && "unsupported basictype for debug info");
|
|
}
|
|
vals.push_back(DtoConstUint(id));
|
|
|
|
LLConstant* c = llvm::ConstantStruct::get(GetDwarfBasicTypeType(), vals);
|
|
LLGlobalVariable* gv = new LLGlobalVariable(c->getType(), true, LLGlobalValue::InternalLinkage, c, "llvm.dbg.basictype", gIR->module);
|
|
gv->setSection("llvm.metadata");
|
|
return gv;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static LLGlobalVariable* DtoDwarfDerivedType(Loc loc, Type* type, llvm::GlobalVariable* compileUnit)
|
|
{
|
|
const LLType* T = DtoType(type);
|
|
Type* t = DtoDType(type);
|
|
|
|
// defaults
|
|
LLConstant* name = getNullPtr(getVoidPtrType());
|
|
|
|
// find tag
|
|
unsigned tag;
|
|
if (t->ty == Tpointer)
|
|
{
|
|
tag = llvm::dwarf::DW_TAG_pointer_type;
|
|
}
|
|
else
|
|
{
|
|
assert(0 && "unsupported derivedtype for debug info");
|
|
}
|
|
|
|
std::vector<LLConstant*> vals;
|
|
// tag
|
|
vals.push_back(llvm::ConstantExpr::getAdd(
|
|
DtoConstUint(tag),
|
|
DtoConstUint(llvm::LLVMDebugVersion)));
|
|
// context
|
|
vals.push_back(dbgToArrTy(compileUnit));
|
|
// name
|
|
vals.push_back(name);
|
|
// compile unit where defined
|
|
vals.push_back(getNullPtr(dbgArrTy()));
|
|
// line number where defined
|
|
vals.push_back(DtoConstInt(0));
|
|
// size in bits
|
|
vals.push_back(LLConstantInt::get(LLType::Int64Ty, getTypeBitSize(T), false));
|
|
// alignment in bits
|
|
vals.push_back(LLConstantInt::get(LLType::Int64Ty, getABITypeAlign(T)*8, false));
|
|
// offset in bits
|
|
vals.push_back(LLConstantInt::get(LLType::Int64Ty, 0, false));
|
|
// FIXME: dont know what this is
|
|
vals.push_back(DtoConstUint(0));
|
|
// base type
|
|
Type* nt = t->nextOf();
|
|
LLGlobalVariable* nTD = DtoDwarfTypeDescription(loc, nt, compileUnit);
|
|
if (nt->ty == Tvoid || !nTD)
|
|
vals.push_back(getNullPtr(dbgArrTy()));
|
|
else
|
|
vals.push_back(dbgToArrTy(nTD));
|
|
|
|
LLConstant* c = llvm::ConstantStruct::get(GetDwarfDerivedTypeType(), vals);
|
|
LLGlobalVariable* gv = new LLGlobalVariable(c->getType(), true, LLGlobalValue::InternalLinkage, c, "llvm.dbg.derivedtype", gIR->module);
|
|
gv->setSection("llvm.metadata");
|
|
return gv;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static LLGlobalVariable* DtoDwarfVariable(VarDeclaration* vd, LLGlobalVariable* typeDescr)
|
|
{
|
|
unsigned tag;
|
|
if (vd->isParameter())
|
|
tag = DW_TAG_arg_variable;
|
|
else if (vd->isCodeseg())
|
|
assert(0 && "a static variable");
|
|
else
|
|
tag = DW_TAG_auto_variable;
|
|
|
|
std::vector<LLConstant*> vals;
|
|
// tag
|
|
vals.push_back(llvm::ConstantExpr::getAdd(
|
|
DtoConstUint(tag),
|
|
DtoConstUint(llvm::LLVMDebugVersion)));
|
|
// context
|
|
vals.push_back(dbgToArrTy(gIR->func()->dwarfSubProg));
|
|
// name
|
|
vals.push_back(DtoConstStringPtr(vd->toChars(), "llvm.metadata"));
|
|
// compile unit where defined
|
|
vals.push_back(dbgToArrTy(DtoDwarfCompileUnit(vd->getModule())));
|
|
// line number where defined
|
|
vals.push_back(DtoConstUint(vd->loc.linnum));
|
|
// type descriptor
|
|
vals.push_back(dbgToArrTy(typeDescr));
|
|
|
|
LLConstant* c = llvm::ConstantStruct::get(GetDwarfVariableType(), vals);
|
|
LLGlobalVariable* gv = new LLGlobalVariable(c->getType(), true, LLGlobalValue::InternalLinkage, c, "llvm.dbg.variable", gIR->module);
|
|
gv->setSection("llvm.metadata");
|
|
return gv;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void DtoDwarfDeclare(LLValue* var, LLGlobalVariable* varDescr)
|
|
{
|
|
LLSmallVector<LLValue*,2> args;
|
|
args.push_back(DtoBitCast(var, dbgArrTy()));
|
|
args.push_back(dbgToArrTy(varDescr));
|
|
gIR->ir->CreateCall(gIR->module->getFunction("llvm.dbg.declare"), args.begin(), args.end());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static LLGlobalVariable* DtoDwarfTypeDescription(Loc loc, Type* type, LLGlobalVariable* cu)
|
|
{
|
|
Type* t = type->toBasetype();
|
|
if (t->isintegral() || t->isfloating())
|
|
return DtoDwarfBasicType(type, cu);
|
|
else if (t->ty == Tpointer)
|
|
return DtoDwarfDerivedType(loc, type, cu);
|
|
|
|
Logger::attention(loc, "unsupport type for debug info: %s", type->toChars());
|
|
return NULL;
|
|
}
|
|
|
|
void DtoDwarfLocalVariable(LLValue* ll, VarDeclaration* vd)
|
|
{
|
|
// get compile units
|
|
LLGlobalVariable* thisCU = DtoDwarfCompileUnit(gIR->dmodule);
|
|
LLGlobalVariable* varCU = thisCU;
|
|
if (vd->getModule() != gIR->dmodule)
|
|
varCU = DtoDwarfCompileUnit(vd->getModule());
|
|
|
|
// get type description
|
|
Type* t = vd->type->toBasetype();
|
|
LLGlobalVariable* TD = DtoDwarfTypeDescription(vd->loc, vd->type, thisCU);
|
|
if (TD == NULL)
|
|
return; // unsupported
|
|
|
|
// get variable description
|
|
LLGlobalVariable* VD;
|
|
VD = DtoDwarfVariable(vd, TD);
|
|
|
|
// declare
|
|
DtoDwarfDeclare(ll, VD);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|