# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-for i in cc 6l 6a 6c 8l 8a 8c 5l 5a 5c gc 6g ar db nm acid cov gobuild prof gotest
+for i in cc 6l 6a 6c 8l 8a 8c 5l 5a 5c gc 6g ar db nm acid cov gobuild godefs prof gotest
do
cd $i
make clean
--- /dev/null
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.conf
+
+TARG=godefs
+OFILES=\
+ main.$O\
+ stabs.$O\
+ util.$O\
+
+HFILES=a.h
+
+$(TARG): $(OFILES)
+ $(LD) -o $(TARG) -L$(GOROOT)/lib $(OFILES) -lbio -l9
+
+clean:
+ rm -f $(OFILES) $(TARG)
+
+install: $(TARG)
+ cp $(TARG) $(BIN)/$(TARG)
+
+$(OFILES): $(HFILES)
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+enum
+{
+ Void = 1,
+ Int8,
+ Uint8,
+ Int16,
+ Uint16,
+ Int32,
+ Uint32,
+ Int64,
+ Uint64,
+ Float32,
+ Float64,
+ Ptr,
+ Struct,
+ Array,
+ Union,
+ Typedef,
+};
+
+typedef struct Field Field;
+typedef struct Type Type;
+
+struct Type
+{
+ Type *next; // next in hash table
+
+ // stabs name and two-integer id
+ char *name;
+ int n1;
+ int n2;
+
+ // int kind
+ int kind;
+
+ // sub-type for ptr, array
+ Type *type;
+
+ // struct fields
+ Field *f;
+ int nf;
+ int size;
+
+ int saved; // recorded in typ array
+ int warned; // warned about needing type
+};
+
+struct Field
+{
+ char *name;
+ Type *type;
+ int offset;
+ int size;
+};
+
+// Constants
+typedef struct Const Const;
+struct Const
+{
+ char *name;
+ vlong value;
+};
+
+// Recorded constants and types, to be printed.
+extern Const *con;
+extern int ncon;
+extern Type **typ;
+extern int ntyp;
+
+// Language output
+typedef struct Lang Lang;
+struct Lang
+{
+ char *constbegin;
+ char *constfmt;
+ char *constend;
+
+ char *typdef;
+
+ char *structbegin;
+ char *unionbegin;
+ char *structpadfmt;
+ char *structend;
+
+ int (*typefmt)(Fmt*);
+};
+
+extern Lang go, c;
+
+void* emalloc(int);
+char* estrdup(char*);
+void* erealloc(void*, int);
+void parsestabtype(char*);
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Godefs takes as input a host-compilable C file that includes
+// standard system headers. From that input file, it generates
+// a standalone (no #includes) C or Go file containing equivalent
+// definitions.
+//
+// The input C file is expected to define new types and enumerated
+// constants whose names begin with $ (a legal identifier character
+// in gcc). The output is the standalone definitions of those names,
+// with the $ removed.
+//
+// For example, if this is x.c:
+//
+// #include <sys/stat.h>
+//
+// typedef struct timespec $Timespec;
+// typedef struct stat $Stat;
+// enum {
+// $S_IFMT = S_IFMT,
+// $S_IFIFO = S_IFIFO,
+// $S_IFCHR = S_IFCHR,
+// };
+//
+// then "godefs x.c" generates:
+//
+// // godefs x.c
+//
+// // MACHINE GENERATED - DO NOT EDIT.
+//
+// // Constants
+// enum {
+// S_IFMT = 0xf000,
+// S_IFIFO = 0x1000,
+// S_IFCHR = 0x2000,
+// };
+//
+// // Types
+// #pragma pack on
+//
+// typedef struct Timespec Timespec;
+// struct Timespec {
+// int32 tv_sec;
+// int32 tv_nsec;
+// };
+//
+// typedef struct Stat Stat;
+// struct Stat {
+// int32 st_dev;
+// uint32 st_ino;
+// uint16 st_mode;
+// uint16 st_nlink;
+// uint32 st_uid;
+// uint32 st_gid;
+// int32 st_rdev;
+// Timespec st_atimespec;
+// Timespec st_mtimespec;
+// Timespec st_ctimespec;
+// int64 st_size;
+// int64 st_blocks;
+// int32 st_blksize;
+// uint32 st_flags;
+// uint32 st_gen;
+// int32 st_lspare;
+// int64 st_qspare[2];
+// };
+// #pragma pack off
+//
+// The -g flag to godefs causes it to generate Go output, not C.
+// In the Go output, struct fields have leading xx_ prefixes removed
+// and the first character capitalized (exported).
+//
+// Godefs works by invoking gcc to compile the given input file
+// and then parses the debug info embedded in the assembly output.
+// This is far easier than reading system headers on most machines.
+//
+// The -c flag sets the compiler (default "gcc").
+//
+// The -f flag adds a flag to pass to the compiler (e.g., -f -m64).
+
+#include "a.h"
+
+void
+usage(void)
+{
+ fprint(2, "usage: godefs [-g] [-c cc] [-f cc-flag] defs.c\n");
+ exit(1);
+}
+
+int gotypefmt(Fmt*);
+int ctypefmt(Fmt*);
+int prefixlen(Type*);
+
+Lang go =
+{
+ "const (\n",
+ "\t%s = %#llx;\n",
+ ")\n",
+
+ "type",
+
+ "type %s struct {\n",
+ "type %s union {\n", // not really, but readable
+ "\tpad%d [%d]byte;\n",
+ "}\n",
+
+ gotypefmt,
+};
+
+Lang c =
+{
+ "enum {\n",
+ "\t%s = %#llx,\n",
+ "};\n",
+
+ "typedef",
+
+ "typedef struct %s %s;\nstruct %s {\n",
+ "typedef union %s %s;\nunion %s {\n",
+ "\tbyte pad%d[%d];\n",
+ "};\n",
+
+ ctypefmt,
+};
+
+int oargc;
+char **oargv;
+Lang *lang = &c;
+
+Const *con;
+int ncon;
+
+Type **typ;
+int ntyp;
+
+void
+main(int argc, char **argv)
+{
+ int p[2], pid, i, j, n, off, npad, prefix;
+ char *av[30], *q, *r, *tofree, *name;
+ Biobuf *bin, *bout;
+ Type *t;
+ Field *f;
+
+ quotefmtinstall();
+
+ oargc = argc;
+ oargv = argv;
+
+ n = 0;
+ av[n++] = "gcc";
+ av[n++] = "-S"; // write assembly
+ av[n++] = "-gstabs"; // include stabs info
+ av[n++] = "-o-"; // to stdout
+
+ ARGBEGIN{
+ case 'g':
+ lang = &go;
+ break;
+ case 'c':
+ av[0] = EARGF(usage());
+ break;
+ case 'f':
+ if(n+2 >= nelem(av))
+ sysfatal("too many -f options");
+ av[n++] = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 1)
+ usage();
+ av[n++] = argv[0];
+ av[n] = nil;
+
+ // Run gcc writing assembly and stabs debugging to p[1].
+ if(pipe(p) < 0)
+ sysfatal("pipe: %r");
+
+ pid = fork();
+ if(pid < 0)
+ sysfatal("fork: %r");
+ if(pid == 0) {
+ close(p[0]);
+ dup(p[1], 1);
+ close(0);
+ open("/dev/null", OREAD);
+ exec(av[0], av);
+ fprint(2, "exec gcc: %r\n");
+ exit(1);
+ }
+ close(p[1]);
+
+ // Read assembly, pulling out .stabs lines.
+ bin = Bfdopen(p[0], OREAD);
+ while((q = Brdstr(bin, '\n', 1)) != nil) {
+ // .stabs "float:t(0,12)=r(0,1);4;0;",128,0,0,0
+ tofree = q;
+ while(*q == ' ' || *q == '\t')
+ q++;
+ if(strncmp(q, ".stabs", 6) != 0)
+ goto Continue;
+ q += 6;
+ while(*q == ' ' || *q == '\t')
+ q++;
+ if(*q++ != '\"') {
+ Bad:
+ sysfatal("cannot parse .stabs line:\n%s", tofree);
+ }
+
+ r = strchr(q, '\"');
+ if(r == nil)
+ goto Bad;
+ *r++ = '\0';
+ if(*r++ != ',')
+ goto Bad;
+ if(*r < '0' || *r > '9')
+ goto Bad;
+ if(atoi(r) != 128) // stabs kind = local symbol
+ goto Continue;
+
+ parsestabtype(q);
+
+ Continue:
+ free(tofree);
+ }
+ Bterm(bin);
+ waitpid();
+
+ // Write defs to standard output.
+ bout = Bfdopen(1, OWRITE);
+ fmtinstall('T', lang->typefmt);
+
+ // Echo original command line in header.
+ Bprint(bout, "//");
+ for(i=0; i<oargc; i++)
+ Bprint(bout, " %q", oargv[i]);
+ Bprint(bout, "\n");
+ Bprint(bout, "\n");
+ Bprint(bout, "// MACHINE GENERATED - DO NOT EDIT.\n");
+ Bprint(bout, "\n");
+
+ // Constants.
+ Bprint(bout, "// Constants\n");
+ if(ncon > 0) {
+ Bprint(bout, lang->constbegin);
+ for(i=0; i<ncon; i++)
+ Bprint(bout, lang->constfmt, con[i].name, con[i].value);
+ Bprint(bout, lang->constend);
+ }
+ Bprint(bout, "\n");
+
+ // Types
+
+ // push our names down
+ for(i=0; i<ntyp; i++) {
+ t = typ[i];
+ name = t->name;
+ while(t && t->kind == Typedef)
+ t = t->type;
+ if(t)
+ t->name = name;
+ }
+
+ Bprint(bout, "// Types\n");
+
+ // Have to turn off structure padding in Plan 9 compiler,
+ // mainly because it is more aggressive than gcc tends to be.
+ if(lang == &c)
+ Bprint(bout, "#pragma pack on\n");
+
+ for(i=0; i<ntyp; i++) {
+ Bprint(bout, "\n");
+ t = typ[i];
+ while(t && t->kind == Typedef)
+ t = t->type;
+ name = t->name;
+ if(name[0] == '$')
+ name++;
+ npad = 0;
+ off = 0;
+ switch(t->kind) {
+ case 0:
+ fprint(2, "unknown type definition for %s\n", name);
+ break;
+ default: // numeric, array, or pointer
+ case Array:
+ case Ptr:
+ Bprint(bout, "%s %lT\n", lang->typdef, name, t);
+ break;
+ case Union:
+ if(lang == &go) {
+ fprint(2, "%s: cannot emit unions in go\n", name);
+ continue;
+ }
+ Bprint(bout, lang->unionbegin, name, name, name);
+ goto StructBody;
+ case Struct:
+ Bprint(bout, lang->structbegin, name, name, name);
+ StructBody:
+ prefix = 0;
+ if(lang == &go)
+ prefix = prefixlen(t);
+ for(j=0; j<t->nf; j++) {
+ f = &t->f[j];
+ // padding
+ if(t->kind == Struct) {
+ if(f->offset%8 != 0 || f->size%8 != 0) {
+ fprint(2, "ignoring bitfield %s.%s\n", t->name, f->name);
+ continue;
+ }
+ if(f->offset < off)
+ sysfatal("%s: struct fields went backward", t->name);
+ if(off < f->offset) {
+ Bprint(bout, lang->structpadfmt, npad++, (f->offset - off) / 8);
+ off = f->offset;
+ }
+ off += f->size;
+ }
+ Bprint(bout, "\t%lT;\n", f->name+prefix, f->type);
+ }
+ // final padding
+ if(t->kind == Struct) {
+ if(off/8 < t->size)
+ Bprint(bout, lang->structpadfmt, npad++, t->size - off/8);
+ }
+ Bprint(bout, lang->structend);
+ }
+ }
+ if(lang == &c)
+ Bprint(bout, "#pragma pack off\n");
+ Bterm(bout);
+ exit(0);
+}
+
+char *kindnames[] = {
+ "void", // actually unknown, but byte is good for pointers
+ "void",
+ "int8",
+ "uint8",
+ "int16",
+ "uint16",
+ "int32",
+ "uint32",
+ "int64",
+ "uint64",
+ "float32",
+ "float64",
+ "ptr",
+ "struct",
+ "array",
+ "union",
+ "typedef",
+};
+
+int
+ctypefmt(Fmt *f)
+{
+ char *name, *s;
+ Type *t;
+
+ name = nil;
+ if(f->flags & FmtLong) {
+ name = va_arg(f->args, char*);
+ if(name == nil || name[0] == '\0')
+ name = "_anon_";
+ }
+ t = va_arg(f->args, Type*);
+ while(t && t->kind == Typedef)
+ t = t->type;
+ switch(t->kind) {
+ case Struct:
+ case Union:
+ // must be named
+ s = t->name;
+ if(s == nil) {
+ fprint(2, "need name for anonymous struct\n");
+ goto bad;
+ }
+ else if(s[0] != '$')
+ fprint(2, "need name for struct %s\n", s);
+ else
+ s++;
+ fmtprint(f, "%s", s);
+ if(name)
+ fmtprint(f, " %s", name);
+ break;
+
+ case Array:
+ if(name)
+ fmtprint(f, "%T %s[%d]", t->type, name, t->size);
+ else
+ fmtprint(f, "%T[%d]", t->type, t->size);
+ break;
+
+ case Ptr:
+ if(name)
+ fmtprint(f, "%T *%s", t->type, name);
+ else
+ fmtprint(f, "%T*", t->type);
+ break;
+
+ default:
+ fmtprint(f, "%s", kindnames[t->kind]);
+ if(name)
+ fmtprint(f, " %s", name);
+ break;
+
+ bad:
+ if(name)
+ fmtprint(f, "byte %s[%d]", name, t->size);
+ else
+ fmtprint(f, "byte[%d]", t->size);
+ break;
+ }
+
+ return 0;
+}
+
+int
+gotypefmt(Fmt *f)
+{
+ char *name, *s;
+ Type *t;
+
+ if(f->flags & FmtLong) {
+ name = va_arg(f->args, char*);
+ if('a' <= name[0] && name[0] <= 'z')
+ name[0] += 'A' - 'a';
+ fmtprint(f, "%s ", name);
+ }
+ t = va_arg(f->args, Type*);
+ while(t && t->kind == Typedef)
+ t = t->type;
+
+ switch(t->kind) {
+ case Struct:
+ case Union:
+ // must be named
+ s = t->name;
+ if(s == nil) {
+ fprint(2, "need name for anonymous struct\n");
+ s = "STRUCT";
+ }
+ else if(s[0] != '$')
+ fprint(2, "need name for struct %s\n", s);
+ else
+ s++;
+ fmtprint(f, "%s", s);
+ break;
+
+ case Array:
+ fmtprint(f, "[%d]%T", t->size, t->type);
+ break;
+
+ case Ptr:
+ fmtprint(f, "*%T", t->type);
+ break;
+
+ default:
+ s = kindnames[t->kind];
+ if(strcmp(s, "void") == 0)
+ s = "byte";
+ fmtprint(f, "%s", s);
+ }
+
+ return 0;
+}
+
+// Figure out common struct prefix len
+int
+prefixlen(Type *t)
+{
+ int i;
+ int len;
+ char *p, *name;
+ Field *f;
+
+ len = 0;
+ name = nil;
+ for(i=0; i<t->nf; i++) {
+ f = &t->f[i];
+ p = strchr(f->name, '_');
+ if(p == nil)
+ return 0;
+ if(name == nil) {
+ name = f->name;
+ len = p+1 - name;
+ }
+ else if(strncmp(f->name, name, len) != 0)
+ return 0;
+ }
+ return len;
+}
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse stabs debug info.
+
+#include "a.h"
+
+int stabsdebug = 1;
+
+// Hash table for type lookup by number.
+Type *hash[1024];
+
+// Look up type by number pair.
+// TODO(rsc): Iant points out that n1 and n2 are always small and dense,
+// so an array of arrays would be a better representation.
+Type*
+typebynum(uint n1, uint n2)
+{
+ uint h;
+ Type *t;
+
+ h = (n1*53+n2) % nelem(hash);
+ for(t=hash[h]; t; t=t->next)
+ if(t->n1 == n1 && t->n2 == n2)
+ return t;
+ t = emalloc(sizeof *t);
+ t->next = hash[h];
+ hash[h] = t;
+ t->n1 = n1;
+ t->n2 = n2;
+ return t;
+}
+
+// Parse name and colon from *pp, leaving copy in *sp.
+static int
+parsename(char **pp, char **sp)
+{
+ char *p;
+ char *s;
+
+ p = *pp;
+ while(*p != '\0' && *p != ':')
+ p++;
+ if(*p == '\0') {
+ fprint(2, "parsename expected colon\n");
+ return -1;
+ }
+ s = emalloc(p - *pp + 1);
+ memmove(s, *pp, p - *pp);
+ *sp = s;
+ *pp = p+1;
+ return 0;
+}
+
+// Parse single number from *pp.
+static int
+parsenum1(char **pp, vlong *np)
+{
+ char *p;
+
+ p = *pp;
+ if(*p != '-' && (*p < '0' || *p > '9')) {
+ fprint(2, "parsenum expected minus or digit\n");
+ return -1;
+ }
+ *np = strtoll(p, pp, 10);
+ return 0;
+}
+
+// Parse type number - either single number or (n1, n2).
+static int
+parsetypenum(char **pp, vlong *n1p, vlong *n2p)
+{
+ char *p;
+
+ p = *pp;
+ if(*p == '(') {
+ p++;
+ if(parsenum1(&p, n1p) < 0)
+ return -1;
+ if(*p++ != ',') {
+ if(stabsdebug)
+ fprint(2, "parsetypenum expected comma\n");
+ return -1;
+ }
+ if(parsenum1(&p, n2p) < 0)
+ return -1;
+ if(*p++ != ')') {
+ if(stabsdebug)
+ fprint(2, "parsetypenum expected right paren\n");
+ return -1;
+ }
+ *pp = p;
+ return 0;
+ }
+
+ if(parsenum1(&p, n1p) < 0)
+ return -1;
+ *n2p = 0;
+ *pp = p;
+ return 0;
+}
+
+// Integer types are represented in stabs as a "range"
+// type with a lo and a hi value. The lo and hi used to
+// be lo and hi for the type, but there are now odd
+// extensions for floating point and 64-bit numbers.
+//
+// Have to keep signs separate from values because
+// Int64's lo is -0.
+typedef struct Intrange Intrange;
+struct Intrange
+{
+ int signlo; // sign of lo
+ vlong lo;
+ int signhi; // sign of hi
+ vlong hi;
+ int kind;
+};
+
+// NOTE(rsc): Iant says that these might be different depending
+// on the gcc mode, though I haven't observed this yet.
+Intrange intranges[] = {
+ '+', 0, '+', 127, Int8, // char
+ '-', 128, '+', 127, Int8, // signed char
+ '+', 0, '+', 255, Uint8,
+ '-', 32768, '+', 32767, Int16,
+ '+', 0, '+', 65535, Uint16,
+ '-', 2147483648LL, '+', 2147483647LL, Int32,
+ '+', 0, '+', 4294967295LL, Uint32,
+
+ // abnormal cases
+ '-', 0, '+', 4294967295LL, Int64,
+ '+', 0, '-', 1, Uint64,
+
+ '+', 4, '+', 0, Float32,
+ '+', 8, '+', 0, Float64,
+ '+', 16, '+', 0, Void,
+};
+
+static int kindsize[] = {
+ 0,
+ 8,
+ 8,
+ 16,
+ 16,
+ 32,
+ 32,
+ 64,
+ 64,
+};
+
+// Parse a single type definition from *pp.
+static Type*
+parsedef(char **pp, char *name)
+{
+ char *p;
+ Type *t, *tt;
+ int i, signlo, signhi;
+ vlong n1, n2, lo, hi;
+ Field *f;
+ Intrange *r;
+
+ p = *pp;
+
+ // reference to another type?
+ if(isdigit(*p) || *p == '(') {
+ if(parsetypenum(&p, &n1, &n2) < 0)
+ return nil;
+ t = typebynum(n1, n2);
+ if(name && t->name == nil) {
+ t->name = name;
+ // save definitions of names beginning with $
+ if(name[0] == '$' && !t->saved) {
+ typ = erealloc(typ, (ntyp+1)*sizeof typ[0]);
+ typ[ntyp] = t;
+ ntyp++;
+ }
+ }
+
+ // is there an =def suffix?
+ if(*p == '=') {
+ p++;
+ tt = parsedef(&p, name);
+ if(tt == nil)
+ return nil;
+
+ if(tt == t) {
+ tt->kind = Void;
+ } else {
+ t->type = tt;
+ t->kind = Typedef;
+ }
+
+ // assign given name, but do not record in typ.
+ // assume the name came from a typedef
+ // which will be recorded.
+ if(name)
+ tt->name = name;
+ }
+
+ *pp = p;
+ return t;
+ }
+
+ // otherwise a type literal. first letter identifies kind
+ t = emalloc(sizeof *t);
+ switch(*p) {
+ default:
+ *pp = "";
+ return t;
+
+ case '*': // pointer
+ p++;
+ t->kind = Ptr;
+ tt = parsedef(&p, nil);
+ if(tt == nil)
+ return nil;
+ t->type = tt;
+ break;
+
+ case 'a': // array
+ p++;
+ t->kind = Array;
+ // index type
+ tt = parsedef(&p, nil);
+ if(tt == nil)
+ return nil;
+ t->size = tt->size;
+ // element type
+ tt = parsedef(&p, nil);
+ if(tt == nil)
+ return nil;
+ t->type = tt;
+ break;
+
+ case 'e': // enum type - record $names in con array.
+ p++;
+ for(;;) {
+ if(*p == '\0')
+ return nil;
+ if(*p == ';') {
+ p++;
+ break;
+ }
+ if(parsename(&p, &name) < 0)
+ return nil;
+ if(parsenum1(&p, &n1) < 0)
+ return nil;
+ if(name[0] == '$') {
+ con = erealloc(con, (ncon+1)*sizeof con[0]);
+ name++;
+ con[ncon].name = name;
+ con[ncon].value = n1;
+ ncon++;
+ }
+ if(*p != ',')
+ return nil;
+ p++;
+ }
+ break;
+
+ case 'f': // function
+ p++;
+ if(parsedef(&p, nil) == nil)
+ return nil;
+ break;
+
+ case 'r': // sub-range (used for integers)
+ p++;
+ if(parsedef(&p, nil) == nil)
+ return nil;
+ // usually, the return from parsedef == t, but not always.
+
+ if(*p != ';' || *++p == ';') {
+ if(stabsdebug)
+ fprint(2, "range expected number: %s\n", p);
+ return nil;
+ }
+ if(*p == '-') {
+ signlo = '-';
+ p++;
+ } else
+ signlo = '+';
+ lo = strtoll(p, &p, 10);
+ if(*p != ';' || *++p == ';') {
+ if(stabsdebug)
+ fprint(2, "range expected number: %s\n", p);
+ return nil;
+ }
+ if(*p == '-') {
+ signhi = '-';
+ p++;
+ } else
+ signhi = '+';
+ hi = strtoll(p, &p, 10);
+ if(*p != ';') {
+ if(stabsdebug)
+ fprint(2, "range expected trailing semi: %s\n", p);
+ return nil;
+ }
+ p++;
+ t->size = hi+1; // might be array size
+ for(i=0; i<nelem(intranges); i++) {
+ r = &intranges[i];
+ if(r->signlo == signlo && r->signhi == signhi && r->lo == lo && r->hi == hi) {
+ t->kind = r->kind;
+ break;
+ }
+ }
+ break;
+
+ case 's': // struct
+ case 'u': // union
+ t->kind = Struct;
+ if(*p == 'u')
+ t->kind = Union;
+
+ // assign given name, but do not record in typ.
+ // assume the name came from a typedef
+ // which will be recorded.
+ if(name)
+ t->name = name;
+ p++;
+ if(parsenum1(&p, &n1) < 0)
+ return nil;
+ t->size = n1;
+ for(;;) {
+ if(*p == '\0')
+ return nil;
+ if(*p == ';') {
+ p++;
+ break;
+ }
+ t->f = erealloc(t->f, (t->nf+1)*sizeof t->f[0]);
+ f = &t->f[t->nf];
+ if(parsename(&p, &f->name) < 0)
+ return nil;
+ f->type = parsedef(&p, nil);
+ if(f->type == nil)
+ return nil;
+ if(*p != ',') {
+ fprint(2, "expected comma after def of %s:\n%s\n", f->name, p);
+ return nil;
+ }
+ p++;
+ if(parsenum1(&p, &n1) < 0)
+ return nil;
+ f->offset = n1;
+ if(*p != ',') {
+ fprint(2, "expected comma after offset of %s:\n%s\n", f->name, p);
+ return nil;
+ }
+ p++;
+ if(parsenum1(&p, &n1) < 0)
+ return nil;
+ f->size = n1;
+ if(*p != ';') {
+ fprint(2, "expected semi after size of %s:\n%s\n", f->name, p);
+ return nil;
+ }
+
+ // rewrite
+ // uint32 x : 8;
+ // into
+ // uint8 x;
+ // hooray for bitfields.
+ while(Int16 <= f->type->kind && f->type->kind <= Uint64 && kindsize[f->type->kind] > f->size) {
+ t = emalloc(sizeof *t);
+ *t = *f->type;
+ f->type = t;
+ f->type->kind -= 2;
+ }
+ p++;
+ t->nf++;
+ }
+ break;
+
+
+ }
+ *pp = p;
+ return t;
+}
+
+
+// Parse a stab type in p, saving info in the type hash table
+// and also in the list of recorded types if appropriate.
+void
+parsestabtype(char *p)
+{
+ char *p0, *name;
+
+ p0 = p;
+
+ // p is the quoted string output from gcc -gstabs on a .stabs line.
+ // name:t(1,2)
+ // name:t(1,2)=def
+ if(parsename(&p, &name) < 0) {
+ Bad:
+ // Use fprint instead of sysfatal to avoid
+ // sysfatal's internal buffer size limit.
+ fprint(2, "cannot parse stabs type:\n%s\n(at %s)\n", p0, p);
+ sysfatal("stabs parse");
+ }
+ if(*p != 't' && *p != 'T')
+ goto Bad;
+ p++;
+
+ // parse the definition.
+ if(name[0] == '\0')
+ name = nil;
+ if(parsedef(&p, name) == nil)
+ goto Bad;
+ if(*p != '\0')
+ goto Bad;
+}
+
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "a.h"
+
+void*
+emalloc(int n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == nil)
+ sysfatal("out of memory");
+ memset(p, 0, n);
+ return p;
+}
+
+char*
+estrdup(char *s)
+{
+ s = strdup(s);
+ if(s == nil)
+ sysfatal("out of memory");
+ return s;
+}
+
+void*
+erealloc(void *v, int n)
+{
+ v = realloc(v, n);
+ if(v == nil)
+ sysfatal("out of memory");
+ return v;
+}
+
make enam.o
cd ..
-for i in cc 6l 6a 6c gc 6g ar db nm acid cov gobuild prof gotest
+for i in cc 6l 6a 6c gc 6g ar db nm acid cov gobuild godefs prof gotest
do
echo; echo; echo %%%% making $i %%%%; echo
cd $i