OLD | NEW |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Annotate Ref in Prog with C types by parsing gcc debug output. | 5 // Annotate Ref in Prog with C types by parsing gcc debug output. |
6 // Conversion of debug output to Go types. | 6 // Conversion of debug output to Go types. |
7 | 7 |
8 package main | 8 package main |
9 | 9 |
10 import ( | 10 import ( |
11 "bytes" | 11 "bytes" |
12 "debug/dwarf" | 12 "debug/dwarf" |
13 "debug/elf" | 13 "debug/elf" |
14 "debug/macho" | 14 "debug/macho" |
15 "debug/pe" | 15 "debug/pe" |
| 16 "encoding/binary" |
16 "flag" | 17 "flag" |
17 "fmt" | 18 "fmt" |
18 "go/ast" | 19 "go/ast" |
19 "go/parser" | 20 "go/parser" |
20 "go/token" | 21 "go/token" |
21 "os" | 22 "os" |
22 "runtime" | 23 "runtime" |
23 "strconv" | 24 "strconv" |
24 "strings" | 25 "strings" |
25 "unicode" | 26 "unicode" |
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
470 // learn for __cgo__i. | 471 // learn for __cgo__i. |
471 var b bytes.Buffer | 472 var b bytes.Buffer |
472 b.WriteString(builtinProlog) | 473 b.WriteString(builtinProlog) |
473 b.WriteString(f.Preamble) | 474 b.WriteString(f.Preamble) |
474 for i, n := range names { | 475 for i, n := range names { |
475 fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n.C, i) | 476 fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n.C, i) |
476 if n.Kind == "const" { | 477 if n.Kind == "const" { |
477 fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.
C) | 478 fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.
C) |
478 } | 479 } |
479 } | 480 } |
480 » d := p.gccDebug(b.Bytes()) | 481 |
| 482 » // Apple's LLVM-based gcc does not include the enumeration |
| 483 » // names and values in its DWARF debug output. In case we're |
| 484 » // using such a gcc, create a data block initialized with the values. |
| 485 » // We can read them out of the object file. |
| 486 » fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n") |
| 487 » for _, n := range names { |
| 488 » » if n.Kind == "const" { |
| 489 » » » fmt.Fprintf(&b, "\t%s,\n", n.C) |
| 490 » » } else { |
| 491 » » » fmt.Fprintf(&b, "\t0,\n") |
| 492 » » } |
| 493 » } |
| 494 » fmt.Fprintf(&b, "\t0\n") |
| 495 » fmt.Fprintf(&b, "};\n") |
| 496 |
| 497 » d, bo, debugData := p.gccDebug(b.Bytes()) |
| 498 » enumVal := make([]int64, len(debugData)/8) |
| 499 » for i := range enumVal { |
| 500 » » enumVal[i] = int64(bo.Uint64(debugData[i*8:])) |
| 501 » } |
481 | 502 |
482 // Scan DWARF info for top-level TagVariable entries with AttrName __cgo
__i. | 503 // Scan DWARF info for top-level TagVariable entries with AttrName __cgo
__i. |
483 types := make([]dwarf.Type, len(names)) | 504 types := make([]dwarf.Type, len(names)) |
484 enums := make([]dwarf.Offset, len(names)) | 505 enums := make([]dwarf.Offset, len(names)) |
485 nameToIndex := make(map[*Name]int) | 506 nameToIndex := make(map[*Name]int) |
486 for i, n := range names { | 507 for i, n := range names { |
487 nameToIndex[n] = i | 508 nameToIndex[n] = i |
488 } | 509 } |
489 r := d.Reader() | 510 r := d.Reader() |
490 for { | 511 for { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
562 n.FuncType = conv.FuncType(f) | 583 n.FuncType = conv.FuncType(f) |
563 } else { | 584 } else { |
564 n.Type = conv.Type(types[i]) | 585 n.Type = conv.Type(types[i]) |
565 if enums[i] != 0 && n.Type.EnumValues != nil { | 586 if enums[i] != 0 && n.Type.EnumValues != nil { |
566 k := fmt.Sprintf("__cgo_enum__%d", i) | 587 k := fmt.Sprintf("__cgo_enum__%d", i) |
567 n.Kind = "const" | 588 n.Kind = "const" |
568 n.Const = strconv.Itoa64(n.Type.EnumValues[k]) | 589 n.Const = strconv.Itoa64(n.Type.EnumValues[k]) |
569 // Remove injected enum to ensure the value will
deep-compare | 590 // Remove injected enum to ensure the value will
deep-compare |
570 // equally in future loads of the same constant. | 591 // equally in future loads of the same constant. |
571 n.Type.EnumValues[k] = 0, false | 592 n.Type.EnumValues[k] = 0, false |
| 593 } else if n.Kind == "const" && i < len(enumVal) { |
| 594 n.Const = strconv.Itoa64(enumVal[i]) |
572 } | 595 } |
573 } | 596 } |
574 } | 597 } |
| 598 |
575 } | 599 } |
576 | 600 |
577 // rewriteRef rewrites all the C.xxx references in f.AST to refer to the | 601 // rewriteRef rewrites all the C.xxx references in f.AST to refer to the |
578 // Go equivalents, now that we have figured out the meaning of all | 602 // Go equivalents, now that we have figured out the meaning of all |
579 // the xxx. | 603 // the xxx. |
580 func (p *Package) rewriteRef(f *File) { | 604 func (p *Package) rewriteRef(f *File) { |
581 // Assign mangled names. | 605 // Assign mangled names. |
582 for _, n := range f.Name { | 606 for _, n := range f.Name { |
583 if n.Kind == "not-type" { | 607 if n.Kind == "not-type" { |
584 n.Kind = "var" | 608 n.Kind = "var" |
585 } | 609 } |
586 if n.Mangle == "" { | 610 if n.Mangle == "" { |
587 n.Mangle = "_C" + n.Kind + "_" + n.Go | 611 n.Mangle = "_C" + n.Kind + "_" + n.Go |
588 } | 612 } |
589 } | 613 } |
590 | 614 |
591 // Now that we have all the name types filled in, | 615 // Now that we have all the name types filled in, |
592 // scan through the Refs to identify the ones that | 616 // scan through the Refs to identify the ones that |
593 // are trying to do a ,err call. Also check that | 617 // are trying to do a ,err call. Also check that |
594 // functions are only used in calls. | 618 // functions are only used in calls. |
595 for _, r := range f.Ref { | 619 for _, r := range f.Ref { |
| 620 if r.Name.Kind == "const" && r.Name.Const == "" { |
| 621 error(r.Pos(), "unable to find value of constant C.%s",
r.Name.Go) |
| 622 } |
596 var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default | 623 var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default |
597 switch r.Context { | 624 switch r.Context { |
598 case "call", "call2": | 625 case "call", "call2": |
599 if r.Name.Kind != "func" { | 626 if r.Name.Kind != "func" { |
600 if r.Name.Kind == "type" { | 627 if r.Name.Kind == "type" { |
601 r.Context = "type" | 628 r.Context = "type" |
602 expr = r.Name.Type.Go | 629 expr = r.Name.Type.Go |
603 break | 630 break |
604 } | 631 } |
605 error(r.Pos(), "call of non-function C.%s", r.Na
me.Go) | 632 error(r.Pos(), "call of non-function C.%s", r.Na
me.Go) |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 "-c", // do not link | 712 "-c", // do not link |
686 "-xc", // input language is C | 713 "-xc", // input language is C |
687 } | 714 } |
688 c = append(c, p.GccOptions...) | 715 c = append(c, p.GccOptions...) |
689 c = append(c, p.gccMachine()...) | 716 c = append(c, p.gccMachine()...) |
690 c = append(c, "-") //read input from standard input | 717 c = append(c, "-") //read input from standard input |
691 return c | 718 return c |
692 } | 719 } |
693 | 720 |
694 // gccDebug runs gcc -gdwarf-2 over the C program stdin and | 721 // gccDebug runs gcc -gdwarf-2 over the C program stdin and |
695 // returns the corresponding DWARF data and any messages | 722 // returns the corresponding DWARF data and, if present, debug data block. |
696 // printed to standard error. | 723 func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
{ |
697 func (p *Package) gccDebug(stdin []byte) *dwarf.Data { | |
698 runGcc(stdin, p.gccCmd()) | 724 runGcc(stdin, p.gccCmd()) |
699 | 725 |
700 » // Try to parse f as ELF and Mach-O and hope one works. | 726 » if f, err := macho.Open(gccTmp); err == nil { |
701 » var f interface { | 727 » » d, err := f.DWARF() |
702 » » DWARF() (*dwarf.Data, os.Error) | 728 » » if err != nil { |
703 » } | 729 » » » fatalf("cannot load DWARF output from %s: %v", gccTmp, e
rr) |
704 » var err os.Error | 730 » » } |
705 » if f, err = elf.Open(gccTmp); err != nil { | 731 » » var data []byte |
706 » » if f, err = macho.Open(gccTmp); err != nil { | 732 » » if f.Symtab != nil { |
707 » » » if f, err = pe.Open(gccTmp); err != nil { | 733 » » » for i := range f.Symtab.Syms { |
708 » » » » fatalf("cannot parse gcc output %s as ELF or Mac
h-O or PE object", gccTmp) | 734 » » » » s := &f.Symtab.Syms[i] |
| 735 » » » » // Mach-O still uses a leading _ to denote non-a
ssembly symbols. |
| 736 » » » » if s.Name == "_"+"__cgodebug_data" { |
| 737 » » » » » // Found it. Now find data section. |
| 738 » » » » » if i := int(s.Sect) - 1; 0 <= i && i < l
en(f.Sections) { |
| 739 » » » » » » sect := f.Sections[i] |
| 740 » » » » » » if sect.Addr <= s.Value && s.Val
ue < sect.Addr+sect.Size { |
| 741 » » » » » » » if sdat, err := sect.Dat
a(); err == nil { |
| 742 » » » » » » » » data = sdat[s.Va
lue-sect.Addr:] |
| 743 » » » » » » » } |
| 744 » » » » » » } |
| 745 » » » » » } |
| 746 » » » » } |
709 } | 747 } |
710 } | 748 } |
| 749 return d, f.ByteOrder, data |
711 } | 750 } |
712 | 751 |
713 » d, err := f.DWARF() | 752 » // Can skip debug data block in ELF and PE for now. |
714 » if err != nil { | 753 » // The DWARF information is complete. |
715 » » fatalf("cannot load DWARF debug information from %s: %s", gccTmp
, err) | 754 |
| 755 » if f, err := elf.Open(gccTmp); err == nil { |
| 756 » » d, err := f.DWARF() |
| 757 » » if err != nil { |
| 758 » » » fatalf("cannot load DWARF output from %s: %v", gccTmp, e
rr) |
| 759 » » } |
| 760 » » return d, f.ByteOrder, nil |
716 } | 761 } |
717 » return d | 762 |
| 763 » if f, err := pe.Open(gccTmp); err == nil { |
| 764 » » d, err := f.DWARF() |
| 765 » » if err != nil { |
| 766 » » » fatalf("cannot load DWARF output from %s: %v", gccTmp, e
rr) |
| 767 » » } |
| 768 » » return d, binary.LittleEndian, nil |
| 769 » } |
| 770 |
| 771 » fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp) |
| 772 » panic("not reached") |
718 } | 773 } |
719 | 774 |
720 // gccDefines runs gcc -E -dM -xc - over the C program stdin | 775 // gccDefines runs gcc -E -dM -xc - over the C program stdin |
721 // and returns the corresponding standard output, which is the | 776 // and returns the corresponding standard output, which is the |
722 // #defines that gcc encountered while processing the input | 777 // #defines that gcc encountered while processing the input |
723 // and its included files. | 778 // and its included files. |
724 func (p *Package) gccDefines(stdin []byte) string { | 779 func (p *Package) gccDefines(stdin []byte) string { |
725 base := []string{p.gccName(), "-E", "-dM", "-xc"} | 780 base := []string{p.gccName(), "-E", "-dM", "-xc"} |
726 base = append(base, p.gccMachine()...) | 781 base = append(base, p.gccMachine()...) |
727 stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-")) | 782 stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-")) |
(...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1303 off = dt.ByteSize | 1358 off = dt.ByteSize |
1304 } | 1359 } |
1305 if off != dt.ByteSize { | 1360 if off != dt.ByteSize { |
1306 fatalf("struct size calculation error") | 1361 fatalf("struct size calculation error") |
1307 } | 1362 } |
1308 buf.WriteString("}") | 1363 buf.WriteString("}") |
1309 csyntax = buf.String() | 1364 csyntax = buf.String() |
1310 expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} | 1365 expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} |
1311 return | 1366 return |
1312 } | 1367 } |
OLD | NEW |