]> Cypherpunks repositories - gostls13.git/commitdiff
6l/8l: global and local variables and type info.
authorLuuk van Dijk <lvd@golang.org>
Sun, 24 Oct 2010 21:07:52 +0000 (23:07 +0200)
committerLuuk van Dijk <lvd@golang.org>
Sun, 24 Oct 2010 21:07:52 +0000 (23:07 +0200)
R=rsc
CC=golang-dev
https://golang.org/cl/2201044

src/cmd/ld/dwarf.c
src/cmd/ld/dwarf.h
src/cmd/ld/dwarf_defs.h
src/cmd/ld/elf.h
src/pkg/runtime/type.go

index cd9c82e02d576ea4bb561e805bc1f05f61858f22..7891f64c9a1d545108037b9dd6cf8f7cd7241f3a 100644 (file)
@@ -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;
+       }
 }
index 928aedd413640d85493381be7a2c1517e078c96f..7881213c21fb40b450e82fb85042ce393d10b6ca 100644 (file)
@@ -2,25 +2,25 @@
 // 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.
  */
 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.
index 3b54f77b0b596e50395c65be48ab5f109d2e5d45..0f1e5417cf0e9af8fb3dd5d1649c5214b1ec4814 100644 (file)
@@ -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,
index 41a6b39669bf0c4c6cef2edb1b520872d11235b3..2ba6e53e61d0faf0c003ef1d95c32e43d5e630c2 100644 (file)
@@ -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
index f84b791386888f36c644e6a0dc43c59bb813136b..bc218682266bce89dccd29701e7f10761c0adc47 100644 (file)
@@ -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
  */