This source file includes following definitions.
- addrput
- uleb128enc
- sleb128enc
- uleb128put
- sleb128put
- writeabbrev
- hashstr
- newattr
- getattr
- newdie
- mkindex
- walktypedef
- find
- find_or_diag
- adddwarfrel
- newrefattr
- putattr
- putattrs
- putdies
- putdie
- reverselist
- reversetree
- newmemberoffsetattr
- newabslocexprattr
- lookup_or_diag
- dotypedef
- defgotype
- defptrto
- copychildrenexcept
- copychildren
- substitutetype
- synthesizestringtypes
- synthesizeslicetypes
- mkinternaltypename
- synthesizemaptypes
- synthesizechantypes
- defdwsymb
- movetomodule
- finddebugruntimepath
- putpclcdelta
- newcfaoffsetattr
- mkvarname
- flushunit
- writelines
- putpccfadelta
- writeframes
- writeinfo
- ispubname
- ispubtype
- writepub
- writearanges
- writegdbscript
- align
- writedwarfreloc
- dwarfemitdebugsections
- dwarfaddshstrings
- dwarfaddelfsectionsyms
- dwarfaddelfrelocheader
- dwarfaddelfheaders
- dwarfaddmachoheaders
- dwarfaddpeheaders
#include "l.h"
#include "lib.h"
#include "../ld/dwarf.h"
#include "../ld/dwarf_defs.h"
#include "../ld/elf.h"
#include "../ld/macho.h"
#include "../ld/pe.h"
#include "../../pkg/runtime/typekind.h"
static vlong abbrevo;
static vlong abbrevsize;
static LSym* abbrevsym;
static vlong abbrevsympos;
static vlong lineo;
static vlong linesize;
static LSym* linesym;
static vlong linesympos;
static vlong infoo;
static vlong infosize;
static LSym* infosym;
static vlong infosympos;
static vlong frameo;
static vlong framesize;
static LSym* framesym;
static vlong framesympos;
static vlong pubnameso;
static vlong pubnamessize;
static vlong pubtypeso;
static vlong pubtypessize;
static vlong arangeso;
static vlong arangessize;
static vlong gdbscripto;
static vlong gdbscriptsize;
static LSym *infosec;
static vlong inforeloco;
static vlong inforelocsize;
static LSym *arangessec;
static vlong arangesreloco;
static vlong arangesrelocsize;
static LSym *linesec;
static vlong linereloco;
static vlong linerelocsize;
static LSym *framesec;
static vlong framereloco;
static vlong framerelocsize;
static char gdbscript[1024];
static void
addrput(vlong addr)
{
switch(PtrSize) {
case 4:
LPUT(addr);
break;
case 8:
VPUT(addr);
break;
}
}
static int
uleb128enc(uvlong v, char* dst)
{
uint8 c, len;
len = 0;
do {
c = v & 0x7f;
v >>= 7;
if (v)
c |= 0x80;
if (dst)
*dst++ = c;
len++;
} while (c & 0x80);
return len;
};
static int
sleb128enc(vlong v, char *dst)
{
uint8 c, s, len;
len = 0;
do {
c = v & 0x7f;
s = v & 0x40;
v >>= 7;
if ((v != -1 || !s) && (v != 0 || s))
c |= 0x80;
if (dst)
*dst++ = c;
len++;
} while(c & 0x80);
return len;
}
static void
uleb128put(vlong v)
{
char buf[10];
strnput(buf, uleb128enc(v, buf));
}
static void
sleb128put(vlong v)
{
char buf[10];
strnput(buf, sleb128enc(v, buf));
}
typedef struct DWAttrForm DWAttrForm;
struct DWAttrForm {
uint8 attr;
uint8 form;
};
enum
{
DW_ABRV_NULL,
DW_ABRV_COMPUNIT,
DW_ABRV_FUNCTION,
DW_ABRV_VARIABLE,
DW_ABRV_AUTO,
DW_ABRV_PARAM,
DW_ABRV_STRUCTFIELD,
DW_ABRV_FUNCTYPEPARAM,
DW_ABRV_DOTDOTDOT,
DW_ABRV_ARRAYRANGE,
DW_ABRV_NULLTYPE,
DW_ABRV_BASETYPE,
DW_ABRV_ARRAYTYPE,
DW_ABRV_CHANTYPE,
DW_ABRV_FUNCTYPE,
DW_ABRV_IFACETYPE,
DW_ABRV_MAPTYPE,
DW_ABRV_PTRTYPE,
DW_ABRV_BARE_PTRTYPE,
DW_ABRV_SLICETYPE,
DW_ABRV_STRINGTYPE,
DW_ABRV_STRUCTTYPE,
DW_ABRV_TYPEDECL,
DW_NABRV
};
typedef struct DWAbbrev DWAbbrev;
static struct DWAbbrev {
uint8 tag;
uint8 children;
DWAttrForm attr[30];
} abbrevs[DW_NABRV] = {
{ 0 },
{
DW_TAG_compile_unit, DW_CHILDREN_yes,
DW_AT_name, DW_FORM_string,
DW_AT_language, DW_FORM_data1,
DW_AT_low_pc, DW_FORM_addr,
DW_AT_high_pc, DW_FORM_addr,
DW_AT_stmt_list, DW_FORM_data4,
0, 0
},
{
DW_TAG_subprogram, DW_CHILDREN_yes,
DW_AT_name, DW_FORM_string,
DW_AT_low_pc, DW_FORM_addr,
DW_AT_high_pc, DW_FORM_addr,
DW_AT_external, DW_FORM_flag,
0, 0
},
{
DW_TAG_variable, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
DW_AT_location, DW_FORM_block1,
DW_AT_type, DW_FORM_ref_addr,
DW_AT_external, DW_FORM_flag,
0, 0
},
{
DW_TAG_variable, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
DW_AT_location, DW_FORM_block1,
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
{
DW_TAG_formal_parameter, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
DW_AT_location, DW_FORM_block1,
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
{
DW_TAG_member, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
DW_AT_data_member_location, DW_FORM_block1,
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
{
DW_TAG_formal_parameter, DW_CHILDREN_no,
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
{
DW_TAG_unspecified_parameters, DW_CHILDREN_no,
0, 0
},
{
DW_TAG_subrange_type, DW_CHILDREN_no,
DW_AT_type, DW_FORM_ref_addr,
DW_AT_upper_bound, DW_FORM_data1,
0, 0
},
{
DW_TAG_unspecified_type, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
0, 0
},
{
DW_TAG_base_type, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
DW_AT_encoding, DW_FORM_data1,
DW_AT_byte_size, DW_FORM_data1,
0, 0
},
{
DW_TAG_array_type, DW_CHILDREN_yes,
DW_AT_name, DW_FORM_string,
DW_AT_type, DW_FORM_ref_addr,
DW_AT_byte_size, DW_FORM_udata,
0, 0
},
{
DW_TAG_typedef, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
{
DW_TAG_subroutine_type, DW_CHILDREN_yes,
DW_AT_name, DW_FORM_string,
0, 0
},
{
DW_TAG_typedef, DW_CHILDREN_yes,
DW_AT_name, DW_FORM_string,
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
{
DW_TAG_typedef, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
{
DW_TAG_pointer_type, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
{
DW_TAG_pointer_type, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
0, 0
},
{
DW_TAG_structure_type, DW_CHILDREN_yes,
DW_AT_name, DW_FORM_string,
DW_AT_byte_size, DW_FORM_udata,
0, 0
},
{
DW_TAG_structure_type, DW_CHILDREN_yes,
DW_AT_name, DW_FORM_string,
DW_AT_byte_size, DW_FORM_udata,
0, 0
},
{
DW_TAG_structure_type, DW_CHILDREN_yes,
DW_AT_name, DW_FORM_string,
DW_AT_byte_size, DW_FORM_udata,
0, 0
},
{
DW_TAG_typedef, DW_CHILDREN_no,
DW_AT_name, DW_FORM_string,
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
};
static void
writeabbrev(void)
{
int i, n;
abbrevo = cpos();
for (i = 1; i < DW_NABRV; i++) {
uleb128put(i);
uleb128put(abbrevs[i].tag);
cput(abbrevs[i].children);
n = strlen((char*)abbrevs[i].attr) / 2;
strnput((char*)abbrevs[i].attr,
(n+1) * sizeof(DWAttrForm));
}
cput(0);
abbrevsize = cpos() - abbrevo;
}
enum
{
HASHSIZE = 107
};
static uint32
hashstr(char* s)
{
uint32 h;
h = 0;
while (*s)
h = h+h+h + *s++;
return h % HASHSIZE;
}
typedef struct DWAttr DWAttr;
struct DWAttr {
DWAttr *link;
uint8 atr;
uint8 cls;
vlong value;
char *data;
};
typedef struct DWDie DWDie;
struct DWDie {
int abbrev;
DWDie *link;
DWDie *child;
DWAttr *attr;
vlong offs;
DWDie **hash;
DWDie *hlink;
};
static DWDie dwroot;
static DWDie dwtypes;
static DWDie dwglobals;
static DWAttr*
newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data)
{
DWAttr *a;
a = mal(sizeof *a);
a->link = die->attr;
die->attr = a;
a->atr = attr;
a->cls = cls;
a->value = value;
a->data = data;
return a;
}
static DWAttr*
getattr(DWDie *die, uint8 attr)
{
DWAttr *a, *b;
if (die->attr->atr == attr)
return die->attr;
a = die->attr;
b = a->link;
while (b != nil) {
if (b->atr == attr) {
a->link = b->link;
b->link = die->attr;
die->attr = b;
return b;
}
a = b;
b = b->link;
}
return nil;
}
static DWDie*
newdie(DWDie *parent, int abbrev, char *name)
{
DWDie *die;
int h;
die = mal(sizeof *die);
die->abbrev = abbrev;
die->link = parent->child;
parent->child = die;
newattr(die, DW_AT_name, DW_CLS_STRING, strlen(name), name);
if (parent->hash) {
h = hashstr(name);
die->hlink = parent->hash[h];
parent->hash[h] = die;
}
return die;
}
static void
mkindex(DWDie *die)
{
die->hash = mal(HASHSIZE * sizeof(DWDie*));
}
static DWDie*
walktypedef(DWDie *die)
{
DWAttr *attr;
if (die->abbrev == DW_ABRV_TYPEDECL) {
for (attr = die->attr; attr; attr = attr->link) {
if (attr->atr == DW_AT_type && attr->cls == DW_CLS_REFERENCE && attr->data != nil) {
return (DWDie*)attr->data;
}
}
}
return die;
}
static DWDie*
find(DWDie *die, char* name)
{
DWDie *a, *b, *die2;
int h;
top:
if (die->hash == nil) {
for (a = die->child; a != nil; a = a->link)
if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
return a;
goto notfound;
}
h = hashstr(name);
a = die->hash[h];
if (a == nil)
goto notfound;
if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
return a;
b = a->hlink;
while (b != nil) {
if (strcmp(name, getattr(b, DW_AT_name)->data) == 0) {
a->hlink = b->hlink;
b->hlink = die->hash[h];
die->hash[h] = b;
return b;
}
a = b;
b = b->hlink;
}
notfound:
die2 = walktypedef(die);
if(die2 != die) {
die = die2;
goto top;
}
return nil;
}
static DWDie*
find_or_diag(DWDie *die, char* name)
{
DWDie *r;
r = find(die, name);
if (r == nil) {
diag("dwarf find: %s %p has no %s", getattr(die, DW_AT_name)->data, die, name);
errorexit();
}
return r;
}
static void
adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend)
{
Reloc *r;
r = addrel(sec);
r->sym = sym;
r->xsym = sym;
r->off = cpos() - offsetbase;
r->siz = siz;
r->type = R_ADDR;
r->add = addend;
r->xadd = addend;
if(iself && thechar == '6')
addend = 0;
switch(siz) {
case 4:
LPUT(addend);
break;
case 8:
VPUT(addend);
break;
default:
diag("bad size in adddwarfrel");
break;
}
}
static DWAttr*
newrefattr(DWDie *die, uint8 attr, DWDie* ref)
{
if (ref == nil)
return nil;
return newattr(die, attr, DW_CLS_REFERENCE, 0, (char*)ref);
}
static int fwdcount;
static void
putattr(int abbrev, int form, int cls, vlong value, char *data)
{
vlong off;
switch(form) {
case DW_FORM_addr:
if(linkmode == LinkExternal) {
value -= ((LSym*)data)->value;
adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
break;
}
addrput(value);
break;
case DW_FORM_block1:
if(cls == DW_CLS_ADDRESS) {
cput(1+PtrSize);
cput(DW_OP_addr);
if(linkmode == LinkExternal) {
value -= ((LSym*)data)->value;
adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
break;
}
addrput(value);
break;
}
value &= 0xff;
cput(value);
while(value--)
cput(*data++);
break;
case DW_FORM_block2:
value &= 0xffff;
WPUT(value);
while(value--)
cput(*data++);
break;
case DW_FORM_block4:
value &= 0xffffffff;
LPUT(value);
while(value--)
cput(*data++);
break;
case DW_FORM_block:
uleb128put(value);
while(value--)
cput(*data++);
break;
case DW_FORM_data1:
cput(value);
break;
case DW_FORM_data2:
WPUT(value);
break;
case DW_FORM_data4:
if(linkmode == LinkExternal && cls == DW_CLS_PTR) {
adddwarfrel(infosec, linesym, infoo, 4, value);
break;
}
LPUT(value);
break;
case DW_FORM_data8:
VPUT(value);
break;
case DW_FORM_sdata:
sleb128put(value);
break;
case DW_FORM_udata:
uleb128put(value);
break;
case DW_FORM_string:
strnput(data, value+1);
break;
case DW_FORM_flag:
cput(value?1:0);
break;
case DW_FORM_ref_addr:
if (data == nil) {
diag("dwarf: null reference in %d", abbrev);
if(PtrSize == 8)
VPUT(0);
else
LPUT(0);
} else {
off = ((DWDie*)data)->offs;
if (off == 0)
fwdcount++;
if(linkmode == LinkExternal) {
adddwarfrel(infosec, infosym, infoo, PtrSize, off);
break;
}
addrput(off);
}
break;
case DW_FORM_ref1:
case DW_FORM_ref2:
case DW_FORM_ref4:
case DW_FORM_ref8:
case DW_FORM_ref_udata:
case DW_FORM_strp:
case DW_FORM_indirect:
default:
diag("dwarf: unsupported attribute form %d / class %d", form, cls);
errorexit();
}
}
static void
putattrs(int abbrev, DWAttr* attr)
{
DWAttr *attrs[DW_AT_recursive + 1];
DWAttrForm* af;
memset(attrs, 0, sizeof attrs);
for( ; attr; attr = attr->link)
if (attr->atr < nelem(attrs))
attrs[attr->atr] = attr;
for(af = abbrevs[abbrev].attr; af->attr; af++)
if (attrs[af->attr])
putattr(abbrev, af->form,
attrs[af->attr]->cls,
attrs[af->attr]->value,
attrs[af->attr]->data);
else
putattr(abbrev, af->form, 0, 0, nil);
}
static void putdie(DWDie* die);
static void
putdies(DWDie* die)
{
for(; die; die = die->link)
putdie(die);
}
static void
putdie(DWDie* die)
{
die->offs = cpos() - infoo;
uleb128put(die->abbrev);
putattrs(die->abbrev, die->attr);
if (abbrevs[die->abbrev].children) {
putdies(die->child);
cput(0);
}
}
static void
reverselist(DWDie** list)
{
DWDie *curr, *prev;
curr = *list;
prev = nil;
while(curr != nil) {
DWDie* next = curr->link;
curr->link = prev;
prev = curr;
curr = next;
}
*list = prev;
}
static void
reversetree(DWDie** list)
{
DWDie *die;
reverselist(list);
for (die = *list; die != nil; die = die->link)
if (abbrevs[die->abbrev].children)
reversetree(&die->child);
}
static void
newmemberoffsetattr(DWDie *die, int32 offs)
{
char block[10];
int i;
i = 0;
if (offs != 0) {
block[i++] = DW_OP_consts;
i += sleb128enc(offs, block+i);
block[i++] = DW_OP_plus;
}
newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, i, mal(i));
memmove(die->attr->data, block, i);
}
static void
newabslocexprattr(DWDie *die, vlong addr, LSym *sym)
{
newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym);
}
enum {
DW_AT_internal_elem_type = 250,
DW_AT_internal_key_type = 251,
DW_AT_internal_val_type = 252,
DW_AT_internal_location = 253,
};
static DWDie* defptrto(DWDie *dwtype);
static LSym*
lookup_or_diag(char *n)
{
LSym *s;
s = linkrlookup(ctxt, n, 0);
if (s == nil || s->size == 0) {
diag("dwarf: missing type: %s", n);
errorexit();
}
return s;
}
static void
dotypedef(DWDie *parent, char *name, DWDie *def)
{
DWDie *die;
if(strncmp(name, "map[", 4) == 0)
return;
if(strncmp(name, "struct {", 8) == 0)
return;
if(strncmp(name, "chan ", 5) == 0)
return;
if(*name == '[' || *name == '*')
return;
if(def == nil)
diag("dwarf: bad def in dotypedef");
die = newdie(parent, DW_ABRV_TYPEDECL, name);
newrefattr(die, DW_AT_type, def);
}
static DWDie*
defgotype(LSym *gotype)
{
DWDie *die, *fld;
LSym *s;
char *name, *f;
uint8 kind;
vlong bytesize;
int i, nfields;
if (gotype == nil)
return find_or_diag(&dwtypes, "<unspecified>");
if (strncmp("type.", gotype->name, 5) != 0) {
diag("dwarf: type name doesn't start with \".type\": %s", gotype->name);
return find_or_diag(&dwtypes, "<unspecified>");
}
name = gotype->name + 5;
die = find(&dwtypes, name);
if (die != nil)
return die;
if (0 && debug['v'] > 2)
print("new type: %Y\n", gotype);
kind = decodetype_kind(gotype);
bytesize = decodetype_size(gotype);
switch (kind) {
case KindBool:
die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
break;
case KindInt:
case KindInt8:
case KindInt16:
case KindInt32:
case KindInt64:
die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
break;
case KindUint:
case KindUint8:
case KindUint16:
case KindUint32:
case KindUint64:
case KindUintptr:
die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
break;
case KindFloat32:
case KindFloat64:
die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
break;
case KindComplex64:
case KindComplex128:
die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
break;
case KindArray:
die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name);
dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
s = decodetype_arrayelem(gotype);
newrefattr(die, DW_AT_type, defgotype(s));
fld = newdie(die, DW_ABRV_ARRAYRANGE, "range");
newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0);
newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
break;
case KindChan:
die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
s = decodetype_chanelem(gotype);
newrefattr(die, DW_AT_internal_elem_type, defgotype(s));
break;
case KindFunc:
die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name);
dotypedef(&dwtypes, name, die);
newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void"));
nfields = decodetype_funcincount(gotype);
for (i = 0; i < nfields; i++) {
s = decodetype_funcintype(gotype, i);
fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
newrefattr(fld, DW_AT_type, defgotype(s));
}
if (decodetype_funcdotdotdot(gotype))
newdie(die, DW_ABRV_DOTDOTDOT, "...");
nfields = decodetype_funcoutcount(gotype);
for (i = 0; i < nfields; i++) {
s = decodetype_funcouttype(gotype, i);
fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
newrefattr(fld, DW_AT_type, defptrto(defgotype(s)));
}
break;
case KindInterface:
die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name);
dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
nfields = decodetype_ifacemethodcount(gotype);
if (nfields == 0)
s = lookup_or_diag("type.runtime.eface");
else
s = lookup_or_diag("type.runtime.iface");
newrefattr(die, DW_AT_type, defgotype(s));
break;
case KindMap:
die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name);
s = decodetype_mapkey(gotype);
newrefattr(die, DW_AT_internal_key_type, defgotype(s));
s = decodetype_mapvalue(gotype);
newrefattr(die, DW_AT_internal_val_type, defgotype(s));
break;
case KindPtr:
die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
dotypedef(&dwtypes, name, die);
s = decodetype_ptrelem(gotype);
newrefattr(die, DW_AT_type, defgotype(s));
break;
case KindSlice:
die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name);
dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
s = decodetype_arrayelem(gotype);
newrefattr(die, DW_AT_internal_elem_type, defgotype(s));
break;
case KindString:
die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
break;
case KindStruct:
die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name);
dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
nfields = decodetype_structfieldcount(gotype);
for (i = 0; i < nfields; i++) {
f = decodetype_structfieldname(gotype, i);
s = decodetype_structfieldtype(gotype, i);
if (f == nil)
f = s->name + 5;
fld = newdie(die, DW_ABRV_STRUCTFIELD, f);
newrefattr(fld, DW_AT_type, defgotype(s));
newmemberoffsetattr(fld, decodetype_structfieldoffs(gotype, i));
}
break;
case KindUnsafePointer:
die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name);
break;
default:
diag("dwarf: definition of unknown kind %d: %s", kind, gotype->name);
die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name);
newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>"));
}
return die;
}
static DWDie*
defptrto(DWDie *dwtype)
{
char ptrname[1024];
DWDie *die;
snprint(ptrname, sizeof ptrname, "*%s", getattr(dwtype, DW_AT_name)->data);
die = find(&dwtypes, ptrname);
if (die == nil) {
die = newdie(&dwtypes, DW_ABRV_PTRTYPE,
strcpy(mal(strlen(ptrname)+1), ptrname));
newrefattr(die, DW_AT_type, dwtype);
}
return die;
}
static void
copychildrenexcept(DWDie *dst, DWDie *src, DWDie *except)
{
DWDie *c;
DWAttr *a;
for (src = src->child; src != nil; src = src->link) {
if(src == except)
continue;
c = newdie(dst, src->abbrev, getattr(src, DW_AT_name)->data);
for (a = src->attr; a != nil; a = a->link)
newattr(c, a->atr, a->cls, a->value, a->data);
copychildrenexcept(c, src, nil);
}
reverselist(&dst->child);
}
static void
copychildren(DWDie *dst, DWDie *src)
{
copychildrenexcept(dst, src, nil);
}
static void
substitutetype(DWDie *structdie, char *field, DWDie* dwtype)
{
DWDie *child;
DWAttr *a;
child = find_or_diag(structdie, field);
if (child == nil)
return;
a = getattr(child, DW_AT_type);
if (a != nil)
a->data = (char*) dwtype;
else
newrefattr(child, DW_AT_type, dwtype);
}
static void
synthesizestringtypes(DWDie* die)
{
DWDie *prototype;
prototype = walktypedef(defgotype(lookup_or_diag("type.runtime._string")));
if (prototype == nil)
return;
for (; die != nil; die = die->link) {
if (die->abbrev != DW_ABRV_STRINGTYPE)
continue;
copychildren(die, prototype);
}
}
static void
synthesizeslicetypes(DWDie *die)
{
DWDie *prototype, *elem;
prototype = walktypedef(defgotype(lookup_or_diag("type.runtime.slice")));
if (prototype == nil)
return;
for (; die != nil; die = die->link) {
if (die->abbrev != DW_ABRV_SLICETYPE)
continue;
copychildren(die, prototype);
elem = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data;
substitutetype(die, "array", defptrto(elem));
}
}
static char*
mkinternaltypename(char *base, char *arg1, char *arg2)
{
char buf[1024];
char *n;
if (arg2 == nil)
snprint(buf, sizeof buf, "%s<%s>", base, arg1);
else
snprint(buf, sizeof buf, "%s<%s,%s>", base, arg1, arg2);
n = mal(strlen(buf) + 1);
memmove(n, buf, strlen(buf));
return n;
}
enum {
MaxKeySize = 128,
MaxValSize = 128,
BucketSize = 8,
};
static void
synthesizemaptypes(DWDie *die)
{
DWDie *hash, *bucket, *dwh, *dwhk, *dwhv, *dwhb, *keytype, *valtype, *fld;
int indirect_key, indirect_val;
int keysize, valsize;
DWAttr *a;
hash = walktypedef(defgotype(lookup_or_diag("type.runtime.hmap")));
bucket = walktypedef(defgotype(lookup_or_diag("type.runtime.bucket")));
if (hash == nil)
return;
for (; die != nil; die = die->link) {
if (die->abbrev != DW_ABRV_MAPTYPE)
continue;
keytype = walktypedef((DWDie*) getattr(die, DW_AT_internal_key_type)->data);
valtype = walktypedef((DWDie*) getattr(die, DW_AT_internal_val_type)->data);
a = getattr(keytype, DW_AT_byte_size);
keysize = a ? a->value : PtrSize;
a = getattr(valtype, DW_AT_byte_size);
valsize = a ? a->value : PtrSize;
indirect_key = 0;
indirect_val = 0;
if(keysize > MaxKeySize) {
keysize = PtrSize;
indirect_key = 1;
}
if(valsize > MaxValSize) {
valsize = PtrSize;
indirect_val = 1;
}
dwhk = newdie(&dwtypes, DW_ABRV_ARRAYTYPE,
mkinternaltypename("[]key",
getattr(keytype, DW_AT_name)->data, nil));
newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * keysize, 0);
newrefattr(dwhk, DW_AT_type, indirect_key ? defptrto(keytype) : keytype);
fld = newdie(dwhk, DW_ABRV_ARRAYRANGE, "size");
newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, BucketSize, 0);
newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
dwhv = newdie(&dwtypes, DW_ABRV_ARRAYTYPE,
mkinternaltypename("[]val",
getattr(valtype, DW_AT_name)->data, nil));
newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * valsize, 0);
newrefattr(dwhv, DW_AT_type, indirect_val ? defptrto(valtype) : valtype);
fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size");
newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, BucketSize, 0);
newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
dwhb = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
mkinternaltypename("bucket",
getattr(keytype, DW_AT_name)->data,
getattr(valtype, DW_AT_name)->data));
copychildrenexcept(dwhb, bucket, find(bucket, "data"));
fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys");
newrefattr(fld, DW_AT_type, dwhk);
newmemberoffsetattr(fld, BucketSize + PtrSize);
fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values");
newrefattr(fld, DW_AT_type, dwhv);
newmemberoffsetattr(fld, BucketSize + PtrSize + BucketSize * keysize);
newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize + PtrSize + BucketSize * keysize + BucketSize * valsize, 0);
substitutetype(dwhb, "overflow", defptrto(dwhb));
dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
mkinternaltypename("hash",
getattr(keytype, DW_AT_name)->data,
getattr(valtype, DW_AT_name)->data));
copychildren(dwh, hash);
substitutetype(dwh, "buckets", defptrto(dwhb));
substitutetype(dwh, "oldbuckets", defptrto(dwhb));
newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
getattr(hash, DW_AT_byte_size)->value, nil);
newrefattr(die, DW_AT_type, defptrto(dwh));
}
}
static void
synthesizechantypes(DWDie *die)
{
DWDie *sudog, *waitq, *hchan,
*dws, *dww, *dwh, *elemtype;
DWAttr *a;
int elemsize, sudogsize;
sudog = walktypedef(defgotype(lookup_or_diag("type.runtime.sudog")));
waitq = walktypedef(defgotype(lookup_or_diag("type.runtime.waitq")));
hchan = walktypedef(defgotype(lookup_or_diag("type.runtime.hchan")));
if (sudog == nil || waitq == nil || hchan == nil)
return;
sudogsize = getattr(sudog, DW_AT_byte_size)->value;
for (; die != nil; die = die->link) {
if (die->abbrev != DW_ABRV_CHANTYPE)
continue;
elemtype = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data;
a = getattr(elemtype, DW_AT_byte_size);
elemsize = a ? a->value : PtrSize;
dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
mkinternaltypename("sudog",
getattr(elemtype, DW_AT_name)->data, nil));
copychildren(dws, sudog);
substitutetype(dws, "elem", elemtype);
newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT,
sudogsize + (elemsize > 8 ? elemsize - 8 : 0), nil);
dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil));
copychildren(dww, waitq);
substitutetype(dww, "first", defptrto(dws));
substitutetype(dww, "last", defptrto(dws));
newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT,
getattr(waitq, DW_AT_byte_size)->value, nil);
dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil));
copychildren(dwh, hchan);
substitutetype(dwh, "recvq", dww);
substitutetype(dwh, "sendq", dww);
newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
getattr(hchan, DW_AT_byte_size)->value, nil);
newrefattr(die, DW_AT_type, defptrto(dwh));
}
}
static void
defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype)
{
DWDie *dv, *dt;
USED(size);
if (strncmp(s, "go.string.", 10) == 0)
return;
if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0 && strncmp(s, "type..", 6) != 0) {
defgotype(sym);
return;
}
dv = nil;
switch (t) {
default:
return;
case 'd':
case 'b':
case 'D':
case 'B':
dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s);
newabslocexprattr(dv, v, sym);
if (ver == 0)
newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0);
case 'a':
case 'p':
dt = defgotype(gotype);
}
if (dv != nil)
newrefattr(dv, DW_AT_type, dt);
}
static void
movetomodule(DWDie *parent)
{
DWDie *die;
die = dwroot.child->child;
while(die->link != nil)
die = die->link;
die->link = parent->child;
}
static void
finddebugruntimepath(LSym *s)
{
int i;
char *p;
LSym *f;
if(gdbscript[0] != '\0')
return;
for(i=0; i<s->pcln->nfile; i++) {
f = s->pcln->file[i];
if((p = strstr(f->name, "runtime/string.goc")) != nil) {
*p = '\0';
snprint(gdbscript, sizeof gdbscript, "%sruntime/runtime-gdb.py", f->name);
*p = 'r';
break;
}
}
}
enum {
LINE_BASE = -1,
LINE_RANGE = 4,
OPCODE_BASE = 10
};
static void
putpclcdelta(vlong delta_pc, vlong delta_lc)
{
if (LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE) {
vlong opcode = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc);
if (OPCODE_BASE <= opcode && opcode < 256) {
cput(opcode);
return;
}
}
if (delta_pc) {
cput(DW_LNS_advance_pc);
sleb128put(delta_pc);
}
cput(DW_LNS_advance_line);
sleb128put(delta_lc);
cput(DW_LNS_copy);
}
static void
newcfaoffsetattr(DWDie *die, int32 offs)
{
char block[10];
int i;
i = 0;
block[i++] = DW_OP_call_frame_cfa;
if (offs != 0) {
block[i++] = DW_OP_consts;
i += sleb128enc(offs, block+i);
block[i++] = DW_OP_plus;
}
newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
memmove(die->attr->data, block, i);
}
static char*
mkvarname(char* name, int da)
{
char buf[1024];
char *n;
snprint(buf, sizeof buf, "%s#%d", name, da);
n = mal(strlen(buf) + 1);
memmove(n, buf, strlen(buf));
return n;
}
static void
flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_length)
{
vlong here;
if (dwinfo != nil && pc != 0) {
newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, (char*)pcsym);
}
if (unitstart >= 0) {
cput(0);
uleb128put(1);
cput(DW_LNE_end_sequence);
here = cpos();
cseek(unitstart);
LPUT(here - unitstart - sizeof(int32));
WPUT(2);
LPUT(header_length);
cseek(here);
}
}
static void
writelines(void)
{
LSym *s, *epcs;
Auto *a;
vlong unitstart, headerend, offs;
vlong pc, epc;
int i, lang, da, dt, line, file;
DWDie *dwinfo, *dwfunc, *dwvar, **dws;
DWDie *varhash[HASHSIZE];
char *n, *nn;
Pciter pcfile, pcline;
LSym **files, *f;
if(linesec == S)
linesec = linklookup(ctxt, ".dwarfline", 0);
linesec->nr = 0;
unitstart = -1;
headerend = -1;
epc = 0;
epcs = S;
lineo = cpos();
dwinfo = nil;
flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
unitstart = cpos();
lang = DW_LANG_Go;
s = ctxt->textp;
dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup("go"));
newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0);
newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s);
LPUT(0);
WPUT(2);
LPUT(0);
cput(1);
cput(1);
cput(LINE_BASE);
cput(LINE_RANGE);
cput(OPCODE_BASE);
cput(0);
cput(1);
cput(1);
cput(1);
cput(1);
cput(0);
cput(0);
cput(0);
cput(1);
cput(0);
files = emallocz(ctxt->nhistfile*sizeof files[0]);
for(f = ctxt->filesyms; f != nil; f = f->next)
files[f->value-1] = f;
for(i=0; i<ctxt->nhistfile; i++) {
strnput(files[i]->name, strlen(files[i]->name) + 4);
}
cput(0);
headerend = cpos();
cput(0);
uleb128put(1 + PtrSize);
cput(DW_LNE_set_address);
pc = s->value;
line = 1;
file = 1;
if(linkmode == LinkExternal)
adddwarfrel(linesec, s, lineo, PtrSize, 0);
else
addrput(pc);
for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
s = ctxt->cursym;
dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name);
newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s);
epc = s->value + s->size;
epcs = s;
newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, (char*)s);
if (s->version == 0)
newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0);
if(s->pcln == nil)
continue;
finddebugruntimepath(s);
pciterinit(ctxt, &pcfile, &s->pcln->pcfile);
pciterinit(ctxt, &pcline, &s->pcln->pcline);
epc = pc;
while(!pcfile.done && !pcline.done) {
if(epc - s->value >= pcfile.nextpc) {
pciternext(&pcfile);
continue;
}
if(epc - s->value >= pcline.nextpc) {
pciternext(&pcline);
continue;
}
if(file != pcfile.value) {
cput(DW_LNS_set_file);
uleb128put(pcfile.value);
file = pcfile.value;
}
putpclcdelta(s->value + pcline.pc - pc, pcline.value - line);
pc = s->value + pcline.pc;
line = pcline.value;
if(pcfile.nextpc < pcline.nextpc)
epc = pcfile.nextpc;
else
epc = pcline.nextpc;
epc += s->value;
}
da = 0;
dwfunc->hash = varhash;
memset(varhash, 0, sizeof varhash);
for(a = s->autom; a; a = a->link) {
switch (a->type) {
case A_AUTO:
dt = DW_ABRV_AUTO;
offs = a->aoffset - PtrSize;
break;
case A_PARAM:
dt = DW_ABRV_PARAM;
offs = a->aoffset;
break;
default:
continue;
}
if (strstr(a->asym->name, ".autotmp_"))
continue;
if (find(dwfunc, a->asym->name) != nil)
n = mkvarname(a->asym->name, da);
else
n = a->asym->name;
nn = strrchr(n, '.');
if (nn)
n = nn + 1;
dwvar = newdie(dwfunc, dt, n);
newcfaoffsetattr(dwvar, offs);
newrefattr(dwvar, DW_AT_type, defgotype(a->gotype));
newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil);
dwfunc->child = dwvar->link;
for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link)
if (offs > getattr(*dws, DW_AT_internal_location)->value)
break;
dwvar->link = *dws;
*dws = dwvar;
da++;
}
dwfunc->hash = nil;
}
flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
linesize = cpos() - lineo;
}
enum
{
CIERESERVE = 16,
DATAALIGNMENTFACTOR = -4,
FAKERETURNCOLUMN = 16
};
static void
putpccfadelta(vlong deltapc, vlong cfa)
{
if (deltapc < 0x40) {
cput(DW_CFA_advance_loc + deltapc);
} else if (deltapc < 0x100) {
cput(DW_CFA_advance_loc1);
cput(deltapc);
} else if (deltapc < 0x10000) {
cput(DW_CFA_advance_loc2);
WPUT(deltapc);
} else {
cput(DW_CFA_advance_loc4);
LPUT(deltapc);
}
cput(DW_CFA_def_cfa_offset_sf);
sleb128put(cfa / DATAALIGNMENTFACTOR);
}
static void
writeframes(void)
{
LSym *s;
vlong fdeo, fdesize, pad;
Pciter pcsp;
if(framesec == S)
framesec = linklookup(ctxt, ".dwarfframe", 0);
framesec->nr = 0;
frameo = cpos();
LPUT(CIERESERVE);
LPUT(0xffffffff);
cput(3);
cput(0);
uleb128put(1);
sleb128put(DATAALIGNMENTFACTOR);
uleb128put(FAKERETURNCOLUMN);
cput(DW_CFA_def_cfa);
uleb128put(DWARFREGSP);
uleb128put(PtrSize);
cput(DW_CFA_offset + FAKERETURNCOLUMN);
uleb128put(-PtrSize / DATAALIGNMENTFACTOR);
pad = CIERESERVE + frameo + 4 - cpos();
if (pad < 0) {
diag("dwarf: CIERESERVE too small by %lld bytes.", -pad);
errorexit();
}
strnput("", pad);
for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
s = ctxt->cursym;
if(s->pcln == nil)
continue;
fdeo = cpos();
LPUT(0);
LPUT(0);
addrput(0);
addrput(0);
for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp))
putpccfadelta(pcsp.nextpc - pcsp.pc, PtrSize + pcsp.value);
fdesize = cpos() - fdeo - 4;
pad = rnd(fdesize, PtrSize) - fdesize;
strnput("", pad);
fdesize += pad;
cseek(fdeo);
LPUT(fdesize);
if(linkmode == LinkExternal) {
adddwarfrel(framesec, framesym, frameo, 4, 0);
adddwarfrel(framesec, s, frameo, PtrSize, 0);
}
else {
LPUT(0);
addrput(s->value);
}
addrput(s->size);
cseek(fdeo + 4 + fdesize);
}
cflush();
framesize = cpos() - frameo;
}
enum
{
COMPUNITHEADERSIZE = 4+2+4+1
};
static void
writeinfo(void)
{
DWDie *compunit;
vlong unitstart, here;
fwdcount = 0;
if (infosec == S)
infosec = linklookup(ctxt, ".dwarfinfo", 0);
infosec->nr = 0;
if(arangessec == S)
arangessec = linklookup(ctxt, ".dwarfaranges", 0);
arangessec->nr = 0;
for (compunit = dwroot.child; compunit; compunit = compunit->link) {
unitstart = cpos();
LPUT(0);
WPUT(2);
if(linkmode == LinkExternal)
adddwarfrel(infosec, abbrevsym, infoo, 4, 0);
else
LPUT(0);
cput(PtrSize);
putdie(compunit);
here = cpos();
cseek(unitstart);
LPUT(here - unitstart - 4);
cseek(here);
}
cflush();
}
static int
ispubname(DWDie *die)
{
DWAttr *a;
switch(die->abbrev) {
case DW_ABRV_FUNCTION:
case DW_ABRV_VARIABLE:
a = getattr(die, DW_AT_external);
return a && a->value;
}
return 0;
}
static int
ispubtype(DWDie *die)
{
return die->abbrev >= DW_ABRV_NULLTYPE;
}
static vlong
writepub(int (*ispub)(DWDie*))
{
DWDie *compunit, *die;
DWAttr *dwa;
vlong unitstart, unitend, sectionstart, here;
sectionstart = cpos();
for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
unitstart = compunit->offs - COMPUNITHEADERSIZE;
if (compunit->link != nil)
unitend = compunit->link->offs - COMPUNITHEADERSIZE;
else
unitend = infoo + infosize;
LPUT(0);
WPUT(2);
LPUT(unitstart);
LPUT(unitend - unitstart);
for (die = compunit->child; die != nil; die = die->link) {
if (!ispub(die)) continue;
LPUT(die->offs - unitstart);
dwa = getattr(die, DW_AT_name);
strnput(dwa->data, dwa->value + 1);
}
LPUT(0);
here = cpos();
cseek(sectionstart);
LPUT(here - sectionstart - 4);
cseek(here);
}
return sectionstart;
}
static vlong
writearanges(void)
{
DWDie *compunit;
DWAttr *b, *e;
int headersize;
vlong sectionstart;
vlong value;
sectionstart = cpos();
headersize = rnd(4+2+4+1+1, PtrSize);
for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
b = getattr(compunit, DW_AT_low_pc);
if (b == nil)
continue;
e = getattr(compunit, DW_AT_high_pc);
if (e == nil)
continue;
LPUT(headersize + 4*PtrSize - 4);
WPUT(2);
value = compunit->offs - COMPUNITHEADERSIZE;
if(linkmode == LinkExternal)
adddwarfrel(arangessec, infosym, sectionstart, 4, value);
else
LPUT(value);
cput(PtrSize);
cput(0);
strnput("", headersize - (4+2+4+1+1));
if(linkmode == LinkExternal)
adddwarfrel(arangessec, (LSym*)b->data, sectionstart, PtrSize, b->value-((LSym*)b->data)->value);
else
addrput(b->value);
addrput(e->value - b->value);
addrput(0);
addrput(0);
}
cflush();
return sectionstart;
}
static vlong
writegdbscript(void)
{
vlong sectionstart;
sectionstart = cpos();
if (gdbscript[0]) {
cput(1);
strnput(gdbscript, strlen(gdbscript)+1);
cflush();
}
return sectionstart;
}
static void
align(vlong size)
{
if(HEADTYPE == Hwindows)
strnput("", rnd(size, PEFILEALIGN) - size);
}
static vlong
writedwarfreloc(LSym* s)
{
int i;
vlong start;
Reloc *r;
start = cpos();
for(r = s->r; r < s->r+s->nr; r++) {
if(iself)
i = elfreloc1(r, r->off);
else if(HEADTYPE == Hdarwin)
i = machoreloc1(r, r->off);
else
i = -1;
if(i < 0)
diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
}
return start;
}
void
dwarfemitdebugsections(void)
{
vlong infoe;
DWDie* die;
if(debug['w'])
return;
if(linkmode == LinkExternal && !iself)
return;
newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes");
mkindex(&dwroot);
mkindex(&dwtypes);
mkindex(&dwglobals);
newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>");
newdie(&dwtypes, DW_ABRV_NULLTYPE, "void");
newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer");
die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr");
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
defgotype(lookup_or_diag("type.runtime.rtype"));
defgotype(lookup_or_diag("type.runtime.interfaceType"));
defgotype(lookup_or_diag("type.runtime.itab"));
genasmsym(defdwsymb);
writeabbrev();
align(abbrevsize);
writelines();
align(linesize);
writeframes();
align(framesize);
synthesizestringtypes(dwtypes.child);
synthesizeslicetypes(dwtypes.child);
synthesizemaptypes(dwtypes.child);
synthesizechantypes(dwtypes.child);
reversetree(&dwroot.child);
reversetree(&dwtypes.child);
reversetree(&dwglobals.child);
movetomodule(&dwtypes);
movetomodule(&dwglobals);
infoo = cpos();
writeinfo();
infoe = cpos();
pubnameso = infoe;
pubtypeso = infoe;
arangeso = infoe;
gdbscripto = infoe;
if (fwdcount > 0) {
if (debug['v'])
Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime());
cseek(infoo);
writeinfo();
if (fwdcount > 0) {
diag("dwarf: unresolved references after first dwarf info pass");
errorexit();
}
if (infoe != cpos()) {
diag("dwarf: inconsistent second dwarf info pass");
errorexit();
}
}
infosize = infoe - infoo;
align(infosize);
pubnameso = writepub(ispubname);
pubnamessize = cpos() - pubnameso;
align(pubnamessize);
pubtypeso = writepub(ispubtype);
pubtypessize = cpos() - pubtypeso;
align(pubtypessize);
arangeso = writearanges();
arangessize = cpos() - arangeso;
align(arangessize);
gdbscripto = writegdbscript();
gdbscriptsize = cpos() - gdbscripto;
align(gdbscriptsize);
while(cpos()&7)
cput(0);
inforeloco = writedwarfreloc(infosec);
inforelocsize = cpos() - inforeloco;
align(inforelocsize);
arangesreloco = writedwarfreloc(arangessec);
arangesrelocsize = cpos() - arangesreloco;
align(arangesrelocsize);
linereloco = writedwarfreloc(linesec);
linerelocsize = cpos() - linereloco;
align(linerelocsize);
framereloco = writedwarfreloc(framesec);
framerelocsize = cpos() - framereloco;
align(framerelocsize);
}
enum
{
ElfStrDebugAbbrev,
ElfStrDebugAranges,
ElfStrDebugFrame,
ElfStrDebugInfo,
ElfStrDebugLine,
ElfStrDebugLoc,
ElfStrDebugMacinfo,
ElfStrDebugPubNames,
ElfStrDebugPubTypes,
ElfStrDebugRanges,
ElfStrDebugStr,
ElfStrGDBScripts,
ElfStrRelDebugInfo,
ElfStrRelDebugAranges,
ElfStrRelDebugLine,
ElfStrRelDebugFrame,
NElfStrDbg
};
vlong elfstrdbg[NElfStrDbg];
void
dwarfaddshstrings(LSym *shstrtab)
{
if(debug['w'])
return;
elfstrdbg[ElfStrDebugAbbrev] = addstring(shstrtab, ".debug_abbrev");
elfstrdbg[ElfStrDebugAranges] = addstring(shstrtab, ".debug_aranges");
elfstrdbg[ElfStrDebugFrame] = addstring(shstrtab, ".debug_frame");
elfstrdbg[ElfStrDebugInfo] = addstring(shstrtab, ".debug_info");
elfstrdbg[ElfStrDebugLine] = addstring(shstrtab, ".debug_line");
elfstrdbg[ElfStrDebugLoc] = addstring(shstrtab, ".debug_loc");
elfstrdbg[ElfStrDebugMacinfo] = addstring(shstrtab, ".debug_macinfo");
elfstrdbg[ElfStrDebugPubNames] = addstring(shstrtab, ".debug_pubnames");
elfstrdbg[ElfStrDebugPubTypes] = addstring(shstrtab, ".debug_pubtypes");
elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges");
elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str");
elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts");
if(linkmode == LinkExternal) {
if(thechar == '6') {
elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rela.debug_info");
elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rela.debug_aranges");
elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rela.debug_line");
elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rela.debug_frame");
} else {
elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rel.debug_info");
elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rel.debug_aranges");
elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rel.debug_line");
elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rel.debug_frame");
}
infosym = linklookup(ctxt, ".debug_info", 0);
infosym->hide = 1;
abbrevsym = linklookup(ctxt, ".debug_abbrev", 0);
abbrevsym->hide = 1;
linesym = linklookup(ctxt, ".debug_line", 0);
linesym->hide = 1;
framesym = linklookup(ctxt, ".debug_frame", 0);
framesym->hide = 1;
}
}
void
dwarfaddelfsectionsyms()
{
if(infosym != nil) {
infosympos = cpos();
putelfsectionsym(infosym, 0);
}
if(abbrevsym != nil) {
abbrevsympos = cpos();
putelfsectionsym(abbrevsym, 0);
}
if(linesym != nil) {
linesympos = cpos();
putelfsectionsym(linesym, 0);
}
if(framesym != nil) {
framesympos = cpos();
putelfsectionsym(framesym, 0);
}
}
static void
dwarfaddelfrelocheader(int elfstr, ElfShdr *shdata, vlong off, vlong size)
{
ElfShdr *sh;
sh = newElfShdr(elfstrdbg[elfstr]);
if(thechar == '6') {
sh->type = SHT_RELA;
} else {
sh->type = SHT_REL;
}
sh->entsize = PtrSize*(2+(sh->type==SHT_RELA));
sh->link = elfshname(".symtab")->shnum;
sh->info = shdata->shnum;
sh->off = off;
sh->size = size;
sh->addralign = PtrSize;
}
void
dwarfaddelfheaders(void)
{
ElfShdr *sh, *shinfo, *sharanges, *shline, *shframe;
if(debug['w'])
return;
sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]);
sh->type = SHT_PROGBITS;
sh->off = abbrevo;
sh->size = abbrevsize;
sh->addralign = 1;
if(abbrevsympos > 0)
putelfsymshndx(abbrevsympos, sh->shnum);
sh = newElfShdr(elfstrdbg[ElfStrDebugLine]);
sh->type = SHT_PROGBITS;
sh->off = lineo;
sh->size = linesize;
sh->addralign = 1;
if(linesympos > 0)
putelfsymshndx(linesympos, sh->shnum);
shline = sh;
sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]);
sh->type = SHT_PROGBITS;
sh->off = frameo;
sh->size = framesize;
sh->addralign = 1;
if(framesympos > 0)
putelfsymshndx(framesympos, sh->shnum);
shframe = sh;
sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]);
sh->type = SHT_PROGBITS;
sh->off = infoo;
sh->size = infosize;
sh->addralign = 1;
if(infosympos > 0)
putelfsymshndx(infosympos, sh->shnum);
shinfo = sh;
if (pubnamessize > 0) {
sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]);
sh->type = SHT_PROGBITS;
sh->off = pubnameso;
sh->size = pubnamessize;
sh->addralign = 1;
}
if (pubtypessize > 0) {
sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes]);
sh->type = SHT_PROGBITS;
sh->off = pubtypeso;
sh->size = pubtypessize;
sh->addralign = 1;
}
sharanges = nil;
if (arangessize) {
sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]);
sh->type = SHT_PROGBITS;
sh->off = arangeso;
sh->size = arangessize;
sh->addralign = 1;
sharanges = sh;
}
if (gdbscriptsize) {
sh = newElfShdr(elfstrdbg[ElfStrGDBScripts]);
sh->type = SHT_PROGBITS;
sh->off = gdbscripto;
sh->size = gdbscriptsize;
sh->addralign = 1;
}
if(inforelocsize)
dwarfaddelfrelocheader(ElfStrRelDebugInfo, shinfo, inforeloco, inforelocsize);
if(arangesrelocsize)
dwarfaddelfrelocheader(ElfStrRelDebugAranges, sharanges, arangesreloco, arangesrelocsize);
if(linerelocsize)
dwarfaddelfrelocheader(ElfStrRelDebugLine, shline, linereloco, linerelocsize);
if(framerelocsize)
dwarfaddelfrelocheader(ElfStrRelDebugFrame, shframe, framereloco, framerelocsize);
}
void
dwarfaddmachoheaders(void)
{
MachoSect *msect;
MachoSeg *ms;
vlong fakestart;
int nsect;
if(debug['w'])
return;
fakestart = abbrevo & ~0xfff;
nsect = 4;
if (pubnamessize > 0)
nsect++;
if (pubtypessize > 0)
nsect++;
if (arangessize > 0)
nsect++;
if (gdbscriptsize > 0)
nsect++;
ms = newMachoSeg("__DWARF", nsect);
ms->fileoffset = fakestart;
ms->filesize = abbrevo-fakestart;
ms->vaddr = ms->fileoffset + segdata.vaddr - segdata.fileoff;
msect = newMachoSect(ms, "__debug_abbrev", "__DWARF");
msect->off = abbrevo;
msect->size = abbrevsize;
msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
msect = newMachoSect(ms, "__debug_line", "__DWARF");
msect->off = lineo;
msect->size = linesize;
msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
msect = newMachoSect(ms, "__debug_frame", "__DWARF");
msect->off = frameo;
msect->size = framesize;
msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
msect = newMachoSect(ms, "__debug_info", "__DWARF");
msect->off = infoo;
msect->size = infosize;
msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
if (pubnamessize > 0) {
msect = newMachoSect(ms, "__debug_pubnames", "__DWARF");
msect->off = pubnameso;
msect->size = pubnamessize;
msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
}
if (pubtypessize > 0) {
msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF");
msect->off = pubtypeso;
msect->size = pubtypessize;
msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
}
if (arangessize > 0) {
msect = newMachoSect(ms, "__debug_aranges", "__DWARF");
msect->off = arangeso;
msect->size = arangessize;
msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
}
if (gdbscriptsize > 0) {
msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF");
msect->off = gdbscripto;
msect->size = gdbscriptsize;
msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
ms->filesize += msect->size;
}
}
void
dwarfaddpeheaders(void)
{
if(debug['w'])
return;
newPEDWARFSection(".debug_abbrev", abbrevsize);
newPEDWARFSection(".debug_line", linesize);
newPEDWARFSection(".debug_frame", framesize);
newPEDWARFSection(".debug_info", infosize);
newPEDWARFSection(".debug_pubnames", pubnamessize);
newPEDWARFSection(".debug_pubtypes", pubtypessize);
newPEDWARFSection(".debug_aranges", arangessize);
newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize);
}