diff options
Diffstat (limited to 'src/cmd/godefs/main.c')
-rw-r--r-- | src/cmd/godefs/main.c | 606 |
1 files changed, 0 insertions, 606 deletions
diff --git a/src/cmd/godefs/main.c b/src/cmd/godefs/main.c deleted file mode 100644 index 6a8630179..000000000 --- a/src/cmd/godefs/main.c +++ /dev/null @@ -1,606 +0,0 @@ -// 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" - -#ifdef _WIN32 -int -spawn(char *prog, char **argv) -{ - return _spawnvp(P_NOWAIT, prog, (const char**)argv); -} -#undef waitfor -void -waitfor(int pid) -{ - _cwait(0, pid, 0); -} -#else -int -spawn(char *prog, char **argv) -{ - int pid = fork(); - if(pid < 0) - sysfatal("fork: %r"); - if(pid == 0) { - exec(argv[0], argv); - fprint(2, "exec gcc: %r\n"); - exit(1); - } - return pid; -} -#endif - -void -usage(void) -{ - fprint(2, "usage: godefs [-g package] [-c cc] [-f cc-arg] [defs.c ...]\n"); - exit(1); -} - -int gotypefmt(Fmt*); -int ctypefmt(Fmt*); -int prefixlen(Type*); -int cutprefix(char*); - -Lang go = -{ - "const (\n", - "\t%s = %#llx;\n", - ")\n", - - "type", - "\n", - - "type %s struct {\n", - "type %s struct {\n", - "\tPad_godefs_%d [%d]byte;\n", - "}\n", - - gotypefmt, -}; - -Lang c = -{ - "enum {\n", - "\t%s = %#llx,\n", - "};\n", - - "typedef", - ";\n", - - "typedef struct %s %s;\nstruct %s {\n", - "typedef union %s %s;\nunion %s {\n", - "\tbyte pad_godefs_%d[%d];\n", - "};\n", - - ctypefmt, -}; - -char *pkg; - -int oargc; -char **oargv; -Lang *lang = &c; - -Const *con; -int ncon; - -Type **typ; -int ntyp; - -void -waitforgcc(void) -{ - waitpid(); -} - -void -main(int argc, char **argv) -{ - int p[2], pid, i, j, n, off, npad, prefix; - char **av, *q, *r, *tofree, *name; - char nambuf[100]; - Biobuf *bin, *bout; - Type *t, *tt; - Field *f; - int orig_output_fd; - - quotefmtinstall(); - - oargc = argc; - oargv = argv; - av = emalloc((30+argc)*sizeof av[0]); - atexit(waitforgcc); - - n = 0; - av[n++] = "gcc"; - av[n++] = "-fdollars-in-identifiers"; - av[n++] = "-S"; // write assembly - av[n++] = "-gstabs+"; // include stabs info - av[n++] = "-o"; // to ... - av[n++] = "-"; // ... stdout - av[n++] = "-xc"; // read C - - ARGBEGIN{ - case 'g': - lang = &go; - pkg = EARGF(usage()); - break; - case 'c': - av[0] = EARGF(usage()); - break; - case 'f': - av[n++] = EARGF(usage()); - break; - default: - usage(); - }ARGEND - - if(argc == 0) - av[n++] = "-"; - else - av[n++] = argv[0]; - av[n] = nil; - - orig_output_fd = dup(1, -1); - for(i=0; i==0 || i < argc; i++) { - // Some versions of gcc do not accept -S with multiple files. - // Run gcc once for each file. - // Write assembly and stabs debugging to p[1]. - if(pipe(p) < 0) - sysfatal("pipe: %r"); - dup(p[1], 1); - close(p[1]); - if (argc) - av[n-1] = argv[i]; - pid = spawn(av[0], av); - dup(orig_output_fd, 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); - waitfor(pid); - } - close(orig_output_fd); - - // 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"); - - if(pkg) - Bprint(bout, "package %s\n\n", pkg); - - // Constants. - Bprint(bout, "// Constants\n"); - if(ncon > 0) { - Bprint(bout, lang->constbegin); - for(i=0; i<ncon; i++) { - // Go can handle negative constants, - // but C enums may not be able to. - if(lang == &go) - Bprint(bout, lang->constfmt, con[i].name, con[i].value); - else - Bprint(bout, lang->constfmt, con[i].name, con[i].value & 0xFFFFFFFF); - } - 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]; - name = t->name; - while(t && t->kind == Typedef) { - if(name == nil && t->name != nil) { - name = t->name; - if(t->printed) - break; - } - t = t->type; - } - if(name == nil && t->name != nil) { - name = t->name; - if(t->printed) - continue; - t->printed = 1; - } - if(name == nil) { - fprint(2, "unknown name for %T", typ[i]); - continue; - } - 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%s", lang->typdef, name, t, lang->typdefend); - break; - case Union: - // In Go, print union as struct with only first element, - // padded the rest of the way. - 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]; - if(f->type->kind == 0 && f->size <= 64 && (f->size&(f->size-1)) == 0) { - // unknown type but <= 64 bits and bit size is a power of two. - // could be enum - make Uint64 and then let it reduce - tt = emalloc(sizeof *tt); - *tt = *f->type; - f->type = tt; - tt->kind = Uint64; - while(tt->kind > Uint8 && kindsize[tt->kind] > f->size) - tt->kind -= 2; - } - // padding - if(t->kind == Struct || lang == &go) { - 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; - } - name = f->name; - if(cutprefix(name)) - name += prefix; - if(strcmp(name, "") == 0) { - snprint(nambuf, sizeof nambuf, "Pad_godefs_%d", npad++); - name = nambuf; - } - Bprint(bout, "\t%#lT;\n", name, f->type); - if(t->kind == Union && lang == &go) - break; - } - // final padding - if(t->kind == Struct || lang == &go) { - 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'; - if(name[0] == '_' && (f->flags & FmtSharp)) - fmtprint(f, "X"); - 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"); - fmtprint(f, "STRUCT"); - } - else if(s[0] != '$') { - fprint(2, "warning: missing name for struct %s\n", s); - fmtprint(f, "[%d]byte /* %s */", t->size, s); - } else - fmtprint(f, "%s", s+1); - 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; -} - -// Is this the kind of name we should cut a prefix from? -// The rule is that the name cannot begin with underscore -// and must have an underscore eventually. -int -cutprefix(char *name) -{ - char *p; - - // special case: orig_ in register struct - if(strncmp(name, "orig_", 5) == 0) - return 0; - - for(p=name; *p; p++) { - if(*p == '_') - return p-name > 0; - } - 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]; - if(!cutprefix(f->name)) - continue; - 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; -} |