aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuuk van Dijk <lvd@golang.org>2010-10-24 23:07:52 +0200
committerLuuk van Dijk <lvd@golang.org>2010-10-24 23:07:52 +0200
commit4228e622591deb90ae381a99f587effc58171a80 (patch)
treebfb315d730b3a3ee557f3b46222e33f4a7f6539c
parentc28fa513f599dd47a9f1e4f4d751131728af6bf4 (diff)
downloadgo-4228e622591deb90ae381a99f587effc58171a80.tar.gz
go-4228e622591deb90ae381a99f587effc58171a80.zip
6l/8l: global and local variables and type info.
R=rsc CC=golang-dev https://golang.org/cl/2201044
-rw-r--r--src/cmd/ld/dwarf.c1092
-rw-r--r--src/cmd/ld/dwarf.h14
-rw-r--r--src/cmd/ld/dwarf_defs.h16
-rw-r--r--src/cmd/ld/elf.h3
-rw-r--r--src/pkg/runtime/type.go1
5 files changed, 1040 insertions, 86 deletions
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index cd9c82e02d..7891f64c9a 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -2,6 +2,15 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// TODO:
+// - eliminate DW_CLS_ if not used
+// - package info in compilation units
+// - assign global variables and types to their packages
+// - (upstream) type info for C parts of runtime
+// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
+// ptype struct '[]uint8' and qualifiers need to be quoted away
+// - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean.
+//
#include "l.h"
#include "lib.h"
#include "../ld/dwarf.h"
@@ -17,10 +26,16 @@ static vlong abbrevo;
static vlong abbrevsize;
static vlong lineo;
static vlong linesize;
-static vlong infoo;
+static vlong infoo; // also the base for DWDie->offs and reference attributes.
static vlong infosize;
static vlong frameo;
static vlong framesize;
+static vlong pubnameso;
+static vlong pubnamessize;
+static vlong pubtypeso;
+static vlong pubtypessize;
+static vlong arangeso;
+static vlong arangessize;
/*
* Basic I/O
@@ -39,7 +54,6 @@ addrput(vlong addr)
}
}
-
static int
uleb128enc(uvlong v, char* dst)
{
@@ -106,17 +120,34 @@ struct DWAttrForm {
uint8 form;
};
-// index into the abbrevs table below.
+// Index into the abbrevs table below.
+// Keep in sync with ispubname() and ispubtype() below.
enum
{
DW_ABRV_NULL,
DW_ABRV_COMPUNIT,
DW_ABRV_FUNCTION,
+ DW_ABRV_VARIABLE,
+ DW_ABRV_AUTO,
+ DW_ABRV_PARAM,
+ DW_ABRV_STRUCTFIELD,
+ 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_SLICETYPE,
+ DW_ABRV_STRINGTYPE,
+ DW_ABRV_STRUCTTYPE,
+ DW_ABRV_TYPEDECL,
DW_NABRV
};
typedef struct DWAbbrev DWAbbrev;
-struct DWAbbrev {
+static struct DWAbbrev {
uint8 tag;
uint8 children;
DWAttrForm attr[30];
@@ -135,10 +166,137 @@ struct DWAbbrev {
},
/* FUNCTION */
{
- DW_TAG_subprogram, DW_CHILDREN_no,
+ 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
+ },
+ /* VARIABLE */
+ {
+ DW_TAG_variable, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_location, DW_FORM_addr,
+ DW_AT_type, DW_FORM_ref_addr,
+ DW_AT_external, DW_FORM_flag,
+ 0, 0
+ },
+ /* AUTO */
+ {
+ 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
+ },
+ /* PARAM */
+ {
+ 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
+ },
+ /* STRUCTFIELD */
+ {
+ 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
+ },
+
+ /* NULLTYPE */
+ {
+ DW_TAG_unspecified_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ 0, 0
+ },
+ /* BASETYPE */
+ {
+ 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
+ },
+ /* ARRAYTYPE */
+ {
+ DW_TAG_array_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* CHANTYPE */
+ {
+ DW_TAG_typedef, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ 0, 0
+ },
+
+ /* FUNCTYPE */
+ {
+ DW_TAG_typedef, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ 0, 0
+ },
+
+ /* IFACETYPE */
+ {
+ DW_TAG_interface_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ 0, 0
+ },
+
+ /* MAPTYPE */
+ {
+ DW_TAG_typedef, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ 0, 0
+ },
+
+ /* PTRTYPE */
+ {
+ DW_TAG_pointer_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* SLICETYPE */
+ // Children are data, len and cap of runtime::struct Slice.
+ {
+ DW_TAG_structure_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* STRINGTYPE */
+ // Children are str and len of runtime::struct String.
+ {
+ DW_TAG_structure_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* STRUCTTYPE */
+ {
+ DW_TAG_structure_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* TYPEDECL */
+ {
+ DW_TAG_typedef, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
0, 0
},
};
@@ -154,8 +312,8 @@ writeabbrev(void)
uleb128put(i);
uleb128put(abbrevs[i].tag);
cput(abbrevs[i].children);
- // 0 is not a valid attr or form, so we can treat this as
- // a string
+ // 0 is not a valid attr or form, and DWAbbrev.attr is
+ // 0-terminated, so we can treat it as a string
n = strlen((char*)abbrevs[i].attr) / 2;
strnput((char*)abbrevs[i].attr,
(n+1) * sizeof(DWAttrForm));
@@ -165,12 +323,29 @@ writeabbrev(void)
}
/*
- * Debugging Information Entries and their attributes
+ * Debugging Information Entries and their attributes.
*/
+enum
+{
+ HASHSIZE = 107
+};
+
+static uint32
+hashstr(char* s)
+{
+ uint32 h;
+
+ h = 0;
+ while (*s)
+ h = h+h+h + *s++;
+ return h % HASHSIZE;
+}
+
// For DW_CLS_string and _block, value should contain the length, and
-// data the data, for all others, value is the whole thing and data is
-// null.
+// data the data, for _reference, value is 0 and data is a DWDie* to
+// the referenced instance, for all others, value is the whole thing
+// and data is null.
typedef struct DWAttr DWAttr;
struct DWAttr {
@@ -187,21 +362,20 @@ struct DWDie {
DWDie *link;
DWDie *child;
DWAttr *attr;
+ // offset into .debug_info section, i.e relative to
+ // infoo. only valid after call to putdie()
+ vlong offs;
+ DWDie **hash; // optional index of children by name, enabled by mkindex()
+ DWDie *hlink; // bucket chain in parent's index
};
-// top level compilation unit DIE's
-static DWDie *dwinfo;
-
-static DWDie*
-newdie(DWDie *link, int abbrev)
-{
- DWDie *die;
+/*
+ * Root DIEs for compilation units, types and global variables.
+ */
- die = mal(sizeof *die);
- die->abbrev = abbrev;
- die->link = link;
- return die;
-}
+static DWDie dwroot;
+static DWDie dwtypes;
+static DWDie dwglobals;
static DWAttr*
newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data)
@@ -218,6 +392,109 @@ newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data)
return a;
}
+// Each DIE (except the root ones) has at least 1 attribute: its
+// name. getattr moves the desired one to the front so
+// frequently searched ones are found faster.
+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;
+}
+
+// Every DIE has at least a DW_AT_name attribute (but it will only be
+// written out if it is listed in the abbrev). If its parent is
+// keeping an index, the new DIE will be inserted there.
+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*
+find(DWDie *die, char* name)
+{
+ DWDie *a, *b;
+ int h;
+
+ if (die->hash == nil) {
+ diag("lookup of %s in non-indexed DIE", name);
+ errorexit();
+ }
+
+ h = hashstr(name);
+ a = die->hash[h];
+
+ if (a == nil)
+ return nil;
+
+ // AT_name always exists.
+ if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
+ return a;
+
+ // Move found ones to head of the list.
+ 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;
+ }
+ return nil;
+}
+
+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 form, int cls, vlong value, char *data)
{
@@ -285,13 +562,24 @@ putattr(int form, int cls, vlong value, char *data)
cput(value?1:0);
break;
- case DW_FORM_strp: // string
- case DW_FORM_ref_addr: // reference
- case DW_FORM_ref1: // reference
+ case DW_FORM_ref_addr: // reference to a DIE in the .info section
+ if (data == nil) {
+ diag("null dwarf reference");
+ LPUT(0); // invalid dwarf, gdb will complain.
+ } else {
+ if (((DWDie*)data)->offs == 0)
+ fwdcount++;
+ LPUT(((DWDie*)data)->offs);
+ }
+ break;
+
+ case DW_FORM_ref1: // reference within the compilation unit
case DW_FORM_ref2: // reference
case DW_FORM_ref4: // reference
case DW_FORM_ref8: // reference
case DW_FORM_ref_udata: // reference
+
+ case DW_FORM_strp: // string
case DW_FORM_indirect: // (see Section 7.5.3)
default:
diag("Unsupported atribute form %d / class %d", form, cls);
@@ -330,6 +618,7 @@ putdies(DWDie* die)
static void
putdie(DWDie* die)
{
+ die->offs = cpos() - infoo;
uleb128put(die->abbrev);
putattrs(die->abbrev, die->attr);
if (abbrevs[die->abbrev].children) {
@@ -344,8 +633,8 @@ reverselist(DWDie** list)
DWDie *curr, * prev;
curr = *list;
- prev = 0;
- while(curr) {
+ prev = nil;
+ while(curr != nil) {
DWDie* next = curr->link;
curr->link = prev;
prev = curr;
@@ -360,11 +649,397 @@ reversetree(DWDie** list)
DWDie *die;
reverselist(list);
- if (*list != nil && abbrevs[(*list)->abbrev].children)
- for (die = *list; die != nil; die = die->link)
+ 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);
+}
+
+// Decoding the type.* symbols. This has to be in sync with
+// ../../pkg/runtime/type.go, or more specificaly, with what
+// ../gc/reflect.c stuffs in these.
+
+enum {
+ KindBool = 1,
+ KindInt,
+ KindInt8,
+ KindInt16,
+ KindInt32,
+ KindInt64,
+ KindUint,
+ KindUint8,
+ KindUint16,
+ KindUint32,
+ KindUint64,
+ KindUintptr,
+ KindFloat,
+ KindFloat32,
+ KindFloat64,
+ KindComplex,
+ KindComplex64,
+ KindComplex128,
+ KindArray,
+ KindChan,
+ KindFunc,
+ KindInterface,
+ KindMap,
+ KindPtr,
+ KindSlice,
+ KindString,
+ KindStruct,
+ KindUnsafePointer,
+
+ KindNoPointers = 1<<7,
+};
+
+static Sym*
+decode_reloc(Sym *s, int32 off)
+{
+ int i;
+
+ for (i = 0; i < s->nr; i++)
+ if (s->r[i].off == off)
+ return s->r[i].sym;
+ return nil;
+}
+
+static uvlong
+decode_inuxi(uchar* p, int sz)
+{
+ uvlong r;
+ uchar *inuxi;
+ int i;
+
+ r = 0;
+ inuxi = nil;
+ switch (sz) {
+ case 2:
+ inuxi = inuxi2;
+ break;
+ case 4:
+ inuxi = inuxi4;
+ break;
+ case 8:
+ inuxi = inuxi8;
+ break;
+ default:
+ diag("decode inuxi %d", sz);
+ errorexit();
+ }
+ for (i = 0; i < sz; i++)
+ r += p[i] << (8*inuxi[i]);
+
+ return r;
+}
+
+// Type.commonType.kind
+static uint8
+decodetype_kind(Sym *s)
+{
+ return s->p[3*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f
+}
+
+// Type.commonType.size
+static vlong
+decodetype_size(Sym *s)
+{
+ return decode_inuxi(s->p + 2*PtrSize, PtrSize); // 0x8 / 0x10
+}
+
+// Type.ArrayType.elem
+static Sym*
+decodetype_arrayelem(Sym *s)
+{
+ return decode_reloc(s, 5*PtrSize + 8); // 0x1c / 0x30
+}
+
+// Type.PtrType.elem
+static Sym*
+decodetype_ptrelem(Sym *s)
+{
+ return decode_reloc(s, 5*PtrSize + 8); // 0x1c / 0x30
+}
+
+// Type.StructType.fields.Slice::len
+static int
+decodetype_structfieldcount(Sym *s)
+{
+ return decode_inuxi(s->p + 6*PtrSize + 8, 4); // 0x20 / 0x38
+}
+
+// Type.StructType.fields[]-> name, typ and offset. sizeof(structField) = 5*PtrSize
+static uchar*
+decodetype_structfieldname(Sym *s, int i)
+{
+ Sym *p;
+ p = decode_reloc(s, 6*PtrSize + 0x10 + i*5*PtrSize); // go.string."foo" 0x28 / 0x40
+ if (p == nil) // embedded structs have a nil name.
+ return nil;
+ p = decode_reloc(p, 0); // string."foo"
+ if (p == nil) // shouldn't happen.
+ return nil;
+ return p->p; // the c-string
+}
+
+static Sym*
+decodetype_structfieldtype(Sym *s, int i)
+{
+ return decode_reloc(s, 8*PtrSize + 0x10 + i*5*PtrSize); // 0x30 / 0x50
+}
+
+static vlong
+decodetype_structfieldoffs(Sym *s, int i)
+{
+ return decode_inuxi(s->p + 10*PtrSize + 0x10 + i*5*PtrSize, 4); // 0x38 / 0x60
+}
+
+// Define gotype, for composite ones recurse into constituents.
+static DWDie*
+defgotype(Sym *gotype)
+{
+ DWDie *die, *fld, *elem, *ptrelem;
+ Sym *s;
+ char *name, *ptrname, *f;
+ uint8 kind;
+ vlong bytesize;
+ int i, nfields;
+
+ if (gotype == nil)
+ return find(&dwtypes, "<unspecified>"); // must be defined before
+
+ if (strncmp("type.", gotype->name, 5) != 0) {
+ diag("Type name doesn't start with \".type\": %s", gotype->name);
+ return find(&dwtypes, "<unspecified>");
+ }
+ name = gotype->name + 5; // Altenatively decode from Type.string
+
+ die = find(&dwtypes, name);
+ if (die != nil)
+ return die;
+
+ if (0 && debug['v'] > 2) {
+ print("new type: %s @0x%08x [%d]", gotype->name, gotype->value, gotype->size);
+ for (i = 0; i < gotype->size; ++i) {
+ if (!(i%8)) print("\n\t%04x ", i);
+ print("%02x ", gotype->p[i]);
+ }
+ print("\n");
+ for (i = 0; i < gotype->nr; ++i) {
+ print("\t%02x %d %d %lld %s\n",
+ gotype->r[i].off,
+ gotype->r[i].siz,
+ gotype->r[i].type,
+ gotype->r[i].add,
+ gotype->r[i].sym->name);
+ }
+ }
+
+ 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 KindFloat:
+ 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 KindComplex:
+ 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);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ s = decodetype_arrayelem(gotype);
+ newrefattr(die, DW_AT_type, defgotype(s));
+ break;
+
+ case KindChan:
+ die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name);
+ // TODO: describe ../../pkg/runtime/chan.c::struct Hchan
+ break;
+
+ case KindFunc:
+ die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name);
+ break;
+
+ case KindInterface:
+ die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name);
+ break;
+
+ case KindMap:
+ die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name);
+ // TODO: describe ../../pkg/runtime/hashmap.c::struct hash
+ break;
+
+ case KindPtr:
+ die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
+ s = decodetype_ptrelem(gotype);
+ newrefattr(die, DW_AT_type, defgotype(s));
+ break;
+
+ case KindSlice:
+ die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ fld = newdie(die, DW_ABRV_STRUCTFIELD, "data");
+ // Synthesize *elemtype if not already exists. Maybe
+ // this should be named '<*T>' to not stand in the way
+ // of the real definition of *T.
+ s = decodetype_arrayelem(gotype);
+ elem = defgotype(s);
+ ptrname = strdup(s->name + 4); // skip "type" but leave the '.'
+ ptrname[0] = '*'; // .. to stuff in the '*'
+ ptrelem = find(&dwtypes, ptrname);
+ if (ptrelem == nil) {
+ ptrelem = newdie(&dwtypes, DW_ABRV_PTRTYPE, ptrname);
+ newrefattr(ptrelem, DW_AT_type, elem);
+ } else {
+ free(ptrname);
+ }
+ newrefattr(fld, DW_AT_type, ptrelem);
+ newmemberoffsetattr(fld, 0);
+ fld = newdie(die, DW_ABRV_STRUCTFIELD, "len");
+ newrefattr(fld, DW_AT_type, find(&dwtypes, "<int32>"));
+ newmemberoffsetattr(fld, PtrSize);
+ fld = newdie(die, DW_ABRV_STRUCTFIELD, "cap");
+ newrefattr(fld, DW_AT_type, find(&dwtypes, "<int32>"));
+ newmemberoffsetattr(fld, PtrSize + 4);
+
+ break;
+
+ case KindString:
+ die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ fld = newdie(die, DW_ABRV_STRUCTFIELD, "str");
+ newrefattr(fld, DW_AT_type, find(&dwtypes, "<byte*>"));
+ newmemberoffsetattr(fld, 0);
+ fld = newdie(die, DW_ABRV_STRUCTFIELD, "len");
+ newrefattr(fld, DW_AT_type, find(&dwtypes, "<int32>"));
+ newmemberoffsetattr(fld, PtrSize);
+ break;
+
+ case KindStruct:
+ die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name);
+ 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; // skip "type."
+ 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_PTRTYPE, name);
+ newrefattr(die, DW_AT_type, find(&dwtypes, "void"));
+ break;
+
+ default:
+ diag("definition of unknown kind %d: %s", kind, gotype->name);
+ die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name);
+ newrefattr(die, DW_AT_type, find(&dwtypes, "<unspecified>"));
+ }
+
+ return die;
+ }
+
+// For use with pass.c::genasmsym
+static void
+defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
+{
+ DWDie *dv, *dt;
+
+ if (gotype == nil) {
+ return;
+ }
+
+ dv = nil;
+
+ switch (t) {
+ default:
+ return;
+ case 'D':
+ case 'B':
+ dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s);
+ newattr(dv, DW_AT_location, DW_CLS_ADDRESS, v, 0);
+ if (ver == 0)
+ newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0);
+ // fallthrough
+ case 'a':
+ case 'p':
+ dt = defgotype(gotype);
+ }
+
+ if (dv != nil)
+ newrefattr(dv, DW_AT_type, dt);
+}
+
+// TODO(lvd) For now, just append them all to the first compilation
+// unit (that should be main), in the future distribute them to the
+// appropriate compilation units.
+static void
+movetomodule(DWDie *parent)
+{
+ DWDie *die;
+
+ for (die = dwroot.child->child; die->link != nil; die = die->link) /* nix */;
+ die->link = parent->child;
+}
+
+
/*
* Filename fragments for the line history stack.
*/
@@ -511,11 +1186,14 @@ checknesting(void)
}
}
-/* find z and Z entries in the Auto list (of a Prog), and reset the history stack */
-static char *
+/*
+ * Return false if the a->link chain contains no history, otherwise
+ * returns true and finds z and Z entries in the Auto list (of a
+ * Prog), and resets the history stack
+ */
+static int
inithist(Auto *a)
{
- char *unitname;
Linehist *lh;
for (; a; a = a->link)
@@ -531,8 +1209,6 @@ inithist(Auto *a)
return 0;
}
- unitname = decodez(a->asym->name);
-
// Clear the history.
clearhistfile();
includetop = 0;
@@ -558,7 +1234,6 @@ inithist(Auto *a)
checknesting();
includestack[includetop].file = f;
includestack[includetop].line = 1;
-
}
absline = a->aoffset;
} else if (a->type == D_FILE1) { // 'Z'
@@ -580,7 +1255,7 @@ inithist(Auto *a)
linehist->file = includestack[includetop].file;
linehist->line = includestack[includetop].line;
}
- return unitname;
+ return 1;
}
static Linehist *
@@ -635,6 +1310,23 @@ putpclcdelta(vlong delta_pc, vlong 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);
+}
/*
* Walk prog table, emit line program and build DIE tree.
@@ -642,7 +1334,7 @@ putpclcdelta(vlong delta_pc, vlong delta_lc)
// flush previous compilation unit.
static void
-flushunit(vlong pc, vlong unitstart)
+flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
{
vlong here;
@@ -669,12 +1361,13 @@ writelines(void)
{
Prog *q;
Sym *s;
- char *unitname;
+ Auto *a;
vlong unitstart;
vlong pc, epc, lc, llc, lline;
int currfile;
- int i;
+ int i, lang;
Linehist *lh;
+ DWDie *dwinfo, *dwfunc, *dwvar;
unitstart = -1;
epc = pc = 0;
@@ -682,32 +1375,39 @@ writelines(void)
llc = 1;
currfile = -1;
lineo = cpos();
+ dwinfo = nil;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
s = cursym;
// Look for history stack. If we find one,
// we're entering a new compilation unit
- if((unitname = inithist(s->autom)) != 0) {
- flushunit(epc, unitstart);
+
+ if (inithist(s->autom)) {
+ flushunit(dwinfo, epc, unitstart);
unitstart = cpos();
+
if(debug['v'] > 1) {
- print("dwarf writelines found %s\n", unitname);
+ print("dwarf writelines found %s\n", histfile[1]);
Linehist* lh;
for (lh = linehist; lh; lh = lh->link)
print("\t%8lld: [%4lld]%s\n",
lh->absline, lh->line, histfile[lh->file]);
}
- dwinfo = newdie(dwinfo, DW_ABRV_COMPUNIT);
- newattr(dwinfo, DW_AT_name, DW_CLS_STRING, strlen(unitname), unitname);
- newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, guesslang(unitname), 0);
+
+ lang = guesslang(histfile[1]);
+
+ dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, strdup(histfile[1]));
+ 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->text->pc, 0);
+
// Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf
LPUT(0); // unit_length (*), will be filled in later.
- WPUT(3); // version
- LPUT(11); // header_length (*)
+ WPUT(3); // dwarf version (appendix F)
+ LPUT(11); // header_length (*), starting here.
+
cput(1); // minimum_instruction_length
cput(1); // default_is_stmt
cput(LINE_BASE); // line_base
@@ -719,6 +1419,8 @@ writelines(void)
cput(1); // standard_opcode_lengths[4]
cput(0); // include_directories (empty)
cput(0); // file_names (empty) (emitted by DW_LNE's below)
+ // header_length ends here.
+
for (i=1; i < histfilesize; i++) {
cput(0); // start extended opcode
uleb128put(1 + strlen(histfile[i]) + 4);
@@ -745,11 +1447,12 @@ writelines(void)
continue;
}
- dwinfo->child = newdie(dwinfo->child, DW_ABRV_FUNCTION);
- newattr(dwinfo->child, DW_AT_name, DW_CLS_STRING, strlen(s->name), s->name);
- newattr(dwinfo->child, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, 0);
+ dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name);
+ newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, 0);
epc = s->value + s->size;
- newattr(dwinfo->child, DW_AT_high_pc, DW_CLS_ADDRESS, epc, 0);
+ newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, 0);
+ if (s->version == 0)
+ newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0);
for(q = s->text; q != P; q = q->link) {
lh = searchhist(q->line);
@@ -757,8 +1460,9 @@ writelines(void)
diag("corrupt history or bad absolute line: %P", q);
continue;
}
+
if (lh->file < 1) { // 0 is the past-EOF entry.
- //diag("instruction with line number past EOF in %s: %P", unitname, q);
+ // diag("instruction with line number past EOF in %s: %P", histfile[1], q);
continue;
}
@@ -778,9 +1482,24 @@ writelines(void)
lc = q->line;
llc = lline;
}
+
+ for(a = s->autom; a; a = a->link) {
+ switch (a->type) {
+ case D_AUTO:
+ dwvar = newdie(dwfunc, DW_ABRV_AUTO, a->asym->name);
+ break;
+ case D_PARAM:
+ dwvar = newdie(dwfunc, DW_ABRV_PARAM, a->asym->name);
+ break;
+ default:
+ continue;
+ }
+ newcfaoffsetattr(dwvar, a->aoffset);
+ newrefattr(dwvar, DW_AT_type, defgotype(a->gotype));
+ }
}
- flushunit(epc, unitstart);
+ flushunit(dwinfo, epc, unitstart);
linesize = cpos() - lineo;
}
@@ -824,20 +1543,20 @@ writeframes(void)
frameo = cpos();
// Emit the CIE, Section 6.4.1
- LPUT(CIERESERVE); // initial length, must be multiple of PtrSize
- LPUT(0xffffffff); // cid.
- cput(3); // dwarf version
- cput(0); // augmentation ""
- uleb128put(1); // code_alignment_factor
+ LPUT(CIERESERVE); // initial length, must be multiple of PtrSize
+ LPUT(0xffffffff); // cid.
+ cput(3); // dwarf version (appendix F)
+ cput(0); // augmentation ""
+ uleb128put(1); // code_alignment_factor
sleb128put(DATAALIGNMENTFACTOR); // guess
- uleb128put(FAKERETURNCOLUMN); // return_address_register
+ uleb128put(FAKERETURNCOLUMN); // return_address_register
cput(DW_CFA_def_cfa);
uleb128put(DWARFREGSP); // register SP (**ABI-dependent, defined in l.h)
uleb128put(PtrSize); // offset
cput(DW_CFA_offset + FAKERETURNCOLUMN); // return address
- uleb128put(-PtrSize / DATAALIGNMENTFACTOR); // at cfa - x*4
+ uleb128put(-PtrSize / DATAALIGNMENTFACTOR); // at cfa - x*4
// 4 is to exclude the length field.
pad = CIERESERVE + frameo + 4 - cpos();
@@ -866,7 +1585,6 @@ writeframes(void)
for(q = p; q->link != P; q = q->link) {
if (q->spadj == 0)
continue;
-
cfa += q->spadj;
putpccfadelta(q->link->pc - pc, cfa);
pc = q->link->pc;
@@ -896,47 +1614,222 @@ writeframes(void)
/*
* Walk DWarfDebugInfoEntries, and emit .debug_info
*/
+enum
+{
+ COMPUNITHEADERSIZE = 4+2+4+1
+};
+
static void
writeinfo(void)
{
DWDie *compunit;
- vlong unitstart;
+ vlong unitstart, here;
- reversetree(&dwinfo);
+ fwdcount = 0;
- infoo = cpos();
-
- for (compunit = dwinfo; compunit; compunit = compunit->link) {
+ for (compunit = dwroot.child; compunit; compunit = compunit->link) {
unitstart = cpos();
// Write .debug_info Compilation Unit Header (sec 7.5.1)
// Fields marked with (*) must be changed for 64-bit dwarf
- LPUT(0); // unit_length (*), will be filled in later.
- WPUT(3); // version
- LPUT(0); // debug_abbrev_offset (*)
- cput(PtrSize); // address_size
+ // This must match COMPUNITHEADERSIZE above.
+ LPUT(0); // unit_length (*), will be filled in later.
+ WPUT(3); // dwarf version (appendix F)
+ LPUT(0); // debug_abbrev_offset (*)
+ cput(PtrSize); // address_size
putdie(compunit);
cflush();
- vlong here = cpos();
+ here = cpos();
seek(cout, unitstart, 0);
- LPUT(here - unitstart - sizeof(int32));
+ LPUT(here - unitstart - 4); // exclude the length field.
+ cflush();
+ seek(cout, here, 0);
+ }
+
+}
+
+/*
+ * Emit .debug_pubnames/_types. _info must have been written before,
+ * because we need die->offs and infoo/infosize;
+ */
+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;
+
+ // Write .debug_pubnames/types Header (sec 6.1.1)
+ LPUT(0); // unit_length (*), will be filled in later.
+ WPUT(2); // dwarf version (appendix F)
+ LPUT(unitstart); // debug_info_offset (of the Comp unit Header)
+ LPUT(unitend - unitstart); // debug_info_length
+
+ 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);
+
+ cflush();
+ here = cpos();
+ seek(cout, sectionstart, 0);
+ LPUT(here - sectionstart - 4); // exclude the length field.
cflush();
seek(cout, here, 0);
+
}
+ return sectionstart;
+}
+
+/*
+ * emit .debug_aranges. _info must have been written before,
+ * because we need die->offs of dw_globals.
+ */
+static vlong
+writearanges()
+{
+ DWDie *compunit;
+ DWAttr *b, *e;
+ int headersize;
+ vlong sectionstart;
+
+ sectionstart = cpos();
+ headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself
+
+ 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;
+
+ // Write .debug_aranges Header + entry (sec 6.1.2)
+ LPUT(headersize + 4*PtrSize - 4); // unit_length (*)
+ WPUT(2); // dwarf version (appendix F)
+ LPUT(compunit->offs - COMPUNITHEADERSIZE); // debug_info_offset
+ cput(PtrSize); // address_size
+ cput(0); // segment_size
+ strnput("", headersize - (4+2+4+1+1)); // align to PtrSize
+
+ addrput(b->value);
+ addrput(e->value - b->value);
+ addrput(0);
+ addrput(0);
+ }
cflush();
- infosize = cpos() - infoo;
+ return sectionstart;
}
+/*
+ * This is the main entry point for generating dwarf. After emitting
+ * the mandatory debug_abbrev section, it calls writelines() to set up
+ * the per-compilation unit part of the DIE tree, while simultaneously
+ * emitting the debug_line section. When the final tree contains
+ * forward references, it will write the debug_info section in 2
+ * passes.
+ *
+ */
void
dwarfemitdebugsections(void)
{
+ vlong infoe;
+ DWDie* die;
+
+ mkindex(&dwroot);
+ mkindex(&dwtypes);
+ mkindex(&dwglobals);
+
+ // Some types that must exist to define other ones.
+ newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>");
+ newdie(&dwtypes, DW_ABRV_NULLTYPE, "void");
+ die = newdie(&dwtypes, DW_ABRV_PTRTYPE, "unsafe.Pointer");
+ newrefattr(die, DW_AT_type, find(&dwtypes, "void"));
+
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, "<int32>");
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, 4, 0);
+
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, "<byte>");
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, 1, 0);
+
+ die = newdie(&dwtypes, DW_ABRV_PTRTYPE, "<byte*>");
+ newrefattr(die, DW_AT_type, find(&dwtypes, "<byte>"));
+
+ genasmsym(defdwsymb);
+ reversetree(&dwtypes.child);
+ reversetree(&dwglobals.child);
+
writeabbrev();
writelines();
writeframes();
+
+ reversetree(&dwroot.child);
+ movetomodule(&dwtypes); // TODO: put before functions
+ movetomodule(&dwglobals);
+
+
+ infoo = cpos();
writeinfo();
+ infoe = cpos();
+
+ if (fwdcount > 0) {
+ if (debug['v'])
+ Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime());
+ seek(cout, infoo, 0);
+ writeinfo();
+ if (fwdcount > 0) {
+ diag("unresolved references after first dwarf info pass");
+ errorexit();
+ }
+ if (infoe != cpos()) {
+ diag("inconsistent second dwarf info pass");
+ errorexit();
+ }
+ }
+ infosize = infoe - infoo;
+
+ pubnameso = writepub(ispubname);
+ pubtypeso = writepub(ispubtype);
+ arangeso = writearanges();
+
+ pubnamessize = pubtypeso - pubnameso;
+ pubtypessize = arangeso - pubtypeso;
+ arangessize = cpos() - arangeso;
}
/*
@@ -1004,6 +1897,30 @@ dwarfaddelfheaders(void)
sh->off = infoo;
sh->size = infosize;
sh->addralign = 1;
+
+ 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;
+ }
+
+ if (arangessize) {
+ sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]);
+ sh->type = SHT_PROGBITS;
+ sh->off = arangeso;
+ sh->size = arangessize;
+ sh->addralign = 1;
+ }
}
/*
@@ -1021,23 +1938,48 @@ dwarfaddmachoheaders(void)
// have to be page aligned in the file.
fakestart = abbrevo & ~0xfff;
- ms = newMachoSeg("__DWARF", 4);
+ ms = newMachoSeg("__DWARF", 7);
ms->fileoffset = fakestart;
- ms->filesize = abbrevo-fakestart + abbrevsize+linesize+framesize+infosize;
+ ms->filesize = abbrevo-fakestart;
msect = newMachoSect(ms, "__debug_abbrev");
msect->off = abbrevo;
msect->size = abbrevsize;
+ ms->filesize += msect->size;
msect = newMachoSect(ms, "__debug_line");
msect->off = lineo;
msect->size = linesize;
+ ms->filesize += msect->size;
msect = newMachoSect(ms, "__debug_frame");
msect->off = frameo;
msect->size = framesize;
+ ms->filesize += msect->size;
msect = newMachoSect(ms, "__debug_info");
msect->off = infoo;
msect->size = infosize;
+ ms->filesize += msect->size;
+
+ if (pubnamessize > 0) {
+ msect = newMachoSect(ms, "__debug_pubnames");
+ msect->off = pubnameso;
+ msect->size = pubnamessize;
+ ms->filesize += msect->size;
+ }
+
+ if (pubtypessize > 0) {
+ msect = newMachoSect(ms, "__debug_pubtypes");
+ msect->off = pubtypeso;
+ msect->size = pubtypessize;
+ ms->filesize += msect->size;
+ }
+
+ if (arangessize > 0) {
+ msect = newMachoSect(ms, "__debug_aranges");
+ msect->off = arangeso;
+ msect->size = arangessize;
+ ms->filesize += msect->size;
+ }
}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
index 928aedd413..7881213c21 100644
--- a/src/cmd/ld/dwarf.h
+++ b/src/cmd/ld/dwarf.h
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-
/*
* Register 'f' symbol file fragments. Doing this while parsing the
* .6 input saves a pass over the symbol table later.
@@ -10,18 +9,19 @@
void dwarfaddfrag(int n, char* frag);
/*
- * Add the dwarf section names to the ELF
- * s[ection]h[eader]str[ing]tab.
- */
-void dwarfaddshstrings(Sym *shstrtab);
-
-/*
* Emit debug_abbrevs, debug_info and debug_line sections to current
* offset in cout.
*/
void dwarfemitdebugsections(void);
/*
+ * Add the dwarf section names to the ELF
+ * s[ection]h[eader]str[ing]tab. Prerequisite for
+ * dwarfaddelfheaders().
+ */
+void dwarfaddshstrings(Sym *shstrtab);
+
+/*
* Add section headers pointing to the sections emitted in
* dwarfemitdebugsections.
*/
diff --git a/src/cmd/ld/dwarf_defs.h b/src/cmd/ld/dwarf_defs.h
index 3b54f77b0b..0f1e5417cf 100644
--- a/src/cmd/ld/dwarf_defs.h
+++ b/src/cmd/ld/dwarf_defs.h
@@ -55,6 +55,7 @@ enum
DW_TAG_variant_part = 0x33,
DW_TAG_variable = 0x34,
DW_TAG_volatile_type = 0x35,
+ // Dwarf3
DW_TAG_dwarf_procedure = 0x36,
DW_TAG_restrict_type = 0x37,
DW_TAG_interface_type = 0x38,
@@ -65,6 +66,12 @@ enum
DW_TAG_imported_unit = 0x3d,
DW_TAG_condition = 0x3f,
DW_TAG_shared_type = 0x40,
+ // Dwarf4
+ DW_TAG_type_unit = 0x41,
+ DW_TAG_rvalue_reference_type = 0x42,
+ DW_TAG_template_alias = 0x43,
+
+ // User defined
DW_TAG_lo_user = 0x4080,
DW_TAG_hi_user = 0xffff,
@@ -84,7 +91,7 @@ enum
DW_CLS_BLOCK,
DW_CLS_CONSTANT,
DW_CLS_FLAG,
- DW_CLS_PTR, // lineptr, loclistptr, macptr, rangelistptr
+ DW_CLS_PTR, // lineptr, loclistptr, macptr, rangelistptr
DW_CLS_REFERENCE,
DW_CLS_STRING
};
@@ -151,6 +158,7 @@ enum
DW_AT_variable_parameter = 0x4b, // flag
DW_AT_virtuality = 0x4c, // constant
DW_AT_vtable_elem_location = 0x4d, // block, loclistptr
+ // Dwarf3
DW_AT_allocated = 0x4e, // block, constant, reference
DW_AT_associated = 0x4f, // block, constant, reference
DW_AT_data_location = 0x50, // block
@@ -178,6 +186,7 @@ enum
DW_AT_elemental = 0x66, // flag
DW_AT_pure = 0x67, // flag
DW_AT_recursive = 0x68, // flag
+
DW_AT_lo_user = 0x2000, // ---
DW_AT_hi_user = 0x3fff, // ---
@@ -358,6 +367,7 @@ enum
DW_LANG_Fortran90 = 0x0008,
DW_LANG_Pascal83 = 0x0009,
DW_LANG_Modula2 = 0x000a,
+ // Dwarf3
DW_LANG_Java = 0x000b,
DW_LANG_C99 = 0x000c,
DW_LANG_Ada95 = 0x000d,
@@ -367,7 +377,8 @@ enum
DW_LANG_ObjC_plus_plus = 0x0011,
DW_LANG_UPC = 0x0012,
DW_LANG_D = 0x0013,
- DW_LANG_Python = 0x0014, // DWARF4
+ // Dwarf4
+ DW_LANG_Python = 0x0014,
DW_LANG_lo_user = 0x8000,
DW_LANG_Go = 0x8015, // TODO(lvd) Temporary
@@ -428,6 +439,7 @@ enum
DW_LNS_set_basic_block = 0x07,
DW_LNS_const_add_pc = 0x08,
DW_LNS_fixed_advance_pc = 0x09,
+ // Dwarf3
DW_LNS_set_prologue_end = 0x0a,
DW_LNS_set_epilogue_begin = 0x0b,
DW_LNS_set_isa = 0x0c,
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index 41a6b39669..2ba6e53e61 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -975,5 +975,4 @@ void elfsetstring(char*, int);
* May waste some.
* On FreeBSD, cannot be larger than a page.
*/
-#define ELFRESERVE 2048
-
+#define ELFRESERVE 3072
diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go
index f84b791386..bc21868226 100644
--- a/src/pkg/runtime/type.go
+++ b/src/pkg/runtime/type.go
@@ -9,6 +9,7 @@
* data structures and must be kept in sync with this file:
*
* ../../cmd/gc/reflect.c
+ * ../../cmd/ld/dwarf.c
* ../reflect/type.go
* type.h
*/