Files
ldc/tocvdebug.c
Alexey Prokhin caad8cde58 Squashed 'dmd2/' content from commit 10017d5
git-subtree-dir: dmd2
git-subtree-split: 10017d50eaaff4ecdc37a0153b6c37ea0b004c81
2012-04-05 11:10:48 +04:00

822 lines
21 KiB
C

// Copyright (c) 2004-2011 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
#include <stdio.h>
#include <stddef.h>
#include <time.h>
#include <assert.h>
#include "mars.h"
#include "module.h"
#include "mtype.h"
#include "declaration.h"
#include "statement.h"
#include "enum.h"
#include "aggregate.h"
#include "init.h"
#include "attrib.h"
#include "id.h"
#include "import.h"
#include "template.h"
#include "rmem.h"
#include "cc.h"
#include "global.h"
#include "oper.h"
#include "code.h"
#include "type.h"
#include "dt.h"
#include "cv4.h"
#include "cgcv.h"
#include "outbuf.h"
#include "irstate.h"
/* The CV4 debug format is defined in:
* "CV4 Symbolic Debug Information Specification"
* rev 3.1 March 5, 1993
* Languages Business Unit
* Microsoft
*/
/******************************
* CV4 pg. 25
* Convert D protection attribute to cv attribute.
*/
unsigned PROTtoATTR(enum PROT prot)
{
unsigned attribute;
switch (prot)
{
case PROTprivate: attribute = 1; break;
case PROTpackage: attribute = 2; break;
case PROTprotected: attribute = 2; break;
case PROTpublic: attribute = 3; break;
case PROTexport: attribute = 3; break;
case PROTundefined:
case PROTnone:
default:
//printf("prot = %d\n", prot);
assert(0);
}
return attribute;
}
unsigned cv4_memfunctypidx(FuncDeclaration *fd)
{ type *t;
debtyp_t *d;
unsigned char *p;
AggregateDeclaration *ad;
//printf("cv4_memfunctypidx(fd = '%s')\n", fd->toChars());
t = fd->type->toCtype();
ad = fd->isMember2();
if (ad)
{
unsigned nparam;
idx_t paramidx;
idx_t thisidx;
unsigned char call;
// It's a member function, which gets a special type record
if (fd->isStatic())
thisidx = dttab4[TYvoid];
else
{
assert(ad->handle);
thisidx = cv4_typidx(ad->handle->toCtype());
}
paramidx = cv4_arglist(t,&nparam);
call = cv4_callconv(t);
d = debtyp_alloc(18);
p = d->data;
TOWORD(p,LF_MFUNCTION);
TOWORD(p + 2,cv4_typidx(t->Tnext));
TOWORD(p + 4,cv4_typidx(ad->type->toCtype()));
TOWORD(p + 6,thisidx);
p[8] = call;
p[9] = 0; // reserved
TOWORD(p + 10,nparam);
TOWORD(p + 12,paramidx);
TOLONG(p + 14,0); // thisadjust
return cv_debtyp(d);
}
return cv4_typidx(t);
}
unsigned cv4_Denum(EnumDeclaration *e)
{
debtyp_t *d,*dt;
unsigned nfields,fnamelen;
unsigned len;
unsigned property;
unsigned attribute;
const char *id;
idx_t typidx;
//dbg_printf("cv4_Denum(%s)\n", e->toChars());
property = 0;
if (!e->members || !e->memtype)
property |= 0x80; // enum is forward referenced
id = e->toPrettyChars();
len = 10;
d = debtyp_alloc(len + cv_stringbytes(id));
TOWORD(d->data,LF_ENUM);
TOWORD(d->data + 4,e->memtype ? cv4_typidx(e->memtype->toCtype()) : 0);
TOWORD(d->data + 8,property);
len += cv_namestring(d->data + len,id);
d->length = 0; // so cv_debtyp() will allocate new
typidx = cv_debtyp(d);
d->length = len; // restore length
// Compute the number of fields, and the length of the fieldlist record
nfields = 0;
fnamelen = 2;
if (!property)
{
for (size_t i = 0; i < e->members->dim; i++)
{ EnumMember *sf = (e->members->tdata()[i])->isEnumMember();
dinteger_t value;
if (sf)
{
value = sf->value->toInteger();
unsigned fnamelen1 = fnamelen;
// store only member's simple name
fnamelen += 4 + cv4_numericbytes(value) + cv_stringbytes(sf->toChars());
/* Optlink dies on longer ones, so just truncate
*/
if (fnamelen > 0xB000) // 0xB000 found by trial and error
{ fnamelen = fnamelen1; // back up
break; // and skip the rest
}
nfields++;
}
}
}
TOWORD(d->data + 2,nfields);
// If forward reference, then field list is 0
if (property)
{
TOWORD(d->data + 6,0);
return typidx;
}
// Generate fieldlist type record
dt = debtyp_alloc(fnamelen);
TOWORD(dt->data,LF_FIELDLIST);
// And fill it in
unsigned j = 2;
unsigned fieldi = 0;
for (size_t i = 0; i < e->members->dim; i++)
{ EnumMember *sf = (e->members->tdata()[i])->isEnumMember();
dinteger_t value;
if (sf)
{
fieldi++;
if (fieldi > nfields)
break; // chop off the rest
value = sf->value->toInteger();
TOWORD(dt->data + j,LF_ENUMERATE);
attribute = 0;
TOWORD(dt->data + j + 2,attribute);
cv4_storenumeric(dt->data + j + 4,value);
j += 4 + cv4_numericbytes(value);
// store only member's simple name
j += cv_namestring(dt->data + j, sf->toChars());
// If enum is not a member of a class, output enum members as constants
// if (!isclassmember(s))
// {
// cv4_outsym(sf);
// }
}
}
assert(j == fnamelen);
TOWORD(d->data + 6,cv_debtyp(dt));
// cv4_outsym(s);
return typidx;
}
/* ==================================================================== */
/****************************
* Emit symbolic debug info in CV format.
*/
void TypedefDeclaration::toDebug()
{
//printf("TypedefDeclaration::toDebug('%s')\n", toChars());
assert(config.fulltypes >= CV4);
// If it is a member, it is handled by cvMember()
if (!isMember())
{
if (basetype->ty == Ttuple)
return;
unsigned length;
const char *id = toPrettyChars();
idx_t typidx = cv4_typidx(basetype->toCtype());
unsigned len = strlen(id);
unsigned char *debsym = (unsigned char *) alloca(39 + IDOHD + len);
// Output a 'user-defined type' for the tag name
TOWORD(debsym + 2,S_UDT);
TOIDX(debsym + 4,typidx);
length = 2 + 2 + cgcv.sz_idx;
length += cv_namestring(debsym + length,id);
TOWORD(debsym,length - 2);
assert(length <= 40 + len);
obj_write_bytes(SegData[DEBSYM],length,debsym);
}
}
void EnumDeclaration::toDebug()
{
//printf("EnumDeclaration::toDebug('%s')\n", toChars());
assert(config.fulltypes >= CV4);
// If it is a member, it is handled by cvMember()
if (!isMember())
{
unsigned length;
const char *id = toPrettyChars();
idx_t typidx = cv4_Denum(this);
unsigned len = strlen(id);
unsigned char *debsym = (unsigned char *) alloca(39 + IDOHD + len);
// Output a 'user-defined type' for the tag name
TOWORD(debsym + 2,S_UDT);
TOIDX(debsym + 4,typidx);
length = 2 + 2 + cgcv.sz_idx;
length += cv_namestring(debsym + length,id);
TOWORD(debsym,length - 2);
assert(length <= 40 + len);
obj_write_bytes(SegData[DEBSYM],length,debsym);
}
}
void StructDeclaration::toDebug()
{
unsigned leaf;
unsigned property;
unsigned nfields;
unsigned fnamelen;
const char *id;
targ_size_t size;
unsigned numidx;
debtyp_t *d,*dt;
unsigned len;
int count; // COUNT field in LF_CLASS
unsigned char *p;
idx_t typidx = 0;
//printf("StructDeclaration::toDebug('%s')\n", toChars());
assert(config.fulltypes >= CV4);
if (isAnonymous())
return /*0*/;
if (typidx) // if reference already generated
return /*typidx*/; // use already existing reference
property = 0;
if (!members)
{ size = 0;
property |= 0x80; // forward reference
}
else
size = structsize;
if (parent->isAggregateDeclaration()) // if class is nested
property |= 8;
// if (st->Sctor || st->Sdtor)
// property |= 2; // class has ctors and/or dtors
// if (st->Sopoverload)
// property |= 4; // class has overloaded operators
// if (st->Scastoverload)
// property |= 0x40; // class has casting methods
// if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug))
// property |= 0x20; // class has overloaded assignment
id = toPrettyChars();
numidx = isUnionDeclaration() ? 8 : 12;
len = numidx + cv4_numericbytes(size);
d = debtyp_alloc(len + cv_stringbytes(id));
cv4_storenumeric(d->data + numidx,size);
len += cv_namestring(d->data + len,id);
leaf = isUnionDeclaration() ? LF_UNION : LF_STRUCTURE;
if (!isUnionDeclaration())
{
TOWORD(d->data + 8,0); // dList
TOWORD(d->data + 10,0); // vshape is 0 (no virtual functions)
}
TOWORD(d->data,leaf);
// Assign a number to prevent infinite recursion if a struct member
// references the same struct.
d->length = 0; // so cv_debtyp() will allocate new
typidx = cv_debtyp(d);
d->length = len; // restore length
if (!members) // if reference only
{
TOWORD(d->data + 2,0); // count: number of fields is 0
TOWORD(d->data + 4,0); // field list is 0
TOWORD(d->data + 6,property);
return /*typidx*/;
}
// Compute the number of fields, and the length of the fieldlist record
nfields = 0;
fnamelen = 2;
count = nfields;
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = members->tdata()[i];
int nwritten;
nwritten = s->cvMember(NULL);
if (nwritten)
{
fnamelen += nwritten;
nfields++;
count++;
}
}
TOWORD(d->data + 2,count);
TOWORD(d->data + 6,property);
// Generate fieldlist type record
dt = debtyp_alloc(fnamelen);
p = dt->data;
// And fill it in
TOWORD(p,LF_FIELDLIST);
p += 2;
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = members->tdata()[i];
p += s->cvMember(p);
}
//dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data);
assert(p - dt->data == fnamelen);
TOWORD(d->data + 4,cv_debtyp(dt));
// cv4_outsym(s);
unsigned char *debsym;
unsigned length;
len = strlen(id);
debsym = (unsigned char *) alloca(39 + IDOHD + len);
// Output a 'user-defined type' for the tag name
TOWORD(debsym + 2,S_UDT);
TOIDX(debsym + 4,typidx);
length = 2 + 2 + cgcv.sz_idx;
length += cv_namestring(debsym + length,id);
TOWORD(debsym,length - 2);
assert(length <= 40 + len);
obj_write_bytes(SegData[DEBSYM],length,debsym);
// return typidx;
}
void ClassDeclaration::toDebug()
{
unsigned leaf;
unsigned property;
unsigned nfields;
unsigned fnamelen;
const char *id;
targ_size_t size;
unsigned numidx;
debtyp_t *d,*dt;
unsigned len;
int i;
int count; // COUNT field in LF_CLASS
unsigned char *p;
idx_t typidx = 0;
//printf("ClassDeclaration::toDebug('%s')\n", toChars());
assert(config.fulltypes >= CV4);
if (isAnonymous())
return /*0*/;
if (typidx) // if reference already generated
return /*typidx*/; // use already existing reference
property = 0;
if (!members)
{ size = 0;
property |= 0x80; // forward reference
}
else
size = structsize;
if (parent->isAggregateDeclaration()) // if class is nested
property |= 8;
if (ctor || dtors.dim)
property |= 2; // class has ctors and/or dtors
// if (st->Sopoverload)
// property |= 4; // class has overloaded operators
// if (st->Scastoverload)
// property |= 0x40; // class has casting methods
// if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug))
// property |= 0x20; // class has overloaded assignment
id = isCPPinterface() ? ident->toChars() : toPrettyChars();
numidx = isUnionDeclaration() ? 8 : 12;
len = numidx + cv4_numericbytes(size);
d = debtyp_alloc(len + cv_stringbytes(id));
cv4_storenumeric(d->data + numidx,size);
len += cv_namestring(d->data + len,id);
leaf = LF_CLASS;
TOWORD(d->data + 8,0); // dList
if (1)
{ debtyp_t *vshape;
unsigned char descriptor;
size_t n = vtbl.dim; // number of virtual functions
if (n == 0)
{
TOWORD(d->data + 10,0); // vshape is 0
}
else
{
vshape = debtyp_alloc(4 + (n + 1) / 2);
TOWORD(vshape->data,LF_VTSHAPE);
TOWORD(vshape->data + 2,1);
n = 0;
descriptor = 0;
for (size_t i = 0; i < vtbl.dim; i++)
{ FuncDeclaration *fd = (FuncDeclaration *)vtbl.tdata()[i];
//if (intsize == 4)
descriptor |= 5;
vshape->data[4 + n / 2] = descriptor;
descriptor <<= 4;
n++;
}
TOWORD(d->data + 10,cv_debtyp(vshape)); // vshape
}
}
else
TOWORD(d->data + 10,0); // vshape is 0 (no virtual functions)
TOWORD(d->data,leaf);
// Assign a number to prevent infinite recursion if a struct member
// references the same struct.
d->length = 0; // so cv_debtyp() will allocate new
typidx = cv_debtyp(d);
d->length = len; // restore length
if (!members) // if reference only
{
TOWORD(d->data + 2,0); // count: number of fields is 0
TOWORD(d->data + 4,0); // field list is 0
TOWORD(d->data + 6,property);
return /*typidx*/;
}
// Compute the number of fields, and the length of the fieldlist record
nfields = 0;
fnamelen = 2;
// Add in base classes
for (size_t i = 0; i < baseclasses->dim; i++)
{ BaseClass *bc = baseclasses->tdata()[i];
nfields++;
fnamelen += 6 + cv4_numericbytes(bc->offset);
}
count = nfields;
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = members->tdata()[i];
int nwritten;
nwritten = s->cvMember(NULL);
if (nwritten)
{
fnamelen += nwritten;
nfields++;
count++;
}
}
TOWORD(d->data + 2,count);
TOWORD(d->data + 6,property);
// Generate fieldlist type record
dt = debtyp_alloc(fnamelen);
p = dt->data;
// And fill it in
TOWORD(p,LF_FIELDLIST);
p += 2;
// Add in base classes
for (size_t i = 0; i < baseclasses->dim; i++)
{ BaseClass *bc = baseclasses->tdata()[i];
idx_t typidx;
unsigned attribute;
typidx = cv4_typidx(bc->base->type->toCtype()->Tnext);
attribute = PROTtoATTR(bc->protection);
TOWORD(p,LF_BCLASS);
TOWORD(p + 2,typidx);
TOWORD(p + 4,attribute);
p += 6;
cv4_storenumeric(p, bc->offset);
p += cv4_numericbytes(bc->offset);
}
for (size_t i = 0; i < members->dim; i++)
{ Dsymbol *s = members->tdata()[i];
p += s->cvMember(p);
}
//dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data);
assert(p - dt->data == fnamelen);
TOWORD(d->data + 4,cv_debtyp(dt));
// cv4_outsym(s);
unsigned char *debsym;
unsigned length;
len = strlen(id);
debsym = (unsigned char *) alloca(39 + IDOHD + len);
// Output a 'user-defined type' for the tag name
TOWORD(debsym + 2,S_UDT);
TOIDX(debsym + 4,typidx);
length = 2 + 2 + cgcv.sz_idx;
length += cv_namestring(debsym + length,id);
TOWORD(debsym,length - 2);
assert(length <= 40 + len);
obj_write_bytes(SegData[DEBSYM],length,debsym);
// return typidx;
}
/* ===================================================================== */
/*****************************************
* Insert CV info into *p.
* Returns:
* number of bytes written, or that would be written if p==NULL
*/
int Dsymbol::cvMember(unsigned char *p)
{
return 0;
}
int TypedefDeclaration::cvMember(unsigned char *p)
{
char *id;
idx_t typidx;
int nwritten = 0;
//printf("TypedefDeclaration::cvMember() '%s'\n", toChars());
id = toChars();
if (!p)
{
nwritten = 4 + cv_stringbytes(id);
}
else
{
TOWORD(p,LF_NESTTYPE);
typidx = cv4_typidx(basetype->toCtype());
TOWORD(p + 2,typidx);
nwritten = 4 + cv_namestring(p + 4, id);
}
return nwritten;
}
int EnumDeclaration::cvMember(unsigned char *p)
{
char *id;
idx_t typidx;
int nwritten = 0;
//printf("EnumDeclaration::cvMember() '%s'\n", toChars());
id = toChars();
if (!p)
{
nwritten = 4 + cv_stringbytes(id);
}
else
{
TOWORD(p,LF_NESTTYPE);
typidx = cv4_Denum(this);
TOWORD(p + 2,typidx);
nwritten = 4 + cv_namestring(p + 4, id);
}
return nwritten;
}
int FuncDeclaration::cvMember(unsigned char *p)
{
char *id;
idx_t typidx;
unsigned attribute;
int nwritten = 0;
debtyp_t *d;
//printf("FuncDeclaration::cvMember() '%s'\n", toChars());
if (!type) // if not compiled in,
return 0; // skip it
id = toChars();
if (!p)
{
nwritten = 6 + cv_stringbytes(id);
}
else
{
int count;
int mlen;
unsigned char *q;
count = 0;
mlen = 2;
{
if (introducing)
mlen += 4;
mlen += cgcv.sz_idx * 2;
count++;
}
// Allocate and fill it in
d = debtyp_alloc(mlen);
q = d->data;
TOWORD(q,LF_METHODLIST);
q += 2;
// for (s = sf; s; s = s->Sfunc->Foversym)
{
attribute = PROTtoATTR(prot());
/* 0*4 vanilla method
* 1*4 virtual method
* 2*4 static method
* 3*4 friend method
* 4*4 introducing virtual method
* 5*4 pure virtual method
* 6*4 pure introducing virtual method
* 7*4 reserved
*/
if (isStatic())
attribute |= 2*4;
else if (isVirtual())
{
if (introducing)
{
if (isAbstract())
attribute |= 6*4;
else
attribute |= 4*4;
}
else
{
if (isAbstract())
attribute |= 5*4;
else
attribute |= 1*4;
}
}
else
attribute |= 0*4;
TOIDX(q,attribute);
q += cgcv.sz_idx;
TOIDX(q, cv4_memfunctypidx(this));
q += cgcv.sz_idx;
if (introducing)
{ TOLONG(q, vtblIndex * PTRSIZE);
q += 4;
}
}
assert(q - d->data == mlen);
typidx = cv_debtyp(d);
if (typidx)
{
TOWORD(p,LF_METHOD);
TOWORD(p + 2,count);
nwritten = 4;
TOIDX(p + nwritten, typidx);
nwritten += cgcv.sz_idx;
nwritten += cv_namestring(p + nwritten, id);
}
}
return nwritten;
}
int VarDeclaration::cvMember(unsigned char *p)
{
char *id;
idx_t typidx;
unsigned attribute;
int nwritten = 0;
//printf("VarDeclaration::cvMember(p = %p) '%s'\n", p, toChars());
if (type->toBasetype()->ty == Ttuple)
return 0;
id = toChars();
if (!p)
{
if (storage_class & STCfield)
{
nwritten += 6 +
cv4_numericbytes(offset) + cv_stringbytes(id);
}
else if (isStatic())
{
nwritten += 6 + cv_stringbytes(id);
}
}
else if (storage_class & STCfield)
{
TOWORD(p,LF_MEMBER);
typidx = cv_typidx(type->toCtype());
attribute = PROTtoATTR(prot());
assert((attribute & ~3) == 0);
TOWORD(p + 2,typidx);
TOWORD(p + 4,attribute);
cv4_storenumeric(p + 6, offset);
nwritten = 6 + cv4_numericbytes( offset);
nwritten += cv_namestring(p + nwritten, id);
}
else if (isStatic())
{
TOWORD(p,LF_STMEMBER);
typidx = cv_typidx(type->toCtype());
attribute = PROTtoATTR(prot());
assert((attribute & ~3) == 0);
TOWORD(p + 2,typidx);
TOWORD(p + 4,attribute);
nwritten = 6 + cv_namestring(p + 6, id);
}
return nwritten;
}