TARG=cgo
GOFILES=\
- cgo.go\
+ ast.go\
+ gcc.go\
+ main.go\
+ util.go\
include $(GOROOT)/src/Make.cmd
--- /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 input AST and prepare Prog structure.
+
+package main
+
+import (
+ "debug/dwarf";
+ "fmt";
+ "go/ast";
+ "go/doc";
+ "go/parser";
+ "go/scanner";
+ "os";
+)
+
+// A Cref refers to an expression of the form C.xxx in the AST.
+type Cref struct {
+ Name string;
+ Expr *ast.Expr;
+ Context string; // "type", "expr", or "call"
+ TypeName bool; // whether xxx is a C type name
+ DebugType dwarf.Type; // the type of xxx
+}
+
+// A Prog collects information about a cgo program.
+type Prog struct {
+ AST *ast.File; // parsed AST
+ Preamble string; // C preamble (doc comment on import "C")
+ Crefs []*Cref;
+}
+
+func openProg(name string) *Prog {
+ p := new(Prog);
+ var err os.Error;
+ p.AST, err = parser.ParsePkgFile("", name, parser.ParseComments);
+ if err != nil {
+ if list, ok := err.(scanner.ErrorList); ok {
+ // If err is a scanner.ErrorList, its String will print just
+ // the first error and then (+n more errors).
+ // Instead, turn it into a new Error that will return
+ // details for all the errors.
+ for _, e := range list {
+ fmt.Fprintln(os.Stderr, e);
+ }
+ os.Exit(2);
+ }
+ fatal("parsing %s: %s", name, err);
+ }
+
+ // Find the import "C" line and get any extra C preamble.
+ found := false;
+ for _, d := range p.AST.Decls {
+ d, ok := d.(*ast.GenDecl);
+ if !ok {
+ continue;
+ }
+ for _, s := range d.Specs {
+ s, ok := s.(*ast.ImportSpec);
+ if !ok {
+ continue;
+ }
+ if len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
+ continue;
+ }
+ found = true;
+ if s.Name != nil {
+ error(s.Path[0].Pos(), `cannot rename import "C"`);
+ }
+ if s.Doc != nil {
+ p.Preamble += doc.CommentText(s.Doc) + "\n";
+ }
+ else if len(d.Specs) == 1 && d.Doc != nil {
+ p.Preamble += doc.CommentText(d.Doc) + "\n";
+ }
+ }
+ }
+ if !found {
+ error(noPos, `cannot find import "C"`);
+ }
+
+ // Accumulate pointers to uses of C.x.
+ p.Crefs = make([]*Cref, 0, 8);
+ walk(p.AST, p, "prog");
+ return p;
+}
+
+func walk(x interface{}, p *Prog, context string) {
+ switch n := x.(type) {
+ case *ast.Expr:
+ if sel, ok := (*n).(*ast.SelectorExpr); ok {
+ // For now, assume that the only instance of capital C is
+ // when used as the imported package identifier.
+ // The parser should take care of scoping in the future,
+ // so that we will be able to distinguish a "top-level C"
+ // from a local C.
+ if l, ok := sel.X.(*ast.Ident); ok && l.Value == "C" {
+ i := len(p.Crefs);
+ if i >= cap(p.Crefs) {
+ new := make([]*Cref, 2*i);
+ for j, v := range p.Crefs {
+ new[j] = v;
+ }
+ p.Crefs = new;
+ }
+ p.Crefs = p.Crefs[0:i+1];
+ p.Crefs[i] = &Cref{
+ Name: sel.Sel.Value,
+ Expr: n,
+ Context: context
+ };
+ break;
+ }
+ }
+ walk(*n, p, context);
+
+ // everything else just recurs
+ default:
+ error(noPos, "unexpected type %T in walk", x);
+ panic();
+
+ case nil:
+
+ // These are ordered and grouped to match ../../pkg/go/ast/ast.go
+ case *ast.Field:
+ walk(&n.Type, p, "type");
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.Ellipsis:
+ case *ast.BasicLit:
+ case *ast.StringList:
+ case *ast.FuncLit:
+ walk(n.Type, p, "type");
+ walk(n.Body, p, "stmt");
+ case *ast.CompositeLit:
+ walk(&n.Type, p, "type");
+ walk(n.Elts, p, "expr");
+ case *ast.ParenExpr:
+ walk(&n.X, p, context);
+ case *ast.SelectorExpr:
+ walk(&n.X, p, "selector");
+ case *ast.IndexExpr:
+ walk(&n.X, p, "expr");
+ walk(&n.Index, p, "expr");
+ if n.End != nil {
+ walk(&n.End, p, "expr");
+ }
+ case *ast.TypeAssertExpr:
+ walk(&n.X, p, "expr");
+ walk(&n.Type, p, "type");
+ case *ast.CallExpr:
+ walk(&n.Fun, p, "call");
+ walk(n.Args, p, "expr");
+ case *ast.StarExpr:
+ walk(&n.X, p, context);
+ case *ast.UnaryExpr:
+ walk(&n.X, p, "expr");
+ case *ast.BinaryExpr:
+ walk(&n.X, p, "expr");
+ walk(&n.Y, p, "expr");
+ case *ast.KeyValueExpr:
+ walk(&n.Key, p, "expr");
+ walk(&n.Value, p, "expr");
+
+ case *ast.ArrayType:
+ walk(&n.Len, p, "expr");
+ walk(&n.Elt, p, "type");
+ case *ast.StructType:
+ walk(n.Fields, p, "field");
+ case *ast.FuncType:
+ walk(n.Params, p, "field");
+ walk(n.Results, p, "field");
+ case *ast.InterfaceType:
+ walk(n.Methods, p, "field");
+ case *ast.MapType:
+ walk(&n.Key, p, "type");
+ walk(&n.Value, p, "type");
+ case *ast.ChanType:
+ walk(&n.Value, p, "type");
+
+ case *ast.BadStmt:
+ case *ast.DeclStmt:
+ walk(n.Decl, p, "decl");
+ case *ast.EmptyStmt:
+ case *ast.LabeledStmt:
+ walk(n.Stmt, p, "stmt");
+ case *ast.ExprStmt:
+ walk(&n.X, p, "expr");
+ case *ast.IncDecStmt:
+ walk(&n.X, p, "expr");
+ case *ast.AssignStmt:
+ walk(n.Lhs, p, "expr");
+ walk(n.Rhs, p, "expr");
+ case *ast.GoStmt:
+ walk(&n.Call, p, "expr");
+ case *ast.DeferStmt:
+ walk(&n.Call, p, "expr");
+ case *ast.ReturnStmt:
+ walk(n.Results, p, "expr");
+ case *ast.BranchStmt:
+ case *ast.BlockStmt:
+ walk(n.List, p, "stmt");
+ case *ast.IfStmt:
+ walk(n.Init, p, "stmt");
+ walk(&n.Cond, p, "expr");
+ walk(n.Body, p, "stmt");
+ walk(n.Else, p, "stmt");
+ case *ast.CaseClause:
+ walk(n.Values, p, "expr");
+ walk(n.Body, p, "stmt");
+ case *ast.SwitchStmt:
+ walk(n.Init, p, "stmt");
+ walk(&n.Tag, p, "expr");
+ walk(n.Body, p, "stmt");
+ case *ast.TypeCaseClause:
+ walk(n.Types, p, "type");
+ walk(n.Body, p, "stmt");
+ case *ast.TypeSwitchStmt:
+ walk(n.Init, p, "stmt");
+ walk(n.Assign, p, "stmt");
+ walk(n.Body, p, "stmt");
+ case *ast.CommClause:
+ walk(n.Lhs, p, "expr");
+ walk(n.Rhs, p, "expr");
+ walk(n.Body, p, "stmt");
+ case *ast.SelectStmt:
+ walk(n.Body, p, "stmt");
+ case *ast.ForStmt:
+ walk(n.Init, p, "stmt");
+ walk(&n.Cond, p, "expr");
+ walk(n.Post, p, "stmt");
+ walk(n.Body, p, "stmt");
+ case *ast.RangeStmt:
+ walk(&n.Key, p, "expr");
+ walk(&n.Value, p, "expr");
+ walk(&n.X, p, "expr");
+ walk(n.Body, p, "stmt");
+
+ case *ast.ImportSpec:
+ case *ast.ValueSpec:
+ walk(&n.Type, p, "type");
+ walk(n.Values, p, "expr");
+ case *ast.TypeSpec:
+ walk(&n.Type, p, "type");
+
+ case *ast.BadDecl:
+ case *ast.GenDecl:
+ walk(n.Specs, p, "spec");
+ case *ast.FuncDecl:
+ if n.Recv != nil {
+ walk(n.Recv, p, "field");
+ }
+ walk(n.Type, p, "type");
+ walk(n.Body, p, "stmt");
+
+ case *ast.File:
+ walk(n.Decls, p, "decl");
+
+ case *ast.Package:
+ for _, f := range n.Files {
+ walk(f, p, "file");
+ }
+
+ case []ast.Decl:
+ for _, d := range n {
+ walk(d, p, context);
+ }
+ case []ast.Expr:
+ for i := range n {
+ walk(&n[i], p, context);
+ }
+ case []*ast.Field:
+ for _, f := range n {
+ walk(f, p, context);
+ }
+ case []ast.Stmt:
+ for _, s := range n {
+ walk(s, p, context);
+ }
+ case []ast.Spec:
+ for _, s := range n {
+ walk(s, p, context);
+ }
+ }
+}
+
+++ /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.
-
-// Cgo; see gmp.go for an overview.
-
-// TODO(rsc):
-// Emit correct line number annotations.
-// Make 6g understand the annotations.
-package main
-
-import (
- "bufio";
- "container/vector";
- "debug/dwarf";
- "debug/elf";
- "flag";
- "fmt";
- "go/ast";
- "go/doc";
- "go/parser";
- "go/scanner";
- "go/token";
- "io";
- "os";
-)
-
-// Map of uses of C.xxx. The key is the pointer
-// to the use (a pointer so it can be rewritten)
-// and the value is the context ("call", "expr", "type").
-type cmap map[*ast.Expr] string
-
-var noPos token.Position
-
-func usage() {
- fmt.Fprint(os.Stderr, "usage: cgo [options] file.cgo\n");
- flag.PrintDefaults();
-}
-
-func main() {
- flag.Usage = usage;
- flag.Parse();
-
- args := flag.Args();
- if len(args) != 1 {
- flag.Usage();
- }
- filename := args[0];
-
- prog, err := parser.ParsePkgFile("", filename, parser.ParseComments);
- if err != nil {
- fatal(err);
- }
-
- // Find the import "C" line and get any extra C preamble.
- preamble := "";
- found := false;
- for _, d := range prog.Decls {
- d, ok := d.(*ast.GenDecl);
- if !ok {
- continue;
- }
- for _, s := range d.Specs {
- s, ok := s.(*ast.ImportSpec);
- if !ok {
- continue;
- }
- if len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
- continue;
- }
- found = true;
- if s.Name != nil {
- error(s.Path[0].Pos(), `cannot rename import "C"`);
- }
- if s.Doc != nil {
- preamble += doc.CommentText(s.Doc) + "\n";
- }
- else if len(d.Specs) == 1 && d.Doc != nil {
- preamble += doc.CommentText(d.Doc) + "\n";
- }
- }
- }
- if !found {
- error(noPos, `cannot find import "C"`);
- }
-
- // Accumulate pointers to uses of C.x.
- m := make(cmap);
- walk(prog, m, "prog");
-
- fmt.Print(preamble);
- for p, context := range m {
- sel := (*p).(*ast.SelectorExpr);
- fmt.Printf("%s: %s as %s\n", sel.Pos(), sel.Sel.Value, context);
- }
-}
-
-func walk(x interface{}, m cmap, context string) {
- switch n := x.(type) {
- case *ast.Expr:
- if sel, ok := (*n).(*ast.SelectorExpr); ok {
- // For now, assume that the only instance of capital C is
- // when used as the imported package identifier.
- // The parser should take care of scoping in the future,
- // so that we will be able to distinguish a "top-level C"
- // from a local C.
- if l, ok := sel.X.(*ast.Ident); ok && l.Value == "C" {
- m[n] = context;
- break;
- }
- }
- walk(*n, m, context);
-
- // everything else just recurs
- default:
- error(noPos, "unexpected type %T in walk", x);
- panic();
-
- case nil:
-
- // These are ordered and grouped to match ../../pkg/go/ast/ast.go
- case *ast.Field:
- walk(&n.Type, m, "type");
- case *ast.BadExpr:
- case *ast.Ident:
- case *ast.Ellipsis:
- case *ast.BasicLit:
- case *ast.StringList:
- case *ast.FuncLit:
- walk(n.Type, m, "type");
- walk(n.Body, m, "stmt");
- case *ast.CompositeLit:
- walk(&n.Type, m, "type");
- walk(n.Elts, m, "expr");
- case *ast.ParenExpr:
- walk(&n.X, m, context);
- case *ast.SelectorExpr:
- walk(&n.X, m, "selector");
- case *ast.IndexExpr:
- walk(&n.X, m, "expr");
- walk(&n.Index, m, "expr");
- if n.End != nil {
- walk(&n.End, m, "expr");
- }
- case *ast.TypeAssertExpr:
- walk(&n.X, m, "expr");
- walk(&n.Type, m, "type");
- case *ast.CallExpr:
- walk(&n.Fun, m, "call");
- walk(n.Args, m, "expr");
- case *ast.StarExpr:
- walk(&n.X, m, context);
- case *ast.UnaryExpr:
- walk(&n.X, m, "expr");
- case *ast.BinaryExpr:
- walk(&n.X, m, "expr");
- walk(&n.Y, m, "expr");
- case *ast.KeyValueExpr:
- walk(&n.Key, m, "expr");
- walk(&n.Value, m, "expr");
-
- case *ast.ArrayType:
- walk(&n.Len, m, "expr");
- walk(&n.Elt, m, "type");
- case *ast.StructType:
- walk(n.Fields, m, "field");
- case *ast.FuncType:
- walk(n.Params, m, "field");
- walk(n.Results, m, "field");
- case *ast.InterfaceType:
- walk(n.Methods, m, "field");
- case *ast.MapType:
- walk(&n.Key, m, "type");
- walk(&n.Value, m, "type");
- case *ast.ChanType:
- walk(&n.Value, m, "type");
-
- case *ast.BadStmt:
- case *ast.DeclStmt:
- walk(n.Decl, m, "decl");
- case *ast.EmptyStmt:
- case *ast.LabeledStmt:
- walk(n.Stmt, m, "stmt");
- case *ast.ExprStmt:
- walk(&n.X, m, "expr");
- case *ast.IncDecStmt:
- walk(&n.X, m, "expr");
- case *ast.AssignStmt:
- walk(n.Lhs, m, "expr");
- walk(n.Rhs, m, "expr");
- case *ast.GoStmt:
- walk(&n.Call, m, "expr");
- case *ast.DeferStmt:
- walk(&n.Call, m, "expr");
- case *ast.ReturnStmt:
- walk(n.Results, m, "expr");
- case *ast.BranchStmt:
- case *ast.BlockStmt:
- walk(n.List, m, "stmt");
- case *ast.IfStmt:
- walk(n.Init, m, "stmt");
- walk(&n.Cond, m, "expr");
- walk(n.Body, m, "stmt");
- walk(n.Else, m, "stmt");
- case *ast.CaseClause:
- walk(n.Values, m, "expr");
- walk(n.Body, m, "stmt");
- case *ast.SwitchStmt:
- walk(n.Init, m, "stmt");
- walk(&n.Tag, m, "expr");
- walk(n.Body, m, "stmt");
- case *ast.TypeCaseClause:
- walk(n.Types, m, "type");
- walk(n.Body, m, "stmt");
- case *ast.TypeSwitchStmt:
- walk(n.Init, m, "stmt");
- walk(n.Assign, m, "stmt");
- walk(n.Body, m, "stmt");
- case *ast.CommClause:
- walk(n.Lhs, m, "expr");
- walk(n.Rhs, m, "expr");
- walk(n.Body, m, "stmt");
- case *ast.SelectStmt:
- walk(n.Body, m, "stmt");
- case *ast.ForStmt:
- walk(n.Init, m, "stmt");
- walk(&n.Cond, m, "expr");
- walk(n.Post, m, "stmt");
- walk(n.Body, m, "stmt");
- case *ast.RangeStmt:
- walk(&n.Key, m, "expr");
- walk(&n.Value, m, "expr");
- walk(&n.X, m, "expr");
- walk(n.Body, m, "stmt");
-
- case *ast.ImportSpec:
- case *ast.ValueSpec:
- walk(&n.Type, m, "type");
- walk(n.Values, m, "expr");
- case *ast.TypeSpec:
- walk(&n.Type, m, "type");
-
- case *ast.BadDecl:
- case *ast.GenDecl:
- walk(n.Specs, m, "spec");
- case *ast.FuncDecl:
- if n.Recv != nil {
- walk(n.Recv, m, "field");
- }
- walk(n.Type, m, "type");
- walk(n.Body, m, "stmt");
-
- case *ast.File:
- walk(n.Decls, m, "decl");
-
- case *ast.Package:
- for _, f := range n.Files {
- walk(f, m, "file");
- }
-
- case []ast.Decl:
- for _, d := range n {
- walk(d, m, context);
- }
- case []ast.Expr:
- for i := range n {
- walk(&n[i], m, context);
- }
- case []*ast.Field:
- for _, f := range n {
- walk(f, m, context);
- }
- case []ast.Stmt:
- for _, s := range n {
- walk(s, m, context);
- }
- case []ast.Spec:
- for _, s := range n {
- walk(s, m, context);
- }
- }
-}
-
-func fatal(err os.Error) {
- // If err is a scanner.ErrorList, its String will print just
- // the first error and then (+n more errors).
- // Instead, turn it into a new Error that will return
- // details for all the errors.
- if list, ok := err.(scanner.ErrorList); ok {
- for _, e := range list {
- fmt.Fprintln(os.Stderr, e);
- }
- } else {
- fmt.Fprintln(os.Stderr, err);
- }
- os.Exit(2);
-}
-
-var nerrors int
-
-func error(pos token.Position, msg string, args ...) {
- nerrors++;
- if pos.IsValid() {
- fmt.Fprintf(os.Stderr, "%s: ", pos);
- }
- fmt.Fprintf(os.Stderr, msg, args);
- fmt.Fprintf(os.Stderr, "\n");
-}
--- /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.
+
+// Annotate Crefs in Prog with C types by parsing gcc debug output.
+
+package main
+
+import (
+ "debug/dwarf";
+ "debug/elf";
+ "debug/macho";
+ "fmt";
+ "os";
+ "strconv";
+ "strings";
+)
+
+func (p *Prog) loadDebugInfo() {
+ // Construct a slice of unique names from p.Crefs.
+ m := make(map[string]int);
+ for _, c := range p.Crefs {
+ m[c.Name] = -1;
+ }
+ names := make([]string, 0, len(m));
+ for name, _ := range m {
+ i := len(names);
+ names = names[0:i+1];
+ names[i] = name;
+ m[name] = i;
+ }
+
+ // Coerce gcc into telling us whether each name is
+ // a type, a value, or undeclared. We compile a function
+ // containing the line:
+ // name;
+ // If name is a type, gcc will print:
+ // x.c:2: warning: useless type name in empty declaration
+ // If name is a value, gcc will print
+ // x.c:2: warning: statement with no effect
+ // If name is undeclared, gcc will print
+ // x.c:2: error: 'name' undeclared (first use in this function)
+ // A line number directive causes the line number to
+ // correspond to the index in the names array.
+ var b strings.Buffer;
+ b.WriteString(p.Preamble);
+ b.WriteString("void f(void) {\n");
+ b.WriteString("#line 0 \"cgo-test\"\n");
+ for _, n := range names {
+ b.WriteString(n);
+ b.WriteString(";\n");
+ }
+ b.WriteString("}\n");
+
+ kind := make(map[string]string);
+ _, stderr := gccDebug(b.Bytes());
+ if stderr == "" {
+ fatal("gcc produced no output");
+ }
+ for _, line := range strings.Split(stderr, "\n", 0) {
+ if len(line) < 9 || line[0:9] != "cgo-test:" {
+ continue;
+ }
+ line = line[9:len(line)];
+ colon := strings.Index(line, ":");
+ if colon < 0 {
+ continue;
+ }
+ i, err := strconv.Atoi(line[0:colon]);
+ if err != nil {
+ continue;
+ }
+ what := "";
+ switch {
+ default:
+ continue;
+ case strings.Index(line, "warning: useless type name in empty declaration") >= 0:
+ what = "type";
+ case strings.Index(line, "warning: statement with no effect") >= 0:
+ what = "value";
+ case strings.Index(line, "undeclared") >= 0:
+ what = "error";
+ }
+ if old, ok := kind[names[i]]; ok && old != what {
+ error(noPos, "inconsistent gcc output about C.%s", names[i]);
+ }
+ kind[names[i]] = what;
+ }
+ for _, n := range names {
+ if _, ok := kind[n]; !ok {
+ error(noPos, "could not determine kind of name for C.%s", n);
+ }
+ }
+
+ // Extract the types from the DWARF section of an object
+ // from a well-formed C program. Gcc only generates DWARF info
+ // for symbols in the object file, so it is not enough to print the
+ // preamble and hope the symbols we care about will be there.
+ // Instead, emit
+ // typeof(names[i]) *__cgo__i;
+ // for each entry in names and then dereference the type we
+ // learn for __cgo__i.
+ b.Reset();
+ b.WriteString(p.Preamble);
+ for i, n := range names {
+ fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n, i);
+ }
+ d, stderr := gccDebug(b.Bytes());
+ if d == nil {
+ fatal("gcc failed:\n%s\non input:\n%s", stderr, b.Bytes());
+ }
+
+ // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
+ types := make([]dwarf.Type, len(names));
+ r := d.Reader();
+ for {
+ e, err := r.Next();
+ if err != nil {
+ fatal("reading DWARF entry: %s", err);
+ }
+ if e == nil {
+ break;
+ }
+ if e.Tag != dwarf.TagVariable {
+ goto Continue;
+ }
+ name, _ := e.Val(dwarf.AttrName).(string);
+ typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset);
+ if name == "" || typOff == 0 {
+ fatal("malformed DWARF TagVariable entry");
+ }
+ if !strings.HasPrefix(name, "__cgo__") {
+ goto Continue;
+ }
+ typ, err := d.Type(typOff);
+ if err != nil {
+ fatal("loading DWARF type: %s", err);
+ }
+ t, ok := typ.(*dwarf.PtrType);
+ if !ok || t == nil {
+ fatal("internal error: %s has non-pointer type", name);
+ }
+ i, err := strconv.Atoi(name[7:len(name)]);
+ if err != nil {
+ fatal("malformed __cgo__ name: %s", name);
+ }
+ types[i] = t.Type;
+
+ Continue:
+ if e.Tag != dwarf.TagCompileUnit {
+ r.SkipChildren();
+ }
+ }
+
+ // Apply types to Crefs.
+ for _, c := range p.Crefs {
+ i := m[c.Name];
+ c.TypeName = kind[c.Name] == "type";
+ c.DebugType = types[i];
+ }
+}
+
+// gccDebug runs gcc -gdwarf-2 over the C program stdin and
+// returns the corresponding DWARF data and any messages
+// printed to standard error.
+func gccDebug(stdin []byte) (*dwarf.Data, string) {
+ machine := "-m32";
+ if os.Getenv("GOARCH") == "amd64" {
+ machine = "-m64";
+ }
+
+ tmp := "_cgo_.o";
+ _, stderr, ok := run(stdin, []string{
+ "gcc",
+ machine,
+ "-Wall", // many warnings
+ "-Werror", // warnings are errors
+ "-o"+tmp, // write object to tmp
+ "-gdwarf-2", // generate DWARF v2 debugging symbols
+ "-c", // do not link
+ "-xc", // input language is C
+ "-", // read input from standard input
+ });
+ if !ok {
+ return nil, string(stderr);
+ }
+
+ // Try to parse f as ELF and Mach-O and hope one works.
+ var f interface{DWARF() (*dwarf.Data, os.Error)};
+ var err os.Error;
+ if f, err = elf.Open(tmp); err != nil {
+ if f, err = macho.Open(tmp); err != nil {
+ fatal("cannot parse gcc output %s as ELF or Mach-O object", tmp);
+ }
+ }
+
+ d, err := f.DWARF();
+ if err != nil {
+ fatal("cannot load DWARF debug information from %s: %s", tmp, err);
+ }
+ return d, "";
+}
+
y.doinit();
z.doinit();
if m == nil {
- C.mpz_pow(&z.i, &x.i, &y.i);
+ C.mpz_pow_ui(&z.i, &x.i, mpz_get_ui(&y.i));
} else {
C.mpz_powm(&z.i, &x.i, &y.i, &m.i);
}
--- /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.
+
+package main
+
+import (
+ "flag";
+ "fmt";
+ "os";
+ "tabwriter";
+)
+
+// Cgo; see gmp.go for an overview.
+
+// TODO(rsc):
+// Emit correct line number annotations.
+// Make 6g understand the annotations.
+
+func usage() {
+ fmt.Fprint(os.Stderr, "usage: cgo file.cgo\n");
+ flag.PrintDefaults();
+}
+
+func main() {
+ flag.Usage = usage;
+ flag.Parse();
+
+ args := flag.Args();
+ if len(args) != 1 {
+ usage();
+ os.Exit(2);
+ }
+ p := openProg(args[0]);
+ p.loadDebugInfo();
+
+ tw := tabwriter.NewWriter(os.Stdout, 1, 1, ' ', 0);
+ for _, cref := range p.Crefs {
+ what := "value";
+ if cref.TypeName {
+ what = "type";
+ }
+ fmt.Fprintf(tw, "%s:\t%s %s\tC %s\t%s\n", (*cref.Expr).Pos(), cref.Context, cref.Name, what, cref.DebugType);
+ }
+ tw.Flush();
+}
--- /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.
+
+package main
+
+import (
+ "bytes";
+ "exec";
+ "fmt";
+ "go/token";
+ "io";
+ "os";
+)
+
+// A ByteReaderAt implements io.ReadAt using a slice of bytes.
+type ByteReaderAt []byte
+
+func (r ByteReaderAt) ReadAt(p []byte, off int64) (n int, err os.Error) {
+ if off >= int64(len(r)) || off < 0 {
+ return 0, os.EOF;
+ }
+ return bytes.Copy(p, r[off:len(r)]), nil;
+}
+
+// run runs the command argv, feeding in stdin on standard input.
+// It returns the output to standard output and standard error.
+// ok indicates whether the command exited successfully.
+func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
+ cmd, err := exec.LookPath(argv[0]);
+ if err != nil {
+ fatal("exec %s: %s", argv[0], err);
+ }
+ r0, w0, err := os.Pipe();
+ if err != nil {
+ fatal("%s", err);
+ }
+ r1, w1, err := os.Pipe();
+ if err != nil {
+ fatal("%s", err);
+ }
+ r2, w2, err := os.Pipe();
+ if err != nil {
+ fatal("%s", err);
+ }
+ pid, err := os.ForkExec(cmd, argv, os.Environ(), "", []*os.File{r0, w1, w2});
+ if err != nil {
+ fatal("%s", err);
+ }
+ r0.Close();
+ w1.Close();
+ w2.Close();
+ c := make(chan bool);
+ go func() {
+ w0.Write(stdin);
+ w0.Close();
+ c <- true;
+ }();
+ var xstdout []byte; // TODO(rsc): delete after 6g can take address of out parameter
+ go func() {
+ xstdout, _ = io.ReadAll(r1);
+ r1.Close();
+ c <- true;
+ }();
+ stderr, _ = io.ReadAll(r2);
+ r2.Close();
+ <-c;
+ <-c;
+ stdout = xstdout;
+
+ w, err := os.Wait(pid, 0);
+ if err != nil {
+ fatal("%s", err);
+ }
+ ok = w.Exited() && w.ExitStatus() == 0;
+ return;
+}
+
+// Die with an error message.
+func fatal(msg string, args ...) {
+ fmt.Fprintf(os.Stderr, msg+"\n", args);
+ os.Exit(2);
+}
+
+var nerrors int
+var noPos token.Position
+
+func error(pos token.Position, msg string, args ...) {
+ nerrors++;
+ if pos.IsValid() {
+ fmt.Fprintf(os.Stderr, "%s: ", pos);
+ }
+ fmt.Fprintf(os.Stderr, msg, args);
+ fmt.Fprintf(os.Stderr, "\n");
+}
+