Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1466)

Side by Side Diff: src/cmd/cgo/gcc.go

Issue 4607045: code review 4607045: cgo: handle new Apple LLVM-based gcc from Xcode 4.2 (Closed)
Patch Set: diff -r 83bf1e008e3e https://go.googlecode.com/hg Created 12 years, 9 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/pkg/debug/dwarf/type.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | src/pkg/debug/dwarf/type.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b