2016-03-01 22:57:46 +00:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// Annotate Ref in Prog with C types by parsing gcc debug output.
|
2009-09-24 11:43:19 -07:00
|
|
|
// Conversion of debug output to Go types.
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2009-12-15 15:33:31 -08:00
|
|
|
"bytes"
|
|
|
|
|
"debug/dwarf"
|
|
|
|
|
"debug/elf"
|
|
|
|
|
"debug/macho"
|
2010-11-01 17:52:26 -04:00
|
|
|
"debug/pe"
|
2011-06-13 14:43:54 -04:00
|
|
|
"encoding/binary"
|
2011-11-01 22:06:05 -04:00
|
|
|
"errors"
|
2010-07-14 17:17:53 -07:00
|
|
|
"flag"
|
2009-12-15 15:33:31 -08:00
|
|
|
"fmt"
|
|
|
|
|
"go/ast"
|
2010-01-11 13:05:26 -08:00
|
|
|
"go/parser"
|
2009-12-15 15:33:31 -08:00
|
|
|
"go/token"
|
2017-01-20 08:34:18 +09:00
|
|
|
"math"
|
2009-12-15 15:33:31 -08:00
|
|
|
"os"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
2011-02-01 08:44:18 -05:00
|
|
|
"unicode"
|
2011-11-10 19:08:04 -05:00
|
|
|
"unicode/utf8"
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
)
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
|
|
|
|
|
var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations")
|
|
|
|
|
|
|
|
|
|
var nameToC = map[string]string{
|
2011-01-19 14:30:57 -05:00
|
|
|
"schar": "signed char",
|
|
|
|
|
"uchar": "unsigned char",
|
|
|
|
|
"ushort": "unsigned short",
|
|
|
|
|
"uint": "unsigned int",
|
|
|
|
|
"ulong": "unsigned long",
|
|
|
|
|
"longlong": "long long",
|
|
|
|
|
"ulonglong": "unsigned long long",
|
2015-12-14 13:05:25 -08:00
|
|
|
"complexfloat": "float _Complex",
|
|
|
|
|
"complexdouble": "double _Complex",
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cname returns the C name to use for C.s.
|
|
|
|
|
// The expansions are listed in nameToC and also
|
|
|
|
|
// struct_foo becomes "struct foo", and similarly for
|
|
|
|
|
// union and enum.
|
|
|
|
|
func cname(s string) string {
|
|
|
|
|
if t, ok := nameToC[s]; ok {
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strings.HasPrefix(s, "struct_") {
|
|
|
|
|
return "struct " + s[len("struct_"):]
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(s, "union_") {
|
|
|
|
|
return "union " + s[len("union_"):]
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(s, "enum_") {
|
|
|
|
|
return "enum " + s[len("enum_"):]
|
|
|
|
|
}
|
2011-11-10 19:08:04 -05:00
|
|
|
if strings.HasPrefix(s, "sizeof_") {
|
|
|
|
|
return "sizeof(" + cname(s[len("sizeof_"):]) + ")"
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-10 21:41:54 -07:00
|
|
|
// DiscardCgoDirectives processes the import C preamble, and discards
|
|
|
|
|
// all #cgo CFLAGS and LDFLAGS directives, so they don't make their
|
|
|
|
|
// way into _cgo_export.h.
|
|
|
|
|
func (f *File) DiscardCgoDirectives() {
|
2011-06-28 09:43:14 +10:00
|
|
|
linesIn := strings.Split(f.Preamble, "\n")
|
2011-02-01 08:44:18 -05:00
|
|
|
linesOut := make([]string, 0, len(linesIn))
|
|
|
|
|
for _, line := range linesIn {
|
|
|
|
|
l := strings.TrimSpace(line)
|
cgo, goyacc, go/build, html, http, path, path/filepath, testing/quick, test: use rune
Nothing terribly interesting here.
R=golang-dev, bradfitz, gri, r
CC=golang-dev
https://golang.org/cl/5300043
2011-10-25 22:20:02 -07:00
|
|
|
if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {
|
2011-02-01 08:44:18 -05:00
|
|
|
linesOut = append(linesOut, line)
|
2013-09-03 21:15:15 -07:00
|
|
|
} else {
|
|
|
|
|
linesOut = append(linesOut, "")
|
2011-02-01 08:44:18 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
f.Preamble = strings.Join(linesOut, "\n")
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-01 23:21:55 +00:00
|
|
|
// addToFlag appends args to flag. All flags are later written out onto the
|
2011-05-26 22:19:23 -03:00
|
|
|
// _cgo_flags file for the build system to use.
|
|
|
|
|
func (p *Package) addToFlag(flag string, args []string) {
|
2013-03-06 16:57:14 -05:00
|
|
|
p.CgoFlags[flag] = append(p.CgoFlags[flag], args...)
|
2011-05-26 22:19:23 -03:00
|
|
|
if flag == "CFLAGS" {
|
|
|
|
|
// We'll also need these when preprocessing for dwarf information.
|
|
|
|
|
p.GccOptions = append(p.GccOptions, args...)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-01 08:44:18 -05:00
|
|
|
// splitQuoted splits the string s around each instance of one or more consecutive
|
|
|
|
|
// white space characters while taking into account quotes and escaping, and
|
|
|
|
|
// returns an array of substrings of s or an empty list if s contains only white space.
|
|
|
|
|
// Single quotes and double quotes are recognized to prevent splitting within the
|
|
|
|
|
// quoted region, and are removed from the resulting substrings. If a quote in s
|
|
|
|
|
// isn't closed err will be set and r will have the unclosed argument as the
|
2016-03-01 23:21:55 +00:00
|
|
|
// last element. The backslash is used for escaping.
|
2011-02-01 08:44:18 -05:00
|
|
|
//
|
|
|
|
|
// For example, the following string:
|
|
|
|
|
//
|
|
|
|
|
// `a b:"c d" 'e''f' "g\""`
|
|
|
|
|
//
|
|
|
|
|
// Would be parsed as:
|
|
|
|
|
//
|
|
|
|
|
// []string{"a", "b:c d", "ef", `g"`}
|
|
|
|
|
//
|
2011-11-01 22:06:05 -04:00
|
|
|
func splitQuoted(s string) (r []string, err error) {
|
2011-02-01 08:44:18 -05:00
|
|
|
var args []string
|
cgo, goyacc, go/build, html, http, path, path/filepath, testing/quick, test: use rune
Nothing terribly interesting here.
R=golang-dev, bradfitz, gri, r
CC=golang-dev
https://golang.org/cl/5300043
2011-10-25 22:20:02 -07:00
|
|
|
arg := make([]rune, len(s))
|
2011-02-01 08:44:18 -05:00
|
|
|
escaped := false
|
|
|
|
|
quoted := false
|
2011-12-08 22:08:03 -05:00
|
|
|
quote := '\x00'
|
2011-02-01 08:44:18 -05:00
|
|
|
i := 0
|
cgo, goyacc, go/build, html, http, path, path/filepath, testing/quick, test: use rune
Nothing terribly interesting here.
R=golang-dev, bradfitz, gri, r
CC=golang-dev
https://golang.org/cl/5300043
2011-10-25 22:20:02 -07:00
|
|
|
for _, r := range s {
|
2011-02-01 08:44:18 -05:00
|
|
|
switch {
|
|
|
|
|
case escaped:
|
|
|
|
|
escaped = false
|
cgo, goyacc, go/build, html, http, path, path/filepath, testing/quick, test: use rune
Nothing terribly interesting here.
R=golang-dev, bradfitz, gri, r
CC=golang-dev
https://golang.org/cl/5300043
2011-10-25 22:20:02 -07:00
|
|
|
case r == '\\':
|
2011-02-01 08:44:18 -05:00
|
|
|
escaped = true
|
|
|
|
|
continue
|
|
|
|
|
case quote != 0:
|
cgo, goyacc, go/build, html, http, path, path/filepath, testing/quick, test: use rune
Nothing terribly interesting here.
R=golang-dev, bradfitz, gri, r
CC=golang-dev
https://golang.org/cl/5300043
2011-10-25 22:20:02 -07:00
|
|
|
if r == quote {
|
2011-02-01 08:44:18 -05:00
|
|
|
quote = 0
|
|
|
|
|
continue
|
|
|
|
|
}
|
cgo, goyacc, go/build, html, http, path, path/filepath, testing/quick, test: use rune
Nothing terribly interesting here.
R=golang-dev, bradfitz, gri, r
CC=golang-dev
https://golang.org/cl/5300043
2011-10-25 22:20:02 -07:00
|
|
|
case r == '"' || r == '\'':
|
2011-02-01 08:44:18 -05:00
|
|
|
quoted = true
|
cgo, goyacc, go/build, html, http, path, path/filepath, testing/quick, test: use rune
Nothing terribly interesting here.
R=golang-dev, bradfitz, gri, r
CC=golang-dev
https://golang.org/cl/5300043
2011-10-25 22:20:02 -07:00
|
|
|
quote = r
|
2011-02-01 08:44:18 -05:00
|
|
|
continue
|
cgo, goyacc, go/build, html, http, path, path/filepath, testing/quick, test: use rune
Nothing terribly interesting here.
R=golang-dev, bradfitz, gri, r
CC=golang-dev
https://golang.org/cl/5300043
2011-10-25 22:20:02 -07:00
|
|
|
case unicode.IsSpace(r):
|
2011-02-01 08:44:18 -05:00
|
|
|
if quoted || i > 0 {
|
|
|
|
|
quoted = false
|
|
|
|
|
args = append(args, string(arg[:i]))
|
|
|
|
|
i = 0
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
cgo, goyacc, go/build, html, http, path, path/filepath, testing/quick, test: use rune
Nothing terribly interesting here.
R=golang-dev, bradfitz, gri, r
CC=golang-dev
https://golang.org/cl/5300043
2011-10-25 22:20:02 -07:00
|
|
|
arg[i] = r
|
2011-02-01 08:44:18 -05:00
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
if quoted || i > 0 {
|
|
|
|
|
args = append(args, string(arg[:i]))
|
|
|
|
|
}
|
|
|
|
|
if quote != 0 {
|
2011-11-01 22:06:05 -04:00
|
|
|
err = errors.New("unclosed quote")
|
2011-02-01 08:44:18 -05:00
|
|
|
} else if escaped {
|
2011-11-01 22:06:05 -04:00
|
|
|
err = errors.New("unfinished escaping")
|
2011-02-01 08:44:18 -05:00
|
|
|
}
|
|
|
|
|
return args, err
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// Translate rewrites f.AST, the original Go input, to remove
|
|
|
|
|
// references to the imported package C, replacing them with
|
|
|
|
|
// references to the equivalent Go types, functions, and variables.
|
|
|
|
|
func (p *Package) Translate(f *File) {
|
|
|
|
|
for _, cref := range f.Ref {
|
|
|
|
|
// Convert C.ulong to C.unsigned long, etc.
|
|
|
|
|
cref.Name.C = cname(cref.Name.Go)
|
|
|
|
|
}
|
|
|
|
|
p.loadDefines(f)
|
|
|
|
|
needType := p.guessKinds(f)
|
|
|
|
|
if len(needType) > 0 {
|
|
|
|
|
p.loadDWARF(f, needType)
|
|
|
|
|
}
|
2016-10-12 17:09:54 -07:00
|
|
|
if p.rewriteCalls(f) {
|
|
|
|
|
// Add `import _cgo_unsafe "unsafe"` as the first decl
|
|
|
|
|
// after the package statement.
|
|
|
|
|
imp := &ast.GenDecl{
|
|
|
|
|
Tok: token.IMPORT,
|
|
|
|
|
Specs: []ast.Spec{
|
|
|
|
|
&ast.ImportSpec{
|
|
|
|
|
Name: ast.NewIdent("_cgo_unsafe"),
|
|
|
|
|
Path: &ast.BasicLit{
|
|
|
|
|
Kind: token.STRING,
|
|
|
|
|
Value: `"unsafe"`,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
f.AST.Decls = append([]ast.Decl{imp}, f.AST.Decls...)
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
p.rewriteRef(f)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// loadDefines coerces gcc into spitting out the #defines in use
|
|
|
|
|
// in the file f and saves relevant renamings in f.Name[name].Define.
|
|
|
|
|
func (p *Package) loadDefines(f *File) {
|
2010-01-11 13:05:26 -08:00
|
|
|
var b bytes.Buffer
|
2013-10-15 15:00:48 -04:00
|
|
|
b.WriteString(builtinProlog)
|
2017-10-13 18:26:10 -07:00
|
|
|
b.WriteString(f.Preamble)
|
2010-07-14 17:17:53 -07:00
|
|
|
stdout := p.gccDefines(b.Bytes())
|
2010-01-11 13:05:26 -08:00
|
|
|
|
2011-06-28 09:43:14 +10:00
|
|
|
for _, line := range strings.Split(stdout, "\n") {
|
2010-01-11 13:05:26 -08:00
|
|
|
if len(line) < 9 || line[0:7] != "#define" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
line = strings.TrimSpace(line[8:])
|
|
|
|
|
|
|
|
|
|
var key, val string
|
2017-10-05 15:49:32 +02:00
|
|
|
spaceIndex := strings.Index(line, " ")
|
2010-01-11 13:05:26 -08:00
|
|
|
tabIndex := strings.Index(line, "\t")
|
|
|
|
|
|
|
|
|
|
if spaceIndex == -1 && tabIndex == -1 {
|
|
|
|
|
continue
|
|
|
|
|
} else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) {
|
|
|
|
|
key = line[0:spaceIndex]
|
|
|
|
|
val = strings.TrimSpace(line[spaceIndex:])
|
|
|
|
|
} else {
|
|
|
|
|
key = line[0:tabIndex]
|
|
|
|
|
val = strings.TrimSpace(line[tabIndex:])
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-17 17:05:47 -07:00
|
|
|
if key == "__clang__" {
|
|
|
|
|
p.GccIsClang = true
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
if n := f.Name[key]; n != nil {
|
|
|
|
|
if *debugDefine {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
|
2010-01-11 13:05:26 -08:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
n.Define = val
|
2010-01-11 13:05:26 -08:00
|
|
|
}
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// guessKinds tricks gcc into revealing the kind of each
|
|
|
|
|
// name xxx for the references C.xxx in the Go input.
|
|
|
|
|
// The kind is either a constant, type, or variable.
|
|
|
|
|
func (p *Package) guessKinds(f *File) []*Name {
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
// Determine kinds for names we already know about,
|
|
|
|
|
// like #defines or 'struct foo', before bothering with gcc.
|
|
|
|
|
var names, needType []*Name
|
2014-08-11 16:49:13 -07:00
|
|
|
for _, key := range nameKeys(f.Name) {
|
|
|
|
|
n := f.Name[key]
|
2010-07-14 17:17:53 -07:00
|
|
|
// If we've already found this name as a #define
|
|
|
|
|
// and we can translate it as a constant value, do so.
|
|
|
|
|
if n.Define != "" {
|
2017-01-20 08:34:18 +09:00
|
|
|
if i, err := strconv.ParseInt(n.Define, 0, 64); err == nil {
|
|
|
|
|
n.Kind = "iconst"
|
2011-11-10 19:08:04 -05:00
|
|
|
// Turn decimal into hex, just for consistency
|
2016-03-01 23:21:55 +00:00
|
|
|
// with enum-derived constants. Otherwise
|
2011-11-10 19:08:04 -05:00
|
|
|
// in the cgo -godefs output half the constants
|
|
|
|
|
// are in hex and half are in whatever the #define used.
|
2017-01-20 08:34:18 +09:00
|
|
|
n.Const = fmt.Sprintf("%#x", i)
|
|
|
|
|
} else if n.Define[0] == '\'' {
|
|
|
|
|
if _, err := parser.ParseExpr(n.Define); err == nil {
|
|
|
|
|
n.Kind = "iconst"
|
|
|
|
|
n.Const = n.Define
|
|
|
|
|
}
|
|
|
|
|
} else if n.Define[0] == '"' {
|
|
|
|
|
if _, err := parser.ParseExpr(n.Define); err == nil {
|
|
|
|
|
n.Kind = "sconst"
|
2011-11-10 19:08:04 -05:00
|
|
|
n.Const = n.Define
|
|
|
|
|
}
|
2017-01-20 08:34:18 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.IsConst() {
|
2010-07-14 17:17:53 -07:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
// If this is a struct, union, or enum type name, no need to guess the kind.
|
2010-07-14 17:17:53 -07:00
|
|
|
if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
|
|
|
|
|
n.Kind = "type"
|
2017-02-02 21:53:52 +09:00
|
|
|
needType = append(needType, n)
|
2010-07-14 17:17:53 -07:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
// Otherwise, we'll need to find out from gcc.
|
|
|
|
|
names = append(names, n)
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
|
|
|
|
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
// Bypass gcc if there's nothing left to find out.
|
|
|
|
|
if len(names) == 0 {
|
2010-07-14 17:17:53 -07:00
|
|
|
return needType
|
|
|
|
|
}
|
|
|
|
|
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
// Coerce gcc into telling us whether each name is a type, a value, or undeclared.
|
|
|
|
|
// For names, find out whether they are integer constants.
|
|
|
|
|
// We used to look at specific warning or error messages here, but that tied the
|
|
|
|
|
// behavior too closely to specific versions of the compilers.
|
|
|
|
|
// Instead, arrange that we can infer what we need from only the presence or absence
|
|
|
|
|
// of an error on a specific line.
|
|
|
|
|
//
|
|
|
|
|
// For each name, we generate these lines, where xxx is the index in toSniff plus one.
|
|
|
|
|
//
|
|
|
|
|
// #line xxx "not-declared"
|
2017-08-29 07:39:57 +09:00
|
|
|
// void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__1; }
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
// #line xxx "not-type"
|
2017-08-29 07:39:57 +09:00
|
|
|
// void __cgo_f_xxx_2(void) { name *__cgo_undefined__2; }
|
2017-01-20 08:34:18 +09:00
|
|
|
// #line xxx "not-int-const"
|
2017-08-29 07:39:57 +09:00
|
|
|
// void __cgo_f_xxx_3(void) { enum { __cgo_undefined__3 = (name)*1 }; }
|
2017-01-20 08:34:18 +09:00
|
|
|
// #line xxx "not-num-const"
|
2017-08-29 07:39:57 +09:00
|
|
|
// void __cgo_f_xxx_4(void) { static const double __cgo_undefined__4 = (name); }
|
2017-01-20 08:34:18 +09:00
|
|
|
// #line xxx "not-str-lit"
|
2017-08-29 07:39:57 +09:00
|
|
|
// void __cgo_f_xxx_5(void) { static const char __cgo_undefined__5[] = (name); }
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
//
|
|
|
|
|
// If we see an error at not-declared:xxx, the corresponding name is not declared.
|
|
|
|
|
// If we see an error at not-type:xxx, the corresponding name is a type.
|
2017-01-20 08:34:18 +09:00
|
|
|
// If we see an error at not-int-const:xxx, the corresponding name is not an integer constant.
|
|
|
|
|
// If we see an error at not-num-const:xxx, the corresponding name is not a number constant.
|
|
|
|
|
// If we see an error at not-str-lit:xxx, the corresponding name is not a string literal.
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
//
|
|
|
|
|
// The specific input forms are chosen so that they are valid C syntax regardless of
|
|
|
|
|
// whether name denotes a type or an expression.
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
var b bytes.Buffer
|
2013-10-15 15:00:48 -04:00
|
|
|
b.WriteString(builtinProlog)
|
2017-10-13 18:26:10 -07:00
|
|
|
b.WriteString(f.Preamble)
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
|
|
|
|
|
for i, n := range names {
|
|
|
|
|
fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+
|
2017-08-29 07:39:57 +09:00
|
|
|
"void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__1; }\n"+
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
"#line %d \"not-type\"\n"+
|
2017-08-29 07:39:57 +09:00
|
|
|
"void __cgo_f_%d_2(void) { %s *__cgo_undefined__2; }\n"+
|
2017-01-20 08:34:18 +09:00
|
|
|
"#line %d \"not-int-const\"\n"+
|
2017-08-29 07:39:57 +09:00
|
|
|
"void __cgo_f_%d_3(void) { enum { __cgo_undefined__3 = (%s)*1 }; }\n"+
|
2017-01-20 08:34:18 +09:00
|
|
|
"#line %d \"not-num-const\"\n"+
|
2017-08-29 07:39:57 +09:00
|
|
|
"void __cgo_f_%d_4(void) { static const double __cgo_undefined__4 = (%s); }\n"+
|
2017-01-20 08:34:18 +09:00
|
|
|
"#line %d \"not-str-lit\"\n"+
|
2017-08-31 13:49:43 +09:00
|
|
|
"void __cgo_f_%d_5(void) { static const char __cgo_undefined__5[] = (%s); }\n",
|
2017-01-20 08:34:18 +09:00
|
|
|
i+1, i+1, n.C,
|
|
|
|
|
i+1, i+1, n.C,
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
i+1, i+1, n.C,
|
|
|
|
|
i+1, i+1, n.C,
|
2017-05-16 21:52:41 +09:00
|
|
|
i+1, i+1, n.C,
|
|
|
|
|
)
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
}
|
|
|
|
|
fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
|
|
|
|
|
"int __cgo__1 = __cgo__2;\n")
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
stderr := p.gccErrors(b.Bytes())
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
if stderr == "" {
|
2013-09-11 09:56:51 -04:00
|
|
|
fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
|
|
|
|
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
completed := false
|
|
|
|
|
sniff := make([]int, len(names))
|
|
|
|
|
const (
|
|
|
|
|
notType = 1 << iota
|
2017-01-20 08:34:18 +09:00
|
|
|
notIntConst
|
|
|
|
|
notNumConst
|
|
|
|
|
notStrLiteral
|
2014-08-14 09:21:58 -07:00
|
|
|
notDeclared
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
)
|
2017-05-25 15:12:54 -07:00
|
|
|
sawUnmatchedErrors := false
|
2011-06-28 09:43:14 +10:00
|
|
|
for _, line := range strings.Split(stderr, "\n") {
|
2017-05-25 15:12:54 -07:00
|
|
|
// Ignore warnings and random comments, with one
|
|
|
|
|
// exception: newer GCC versions will sometimes emit
|
|
|
|
|
// an error on a macro #define with a note referring
|
|
|
|
|
// to where the expansion occurs. We care about where
|
|
|
|
|
// the expansion occurs, so in that case treat the note
|
|
|
|
|
// as an error.
|
|
|
|
|
isError := strings.Contains(line, ": error:")
|
|
|
|
|
isErrorNote := strings.Contains(line, ": note:") && sawUnmatchedErrors
|
|
|
|
|
if !isError && !isErrorNote {
|
2009-11-09 12:07:39 -08:00
|
|
|
continue
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
|
2017-10-05 15:49:32 +02:00
|
|
|
c1 := strings.Index(line, ":")
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
if c1 < 0 {
|
2009-11-09 12:07:39 -08:00
|
|
|
continue
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
2017-10-05 15:49:32 +02:00
|
|
|
c2 := strings.Index(line[c1+1:], ":")
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
if c2 < 0 {
|
2010-07-14 17:17:53 -07:00
|
|
|
continue
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
c2 += c1 + 1
|
|
|
|
|
|
|
|
|
|
filename := line[:c1]
|
|
|
|
|
i, _ := strconv.Atoi(line[c1+1 : c2])
|
|
|
|
|
i--
|
|
|
|
|
if i < 0 || i >= len(names) {
|
2017-05-25 15:12:54 -07:00
|
|
|
if isError {
|
|
|
|
|
sawUnmatchedErrors = true
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
continue
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
switch filename {
|
|
|
|
|
case "completed":
|
|
|
|
|
// Strictly speaking, there is no guarantee that seeing the error at completed:1
|
|
|
|
|
// (at the end of the file) means we've seen all the errors from earlier in the file,
|
|
|
|
|
// but usually it does. Certainly if we don't see the completed:1 error, we did
|
|
|
|
|
// not get all the errors we expected.
|
|
|
|
|
completed = true
|
|
|
|
|
|
|
|
|
|
case "not-declared":
|
2014-08-14 09:21:58 -07:00
|
|
|
sniff[i] |= notDeclared
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
case "not-type":
|
|
|
|
|
sniff[i] |= notType
|
2017-01-20 08:34:18 +09:00
|
|
|
case "not-int-const":
|
|
|
|
|
sniff[i] |= notIntConst
|
|
|
|
|
case "not-num-const":
|
|
|
|
|
sniff[i] |= notNumConst
|
|
|
|
|
case "not-str-lit":
|
|
|
|
|
sniff[i] |= notStrLiteral
|
2017-05-25 15:12:54 -07:00
|
|
|
default:
|
|
|
|
|
if isError {
|
|
|
|
|
sawUnmatchedErrors = true
|
|
|
|
|
}
|
|
|
|
|
continue
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
2017-05-25 15:12:54 -07:00
|
|
|
|
|
|
|
|
sawUnmatchedErrors = false
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
|
|
|
|
|
if !completed {
|
2014-08-14 09:21:58 -07:00
|
|
|
fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr)
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i, n := range names {
|
2017-08-31 13:49:43 +09:00
|
|
|
switch sniff[i] {
|
2014-08-14 09:21:58 -07:00
|
|
|
default:
|
2017-06-05 09:06:30 +09:00
|
|
|
error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go))
|
2017-01-20 08:34:18 +09:00
|
|
|
case notStrLiteral | notType:
|
2017-08-31 13:49:43 +09:00
|
|
|
n.Kind = "iconst"
|
2017-01-20 08:34:18 +09:00
|
|
|
case notIntConst | notStrLiteral | notType:
|
|
|
|
|
n.Kind = "fconst"
|
|
|
|
|
case notIntConst | notNumConst | notType:
|
|
|
|
|
n.Kind = "sconst"
|
|
|
|
|
case notIntConst | notNumConst | notStrLiteral:
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
n.Kind = "type"
|
2017-01-20 08:34:18 +09:00
|
|
|
case notIntConst | notNumConst | notStrLiteral | notType:
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
n.Kind = "not-type"
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
|
|
|
|
}
|
2009-11-11 16:58:27 -08:00
|
|
|
if nerrors > 0 {
|
2014-08-14 09:21:58 -07:00
|
|
|
// Check if compiling the preamble by itself causes any errors,
|
|
|
|
|
// because the messages we've printed out so far aren't helpful
|
2016-03-01 23:21:55 +00:00
|
|
|
// to users debugging preamble mistakes. See issue 8442.
|
2014-08-14 09:21:58 -07:00
|
|
|
preambleErrors := p.gccErrors([]byte(f.Preamble))
|
|
|
|
|
if len(preambleErrors) > 0 {
|
|
|
|
|
error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-13 16:57:44 -07:00
|
|
|
fatalf("unresolved names")
|
2009-11-11 16:58:27 -08:00
|
|
|
}
|
cmd/cgo: stop using compiler error message text to analyze C names
The old approach to determining whether "name" was a type, constant,
or expression was to compile the C program
name;
and scan the errors and warnings generated by the compiler.
This requires looking for specific substrings in the errors and warnings,
which ties the implementation to specific compiler versions.
As compilers change their errors or drop warnings, cgo breaks.
This happens slowly but it does happen.
Clang in particular (now required on OS X) has a significant churn rate.
The new approach compiles a slightly more complex program
that is either valid C or not valid C depending on what kind of
thing "name" is. It uses only the presence or absence of an error
message on a particular line, not the error text itself. The program is:
// error if and only if name is undeclared
void f1(void) { typeof(name) *x; }
// error if and only if name is not a type
void f2(void) { name *x; }
// error if and only if name is not an integer constant
void f3(void) { enum { x = (name)*1 }; }
I had not been planning to do this until Go 1.3, because it is a
non-trivial change, but it fixes a real Xcode 5 problem in Go 1.2,
and the new code is easier to understand than the old code.
It should be significantly more robust.
Fixes #6596.
Fixes #6612.
R=golang-dev, r, james, iant
CC=golang-dev
https://golang.org/cl/15070043
2013-10-18 15:56:25 -04:00
|
|
|
|
|
|
|
|
needType = append(needType, names...)
|
2010-07-14 17:17:53 -07:00
|
|
|
return needType
|
|
|
|
|
}
|
2009-11-11 16:58:27 -08:00
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// loadDWARF parses the DWARF debug information generated
|
|
|
|
|
// by gcc to learn the details of the constants, variables, and types
|
|
|
|
|
// being referred to as C.xxx.
|
|
|
|
|
func (p *Package) loadDWARF(f *File, names []*Name) {
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
// Extract the types from the DWARF section of an object
|
2016-03-01 23:21:55 +00:00
|
|
|
// from a well-formed C program. Gcc only generates DWARF info
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
// 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
|
2013-10-22 18:33:23 -04:00
|
|
|
// __typeof__(names[i]) *__cgo__i;
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
// for each entry in names and then dereference the type we
|
|
|
|
|
// learn for __cgo__i.
|
2010-07-14 17:17:53 -07:00
|
|
|
var b bytes.Buffer
|
2013-10-15 15:00:48 -04:00
|
|
|
b.WriteString(builtinProlog)
|
2017-10-13 18:26:10 -07:00
|
|
|
b.WriteString(f.Preamble)
|
2016-11-02 19:41:01 -04:00
|
|
|
b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
for i, n := range names {
|
2013-10-22 18:33:23 -04:00
|
|
|
fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
|
2017-08-31 13:49:43 +09:00
|
|
|
if n.Kind == "iconst" {
|
2010-07-14 17:17:53 -07:00
|
|
|
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
|
|
|
|
|
}
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
2011-06-13 14:43:54 -04:00
|
|
|
|
2017-04-09 11:38:06 +09:00
|
|
|
// We create a data block initialized with the values,
|
|
|
|
|
// so we can read them out of the object file.
|
2017-01-20 08:34:18 +09:00
|
|
|
fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n")
|
2011-06-13 14:43:54 -04:00
|
|
|
for _, n := range names {
|
2017-08-31 13:49:43 +09:00
|
|
|
if n.Kind == "iconst" {
|
2011-06-13 14:43:54 -04:00
|
|
|
fmt.Fprintf(&b, "\t%s,\n", n.C)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(&b, "\t0,\n")
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-27 12:49:13 -08:00
|
|
|
// for the last entry, we cannot use 0, otherwise
|
2012-07-30 18:44:48 -04:00
|
|
|
// in case all __cgodebug_data is zero initialized,
|
|
|
|
|
// LLVM-based gcc will place the it in the __DATA.__common
|
|
|
|
|
// zero-filled section (our debug/macho doesn't support
|
|
|
|
|
// this)
|
|
|
|
|
fmt.Fprintf(&b, "\t1\n")
|
2011-06-13 14:43:54 -04:00
|
|
|
fmt.Fprintf(&b, "};\n")
|
|
|
|
|
|
2017-01-20 08:34:18 +09:00
|
|
|
// do the same work for floats.
|
|
|
|
|
fmt.Fprintf(&b, "double __cgodebug_floats[] = {\n")
|
|
|
|
|
for _, n := range names {
|
|
|
|
|
if n.Kind == "fconst" {
|
|
|
|
|
fmt.Fprintf(&b, "\t%s,\n", n.C)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(&b, "\t0,\n")
|
|
|
|
|
}
|
2011-06-13 14:43:54 -04:00
|
|
|
}
|
2017-01-20 08:34:18 +09:00
|
|
|
fmt.Fprintf(&b, "\t1\n")
|
|
|
|
|
fmt.Fprintf(&b, "};\n")
|
|
|
|
|
|
2017-04-21 19:18:36 +09:00
|
|
|
// do the same work for strings.
|
|
|
|
|
for i, n := range names {
|
|
|
|
|
if n.Kind == "sconst" {
|
|
|
|
|
fmt.Fprintf(&b, "const char __cgodebug_str__%d[] = %s;\n", i, n.C)
|
|
|
|
|
fmt.Fprintf(&b, "const unsigned long long __cgodebug_strlen__%d = sizeof(%s)-1;\n", i, n.C)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d, ints, floats, strs := p.gccDebug(b.Bytes(), len(names))
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
|
2009-11-02 12:02:16 -08:00
|
|
|
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
|
2009-12-15 15:33:31 -08:00
|
|
|
types := make([]dwarf.Type, len(names))
|
|
|
|
|
r := d.Reader()
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
for {
|
2009-12-15 15:33:31 -08:00
|
|
|
e, err := r.Next()
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
if err != nil {
|
2011-04-13 16:57:44 -07:00
|
|
|
fatalf("reading DWARF entry: %s", err)
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
|
|
|
|
if e == nil {
|
2009-11-09 12:07:39 -08:00
|
|
|
break
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
2009-12-15 21:24:17 -08:00
|
|
|
switch e.Tag {
|
|
|
|
|
case dwarf.TagVariable:
|
|
|
|
|
name, _ := e.Val(dwarf.AttrName).(string)
|
|
|
|
|
typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
|
|
|
|
|
if name == "" || typOff == 0 {
|
2015-11-20 13:53:18 -08:00
|
|
|
if e.Val(dwarf.AttrSpecification) != nil {
|
|
|
|
|
// Since we are reading all the DWARF,
|
|
|
|
|
// assume we will see the variable elsewhere.
|
|
|
|
|
break
|
|
|
|
|
}
|
2011-04-13 16:57:44 -07:00
|
|
|
fatalf("malformed DWARF TagVariable entry")
|
2009-12-15 21:24:17 -08:00
|
|
|
}
|
|
|
|
|
if !strings.HasPrefix(name, "__cgo__") {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
typ, err := d.Type(typOff)
|
|
|
|
|
if err != nil {
|
2011-04-13 16:57:44 -07:00
|
|
|
fatalf("loading DWARF type: %s", err)
|
2009-12-15 21:24:17 -08:00
|
|
|
}
|
|
|
|
|
t, ok := typ.(*dwarf.PtrType)
|
|
|
|
|
if !ok || t == nil {
|
2011-04-13 16:57:44 -07:00
|
|
|
fatalf("internal error: %s has non-pointer type", name)
|
2009-12-15 21:24:17 -08:00
|
|
|
}
|
|
|
|
|
i, err := strconv.Atoi(name[7:])
|
|
|
|
|
if err != nil {
|
2011-04-13 16:57:44 -07:00
|
|
|
fatalf("malformed __cgo__ name: %s", name)
|
2009-12-15 21:24:17 -08:00
|
|
|
}
|
2017-04-09 11:38:06 +09:00
|
|
|
types[i] = t.Type
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
|
|
|
|
if e.Tag != dwarf.TagCompileUnit {
|
2009-11-09 12:07:39 -08:00
|
|
|
r.SkipChildren()
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// Record types and typedef information.
|
2009-12-15 15:33:31 -08:00
|
|
|
var conv typeConv
|
2012-09-24 14:58:57 -04:00
|
|
|
conv.Init(p.PtrSize, p.IntSize)
|
2010-07-14 17:17:53 -07:00
|
|
|
for i, n := range names {
|
2011-11-09 16:01:55 -05:00
|
|
|
if types[i] == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2017-06-05 09:06:30 +09:00
|
|
|
pos := f.NamePos[n]
|
2009-12-15 15:33:31 -08:00
|
|
|
f, fok := types[i].(*dwarf.FuncType)
|
2010-07-14 17:17:53 -07:00
|
|
|
if n.Kind != "type" && fok {
|
|
|
|
|
n.Kind = "func"
|
2013-10-15 21:35:52 -04:00
|
|
|
n.FuncType = conv.FuncType(f, pos)
|
2009-09-24 11:43:19 -07:00
|
|
|
} else {
|
2012-02-06 20:38:54 +01:00
|
|
|
n.Type = conv.Type(types[i], pos)
|
2017-01-20 08:34:18 +09:00
|
|
|
switch n.Kind {
|
|
|
|
|
case "iconst":
|
|
|
|
|
if i < len(ints) {
|
2017-08-31 13:49:43 +09:00
|
|
|
if _, ok := types[i].(*dwarf.UintType); ok {
|
|
|
|
|
n.Const = fmt.Sprintf("%#x", uint64(ints[i]))
|
|
|
|
|
} else {
|
|
|
|
|
n.Const = fmt.Sprintf("%#x", ints[i])
|
|
|
|
|
}
|
2017-05-16 21:52:41 +09:00
|
|
|
}
|
2017-01-20 08:34:18 +09:00
|
|
|
case "fconst":
|
|
|
|
|
if i < len(floats) {
|
|
|
|
|
n.Const = fmt.Sprintf("%f", floats[i])
|
|
|
|
|
}
|
2017-04-21 19:18:36 +09:00
|
|
|
case "sconst":
|
|
|
|
|
if i < len(strs) {
|
|
|
|
|
n.Const = fmt.Sprintf("%q", strs[i])
|
|
|
|
|
}
|
2012-09-20 13:20:33 +10:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2014-08-05 18:16:56 -07:00
|
|
|
conv.FinishType(pos)
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-13 12:42:21 -04:00
|
|
|
// mangleName does name mangling to translate names
|
|
|
|
|
// from the original Go source files to the names
|
|
|
|
|
// used in the final Go files generated by cgo.
|
|
|
|
|
func (p *Package) mangleName(n *Name) {
|
|
|
|
|
// When using gccgo variables have to be
|
|
|
|
|
// exported so that they become global symbols
|
|
|
|
|
// that the C code can refer to.
|
|
|
|
|
prefix := "_C"
|
|
|
|
|
if *gccgo && n.IsVar() {
|
|
|
|
|
prefix = "C"
|
|
|
|
|
}
|
|
|
|
|
n.Mangle = prefix + n.Kind + "_" + n.Go
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-16 15:26:00 -07:00
|
|
|
// rewriteCalls rewrites all calls that pass pointers to check that
|
|
|
|
|
// they follow the rules for passing pointers between Go and C.
|
2016-10-12 17:09:54 -07:00
|
|
|
// This returns whether the package needs to import unsafe as _cgo_unsafe.
|
|
|
|
|
func (p *Package) rewriteCalls(f *File) bool {
|
|
|
|
|
needsUnsafe := false
|
2015-10-16 15:26:00 -07:00
|
|
|
for _, call := range f.Calls {
|
|
|
|
|
// This is a call to C.xxx; set goname to "xxx".
|
2016-06-01 15:24:14 -07:00
|
|
|
goname := call.Call.Fun.(*ast.SelectorExpr).Sel.Name
|
2015-10-16 15:26:00 -07:00
|
|
|
if goname == "malloc" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
name := f.Name[goname]
|
|
|
|
|
if name.Kind != "func" {
|
|
|
|
|
// Probably a type conversion.
|
|
|
|
|
continue
|
|
|
|
|
}
|
2016-10-12 17:09:54 -07:00
|
|
|
if p.rewriteCall(f, call, name) {
|
|
|
|
|
needsUnsafe = true
|
|
|
|
|
}
|
2015-10-16 15:26:00 -07:00
|
|
|
}
|
2016-10-12 17:09:54 -07:00
|
|
|
return needsUnsafe
|
2015-10-16 15:26:00 -07:00
|
|
|
}
|
|
|
|
|
|
2016-10-20 11:10:03 -07:00
|
|
|
// rewriteCall rewrites one call to add pointer checks.
|
|
|
|
|
// If any pointer checks are required, we rewrite the call into a
|
|
|
|
|
// function literal that calls _cgoCheckPointer for each pointer
|
|
|
|
|
// argument and then calls the original function.
|
2016-10-12 17:09:54 -07:00
|
|
|
// This returns whether the package needs to import unsafe as _cgo_unsafe.
|
|
|
|
|
func (p *Package) rewriteCall(f *File, call *Call, name *Name) bool {
|
2016-06-20 21:11:53 -04:00
|
|
|
// Avoid a crash if the number of arguments is
|
|
|
|
|
// less than the number of parameters.
|
|
|
|
|
// This will be caught when the generated file is compiled.
|
|
|
|
|
if len(call.Call.Args) < len(name.FuncType.Params) {
|
2016-10-12 17:09:54 -07:00
|
|
|
return false
|
2016-06-20 21:11:53 -04:00
|
|
|
}
|
|
|
|
|
|
2016-06-01 15:24:14 -07:00
|
|
|
any := false
|
2015-10-16 15:26:00 -07:00
|
|
|
for i, param := range name.FuncType.Params {
|
2016-06-01 15:24:14 -07:00
|
|
|
if p.needsPointerCheck(f, param.Go, call.Call.Args[i]) {
|
|
|
|
|
any = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !any {
|
2016-10-12 17:09:54 -07:00
|
|
|
return false
|
2016-06-01 15:24:14 -07:00
|
|
|
}
|
2015-12-02 12:07:57 -08:00
|
|
|
|
2016-06-01 15:24:14 -07:00
|
|
|
// We need to rewrite this call.
|
|
|
|
|
//
|
2016-10-14 14:53:59 -07:00
|
|
|
// We are going to rewrite C.f(p) to
|
|
|
|
|
// func (_cgo0 ptype) {
|
|
|
|
|
// _cgoCheckPointer(_cgo0)
|
|
|
|
|
// C.f(_cgo0)
|
|
|
|
|
// }(p)
|
|
|
|
|
// Using a function literal like this lets us do correct
|
|
|
|
|
// argument type checking, and works correctly if the call is
|
|
|
|
|
// deferred.
|
2016-10-12 17:09:54 -07:00
|
|
|
needsUnsafe := false
|
2016-10-14 14:53:59 -07:00
|
|
|
params := make([]*ast.Field, len(name.FuncType.Params))
|
2016-10-21 07:54:46 -07:00
|
|
|
nargs := make([]ast.Expr, len(name.FuncType.Params))
|
2016-10-14 14:53:59 -07:00
|
|
|
var stmts []ast.Stmt
|
2016-06-01 15:24:14 -07:00
|
|
|
for i, param := range name.FuncType.Params {
|
2016-10-14 14:53:59 -07:00
|
|
|
// params is going to become the parameters of the
|
|
|
|
|
// function literal.
|
2016-10-21 07:54:46 -07:00
|
|
|
// nargs is going to become the list of arguments made
|
|
|
|
|
// by the call within the function literal.
|
2016-10-14 14:53:59 -07:00
|
|
|
// nparam is the parameter of the function literal that
|
|
|
|
|
// corresponds to param.
|
|
|
|
|
|
2016-06-01 15:24:14 -07:00
|
|
|
origArg := call.Call.Args[i]
|
2016-10-14 14:53:59 -07:00
|
|
|
nparam := ast.NewIdent(fmt.Sprintf("_cgo%d", i))
|
2016-10-21 07:54:46 -07:00
|
|
|
nargs[i] = nparam
|
2016-10-14 14:53:59 -07:00
|
|
|
|
|
|
|
|
// The Go version of the C type might use unsafe.Pointer,
|
|
|
|
|
// but the file might not import unsafe.
|
|
|
|
|
// Rewrite the Go type if necessary to use _cgo_unsafe.
|
|
|
|
|
ptype := p.rewriteUnsafe(param.Go)
|
|
|
|
|
if ptype != param.Go {
|
|
|
|
|
needsUnsafe = true
|
|
|
|
|
}
|
2016-06-01 15:24:14 -07:00
|
|
|
|
2016-10-14 14:53:59 -07:00
|
|
|
params[i] = &ast.Field{
|
|
|
|
|
Names: []*ast.Ident{nparam},
|
|
|
|
|
Type: ptype,
|
2015-10-16 15:26:00 -07:00
|
|
|
}
|
|
|
|
|
|
2016-06-01 15:24:14 -07:00
|
|
|
if !p.needsPointerCheck(f, param.Go, origArg) {
|
2015-10-16 15:26:00 -07:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-14 14:53:59 -07:00
|
|
|
// Run the cgo pointer checks on nparam.
|
|
|
|
|
|
|
|
|
|
// Change the function literal to call the real function
|
|
|
|
|
// with the parameter passed through _cgoCheckPointer.
|
2015-10-16 15:26:00 -07:00
|
|
|
c := &ast.CallExpr{
|
|
|
|
|
Fun: ast.NewIdent("_cgoCheckPointer"),
|
|
|
|
|
Args: []ast.Expr{
|
2016-10-14 14:53:59 -07:00
|
|
|
nparam,
|
2015-10-16 15:26:00 -07:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add optional additional arguments for an address
|
|
|
|
|
// expression.
|
2016-06-01 15:24:14 -07:00
|
|
|
c.Args = p.checkAddrArgs(f, c.Args, origArg)
|
2015-10-16 15:26:00 -07:00
|
|
|
|
2016-10-14 14:53:59 -07:00
|
|
|
stmt := &ast.ExprStmt{
|
|
|
|
|
X: c,
|
2016-10-12 17:09:54 -07:00
|
|
|
}
|
2016-10-14 14:53:59 -07:00
|
|
|
stmts = append(stmts, stmt)
|
2016-06-01 15:24:14 -07:00
|
|
|
}
|
|
|
|
|
|
2016-10-14 14:53:59 -07:00
|
|
|
fcall := &ast.CallExpr{
|
|
|
|
|
Fun: call.Call.Fun,
|
2016-10-21 07:54:46 -07:00
|
|
|
Args: nargs,
|
2016-10-14 14:53:59 -07:00
|
|
|
}
|
|
|
|
|
ftype := &ast.FuncType{
|
|
|
|
|
Params: &ast.FieldList{
|
|
|
|
|
List: params,
|
|
|
|
|
},
|
|
|
|
|
}
|
2016-11-30 15:46:37 -08:00
|
|
|
if name.FuncType.Result != nil {
|
2016-10-14 14:53:59 -07:00
|
|
|
rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
|
|
|
|
|
if rtype != name.FuncType.Result.Go {
|
|
|
|
|
needsUnsafe = true
|
|
|
|
|
}
|
|
|
|
|
ftype.Results = &ast.FieldList{
|
|
|
|
|
List: []*ast.Field{
|
|
|
|
|
&ast.Field{
|
|
|
|
|
Type: rtype,
|
2016-06-01 15:24:14 -07:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
2016-10-14 14:53:59 -07:00
|
|
|
}
|
2016-06-01 15:24:14 -07:00
|
|
|
|
2016-10-14 14:53:59 -07:00
|
|
|
// There is a Ref pointing to the old call.Call.Fun.
|
|
|
|
|
for _, ref := range f.Ref {
|
|
|
|
|
if ref.Expr == &call.Call.Fun {
|
|
|
|
|
ref.Expr = &fcall.Fun
|
|
|
|
|
|
|
|
|
|
// If this call expects two results, we have to
|
2016-11-30 15:46:37 -08:00
|
|
|
// adjust the results of the function we generated.
|
2017-09-14 11:36:21 -04:00
|
|
|
if ref.Context == ctxCall2 {
|
2016-11-30 15:46:37 -08:00
|
|
|
if ftype.Results == nil {
|
|
|
|
|
// An explicit void argument
|
|
|
|
|
// looks odd but it seems to
|
|
|
|
|
// be how cgo has worked historically.
|
|
|
|
|
ftype.Results = &ast.FieldList{
|
|
|
|
|
List: []*ast.Field{
|
|
|
|
|
&ast.Field{
|
|
|
|
|
Type: ast.NewIdent("_Ctype_void"),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-14 14:53:59 -07:00
|
|
|
ftype.Results.List = append(ftype.Results.List,
|
|
|
|
|
&ast.Field{
|
|
|
|
|
Type: ast.NewIdent("error"),
|
|
|
|
|
})
|
2016-06-01 15:24:14 -07:00
|
|
|
}
|
|
|
|
|
}
|
2015-10-16 15:26:00 -07:00
|
|
|
}
|
2016-10-12 17:09:54 -07:00
|
|
|
|
2016-11-30 15:46:37 -08:00
|
|
|
var fbody ast.Stmt
|
|
|
|
|
if ftype.Results == nil {
|
|
|
|
|
fbody = &ast.ExprStmt{
|
|
|
|
|
X: fcall,
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
fbody = &ast.ReturnStmt{
|
|
|
|
|
Results: []ast.Expr{fcall},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
call.Call.Fun = &ast.FuncLit{
|
|
|
|
|
Type: ftype,
|
|
|
|
|
Body: &ast.BlockStmt{
|
|
|
|
|
List: append(stmts, fbody),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
call.Call.Lparen = token.NoPos
|
|
|
|
|
call.Call.Rparen = token.NoPos
|
|
|
|
|
|
2016-10-12 17:09:54 -07:00
|
|
|
return needsUnsafe
|
2015-10-16 15:26:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// needsPointerCheck returns whether the type t needs a pointer check.
|
|
|
|
|
// This is true if t is a pointer and if the value to which it points
|
|
|
|
|
// might contain a pointer.
|
2016-06-01 15:24:14 -07:00
|
|
|
func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
|
|
|
|
|
// An untyped nil does not need a pointer check, and when
|
|
|
|
|
// _cgoCheckPointer returns the untyped nil the type assertion we
|
|
|
|
|
// are going to insert will fail. Easier to just skip nil arguments.
|
|
|
|
|
// TODO: Note that this fails if nil is shadowed.
|
|
|
|
|
if id, ok := arg.(*ast.Ident); ok && id.Name == "nil" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-16 15:26:00 -07:00
|
|
|
return p.hasPointer(f, t, true)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-01 23:21:55 +00:00
|
|
|
// hasPointer is used by needsPointerCheck. If top is true it returns
|
2015-10-16 15:26:00 -07:00
|
|
|
// whether t is or contains a pointer that might point to a pointer.
|
|
|
|
|
// If top is false it returns whether t is or contains a pointer.
|
2015-11-18 21:25:44 -08:00
|
|
|
// f may be nil.
|
2015-10-16 15:26:00 -07:00
|
|
|
func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
|
|
|
|
|
switch t := t.(type) {
|
|
|
|
|
case *ast.ArrayType:
|
|
|
|
|
if t.Len == nil {
|
|
|
|
|
if !top {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return p.hasPointer(f, t.Elt, false)
|
|
|
|
|
}
|
|
|
|
|
return p.hasPointer(f, t.Elt, top)
|
|
|
|
|
case *ast.StructType:
|
|
|
|
|
for _, field := range t.Fields.List {
|
|
|
|
|
if p.hasPointer(f, field.Type, top) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
case *ast.StarExpr: // Pointer type.
|
|
|
|
|
if !top {
|
|
|
|
|
return true
|
|
|
|
|
}
|
2016-11-14 15:51:30 -08:00
|
|
|
// Check whether this is a pointer to a C union (or class)
|
|
|
|
|
// type that contains a pointer.
|
|
|
|
|
if unionWithPointer[t.X] {
|
|
|
|
|
return true
|
|
|
|
|
}
|
2015-10-16 15:26:00 -07:00
|
|
|
return p.hasPointer(f, t.X, false)
|
|
|
|
|
case *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
|
|
|
|
|
return true
|
|
|
|
|
case *ast.Ident:
|
|
|
|
|
// TODO: Handle types defined within function.
|
|
|
|
|
for _, d := range p.Decl {
|
|
|
|
|
gd, ok := d.(*ast.GenDecl)
|
|
|
|
|
if !ok || gd.Tok != token.TYPE {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
for _, spec := range gd.Specs {
|
|
|
|
|
ts, ok := spec.(*ast.TypeSpec)
|
|
|
|
|
if !ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if ts.Name.Name == t.Name {
|
|
|
|
|
return p.hasPointer(f, ts.Type, top)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if def := typedef[t.Name]; def != nil {
|
|
|
|
|
return p.hasPointer(f, def.Go, top)
|
|
|
|
|
}
|
|
|
|
|
if t.Name == "string" {
|
|
|
|
|
return !top
|
|
|
|
|
}
|
|
|
|
|
if t.Name == "error" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if goTypes[t.Name] != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
2016-03-01 23:21:55 +00:00
|
|
|
// We can't figure out the type. Conservative
|
2015-10-16 15:26:00 -07:00
|
|
|
// approach is to assume it has a pointer.
|
|
|
|
|
return true
|
|
|
|
|
case *ast.SelectorExpr:
|
|
|
|
|
if l, ok := t.X.(*ast.Ident); !ok || l.Name != "C" {
|
|
|
|
|
// Type defined in a different package.
|
|
|
|
|
// Conservative approach is to assume it has a
|
|
|
|
|
// pointer.
|
|
|
|
|
return true
|
|
|
|
|
}
|
2015-11-18 21:25:44 -08:00
|
|
|
if f == nil {
|
|
|
|
|
// Conservative approach: assume pointer.
|
|
|
|
|
return true
|
|
|
|
|
}
|
2015-10-16 15:26:00 -07:00
|
|
|
name := f.Name[t.Sel.Name]
|
|
|
|
|
if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
|
|
|
|
|
return p.hasPointer(f, name.Type.Go, top)
|
|
|
|
|
}
|
2016-03-01 23:21:55 +00:00
|
|
|
// We can't figure out the type. Conservative
|
2015-10-16 15:26:00 -07:00
|
|
|
// approach is to assume it has a pointer.
|
|
|
|
|
return true
|
|
|
|
|
default:
|
|
|
|
|
error_(t.Pos(), "could not understand type %s", gofmt(t))
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// checkAddrArgs tries to add arguments to the call of
|
2016-03-01 23:21:55 +00:00
|
|
|
// _cgoCheckPointer when the argument is an address expression. We
|
2015-10-16 15:26:00 -07:00
|
|
|
// pass true to mean that the argument is an address operation of
|
|
|
|
|
// something other than a slice index, which means that it's only
|
|
|
|
|
// necessary to check the specific element pointed to, not the entire
|
2016-03-01 23:21:55 +00:00
|
|
|
// object. This is for &s.f, where f is a field in a struct. We can
|
2015-10-16 15:26:00 -07:00
|
|
|
// pass a slice or array, meaning that we should check the entire
|
|
|
|
|
// slice or array but need not check any other part of the object.
|
2016-03-01 23:21:55 +00:00
|
|
|
// This is for &s.a[i], where we need to check all of a. However, we
|
2015-10-16 15:26:00 -07:00
|
|
|
// only pass the slice or array if we can refer to it without side
|
|
|
|
|
// effects.
|
|
|
|
|
func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr {
|
2016-01-07 15:22:39 -08:00
|
|
|
// Strip type conversions.
|
|
|
|
|
for {
|
|
|
|
|
c, ok := x.(*ast.CallExpr)
|
|
|
|
|
if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
x = c.Args[0]
|
|
|
|
|
}
|
|
|
|
|
u, ok := x.(*ast.UnaryExpr)
|
|
|
|
|
if !ok || u.Op != token.AND {
|
|
|
|
|
return args
|
|
|
|
|
}
|
|
|
|
|
index, ok := u.X.(*ast.IndexExpr)
|
2015-10-16 15:26:00 -07:00
|
|
|
if !ok {
|
|
|
|
|
// This is the address of something that is not an
|
2016-03-01 23:21:55 +00:00
|
|
|
// index expression. We only need to examine the
|
2015-10-16 15:26:00 -07:00
|
|
|
// single value to which it points.
|
2015-11-18 21:25:44 -08:00
|
|
|
// TODO: what if true is shadowed?
|
2015-10-16 15:26:00 -07:00
|
|
|
return append(args, ast.NewIdent("true"))
|
|
|
|
|
}
|
|
|
|
|
if !p.hasSideEffects(f, index.X) {
|
|
|
|
|
// Examine the entire slice.
|
|
|
|
|
return append(args, index.X)
|
|
|
|
|
}
|
|
|
|
|
// Treat the pointer as unknown.
|
|
|
|
|
return args
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// hasSideEffects returns whether the expression x has any side
|
|
|
|
|
// effects. x is an expression, not a statement, so the only side
|
|
|
|
|
// effect is a function call.
|
|
|
|
|
func (p *Package) hasSideEffects(f *File, x ast.Expr) bool {
|
|
|
|
|
found := false
|
2017-09-14 11:36:21 -04:00
|
|
|
f.walk(x, ctxExpr,
|
|
|
|
|
func(f *File, x interface{}, context astContext) {
|
2015-10-16 15:26:00 -07:00
|
|
|
switch x.(type) {
|
|
|
|
|
case *ast.CallExpr:
|
|
|
|
|
found = true
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return found
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-07 15:22:39 -08:00
|
|
|
// isType returns whether the expression is definitely a type.
|
|
|
|
|
// This is conservative--it returns false for an unknown identifier.
|
|
|
|
|
func (p *Package) isType(t ast.Expr) bool {
|
|
|
|
|
switch t := t.(type) {
|
|
|
|
|
case *ast.SelectorExpr:
|
|
|
|
|
id, ok := t.X.(*ast.Ident)
|
|
|
|
|
if !ok {
|
|
|
|
|
return false
|
|
|
|
|
}
|
2016-02-23 16:11:46 -08:00
|
|
|
if id.Name == "unsafe" && t.Sel.Name == "Pointer" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if id.Name == "C" && typedef["_Ctype_"+t.Sel.Name] != nil {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
2016-01-07 15:22:39 -08:00
|
|
|
case *ast.Ident:
|
|
|
|
|
// TODO: This ignores shadowing.
|
|
|
|
|
switch t.Name {
|
|
|
|
|
case "unsafe.Pointer", "bool", "byte",
|
|
|
|
|
"complex64", "complex128",
|
|
|
|
|
"error",
|
|
|
|
|
"float32", "float64",
|
|
|
|
|
"int", "int8", "int16", "int32", "int64",
|
|
|
|
|
"rune", "string",
|
|
|
|
|
"uint", "uint8", "uint16", "uint32", "uint64", "uintptr":
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
case *ast.StarExpr:
|
|
|
|
|
return p.isType(t.X)
|
|
|
|
|
case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType,
|
|
|
|
|
*ast.MapType, *ast.ChanType:
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-12 17:09:54 -07:00
|
|
|
// rewriteUnsafe returns a version of t with references to unsafe.Pointer
|
|
|
|
|
// rewritten to use _cgo_unsafe.Pointer instead.
|
|
|
|
|
func (p *Package) rewriteUnsafe(t ast.Expr) ast.Expr {
|
2015-10-16 15:26:00 -07:00
|
|
|
switch t := t.(type) {
|
|
|
|
|
case *ast.Ident:
|
2016-01-07 15:22:39 -08:00
|
|
|
// We don't see a SelectorExpr for unsafe.Pointer;
|
|
|
|
|
// this is created by code in this file.
|
2016-10-12 17:09:54 -07:00
|
|
|
if t.Name == "unsafe.Pointer" {
|
|
|
|
|
return ast.NewIdent("_cgo_unsafe.Pointer")
|
|
|
|
|
}
|
2015-10-16 15:26:00 -07:00
|
|
|
case *ast.ArrayType:
|
2016-10-12 17:09:54 -07:00
|
|
|
t1 := p.rewriteUnsafe(t.Elt)
|
|
|
|
|
if t1 != t.Elt {
|
|
|
|
|
r := *t
|
|
|
|
|
r.Elt = t1
|
|
|
|
|
return &r
|
|
|
|
|
}
|
2015-10-16 15:26:00 -07:00
|
|
|
case *ast.StructType:
|
2016-10-12 17:09:54 -07:00
|
|
|
changed := false
|
|
|
|
|
fields := *t.Fields
|
|
|
|
|
fields.List = nil
|
2015-10-16 15:26:00 -07:00
|
|
|
for _, f := range t.Fields.List {
|
2016-10-12 17:09:54 -07:00
|
|
|
ft := p.rewriteUnsafe(f.Type)
|
|
|
|
|
if ft == f.Type {
|
|
|
|
|
fields.List = append(fields.List, f)
|
|
|
|
|
} else {
|
|
|
|
|
fn := *f
|
|
|
|
|
fn.Type = ft
|
|
|
|
|
fields.List = append(fields.List, &fn)
|
|
|
|
|
changed = true
|
2015-10-16 15:26:00 -07:00
|
|
|
}
|
|
|
|
|
}
|
2016-10-12 17:09:54 -07:00
|
|
|
if changed {
|
|
|
|
|
r := *t
|
|
|
|
|
r.Fields = &fields
|
|
|
|
|
return &r
|
|
|
|
|
}
|
2015-10-16 15:26:00 -07:00
|
|
|
case *ast.StarExpr: // Pointer type.
|
2016-10-12 17:09:54 -07:00
|
|
|
x1 := p.rewriteUnsafe(t.X)
|
|
|
|
|
if x1 != t.X {
|
|
|
|
|
r := *t
|
|
|
|
|
r.X = x1
|
|
|
|
|
return &r
|
|
|
|
|
}
|
2016-06-09 11:19:26 -07:00
|
|
|
}
|
2016-10-12 17:09:54 -07:00
|
|
|
return t
|
2015-10-16 15:26:00 -07:00
|
|
|
}
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
|
|
|
|
|
// Go equivalents, now that we have figured out the meaning of all
|
2016-03-01 23:21:55 +00:00
|
|
|
// the xxx. In *godefs mode, rewriteRef replaces the names
|
2011-11-10 19:08:04 -05:00
|
|
|
// with full definitions instead of mangled names.
|
2010-07-14 17:17:53 -07:00
|
|
|
func (p *Package) rewriteRef(f *File) {
|
2013-08-13 12:42:21 -04:00
|
|
|
// Keep a list of all the functions, to remove the ones
|
|
|
|
|
// only used as expressions and avoid generating bridge
|
|
|
|
|
// code for them.
|
|
|
|
|
functions := make(map[string]bool)
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// Assign mangled names.
|
|
|
|
|
for _, n := range f.Name {
|
|
|
|
|
if n.Kind == "not-type" {
|
2017-05-23 23:01:08 +09:00
|
|
|
if n.Define == "" {
|
|
|
|
|
n.Kind = "var"
|
|
|
|
|
} else {
|
|
|
|
|
n.Kind = "macro"
|
|
|
|
|
n.FuncType = &FuncType{
|
|
|
|
|
Result: n.Type,
|
|
|
|
|
Go: &ast.FuncType{
|
|
|
|
|
Results: &ast.FieldList{List: []*ast.Field{{Type: n.Type.Go}}},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
|
|
|
|
if n.Mangle == "" {
|
2013-08-13 12:42:21 -04:00
|
|
|
p.mangleName(n)
|
|
|
|
|
}
|
|
|
|
|
if n.Kind == "func" {
|
|
|
|
|
functions[n.Go] = false
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
2009-10-03 10:37:12 -07:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
|
|
|
|
|
// Now that we have all the name types filled in,
|
|
|
|
|
// scan through the Refs to identify the ones that
|
2016-03-01 23:21:55 +00:00
|
|
|
// are trying to do a ,err call. Also check that
|
2010-07-14 17:17:53 -07:00
|
|
|
// functions are only used in calls.
|
|
|
|
|
for _, r := range f.Ref {
|
2017-01-20 08:34:18 +09:00
|
|
|
if r.Name.IsConst() && r.Name.Const == "" {
|
2013-09-11 09:56:51 -04:00
|
|
|
error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
|
2011-06-13 14:43:54 -04:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
|
|
|
|
|
switch r.Context {
|
2017-09-14 11:36:21 -04:00
|
|
|
case ctxCall, ctxCall2:
|
2010-07-14 17:17:53 -07:00
|
|
|
if r.Name.Kind != "func" {
|
|
|
|
|
if r.Name.Kind == "type" {
|
2017-09-14 11:36:21 -04:00
|
|
|
r.Context = ctxType
|
2015-10-03 15:50:45 +00:00
|
|
|
if r.Name.Type == nil {
|
|
|
|
|
error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
|
|
|
|
|
break
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
expr = r.Name.Type.Go
|
|
|
|
|
break
|
|
|
|
|
}
|
2013-09-11 09:56:51 -04:00
|
|
|
error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
|
2010-07-14 17:17:53 -07:00
|
|
|
break
|
|
|
|
|
}
|
2013-08-13 12:42:21 -04:00
|
|
|
functions[r.Name.Go] = true
|
2017-09-14 11:36:21 -04:00
|
|
|
if r.Context == ctxCall2 {
|
2013-09-11 09:56:51 -04:00
|
|
|
if r.Name.Go == "_CMalloc" {
|
|
|
|
|
error_(r.Pos(), "no two-result form for C.malloc")
|
|
|
|
|
break
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
// Invent new Name for the two-result function.
|
|
|
|
|
n := f.Name["2"+r.Name.Go]
|
|
|
|
|
if n == nil {
|
|
|
|
|
n = new(Name)
|
|
|
|
|
*n = *r.Name
|
|
|
|
|
n.AddError = true
|
|
|
|
|
n.Mangle = "_C2func_" + n.Go
|
|
|
|
|
f.Name["2"+r.Name.Go] = n
|
|
|
|
|
}
|
2010-08-04 17:15:04 -07:00
|
|
|
expr = ast.NewIdent(n.Mangle)
|
2010-07-14 17:17:53 -07:00
|
|
|
r.Name = n
|
|
|
|
|
break
|
|
|
|
|
}
|
2017-09-14 11:36:21 -04:00
|
|
|
case ctxExpr:
|
2017-05-23 23:01:08 +09:00
|
|
|
switch r.Name.Kind {
|
|
|
|
|
case "func":
|
2017-04-17 16:13:59 -05:00
|
|
|
if builtinDefs[r.Name.C] != "" {
|
|
|
|
|
error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-13 12:42:21 -04:00
|
|
|
// Function is being used in an expression, to e.g. pass around a C function pointer.
|
|
|
|
|
// Create a new Name for this Ref which causes the variable to be declared in Go land.
|
|
|
|
|
fpName := "fp_" + r.Name.Go
|
|
|
|
|
name := f.Name[fpName]
|
|
|
|
|
if name == nil {
|
|
|
|
|
name = &Name{
|
|
|
|
|
Go: fpName,
|
|
|
|
|
C: r.Name.C,
|
|
|
|
|
Kind: "fpvar",
|
|
|
|
|
Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")},
|
|
|
|
|
}
|
|
|
|
|
p.mangleName(name)
|
|
|
|
|
f.Name[fpName] = name
|
|
|
|
|
}
|
|
|
|
|
r.Name = name
|
2016-03-01 23:21:55 +00:00
|
|
|
// Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
|
2014-08-12 12:55:12 -07:00
|
|
|
// function is defined in out.go and simply returns its argument. See
|
|
|
|
|
// issue 7757.
|
|
|
|
|
expr = &ast.CallExpr{
|
|
|
|
|
Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
|
|
|
|
|
Args: []ast.Expr{ast.NewIdent(name.Mangle)},
|
|
|
|
|
}
|
2017-05-23 23:01:08 +09:00
|
|
|
case "type":
|
2010-07-14 17:17:53 -07:00
|
|
|
// Okay - might be new(T)
|
2015-10-03 15:50:45 +00:00
|
|
|
if r.Name.Type == nil {
|
|
|
|
|
error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
|
|
|
|
|
break
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
expr = r.Name.Type.Go
|
2017-05-23 23:01:08 +09:00
|
|
|
case "var":
|
2013-10-18 16:52:44 -04:00
|
|
|
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
|
2017-05-23 23:01:08 +09:00
|
|
|
case "macro":
|
|
|
|
|
expr = &ast.CallExpr{Fun: expr}
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
2017-09-14 11:36:21 -04:00
|
|
|
case ctxSelector:
|
2015-01-12 00:12:59 -05:00
|
|
|
if r.Name.Kind == "var" {
|
|
|
|
|
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
|
|
|
|
|
} else {
|
2016-04-14 16:51:18 -07:00
|
|
|
error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
|
2015-01-12 00:12:59 -05:00
|
|
|
}
|
2017-09-14 11:36:21 -04:00
|
|
|
case ctxType:
|
2010-07-14 17:17:53 -07:00
|
|
|
if r.Name.Kind != "type" {
|
2013-09-11 09:56:51 -04:00
|
|
|
error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
|
2011-11-09 16:01:55 -05:00
|
|
|
} else if r.Name.Type == nil {
|
|
|
|
|
// Use of C.enum_x, C.struct_x or C.union_x without C definition.
|
|
|
|
|
// GCC won't raise an error when using pointers to such unknown types.
|
2013-09-11 09:56:51 -04:00
|
|
|
error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
|
2010-09-16 13:38:23 -04:00
|
|
|
} else {
|
|
|
|
|
expr = r.Name.Type.Go
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
if r.Name.Kind == "func" {
|
2013-09-11 09:56:51 -04:00
|
|
|
error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
|
|
|
|
}
|
2015-01-07 13:23:45 -08:00
|
|
|
if *godefs {
|
2011-11-10 19:08:04 -05:00
|
|
|
// Substitute definition for mangled type name.
|
|
|
|
|
if id, ok := expr.(*ast.Ident); ok {
|
|
|
|
|
if t := typedef[id.Name]; t != nil {
|
2012-02-19 13:32:55 -05:00
|
|
|
expr = t.Go
|
2011-11-10 19:08:04 -05:00
|
|
|
}
|
|
|
|
|
if id.Name == r.Name.Mangle && r.Name.Const != "" {
|
|
|
|
|
expr = ast.NewIdent(r.Name.Const)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-18 16:52:44 -04:00
|
|
|
|
|
|
|
|
// Copy position information from old expr into new expr,
|
|
|
|
|
// in case expression being replaced is first on line.
|
|
|
|
|
// See golang.org/issue/6563.
|
|
|
|
|
pos := (*r.Expr).Pos()
|
|
|
|
|
switch x := expr.(type) {
|
|
|
|
|
case *ast.Ident:
|
|
|
|
|
expr = &ast.Ident{NamePos: pos, Name: x.Name}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
*r.Expr = expr
|
2009-10-03 10:37:12 -07:00
|
|
|
}
|
2013-08-13 12:42:21 -04:00
|
|
|
|
|
|
|
|
// Remove functions only used as expressions, so their respective
|
|
|
|
|
// bridge functions are not generated.
|
|
|
|
|
for name, used := range functions {
|
|
|
|
|
if !used {
|
|
|
|
|
delete(f.Name, name)
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-03 10:37:12 -07:00
|
|
|
}
|
|
|
|
|
|
2013-08-02 14:58:27 -04:00
|
|
|
// gccBaseCmd returns the start of the compiler command line.
|
|
|
|
|
// It uses $CC if set, or else $GCC, or else the compiler recorded
|
|
|
|
|
// during the initial build as defaultCC.
|
|
|
|
|
// defaultCC is defined in zdefaultcc.go, written by cmd/dist.
|
|
|
|
|
func (p *Package) gccBaseCmd() []string {
|
2013-02-15 13:37:43 -08:00
|
|
|
// Use $CC if set, since that's what the build uses.
|
2013-08-02 14:58:27 -04:00
|
|
|
if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 {
|
2013-02-15 13:37:43 -08:00
|
|
|
return ret
|
2010-07-16 11:01:04 -07:00
|
|
|
}
|
2013-08-02 14:58:27 -04:00
|
|
|
// Try $GCC if set, since that's what we used to use.
|
|
|
|
|
if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 {
|
2013-02-15 13:37:43 -08:00
|
|
|
return ret
|
|
|
|
|
}
|
2017-11-05 17:09:54 -05:00
|
|
|
return strings.Fields(defaultCC(goos, goarch))
|
2010-07-16 11:01:04 -07:00
|
|
|
}
|
|
|
|
|
|
2012-05-04 18:26:16 +08:00
|
|
|
// gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
|
2011-06-07 16:59:35 +10:00
|
|
|
func (p *Package) gccMachine() []string {
|
2011-09-19 11:50:59 -04:00
|
|
|
switch goarch {
|
2011-06-07 16:59:35 +10:00
|
|
|
case "amd64":
|
|
|
|
|
return []string{"-m64"}
|
|
|
|
|
case "386":
|
|
|
|
|
return []string{"-m32"}
|
2012-05-04 18:26:16 +08:00
|
|
|
case "arm":
|
2014-10-21 23:42:13 +00:00
|
|
|
return []string{"-marm"} // not thumb
|
2015-01-13 12:36:44 +01:00
|
|
|
case "s390":
|
|
|
|
|
return []string{"-m31"}
|
|
|
|
|
case "s390x":
|
|
|
|
|
return []string{"-m64"}
|
2016-05-05 09:10:49 -07:00
|
|
|
case "mips64", "mips64le":
|
|
|
|
|
return []string{"-mabi=64"}
|
2016-12-13 22:03:18 +01:00
|
|
|
case "mips", "mipsle":
|
|
|
|
|
return []string{"-mabi=32"}
|
2011-06-07 16:59:35 +10:00
|
|
|
}
|
|
|
|
|
return nil
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
|
2011-12-14 22:42:42 -05:00
|
|
|
func gccTmp() string {
|
|
|
|
|
return *objDir + "_cgo_.o"
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
|
|
|
|
|
// gccCmd returns the gcc command line to use for compiling
|
|
|
|
|
// the input.
|
|
|
|
|
func (p *Package) gccCmd() []string {
|
2013-08-02 14:58:27 -04:00
|
|
|
c := append(p.gccBaseCmd(),
|
2013-10-28 22:21:26 -04:00
|
|
|
"-w", // no warnings
|
|
|
|
|
"-Wno-error", // warnings are not errors
|
|
|
|
|
"-o"+gccTmp(), // write object to tmp
|
|
|
|
|
"-gdwarf-2", // generate DWARF v2 debugging symbols
|
|
|
|
|
"-c", // do not link
|
|
|
|
|
"-xc", // input language is C
|
2013-08-02 14:58:27 -04:00
|
|
|
)
|
2015-04-17 17:05:47 -07:00
|
|
|
if p.GccIsClang {
|
2013-02-15 13:37:43 -08:00
|
|
|
c = append(c,
|
|
|
|
|
"-ferror-limit=0",
|
2013-02-23 20:24:38 +08:00
|
|
|
// Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn)
|
|
|
|
|
// doesn't have -Wno-unneeded-internal-declaration, so we need yet another
|
|
|
|
|
// flag to disable the warning. Yes, really good diagnostics, clang.
|
|
|
|
|
"-Wno-unknown-warning-option",
|
2013-02-15 13:37:43 -08:00
|
|
|
"-Wno-unneeded-internal-declaration",
|
2013-02-23 20:24:38 +08:00
|
|
|
"-Wno-unused-function",
|
|
|
|
|
"-Qunused-arguments",
|
2013-10-15 21:35:52 -04:00
|
|
|
// Clang embeds prototypes for some builtin functions,
|
|
|
|
|
// like malloc and calloc, but all size_t parameters are
|
|
|
|
|
// incorrectly typed unsigned long. We work around that
|
|
|
|
|
// by disabling the builtin functions (this is safe as
|
|
|
|
|
// it won't affect the actual compilation of the C code).
|
2015-07-10 17:17:11 -06:00
|
|
|
// See: https://golang.org/issue/6506.
|
2013-10-15 21:35:52 -04:00
|
|
|
"-fno-builtin",
|
2013-02-15 13:37:43 -08:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-06 13:35:51 -07:00
|
|
|
c = append(c, p.GccOptions...)
|
2011-06-07 16:59:35 +10:00
|
|
|
c = append(c, p.gccMachine()...)
|
2011-05-06 13:35:51 -07:00
|
|
|
c = append(c, "-") //read input from standard input
|
|
|
|
|
return c
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// gccDebug runs gcc -gdwarf-2 over the C program stdin and
|
2011-06-13 14:43:54 -04:00
|
|
|
// returns the corresponding DWARF data and, if present, debug data block.
|
2017-04-21 19:18:36 +09:00
|
|
|
func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) {
|
2011-05-06 13:35:51 -07:00
|
|
|
runGcc(stdin, p.gccCmd())
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
|
2017-01-20 08:34:18 +09:00
|
|
|
isDebugInts := func(s string) bool {
|
2013-10-30 10:24:42 -04:00
|
|
|
// Some systems use leading _ to denote non-assembly symbols.
|
2017-01-20 08:34:18 +09:00
|
|
|
return s == "__cgodebug_ints" || s == "___cgodebug_ints"
|
|
|
|
|
}
|
|
|
|
|
isDebugFloats := func(s string) bool {
|
|
|
|
|
// Some systems use leading _ to denote non-assembly symbols.
|
|
|
|
|
return s == "__cgodebug_floats" || s == "___cgodebug_floats"
|
2013-10-30 10:24:42 -04:00
|
|
|
}
|
2017-04-21 19:18:36 +09:00
|
|
|
indexOfDebugStr := func(s string) int {
|
|
|
|
|
// Some systems use leading _ to denote non-assembly symbols.
|
|
|
|
|
if strings.HasPrefix(s, "___") {
|
|
|
|
|
s = s[1:]
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(s, "__cgodebug_str__") {
|
|
|
|
|
if n, err := strconv.Atoi(s[len("__cgodebug_str__"):]); err == nil {
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
indexOfDebugStrlen := func(s string) int {
|
|
|
|
|
// Some systems use leading _ to denote non-assembly symbols.
|
|
|
|
|
if strings.HasPrefix(s, "___") {
|
|
|
|
|
s = s[1:]
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(s, "__cgodebug_strlen__") {
|
|
|
|
|
if n, err := strconv.Atoi(s[len("__cgodebug_strlen__"):]); err == nil {
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strs = make([]string, nnames)
|
|
|
|
|
|
|
|
|
|
strdata := make(map[int]string, nnames)
|
|
|
|
|
strlens := make(map[int]int, nnames)
|
|
|
|
|
|
|
|
|
|
buildStrings := func() {
|
|
|
|
|
for n, strlen := range strlens {
|
|
|
|
|
data := strdata[n]
|
|
|
|
|
if len(data) <= strlen {
|
|
|
|
|
fatalf("invalid string literal")
|
|
|
|
|
}
|
|
|
|
|
strs[n] = string(data[:strlen])
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-10-30 10:24:42 -04:00
|
|
|
|
2011-12-14 22:42:42 -05:00
|
|
|
if f, err := macho.Open(gccTmp()); err == nil {
|
2013-06-18 23:20:17 +10:00
|
|
|
defer f.Close()
|
2011-06-13 14:43:54 -04:00
|
|
|
d, err := f.DWARF()
|
|
|
|
|
if err != nil {
|
2011-12-14 22:42:42 -05:00
|
|
|
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
|
2011-06-13 14:43:54 -04:00
|
|
|
}
|
2017-01-20 08:34:18 +09:00
|
|
|
bo := f.ByteOrder
|
2011-06-13 14:43:54 -04:00
|
|
|
if f.Symtab != nil {
|
|
|
|
|
for i := range f.Symtab.Syms {
|
|
|
|
|
s := &f.Symtab.Syms[i]
|
2017-01-20 08:34:18 +09:00
|
|
|
switch {
|
|
|
|
|
case isDebugInts(s.Name):
|
|
|
|
|
// Found it. Now find data section.
|
|
|
|
|
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
|
|
|
|
data := sdat[s.Value-sect.Addr:]
|
|
|
|
|
ints = make([]int64, len(data)/8)
|
|
|
|
|
for i := range ints {
|
|
|
|
|
ints[i] = int64(bo.Uint64(data[i*8:]))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case isDebugFloats(s.Name):
|
2016-03-01 23:21:55 +00:00
|
|
|
// Found it. Now find data section.
|
2011-06-13 14:43:54 -04:00
|
|
|
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
2017-01-20 08:34:18 +09:00
|
|
|
data := sdat[s.Value-sect.Addr:]
|
|
|
|
|
floats = make([]float64, len(data)/8)
|
|
|
|
|
for i := range floats {
|
|
|
|
|
floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
|
|
|
|
|
}
|
2011-06-13 14:43:54 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-21 19:18:36 +09:00
|
|
|
default:
|
|
|
|
|
if n := indexOfDebugStr(s.Name); n != -1 {
|
|
|
|
|
// Found it. Now find data section.
|
|
|
|
|
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
|
|
|
|
data := sdat[s.Value-sect.Addr:]
|
|
|
|
|
strdata[n] = string(data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if n := indexOfDebugStrlen(s.Name); n != -1 {
|
|
|
|
|
// Found it. Now find data section.
|
|
|
|
|
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
|
|
|
|
data := sdat[s.Value-sect.Addr:]
|
|
|
|
|
strlen := bo.Uint64(data[:8])
|
|
|
|
|
if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
|
|
|
|
|
fatalf("string literal too big")
|
|
|
|
|
}
|
|
|
|
|
strlens[n] = int(strlen)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
2011-06-13 14:43:54 -04:00
|
|
|
}
|
2010-11-01 17:52:26 -04:00
|
|
|
}
|
2017-04-21 19:18:36 +09:00
|
|
|
|
|
|
|
|
buildStrings()
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
2017-04-21 19:18:36 +09:00
|
|
|
return d, ints, floats, strs
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 22:42:42 -05:00
|
|
|
if f, err := elf.Open(gccTmp()); err == nil {
|
2013-06-18 23:20:17 +10:00
|
|
|
defer f.Close()
|
2011-06-13 14:43:54 -04:00
|
|
|
d, err := f.DWARF()
|
|
|
|
|
if err != nil {
|
2011-12-14 22:42:42 -05:00
|
|
|
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
|
2011-06-13 14:43:54 -04:00
|
|
|
}
|
2017-01-20 08:34:18 +09:00
|
|
|
bo := f.ByteOrder
|
2012-09-07 13:32:40 +10:00
|
|
|
symtab, err := f.Symbols()
|
|
|
|
|
if err == nil {
|
|
|
|
|
for i := range symtab {
|
|
|
|
|
s := &symtab[i]
|
2017-01-20 08:34:18 +09:00
|
|
|
switch {
|
|
|
|
|
case isDebugInts(s.Name):
|
|
|
|
|
// Found it. Now find data section.
|
|
|
|
|
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
|
|
|
|
data := sdat[s.Value-sect.Addr:]
|
|
|
|
|
ints = make([]int64, len(data)/8)
|
|
|
|
|
for i := range ints {
|
|
|
|
|
ints[i] = int64(bo.Uint64(data[i*8:]))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case isDebugFloats(s.Name):
|
2016-03-01 23:21:55 +00:00
|
|
|
// Found it. Now find data section.
|
2012-09-07 13:32:40 +10:00
|
|
|
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
2017-01-20 08:34:18 +09:00
|
|
|
data := sdat[s.Value-sect.Addr:]
|
|
|
|
|
floats = make([]float64, len(data)/8)
|
|
|
|
|
for i := range floats {
|
|
|
|
|
floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
|
|
|
|
|
}
|
2012-09-07 13:32:40 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-21 19:18:36 +09:00
|
|
|
default:
|
|
|
|
|
if n := indexOfDebugStr(s.Name); n != -1 {
|
|
|
|
|
// Found it. Now find data section.
|
|
|
|
|
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
|
|
|
|
data := sdat[s.Value-sect.Addr:]
|
|
|
|
|
strdata[n] = string(data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if n := indexOfDebugStrlen(s.Name); n != -1 {
|
|
|
|
|
// Found it. Now find data section.
|
|
|
|
|
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
|
|
|
|
data := sdat[s.Value-sect.Addr:]
|
|
|
|
|
strlen := bo.Uint64(data[:8])
|
|
|
|
|
if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
|
|
|
|
|
fatalf("string literal too big")
|
|
|
|
|
}
|
|
|
|
|
strlens[n] = int(strlen)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
2012-09-07 13:32:40 +10:00
|
|
|
}
|
|
|
|
|
}
|
2017-04-21 19:18:36 +09:00
|
|
|
|
|
|
|
|
buildStrings()
|
2012-09-07 13:32:40 +10:00
|
|
|
}
|
2017-04-21 19:18:36 +09:00
|
|
|
return d, ints, floats, strs
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
2011-06-13 14:43:54 -04:00
|
|
|
|
2011-12-14 22:42:42 -05:00
|
|
|
if f, err := pe.Open(gccTmp()); err == nil {
|
2013-06-18 23:20:17 +10:00
|
|
|
defer f.Close()
|
2011-06-13 14:43:54 -04:00
|
|
|
d, err := f.DWARF()
|
|
|
|
|
if err != nil {
|
2011-12-14 22:42:42 -05:00
|
|
|
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
|
2011-06-13 14:43:54 -04:00
|
|
|
}
|
2017-01-20 08:34:18 +09:00
|
|
|
bo := binary.LittleEndian
|
2012-09-22 17:57:54 +10:00
|
|
|
for _, s := range f.Symbols {
|
2017-01-20 08:34:18 +09:00
|
|
|
switch {
|
|
|
|
|
case isDebugInts(s.Name):
|
|
|
|
|
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if s.Value < sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
|
|
|
|
data := sdat[s.Value:]
|
|
|
|
|
ints = make([]int64, len(data)/8)
|
|
|
|
|
for i := range ints {
|
|
|
|
|
ints[i] = int64(bo.Uint64(data[i*8:]))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case isDebugFloats(s.Name):
|
2012-09-22 17:57:54 +10:00
|
|
|
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if s.Value < sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
2017-01-20 08:34:18 +09:00
|
|
|
data := sdat[s.Value:]
|
|
|
|
|
floats = make([]float64, len(data)/8)
|
|
|
|
|
for i := range floats {
|
|
|
|
|
floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
|
|
|
|
|
}
|
2012-09-22 17:57:54 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-21 19:18:36 +09:00
|
|
|
default:
|
|
|
|
|
if n := indexOfDebugStr(s.Name); n != -1 {
|
|
|
|
|
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if s.Value < sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
|
|
|
|
data := sdat[s.Value:]
|
|
|
|
|
strdata[n] = string(data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if n := indexOfDebugStrlen(s.Name); n != -1 {
|
|
|
|
|
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
|
|
|
|
|
sect := f.Sections[i]
|
|
|
|
|
if s.Value < sect.Size {
|
|
|
|
|
if sdat, err := sect.Data(); err == nil {
|
|
|
|
|
data := sdat[s.Value:]
|
|
|
|
|
strlen := bo.Uint64(data[:8])
|
|
|
|
|
if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
|
|
|
|
|
fatalf("string literal too big")
|
|
|
|
|
}
|
|
|
|
|
strlens[n] = int(strlen)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
2012-09-22 17:57:54 +10:00
|
|
|
}
|
|
|
|
|
}
|
2017-04-21 19:18:36 +09:00
|
|
|
|
|
|
|
|
buildStrings()
|
|
|
|
|
|
|
|
|
|
return d, ints, floats, strs
|
2011-06-13 14:43:54 -04:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 22:42:42 -05:00
|
|
|
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp())
|
2011-06-13 14:43:54 -04:00
|
|
|
panic("not reached")
|
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t
gmp.go:205:2: call mpz_init C value func(mpz_ptr) void
gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:221:2: call mpz_init C value func(mpz_ptr) void
gmp.go:227:7: call size_t C type size_t
gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void
gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t
gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void
gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void
gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void
gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int
gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char
gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void
gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void
gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void
gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void
gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void
gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int
gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void
R=r
DELTA=938 (628 added, 308 deleted, 2 changed)
OCL=34733
CL=34791
2009-09-18 11:52:00 -07:00
|
|
|
}
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// gccDefines runs gcc -E -dM -xc - over the C program stdin
|
|
|
|
|
// and returns the corresponding standard output, which is the
|
|
|
|
|
// #defines that gcc encountered while processing the input
|
|
|
|
|
// and its included files.
|
|
|
|
|
func (p *Package) gccDefines(stdin []byte) string {
|
2013-08-02 14:58:27 -04:00
|
|
|
base := append(p.gccBaseCmd(), "-E", "-dM", "-xc")
|
2011-06-07 16:59:35 +10:00
|
|
|
base = append(base, p.gccMachine()...)
|
2011-05-06 13:35:51 -07:00
|
|
|
stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
|
2010-07-14 17:17:53 -07:00
|
|
|
return stdout
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// gccErrors runs gcc over the C program stdin and returns
|
2016-03-01 23:21:55 +00:00
|
|
|
// the errors that gcc prints. That is, this function expects
|
2010-07-14 17:17:53 -07:00
|
|
|
// gcc to fail.
|
|
|
|
|
func (p *Package) gccErrors(stdin []byte) string {
|
|
|
|
|
// TODO(rsc): require failure
|
2011-05-06 13:35:51 -07:00
|
|
|
args := p.gccCmd()
|
2013-05-08 06:28:33 -07:00
|
|
|
|
2016-05-18 18:42:25 -07:00
|
|
|
// Optimization options can confuse the error messages; remove them.
|
|
|
|
|
nargs := make([]string, 0, len(args))
|
|
|
|
|
for _, arg := range args {
|
|
|
|
|
if !strings.HasPrefix(arg, "-O") {
|
|
|
|
|
nargs = append(nargs, arg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
if *debugGcc {
|
2016-05-18 18:42:25 -07:00
|
|
|
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
|
2010-07-14 17:17:53 -07:00
|
|
|
os.Stderr.Write(stdin)
|
|
|
|
|
fmt.Fprint(os.Stderr, "EOF\n")
|
|
|
|
|
}
|
2016-05-18 18:42:25 -07:00
|
|
|
stdout, stderr, _ := run(stdin, nargs)
|
2010-07-14 17:17:53 -07:00
|
|
|
if *debugGcc {
|
|
|
|
|
os.Stderr.Write(stdout)
|
|
|
|
|
os.Stderr.Write(stderr)
|
2010-01-11 13:05:26 -08:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
return string(stderr)
|
|
|
|
|
}
|
2010-01-11 13:05:26 -08:00
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// runGcc runs the gcc command line args with stdin on standard input.
|
|
|
|
|
// If the command exits with a non-zero exit status, runGcc prints
|
|
|
|
|
// details about what was run and exits.
|
|
|
|
|
// Otherwise runGcc returns the data written to standard output and standard error.
|
|
|
|
|
// Note that for some of the uses we expect useful data back
|
|
|
|
|
// on standard error, but for those uses gcc must still exit 0.
|
|
|
|
|
func runGcc(stdin []byte, args []string) (string, string) {
|
|
|
|
|
if *debugGcc {
|
|
|
|
|
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
|
|
|
|
|
os.Stderr.Write(stdin)
|
|
|
|
|
fmt.Fprint(os.Stderr, "EOF\n")
|
|
|
|
|
}
|
|
|
|
|
stdout, stderr, ok := run(stdin, args)
|
|
|
|
|
if *debugGcc {
|
|
|
|
|
os.Stderr.Write(stdout)
|
|
|
|
|
os.Stderr.Write(stderr)
|
|
|
|
|
}
|
2010-01-11 13:05:26 -08:00
|
|
|
if !ok {
|
2010-07-14 17:17:53 -07:00
|
|
|
os.Stderr.Write(stderr)
|
|
|
|
|
os.Exit(2)
|
2010-01-11 13:05:26 -08:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
return string(stdout), string(stderr)
|
2010-01-11 13:05:26 -08:00
|
|
|
}
|
|
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
// A typeConv is a translator from dwarf types to Go types
|
|
|
|
|
// with equivalent memory layout.
|
|
|
|
|
type typeConv struct {
|
|
|
|
|
// Cache of already-translated or in-progress types.
|
2016-03-21 00:12:18 +01:00
|
|
|
m map[dwarf.Type]*Type
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2014-08-05 18:16:56 -07:00
|
|
|
// Map from types to incomplete pointers to those types.
|
|
|
|
|
ptrs map[dwarf.Type][]*Type
|
2014-10-30 14:01:14 -04:00
|
|
|
// Keys of ptrs in insertion order (deterministic worklist)
|
|
|
|
|
ptrKeys []dwarf.Type
|
2014-08-05 18:16:56 -07:00
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
// Predeclared types.
|
2010-01-13 10:25:28 -08:00
|
|
|
bool ast.Expr
|
2009-12-15 15:33:31 -08:00
|
|
|
byte ast.Expr // denotes padding
|
|
|
|
|
int8, int16, int32, int64 ast.Expr
|
|
|
|
|
uint8, uint16, uint32, uint64, uintptr ast.Expr
|
|
|
|
|
float32, float64 ast.Expr
|
2011-01-19 14:30:57 -05:00
|
|
|
complex64, complex128 ast.Expr
|
2009-12-15 15:33:31 -08:00
|
|
|
void ast.Expr
|
|
|
|
|
string ast.Expr
|
2012-12-18 00:26:08 +08:00
|
|
|
goVoid ast.Expr // _Ctype_void, denotes C's void
|
2014-08-06 10:28:19 -07:00
|
|
|
goVoidPtr ast.Expr // unsafe.Pointer or *byte
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2009-12-15 15:33:31 -08:00
|
|
|
ptrSize int64
|
2012-09-24 14:58:57 -04:00
|
|
|
intSize int64
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
2010-12-13 13:20:04 -05:00
|
|
|
var tagGen int
|
2012-02-19 13:32:55 -05:00
|
|
|
var typedef = make(map[string]*Type)
|
2011-11-10 19:08:04 -05:00
|
|
|
var goIdent = make(map[string]*ast.Ident)
|
2010-12-13 13:20:04 -05:00
|
|
|
|
2016-11-14 15:51:30 -08:00
|
|
|
// unionWithPointer is true for a Go type that represents a C union (or class)
|
2016-11-14 15:51:30 -08:00
|
|
|
// that may contain a pointer. This is used for cgo pointer checking.
|
2016-11-14 15:51:30 -08:00
|
|
|
var unionWithPointer = make(map[ast.Expr]bool)
|
|
|
|
|
|
2012-09-24 14:58:57 -04:00
|
|
|
func (c *typeConv) Init(ptrSize, intSize int64) {
|
2009-12-15 15:33:31 -08:00
|
|
|
c.ptrSize = ptrSize
|
2012-09-24 14:58:57 -04:00
|
|
|
c.intSize = intSize
|
2009-12-15 15:33:31 -08:00
|
|
|
c.m = make(map[dwarf.Type]*Type)
|
2014-08-05 18:16:56 -07:00
|
|
|
c.ptrs = make(map[dwarf.Type][]*Type)
|
2010-01-13 10:25:28 -08:00
|
|
|
c.bool = c.Ident("bool")
|
2009-12-15 15:33:31 -08:00
|
|
|
c.byte = c.Ident("byte")
|
|
|
|
|
c.int8 = c.Ident("int8")
|
|
|
|
|
c.int16 = c.Ident("int16")
|
|
|
|
|
c.int32 = c.Ident("int32")
|
|
|
|
|
c.int64 = c.Ident("int64")
|
|
|
|
|
c.uint8 = c.Ident("uint8")
|
|
|
|
|
c.uint16 = c.Ident("uint16")
|
|
|
|
|
c.uint32 = c.Ident("uint32")
|
|
|
|
|
c.uint64 = c.Ident("uint64")
|
|
|
|
|
c.uintptr = c.Ident("uintptr")
|
|
|
|
|
c.float32 = c.Ident("float32")
|
|
|
|
|
c.float64 = c.Ident("float64")
|
2011-01-19 14:30:57 -05:00
|
|
|
c.complex64 = c.Ident("complex64")
|
|
|
|
|
c.complex128 = c.Ident("complex128")
|
2009-12-15 15:33:31 -08:00
|
|
|
c.void = c.Ident("void")
|
|
|
|
|
c.string = c.Ident("string")
|
2012-12-18 00:26:08 +08:00
|
|
|
c.goVoid = c.Ident("_Ctype_void")
|
2014-08-06 10:28:19 -07:00
|
|
|
|
|
|
|
|
// Normally cgo translates void* to unsafe.Pointer,
|
2015-01-07 13:23:45 -08:00
|
|
|
// but for historical reasons -godefs uses *byte instead.
|
|
|
|
|
if *godefs {
|
2014-08-06 10:28:19 -07:00
|
|
|
c.goVoidPtr = &ast.StarExpr{X: c.byte}
|
|
|
|
|
} else {
|
|
|
|
|
c.goVoidPtr = c.Ident("unsafe.Pointer")
|
|
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// base strips away qualifiers and typedefs to get the underlying type
|
|
|
|
|
func base(dt dwarf.Type) dwarf.Type {
|
|
|
|
|
for {
|
|
|
|
|
if d, ok := dt.(*dwarf.QualType); ok {
|
2009-12-15 15:33:31 -08:00
|
|
|
dt = d.Type
|
|
|
|
|
continue
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
if d, ok := dt.(*dwarf.TypedefType); ok {
|
2009-12-15 15:33:31 -08:00
|
|
|
dt = d.Type
|
|
|
|
|
continue
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
break
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
return dt
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
2016-11-16 09:55:24 -08:00
|
|
|
// unqual strips away qualifiers from a DWARF type.
|
|
|
|
|
// In general we don't care about top-level qualifiers.
|
|
|
|
|
func unqual(dt dwarf.Type) dwarf.Type {
|
|
|
|
|
for {
|
|
|
|
|
if d, ok := dt.(*dwarf.QualType); ok {
|
|
|
|
|
dt = d.Type
|
|
|
|
|
} else {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return dt
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
// Map from dwarf text names to aliases we use in package "C".
|
2010-07-14 17:17:53 -07:00
|
|
|
var dwarfToName = map[string]string{
|
2010-03-02 13:46:51 -08:00
|
|
|
"long int": "long",
|
|
|
|
|
"long unsigned int": "ulong",
|
|
|
|
|
"unsigned int": "uint",
|
|
|
|
|
"short unsigned int": "ushort",
|
2015-11-25 12:40:43 -08:00
|
|
|
"unsigned short": "ushort", // Used by Clang; issue 13129.
|
2010-03-02 13:46:51 -08:00
|
|
|
"short int": "short",
|
|
|
|
|
"long long int": "longlong",
|
2009-09-24 11:43:19 -07:00
|
|
|
"long long unsigned int": "ulonglong",
|
2010-03-02 13:46:51 -08:00
|
|
|
"signed char": "schar",
|
2015-12-16 00:06:45 -05:00
|
|
|
"unsigned char": "uchar",
|
2009-11-05 15:33:26 -08:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2011-02-08 23:50:14 -05:00
|
|
|
const signedDelta = 64
|
|
|
|
|
|
2016-03-01 23:21:55 +00:00
|
|
|
// String returns the current type representation. Format arguments
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
// are assembled within this method so that any changes in mutable
|
|
|
|
|
// values are taken into account.
|
|
|
|
|
func (tr *TypeRepr) String() string {
|
|
|
|
|
if len(tr.Repr) == 0 {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
if len(tr.FormatArgs) == 0 {
|
|
|
|
|
return tr.Repr
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 15:44:42 -08:00
|
|
|
// Empty reports whether the result of String would be "".
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
func (tr *TypeRepr) Empty() bool {
|
|
|
|
|
return len(tr.Repr) == 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set modifies the type representation.
|
|
|
|
|
// If fargs are provided, repr is used as a format for fmt.Sprintf.
|
|
|
|
|
// Otherwise, repr is used unprocessed as the type representation.
|
|
|
|
|
func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
|
|
|
|
|
tr.Repr = repr
|
|
|
|
|
tr.FormatArgs = fargs
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-05 18:16:56 -07:00
|
|
|
// FinishType completes any outstanding type mapping work.
|
2014-08-06 10:28:19 -07:00
|
|
|
// In particular, it resolves incomplete pointer types.
|
2014-08-05 18:16:56 -07:00
|
|
|
func (c *typeConv) FinishType(pos token.Pos) {
|
|
|
|
|
// Completing one pointer type might produce more to complete.
|
|
|
|
|
// Keep looping until they're all done.
|
2014-10-30 14:01:14 -04:00
|
|
|
for len(c.ptrKeys) > 0 {
|
|
|
|
|
dtype := c.ptrKeys[0]
|
|
|
|
|
c.ptrKeys = c.ptrKeys[1:]
|
|
|
|
|
|
|
|
|
|
// Note Type might invalidate c.ptrs[dtype].
|
|
|
|
|
t := c.Type(dtype, pos)
|
|
|
|
|
for _, ptr := range c.ptrs[dtype] {
|
|
|
|
|
ptr.Go.(*ast.StarExpr).X = t.Go
|
|
|
|
|
ptr.C.Set("%s*", t.C)
|
2014-08-05 18:16:56 -07:00
|
|
|
}
|
2014-10-30 14:01:14 -04:00
|
|
|
c.ptrs[dtype] = nil // retain the map key
|
2014-08-05 18:16:56 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
// Type returns a *Type with the same memory layout as
|
|
|
|
|
// dtype when used as the type of a variable or a struct field.
|
2012-02-06 20:38:54 +01:00
|
|
|
func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
2009-09-24 11:43:19 -07:00
|
|
|
if t, ok := c.m[dtype]; ok {
|
|
|
|
|
if t.Go == nil {
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
return t
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
2009-12-15 15:33:31 -08:00
|
|
|
t := new(Type)
|
2013-11-07 15:24:51 -05:00
|
|
|
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Align = -1
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
t.C = &TypeRepr{Repr: dtype.Common().Name}
|
2009-12-15 15:33:31 -08:00
|
|
|
c.m[dtype] = t
|
2010-07-14 17:17:53 -07:00
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
switch dt := dtype.(type) {
|
|
|
|
|
default:
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected type: %s", lineno(pos), dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
case *dwarf.AddrType:
|
|
|
|
|
if t.Size != c.ptrSize {
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Go = c.uintptr
|
|
|
|
|
t.Align = t.Size
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
case *dwarf.ArrayType:
|
|
|
|
|
if dt.StrideBitSize > 0 {
|
|
|
|
|
// Cannot represent bit-sized elements in Go.
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Go = c.Opaque(t.Size)
|
|
|
|
|
break
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
cmd/cgo, debug/dwarf: fix translation of zero-size arrays
In cgo, now that recursive calls to typeConv.Type() always work,
we can more robustly calculate the array sizes based on the size
of our element type.
Also, in debug/dwarf, the decision to call zeroType is made
based on a type's usage within a particular struct, but dwarf.Type
values are cached in typeCache, so the modification might affect
uses of the type in other structs. Current compilers don't appear
to share DWARF type entries for "[]foo" and "[0]foo", but they also
don't consistently share type entries in other cases. Arguably
modifying the types is an improvement in some cases, but varying
translated types according to compiler whims seems like a bad idea.
Lastly, also in debug/dwarf, zeroType only needs to rewrite the
top-level dimension, and only if the rest of the array size is
non-zero.
Fixes #8428.
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/127980043
2014-08-13 11:16:30 -07:00
|
|
|
count := dt.Count
|
|
|
|
|
if count == -1 {
|
|
|
|
|
// Indicates flexible array member, which Go doesn't support.
|
|
|
|
|
// Translate to zero-length array instead.
|
|
|
|
|
count = 0
|
|
|
|
|
}
|
2012-02-06 20:38:54 +01:00
|
|
|
sub := c.Type(dt.Type, pos)
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Align = sub.Align
|
2014-08-05 18:16:56 -07:00
|
|
|
t.Go = &ast.ArrayType{
|
cmd/cgo, debug/dwarf: fix translation of zero-size arrays
In cgo, now that recursive calls to typeConv.Type() always work,
we can more robustly calculate the array sizes based on the size
of our element type.
Also, in debug/dwarf, the decision to call zeroType is made
based on a type's usage within a particular struct, but dwarf.Type
values are cached in typeCache, so the modification might affect
uses of the type in other structs. Current compilers don't appear
to share DWARF type entries for "[]foo" and "[0]foo", but they also
don't consistently share type entries in other cases. Arguably
modifying the types is an improvement in some cases, but varying
translated types according to compiler whims seems like a bad idea.
Lastly, also in debug/dwarf, zeroType only needs to rewrite the
top-level dimension, and only if the rest of the array size is
non-zero.
Fixes #8428.
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/127980043
2014-08-13 11:16:30 -07:00
|
|
|
Len: c.intExpr(count),
|
2014-08-05 18:16:56 -07:00
|
|
|
Elt: sub.Go,
|
|
|
|
|
}
|
cmd/cgo, debug/dwarf: fix translation of zero-size arrays
In cgo, now that recursive calls to typeConv.Type() always work,
we can more robustly calculate the array sizes based on the size
of our element type.
Also, in debug/dwarf, the decision to call zeroType is made
based on a type's usage within a particular struct, but dwarf.Type
values are cached in typeCache, so the modification might affect
uses of the type in other structs. Current compilers don't appear
to share DWARF type entries for "[]foo" and "[0]foo", but they also
don't consistently share type entries in other cases. Arguably
modifying the types is an improvement in some cases, but varying
translated types according to compiler whims seems like a bad idea.
Lastly, also in debug/dwarf, zeroType only needs to rewrite the
top-level dimension, and only if the rest of the array size is
non-zero.
Fixes #8428.
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/127980043
2014-08-13 11:16:30 -07:00
|
|
|
// Recalculate t.Size now that we know sub.Size.
|
|
|
|
|
t.Size = count * sub.Size
|
2013-10-22 18:33:23 -04:00
|
|
|
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2010-01-13 10:25:28 -08:00
|
|
|
case *dwarf.BoolType:
|
|
|
|
|
t.Go = c.bool
|
2012-11-21 13:04:38 -08:00
|
|
|
t.Align = 1
|
2010-01-13 10:25:28 -08:00
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
case *dwarf.CharType:
|
|
|
|
|
if t.Size != 1 {
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Go = c.int8
|
|
|
|
|
t.Align = 1
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
case *dwarf.EnumType:
|
2011-02-08 23:50:14 -05:00
|
|
|
if t.Align = t.Size; t.Align >= c.ptrSize {
|
|
|
|
|
t.Align = c.ptrSize
|
|
|
|
|
}
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
t.C.Set("enum " + dt.EnumName)
|
2011-02-08 23:50:14 -05:00
|
|
|
signed := 0
|
|
|
|
|
t.EnumValues = make(map[string]int64)
|
|
|
|
|
for _, ev := range dt.Val {
|
|
|
|
|
t.EnumValues[ev.Name] = ev.Val
|
|
|
|
|
if ev.Val < 0 {
|
|
|
|
|
signed = signedDelta
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
switch t.Size + int64(signed) {
|
2009-09-24 11:43:19 -07:00
|
|
|
default:
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
case 1:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.uint8
|
2009-09-24 11:43:19 -07:00
|
|
|
case 2:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.uint16
|
2009-09-24 11:43:19 -07:00
|
|
|
case 4:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.uint32
|
2009-09-24 11:43:19 -07:00
|
|
|
case 8:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.uint64
|
2011-02-08 23:50:14 -05:00
|
|
|
case 1 + signedDelta:
|
|
|
|
|
t.Go = c.int8
|
|
|
|
|
case 2 + signedDelta:
|
|
|
|
|
t.Go = c.int16
|
|
|
|
|
case 4 + signedDelta:
|
|
|
|
|
t.Go = c.int32
|
|
|
|
|
case 8 + signedDelta:
|
|
|
|
|
t.Go = c.int64
|
2009-12-15 21:24:17 -08:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
case *dwarf.FloatType:
|
|
|
|
|
switch t.Size {
|
|
|
|
|
default:
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
case 4:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.float32
|
2009-09-24 11:43:19 -07:00
|
|
|
case 8:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.float64
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
if t.Align = t.Size; t.Align >= c.ptrSize {
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Align = c.ptrSize
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
2011-01-19 14:30:57 -05:00
|
|
|
case *dwarf.ComplexType:
|
|
|
|
|
switch t.Size {
|
|
|
|
|
default:
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype)
|
2011-01-19 14:30:57 -05:00
|
|
|
case 8:
|
|
|
|
|
t.Go = c.complex64
|
|
|
|
|
case 16:
|
|
|
|
|
t.Go = c.complex128
|
|
|
|
|
}
|
2016-02-21 02:28:37 -08:00
|
|
|
if t.Align = t.Size / 2; t.Align >= c.ptrSize {
|
2011-01-19 14:30:57 -05:00
|
|
|
t.Align = c.ptrSize
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
case *dwarf.FuncType:
|
|
|
|
|
// No attempt at translation: would enable calls
|
|
|
|
|
// directly between worlds, but we need to moderate those.
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Go = c.uintptr
|
|
|
|
|
t.Align = c.ptrSize
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
case *dwarf.IntType:
|
|
|
|
|
if dt.BitSize > 0 {
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
switch t.Size {
|
|
|
|
|
default:
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
case 1:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.int8
|
2009-09-24 11:43:19 -07:00
|
|
|
case 2:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.int16
|
2009-09-24 11:43:19 -07:00
|
|
|
case 4:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.int32
|
2009-09-24 11:43:19 -07:00
|
|
|
case 8:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.int64
|
2015-10-18 13:32:11 -04:00
|
|
|
case 16:
|
|
|
|
|
t.Go = &ast.ArrayType{
|
|
|
|
|
Len: c.intExpr(t.Size),
|
|
|
|
|
Elt: c.uint8,
|
|
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
if t.Align = t.Size; t.Align >= c.ptrSize {
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Align = c.ptrSize
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case *dwarf.PtrType:
|
cmd/cgo, debug/dwarf: fix translation of zero-size arrays
In cgo, now that recursive calls to typeConv.Type() always work,
we can more robustly calculate the array sizes based on the size
of our element type.
Also, in debug/dwarf, the decision to call zeroType is made
based on a type's usage within a particular struct, but dwarf.Type
values are cached in typeCache, so the modification might affect
uses of the type in other structs. Current compilers don't appear
to share DWARF type entries for "[]foo" and "[0]foo", but they also
don't consistently share type entries in other cases. Arguably
modifying the types is an improvement in some cases, but varying
translated types according to compiler whims seems like a bad idea.
Lastly, also in debug/dwarf, zeroType only needs to rewrite the
top-level dimension, and only if the rest of the array size is
non-zero.
Fixes #8428.
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/127980043
2014-08-13 11:16:30 -07:00
|
|
|
// Clang doesn't emit DW_AT_byte_size for pointer types.
|
|
|
|
|
if t.Size != c.ptrSize && t.Size != -1 {
|
|
|
|
|
fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype)
|
|
|
|
|
}
|
|
|
|
|
t.Size = c.ptrSize
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Align = c.ptrSize
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
|
2014-08-06 10:28:19 -07:00
|
|
|
t.Go = c.goVoidPtr
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
t.C.Set("void*")
|
2016-12-13 14:29:57 -08:00
|
|
|
dq := dt.Type
|
|
|
|
|
for {
|
|
|
|
|
if d, ok := dq.(*dwarf.QualType); ok {
|
|
|
|
|
t.C.Set(d.Qual + " " + t.C.String())
|
|
|
|
|
dq = d.Type
|
|
|
|
|
} else {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
break
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
2014-08-05 18:16:56 -07:00
|
|
|
// Placeholder initialization; completed in FinishType.
|
|
|
|
|
t.Go = &ast.StarExpr{}
|
|
|
|
|
t.C.Set("<incomplete>*")
|
2014-10-30 14:01:14 -04:00
|
|
|
if _, ok := c.ptrs[dt.Type]; !ok {
|
|
|
|
|
c.ptrKeys = append(c.ptrKeys, dt.Type)
|
|
|
|
|
}
|
2014-08-05 18:16:56 -07:00
|
|
|
c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
case *dwarf.QualType:
|
2016-11-10 14:34:32 -08:00
|
|
|
t1 := c.Type(dt.Type, pos)
|
|
|
|
|
t.Size = t1.Size
|
|
|
|
|
t.Align = t1.Align
|
|
|
|
|
t.Go = t1.Go
|
2016-11-14 15:51:30 -08:00
|
|
|
if unionWithPointer[t1.Go] {
|
|
|
|
|
unionWithPointer[t.Go] = true
|
|
|
|
|
}
|
2016-11-10 14:34:32 -08:00
|
|
|
t.EnumValues = nil
|
|
|
|
|
t.Typedef = ""
|
|
|
|
|
t.C.Set("%s "+dt.Qual, t1.C)
|
2009-12-15 15:33:31 -08:00
|
|
|
return t
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
case *dwarf.StructType:
|
|
|
|
|
// Convert to Go struct, being careful about alignment.
|
|
|
|
|
// Have to give it a name to simulate C "struct foo" references.
|
2009-12-15 15:33:31 -08:00
|
|
|
tag := dt.StructName
|
cmd/cgo: given typedef struct S T, make C.T and C.struct_S interchangeable
For incomplete struct S, C.T and C.struct_S were interchangeable in Go 1.2
and earlier, because all incomplete types were interchangeable
(even C.struct_S1 and C.struct_S2).
CL 76450043, which fixed issue 7409, made different incomplete types
different from Go's point of view, so that they were no longer completely
interchangeable.
However, imprecision about C.T and C.struct_S - really the same
underlying C type - is the one behavior enabled by the bug that
is most likely to be depended on by existing cgo code.
Explicitly allow it, to keep that code working.
Fixes #7786.
LGTM=iant, r
R=golang-codereviews, iant, r
CC=golang-codereviews
https://golang.org/cl/98580046
2014-05-28 14:04:31 -04:00
|
|
|
if dt.ByteSize < 0 && tag == "" { // opaque unnamed struct - should not be possible
|
|
|
|
|
break
|
|
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
if tag == "" {
|
2010-12-13 13:20:04 -05:00
|
|
|
tag = "__" + strconv.Itoa(tagGen)
|
|
|
|
|
tagGen++
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
} else if t.C.Empty() {
|
|
|
|
|
t.C.Set(dt.Kind + " " + tag)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Go = name // publish before recursive calls
|
2011-11-10 19:08:04 -05:00
|
|
|
goIdent[name.Name] = name
|
cmd/cgo: given typedef struct S T, make C.T and C.struct_S interchangeable
For incomplete struct S, C.T and C.struct_S were interchangeable in Go 1.2
and earlier, because all incomplete types were interchangeable
(even C.struct_S1 and C.struct_S2).
CL 76450043, which fixed issue 7409, made different incomplete types
different from Go's point of view, so that they were no longer completely
interchangeable.
However, imprecision about C.T and C.struct_S - really the same
underlying C type - is the one behavior enabled by the bug that
is most likely to be depended on by existing cgo code.
Explicitly allow it, to keep that code working.
Fixes #7786.
LGTM=iant, r
R=golang-codereviews, iant, r
CC=golang-codereviews
https://golang.org/cl/98580046
2014-05-28 14:04:31 -04:00
|
|
|
if dt.ByteSize < 0 {
|
|
|
|
|
// Size calculation in c.Struct/c.Opaque will die with size=-1 (unknown),
|
|
|
|
|
// so execute the basic things that the struct case would do
|
|
|
|
|
// other than try to determine a Go representation.
|
|
|
|
|
tt := *t
|
|
|
|
|
tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}}
|
|
|
|
|
tt.Go = c.Ident("struct{}")
|
|
|
|
|
typedef[name.Name] = &tt
|
|
|
|
|
break
|
|
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
switch dt.Kind {
|
2012-09-22 07:25:41 +10:00
|
|
|
case "class", "union":
|
2012-02-22 17:10:25 -02:00
|
|
|
t.Go = c.Opaque(t.Size)
|
2016-11-14 15:51:30 -08:00
|
|
|
if c.dwarfHasPointer(dt, pos) {
|
|
|
|
|
unionWithPointer[t.Go] = true
|
|
|
|
|
}
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
if t.C.Empty() {
|
2013-10-22 18:33:23 -04:00
|
|
|
t.C.Set("__typeof__(unsigned char[%d])", t.Size)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2012-09-22 07:25:41 +10:00
|
|
|
t.Align = 1 // TODO: should probably base this on field alignment.
|
2012-02-19 13:32:55 -05:00
|
|
|
typedef[name.Name] = t
|
2009-09-24 11:43:19 -07:00
|
|
|
case "struct":
|
2012-02-06 20:38:54 +01:00
|
|
|
g, csyntax, align := c.Struct(dt, pos)
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
if t.C.Empty() {
|
|
|
|
|
t.C.Set(csyntax)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Align = align
|
2012-02-19 13:32:55 -05:00
|
|
|
tt := *t
|
|
|
|
|
if tag != "" {
|
|
|
|
|
tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
|
|
|
|
|
}
|
|
|
|
|
tt.Go = g
|
|
|
|
|
typedef[name.Name] = &tt
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case *dwarf.TypedefType:
|
|
|
|
|
// Record typedef for printing.
|
|
|
|
|
if dt.Name == "_GoString_" {
|
|
|
|
|
// Special C name for Go string type.
|
|
|
|
|
// Knows string layout used by compilers: pointer plus length,
|
|
|
|
|
// which rounds up to 2 pointers after alignment.
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Go = c.string
|
|
|
|
|
t.Size = c.ptrSize * 2
|
|
|
|
|
t.Align = c.ptrSize
|
|
|
|
|
break
|
|
|
|
|
}
|
2011-07-28 12:39:50 -04:00
|
|
|
if dt.Name == "_GoBytes_" {
|
|
|
|
|
// Special C name for Go []byte type.
|
|
|
|
|
// Knows slice layout used by compilers: pointer, length, cap.
|
|
|
|
|
t.Go = c.Ident("[]byte")
|
|
|
|
|
t.Size = c.ptrSize + 4 + 4
|
|
|
|
|
t.Align = c.ptrSize
|
|
|
|
|
break
|
|
|
|
|
}
|
2011-11-10 19:08:04 -05:00
|
|
|
name := c.Ident("_Ctype_" + dt.Name)
|
|
|
|
|
goIdent[name.Name] = name
|
2012-02-06 20:38:54 +01:00
|
|
|
sub := c.Type(dt.Type, pos)
|
2014-08-05 18:16:56 -07:00
|
|
|
t.Go = name
|
2016-11-14 15:51:30 -08:00
|
|
|
if unionWithPointer[sub.Go] {
|
|
|
|
|
unionWithPointer[t.Go] = true
|
|
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Size = sub.Size
|
|
|
|
|
t.Align = sub.Align
|
2014-06-02 12:55:43 -07:00
|
|
|
oldType := typedef[name.Name]
|
|
|
|
|
if oldType == nil {
|
2012-02-19 13:32:55 -05:00
|
|
|
tt := *t
|
|
|
|
|
tt.Go = sub.Go
|
|
|
|
|
typedef[name.Name] = &tt
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
cmd/cgo: given typedef struct S T, make C.T and C.struct_S interchangeable
For incomplete struct S, C.T and C.struct_S were interchangeable in Go 1.2
and earlier, because all incomplete types were interchangeable
(even C.struct_S1 and C.struct_S2).
CL 76450043, which fixed issue 7409, made different incomplete types
different from Go's point of view, so that they were no longer completely
interchangeable.
However, imprecision about C.T and C.struct_S - really the same
underlying C type - is the one behavior enabled by the bug that
is most likely to be depended on by existing cgo code.
Explicitly allow it, to keep that code working.
Fixes #7786.
LGTM=iant, r
R=golang-codereviews, iant, r
CC=golang-codereviews
https://golang.org/cl/98580046
2014-05-28 14:04:31 -04:00
|
|
|
|
|
|
|
|
// If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo",
|
|
|
|
|
// use that as the Go form for this typedef too, so that the typedef will be interchangeable
|
|
|
|
|
// with the base type.
|
2015-01-07 13:23:45 -08:00
|
|
|
// In -godefs mode, do this for all typedefs.
|
|
|
|
|
if isStructUnionClass(sub.Go) || *godefs {
|
2011-11-10 19:08:04 -05:00
|
|
|
t.Go = sub.Go
|
2014-06-02 12:55:43 -07:00
|
|
|
|
2014-06-05 10:42:03 -07:00
|
|
|
if isStructUnionClass(sub.Go) {
|
|
|
|
|
// Use the typedef name for C code.
|
|
|
|
|
typedef[sub.Go.(*ast.Ident).Name].C = t.C
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-02 12:55:43 -07:00
|
|
|
// If we've seen this typedef before, and it
|
|
|
|
|
// was an anonymous struct/union/class before
|
|
|
|
|
// too, use the old definition.
|
|
|
|
|
// TODO: it would be safer to only do this if
|
|
|
|
|
// we verify that the types are the same.
|
|
|
|
|
if oldType != nil && isStructUnionClass(oldType.Go) {
|
|
|
|
|
t.Go = oldType.Go
|
|
|
|
|
}
|
2011-11-10 19:08:04 -05:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
case *dwarf.UcharType:
|
|
|
|
|
if t.Size != 1 {
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
t.Go = c.uint8
|
|
|
|
|
t.Align = 1
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
case *dwarf.UintType:
|
|
|
|
|
if dt.BitSize > 0 {
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
switch t.Size {
|
|
|
|
|
default:
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
case 1:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.uint8
|
2009-09-24 11:43:19 -07:00
|
|
|
case 2:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.uint16
|
2009-09-24 11:43:19 -07:00
|
|
|
case 4:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.uint32
|
2009-09-24 11:43:19 -07:00
|
|
|
case 8:
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Go = c.uint64
|
2015-10-18 13:32:11 -04:00
|
|
|
case 16:
|
|
|
|
|
t.Go = &ast.ArrayType{
|
|
|
|
|
Len: c.intExpr(t.Size),
|
|
|
|
|
Elt: c.uint8,
|
|
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
if t.Align = t.Size; t.Align >= c.ptrSize {
|
2009-11-09 12:07:39 -08:00
|
|
|
t.Align = c.ptrSize
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case *dwarf.VoidType:
|
2012-12-18 00:26:08 +08:00
|
|
|
t.Go = c.goVoid
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
t.C.Set("void")
|
2012-12-18 00:26:08 +08:00
|
|
|
t.Align = 1
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch dtype.(type) {
|
2015-11-25 13:09:14 -08:00
|
|
|
case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.ComplexType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
|
2009-12-15 15:33:31 -08:00
|
|
|
s := dtype.Common().Name
|
2009-09-24 11:43:19 -07:00
|
|
|
if s != "" {
|
2010-07-14 17:17:53 -07:00
|
|
|
if ss, ok := dwarfToName[s]; ok {
|
2009-11-09 12:07:39 -08:00
|
|
|
s = ss
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2017-09-27 23:30:43 +05:30
|
|
|
s = strings.Replace(s, " ", "", -1)
|
2010-07-14 17:17:53 -07:00
|
|
|
name := c.Ident("_Ctype_" + s)
|
2012-02-19 13:32:55 -05:00
|
|
|
tt := *t
|
|
|
|
|
typedef[name.Name] = &tt
|
2015-01-07 13:23:45 -08:00
|
|
|
if !*godefs {
|
2011-11-10 19:08:04 -05:00
|
|
|
t.Go = name
|
|
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
cmd/cgo, debug/dwarf: fix translation of zero-size arrays
In cgo, now that recursive calls to typeConv.Type() always work,
we can more robustly calculate the array sizes based on the size
of our element type.
Also, in debug/dwarf, the decision to call zeroType is made
based on a type's usage within a particular struct, but dwarf.Type
values are cached in typeCache, so the modification might affect
uses of the type in other structs. Current compilers don't appear
to share DWARF type entries for "[]foo" and "[0]foo", but they also
don't consistently share type entries in other cases. Arguably
modifying the types is an improvement in some cases, but varying
translated types according to compiler whims seems like a bad idea.
Lastly, also in debug/dwarf, zeroType only needs to rewrite the
top-level dimension, and only if the rest of the array size is
non-zero.
Fixes #8428.
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/127980043
2014-08-13 11:16:30 -07:00
|
|
|
if t.Size < 0 {
|
|
|
|
|
// Unsized types are [0]byte, unless they're typedefs of other types
|
|
|
|
|
// or structs with tags.
|
|
|
|
|
// if so, use the name we've already defined.
|
|
|
|
|
t.Size = 0
|
|
|
|
|
switch dt := dtype.(type) {
|
|
|
|
|
case *dwarf.TypedefType:
|
|
|
|
|
// ok
|
|
|
|
|
case *dwarf.StructType:
|
|
|
|
|
if dt.StructName != "" {
|
|
|
|
|
break
|
2013-11-07 15:24:51 -05:00
|
|
|
}
|
cmd/cgo, debug/dwarf: fix translation of zero-size arrays
In cgo, now that recursive calls to typeConv.Type() always work,
we can more robustly calculate the array sizes based on the size
of our element type.
Also, in debug/dwarf, the decision to call zeroType is made
based on a type's usage within a particular struct, but dwarf.Type
values are cached in typeCache, so the modification might affect
uses of the type in other structs. Current compilers don't appear
to share DWARF type entries for "[]foo" and "[0]foo", but they also
don't consistently share type entries in other cases. Arguably
modifying the types is an improvement in some cases, but varying
translated types according to compiler whims seems like a bad idea.
Lastly, also in debug/dwarf, zeroType only needs to rewrite the
top-level dimension, and only if the rest of the array size is
non-zero.
Fixes #8428.
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/127980043
2014-08-13 11:16:30 -07:00
|
|
|
t.Go = c.Opaque(0)
|
|
|
|
|
default:
|
|
|
|
|
t.Go = c.Opaque(0)
|
|
|
|
|
}
|
|
|
|
|
if t.C.Empty() {
|
|
|
|
|
t.C.Set("void")
|
2013-11-07 15:24:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
if t.C.Empty() {
|
2012-02-06 20:38:54 +01:00
|
|
|
fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
2009-12-15 15:33:31 -08:00
|
|
|
return t
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
cmd/cgo: given typedef struct S T, make C.T and C.struct_S interchangeable
For incomplete struct S, C.T and C.struct_S were interchangeable in Go 1.2
and earlier, because all incomplete types were interchangeable
(even C.struct_S1 and C.struct_S2).
CL 76450043, which fixed issue 7409, made different incomplete types
different from Go's point of view, so that they were no longer completely
interchangeable.
However, imprecision about C.T and C.struct_S - really the same
underlying C type - is the one behavior enabled by the bug that
is most likely to be depended on by existing cgo code.
Explicitly allow it, to keep that code working.
Fixes #7786.
LGTM=iant, r
R=golang-codereviews, iant, r
CC=golang-codereviews
https://golang.org/cl/98580046
2014-05-28 14:04:31 -04:00
|
|
|
// isStructUnionClass reports whether the type described by the Go syntax x
|
|
|
|
|
// is a struct, union, or class with a tag.
|
|
|
|
|
func isStructUnionClass(x ast.Expr) bool {
|
|
|
|
|
id, ok := x.(*ast.Ident)
|
|
|
|
|
if !ok {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
name := id.Name
|
|
|
|
|
return strings.HasPrefix(name, "_Ctype_struct_") ||
|
|
|
|
|
strings.HasPrefix(name, "_Ctype_union_") ||
|
|
|
|
|
strings.HasPrefix(name, "_Ctype_class_")
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
// FuncArg returns a Go type with the same memory layout as
|
|
|
|
|
// dtype when used as the type of a C function argument.
|
2012-02-06 20:38:54 +01:00
|
|
|
func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
|
2016-11-16 09:55:24 -08:00
|
|
|
t := c.Type(unqual(dtype), pos)
|
2009-09-24 11:43:19 -07:00
|
|
|
switch dt := dtype.(type) {
|
|
|
|
|
case *dwarf.ArrayType:
|
|
|
|
|
// Arrays are passed implicitly as pointers in C.
|
|
|
|
|
// In Go, we must be explicit.
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
tr := &TypeRepr{}
|
|
|
|
|
tr.Set("%s*", t.C)
|
2009-09-24 11:43:19 -07:00
|
|
|
return &Type{
|
2010-03-02 13:46:51 -08:00
|
|
|
Size: c.ptrSize,
|
2009-09-24 11:43:19 -07:00
|
|
|
Align: c.ptrSize,
|
2010-03-02 13:46:51 -08:00
|
|
|
Go: &ast.StarExpr{X: t.Go},
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
C: tr,
|
2009-11-09 12:07:39 -08:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
case *dwarf.TypedefType:
|
|
|
|
|
// C has much more relaxed rules than Go for
|
2016-03-01 23:21:55 +00:00
|
|
|
// implicit type conversions. When the parameter
|
2009-09-24 11:43:19 -07:00
|
|
|
// is type T defined as *X, simulate a little of the
|
|
|
|
|
// laxness of C by making the argument *X instead of T.
|
|
|
|
|
if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
|
2009-11-17 23:42:21 -08:00
|
|
|
// Unless the typedef happens to point to void* since
|
|
|
|
|
// Go has special rules around using unsafe.Pointer.
|
2012-02-19 13:32:55 -05:00
|
|
|
if _, void := base(ptr.Type).(*dwarf.VoidType); void {
|
|
|
|
|
break
|
2009-11-17 23:42:21 -08:00
|
|
|
}
|
2012-02-19 13:32:55 -05:00
|
|
|
|
|
|
|
|
t = c.Type(ptr, pos)
|
|
|
|
|
if t == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-01 14:13:34 -07:00
|
|
|
// For a struct/union/class, remember the C spelling,
|
|
|
|
|
// in case it has __attribute__((unavailable)).
|
|
|
|
|
// See issue 2888.
|
|
|
|
|
if isStructUnionClass(t.Go) {
|
|
|
|
|
t.Typedef = dt.Name
|
|
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
return t
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FuncType returns the Go type analogous to dtype.
|
|
|
|
|
// There is no guarantee about matching memory layout.
|
2013-10-15 21:35:52 -04:00
|
|
|
func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
|
2009-12-15 15:33:31 -08:00
|
|
|
p := make([]*Type, len(dtype.ParamType))
|
|
|
|
|
gp := make([]*ast.Field, len(dtype.ParamType))
|
2009-09-24 11:43:19 -07:00
|
|
|
for i, f := range dtype.ParamType {
|
2009-11-23 22:02:12 -08:00
|
|
|
// gcc's DWARF generator outputs a single DotDotDotType parameter for
|
|
|
|
|
// function pointers that specify no parameters (e.g. void
|
2016-03-01 23:21:55 +00:00
|
|
|
// (*__cgo_0)()). Treat this special case as void. This case is
|
2009-11-23 22:02:12 -08:00
|
|
|
// invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
|
|
|
|
|
// legal).
|
|
|
|
|
if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
|
2009-12-15 15:33:31 -08:00
|
|
|
p, gp = nil, nil
|
|
|
|
|
break
|
2009-11-23 22:02:12 -08:00
|
|
|
}
|
2012-02-06 20:38:54 +01:00
|
|
|
p[i] = c.FuncArg(f, pos)
|
2009-12-15 15:33:31 -08:00
|
|
|
gp[i] = &ast.Field{Type: p[i].Go}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
var r *Type
|
|
|
|
|
var gr []*ast.Field
|
2017-06-04 12:11:19 +09:00
|
|
|
if _, ok := base(dtype.ReturnType).(*dwarf.VoidType); ok {
|
2012-12-18 00:26:08 +08:00
|
|
|
gr = []*ast.Field{{Type: c.goVoid}}
|
|
|
|
|
} else if dtype.ReturnType != nil {
|
2016-11-16 09:55:24 -08:00
|
|
|
r = c.Type(unqual(dtype.ReturnType), pos)
|
2011-12-02 14:14:25 -05:00
|
|
|
gr = []*ast.Field{{Type: r.Go}}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
return &FuncType{
|
|
|
|
|
Params: p,
|
|
|
|
|
Result: r,
|
|
|
|
|
Go: &ast.FuncType{
|
2010-03-02 13:46:51 -08:00
|
|
|
Params: &ast.FieldList{List: gp},
|
2010-02-24 16:17:11 -08:00
|
|
|
Results: &ast.FieldList{List: gr},
|
2009-11-05 15:33:26 -08:00
|
|
|
},
|
2009-12-15 15:33:31 -08:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Identifier
|
2010-07-14 17:17:53 -07:00
|
|
|
func (c *typeConv) Ident(s string) *ast.Ident {
|
|
|
|
|
return ast.NewIdent(s)
|
|
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
|
|
|
|
|
// Opaque type of n bytes.
|
|
|
|
|
func (c *typeConv) Opaque(n int64) ast.Expr {
|
|
|
|
|
return &ast.ArrayType{
|
|
|
|
|
Len: c.intExpr(n),
|
2009-11-05 15:33:26 -08:00
|
|
|
Elt: c.byte,
|
2009-11-09 12:07:39 -08:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Expr for integer n.
|
|
|
|
|
func (c *typeConv) intExpr(n int64) ast.Expr {
|
|
|
|
|
return &ast.BasicLit{
|
2010-03-02 13:46:51 -08:00
|
|
|
Kind: token.INT,
|
2011-12-05 15:48:46 -05:00
|
|
|
Value: strconv.FormatInt(n, 10),
|
2009-11-09 12:07:39 -08:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add padding of given size to fld.
|
2015-07-29 22:04:09 -07:00
|
|
|
func (c *typeConv) pad(fld []*ast.Field, sizes []int64, size int64) ([]*ast.Field, []int64) {
|
2009-12-15 15:33:31 -08:00
|
|
|
n := len(fld)
|
|
|
|
|
fld = fld[0 : n+1]
|
|
|
|
|
fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
|
2015-07-29 22:04:09 -07:00
|
|
|
sizes = sizes[0 : n+1]
|
|
|
|
|
sizes[n] = size
|
|
|
|
|
return fld, sizes
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-24 09:50:12 +10:00
|
|
|
// Struct conversion: return Go and (gc) C syntax for type.
|
2012-02-06 20:38:54 +01:00
|
|
|
func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
|
2014-08-11 22:10:17 -07:00
|
|
|
// Minimum alignment for a struct is 1 byte.
|
|
|
|
|
align = 1
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
var buf bytes.Buffer
|
|
|
|
|
buf.WriteString("struct {")
|
2009-12-15 15:33:31 -08:00
|
|
|
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
|
2015-07-29 22:04:09 -07:00
|
|
|
sizes := make([]int64, 0, 2*len(dt.Field)+1)
|
2009-12-15 15:33:31 -08:00
|
|
|
off := int64(0)
|
2009-11-18 09:59:10 -08:00
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// Rename struct fields that happen to be named Go keywords into
|
2016-03-01 23:21:55 +00:00
|
|
|
// _{keyword}. Create a map from C ident -> Go ident. The Go ident will
|
|
|
|
|
// be mangled. Any existing identifier that already has the same name on
|
2009-11-18 09:59:10 -08:00
|
|
|
// the C-side will cause the Go-mangled version to be prefixed with _.
|
|
|
|
|
// (e.g. in a struct with fields '_type' and 'type', the latter would be
|
|
|
|
|
// rendered as '__type' in Go).
|
2009-12-15 15:33:31 -08:00
|
|
|
ident := make(map[string]string)
|
|
|
|
|
used := make(map[string]bool)
|
2009-11-18 09:59:10 -08:00
|
|
|
for _, f := range dt.Field {
|
2009-12-15 15:33:31 -08:00
|
|
|
ident[f.Name] = f.Name
|
|
|
|
|
used[f.Name] = true
|
2009-11-18 09:59:10 -08:00
|
|
|
}
|
|
|
|
|
|
2015-01-07 13:23:45 -08:00
|
|
|
if !*godefs {
|
2011-11-10 19:08:04 -05:00
|
|
|
for cid, goid := range ident {
|
2012-01-11 14:20:32 -08:00
|
|
|
if token.Lookup(goid).IsKeyword() {
|
2011-11-10 19:08:04 -05:00
|
|
|
// Avoid keyword
|
2009-11-18 09:59:10 -08:00
|
|
|
goid = "_" + goid
|
|
|
|
|
|
2011-11-10 19:08:04 -05:00
|
|
|
// Also avoid existing fields
|
|
|
|
|
for _, exist := used[goid]; exist; _, exist = used[goid] {
|
|
|
|
|
goid = "_" + goid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
used[goid] = true
|
|
|
|
|
ident[cid] = goid
|
|
|
|
|
}
|
2009-11-18 09:59:10 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-10 19:08:04 -05:00
|
|
|
anon := 0
|
2009-09-24 11:43:19 -07:00
|
|
|
for _, f := range dt.Field {
|
|
|
|
|
if f.ByteOffset > off {
|
2015-07-29 22:04:09 -07:00
|
|
|
fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
|
2009-12-15 15:33:31 -08:00
|
|
|
off = f.ByteOffset
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2014-08-05 17:10:15 -07:00
|
|
|
|
|
|
|
|
name := f.Name
|
|
|
|
|
ft := f.Type
|
|
|
|
|
|
2015-01-07 13:23:45 -08:00
|
|
|
// In godefs mode, if this field is a C11
|
2014-08-05 17:10:15 -07:00
|
|
|
// anonymous union then treat the first field in the
|
2016-03-01 23:21:55 +00:00
|
|
|
// union as the field in the struct. This handles
|
2014-08-05 17:10:15 -07:00
|
|
|
// cases like the glibc <sys/resource.h> file; see
|
|
|
|
|
// issue 6677.
|
2015-01-07 13:23:45 -08:00
|
|
|
if *godefs {
|
2014-08-05 17:10:15 -07:00
|
|
|
if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
|
|
|
|
|
name = st.Field[0].Name
|
|
|
|
|
ident[name] = name
|
|
|
|
|
ft = st.Field[0].Type
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Handle fields that are anonymous structs by
|
|
|
|
|
// promoting the fields of the inner struct.
|
|
|
|
|
|
|
|
|
|
t := c.Type(ft, pos)
|
2011-11-10 19:08:04 -05:00
|
|
|
tgo := t.Go
|
|
|
|
|
size := t.Size
|
2014-05-12 23:48:20 -04:00
|
|
|
talign := t.Align
|
2011-11-10 19:08:04 -05:00
|
|
|
if f.BitSize > 0 {
|
|
|
|
|
if f.BitSize%8 != 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
size = f.BitSize / 8
|
|
|
|
|
name := tgo.(*ast.Ident).String()
|
|
|
|
|
if strings.HasPrefix(name, "int") {
|
|
|
|
|
name = "int"
|
|
|
|
|
} else {
|
|
|
|
|
name = "uint"
|
|
|
|
|
}
|
|
|
|
|
tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize))
|
2014-05-12 23:48:20 -04:00
|
|
|
talign = size
|
2011-11-10 19:08:04 -05:00
|
|
|
}
|
|
|
|
|
|
2015-01-07 13:23:45 -08:00
|
|
|
if talign > 0 && f.ByteOffset%talign != 0 {
|
2014-05-12 23:48:20 -04:00
|
|
|
// Drop misaligned fields, the same way we drop integer bit fields.
|
|
|
|
|
// The goal is to make available what can be made available.
|
|
|
|
|
// Otherwise one bad and unneeded field in an otherwise okay struct
|
|
|
|
|
// makes the whole program not compile. Much of the time these
|
|
|
|
|
// structs are in system headers that cannot be corrected.
|
|
|
|
|
continue
|
|
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
n := len(fld)
|
|
|
|
|
fld = fld[0 : n+1]
|
2011-11-10 19:08:04 -05:00
|
|
|
if name == "" {
|
|
|
|
|
name = fmt.Sprintf("anon%d", anon)
|
|
|
|
|
anon++
|
|
|
|
|
ident[name] = name
|
|
|
|
|
}
|
|
|
|
|
fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo}
|
2015-07-29 22:04:09 -07:00
|
|
|
sizes = sizes[0 : n+1]
|
|
|
|
|
sizes[n] = size
|
2011-11-10 19:08:04 -05:00
|
|
|
off += size
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
buf.WriteString(t.C.String())
|
2010-07-14 17:17:53 -07:00
|
|
|
buf.WriteString(" ")
|
2011-11-10 19:08:04 -05:00
|
|
|
buf.WriteString(name)
|
2010-07-14 17:17:53 -07:00
|
|
|
buf.WriteString("; ")
|
2014-05-12 23:48:20 -04:00
|
|
|
if talign > align {
|
|
|
|
|
align = talign
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if off < dt.ByteSize {
|
2015-07-29 22:04:09 -07:00
|
|
|
fld, sizes = c.pad(fld, sizes, dt.ByteSize-off)
|
2009-12-15 15:33:31 -08:00
|
|
|
off = dt.ByteSize
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2015-07-29 22:04:09 -07:00
|
|
|
|
|
|
|
|
// If the last field in a non-zero-sized struct is zero-sized
|
|
|
|
|
// the compiler is going to pad it by one (see issue 9401).
|
|
|
|
|
// We can't permit that, because then the size of the Go
|
|
|
|
|
// struct will not be the same as the size of the C struct.
|
|
|
|
|
// Our only option in such a case is to remove the field,
|
2016-01-27 12:49:13 -08:00
|
|
|
// which means that it cannot be referenced from Go.
|
2015-07-29 22:04:09 -07:00
|
|
|
for off > 0 && sizes[len(sizes)-1] == 0 {
|
|
|
|
|
n := len(sizes)
|
|
|
|
|
fld = fld[0 : n-1]
|
|
|
|
|
sizes = sizes[0 : n-1]
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
if off != dt.ByteSize {
|
2012-02-19 13:32:55 -05:00
|
|
|
fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
buf.WriteString("}")
|
|
|
|
|
csyntax = buf.String()
|
2011-11-10 19:08:04 -05:00
|
|
|
|
2015-01-07 13:23:45 -08:00
|
|
|
if *godefs {
|
2014-08-06 10:28:19 -07:00
|
|
|
godefsFields(fld)
|
2011-11-10 19:08:04 -05:00
|
|
|
}
|
2010-02-24 16:17:11 -08:00
|
|
|
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
|
2009-12-15 15:33:31 -08:00
|
|
|
return
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2011-11-10 19:08:04 -05:00
|
|
|
|
2016-11-14 15:51:30 -08:00
|
|
|
// dwarfHasPointer returns whether the DWARF type dt contains a pointer.
|
|
|
|
|
func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool {
|
|
|
|
|
switch dt := dt.(type) {
|
|
|
|
|
default:
|
|
|
|
|
fatalf("%s: unexpected type: %s", lineno(pos), dt)
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
|
|
case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.EnumType,
|
|
|
|
|
*dwarf.FloatType, *dwarf.ComplexType, *dwarf.FuncType,
|
|
|
|
|
*dwarf.IntType, *dwarf.UcharType, *dwarf.UintType, *dwarf.VoidType:
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
|
|
case *dwarf.ArrayType:
|
|
|
|
|
return c.dwarfHasPointer(dt.Type, pos)
|
|
|
|
|
|
|
|
|
|
case *dwarf.PtrType:
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
|
|
case *dwarf.QualType:
|
|
|
|
|
return c.dwarfHasPointer(dt.Type, pos)
|
|
|
|
|
|
|
|
|
|
case *dwarf.StructType:
|
|
|
|
|
for _, f := range dt.Field {
|
|
|
|
|
if c.dwarfHasPointer(f.Type, pos) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
|
|
case *dwarf.TypedefType:
|
|
|
|
|
if dt.Name == "_GoString_" || dt.Name == "_GoBytes_" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return c.dwarfHasPointer(dt.Type, pos)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-10 19:08:04 -05:00
|
|
|
func upper(s string) string {
|
|
|
|
|
if s == "" {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
r, size := utf8.DecodeRuneInString(s)
|
|
|
|
|
if r == '_' {
|
|
|
|
|
return "X" + s
|
|
|
|
|
}
|
|
|
|
|
return string(unicode.ToUpper(r)) + s[size:]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// godefsFields rewrites field names for use in Go or C definitions.
|
|
|
|
|
// It strips leading common prefixes (like tv_ in tv_sec, tv_usec)
|
|
|
|
|
// converts names to upper case, and rewrites _ into Pad_godefs_n,
|
|
|
|
|
// so that all fields are exported.
|
|
|
|
|
func godefsFields(fld []*ast.Field) {
|
|
|
|
|
prefix := fieldPrefix(fld)
|
|
|
|
|
npad := 0
|
|
|
|
|
for _, f := range fld {
|
|
|
|
|
for _, n := range f.Names {
|
2013-02-01 08:41:25 -08:00
|
|
|
if n.Name != prefix {
|
|
|
|
|
n.Name = strings.TrimPrefix(n.Name, prefix)
|
2011-11-10 19:08:04 -05:00
|
|
|
}
|
|
|
|
|
if n.Name == "_" {
|
|
|
|
|
// Use exported name instead.
|
|
|
|
|
n.Name = "Pad_cgo_" + strconv.Itoa(npad)
|
|
|
|
|
npad++
|
|
|
|
|
}
|
2015-01-07 13:23:45 -08:00
|
|
|
n.Name = upper(n.Name)
|
2011-11-10 19:08:04 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fieldPrefix returns the prefix that should be removed from all the
|
2016-03-01 23:21:55 +00:00
|
|
|
// field names when generating the C or Go code. For generated
|
2011-11-10 19:08:04 -05:00
|
|
|
// C, we leave the names as is (tv_sec, tv_usec), since that's what
|
|
|
|
|
// people are used to seeing in C. For generated Go code, such as
|
|
|
|
|
// package syscall's data structures, we drop a common prefix
|
|
|
|
|
// (so sec, usec, which will get turned into Sec, Usec for exporting).
|
|
|
|
|
func fieldPrefix(fld []*ast.Field) string {
|
|
|
|
|
prefix := ""
|
|
|
|
|
for _, f := range fld {
|
|
|
|
|
for _, n := range f.Names {
|
|
|
|
|
// Ignore field names that don't have the prefix we're
|
2016-03-01 23:21:55 +00:00
|
|
|
// looking for. It is common in C headers to have fields
|
2011-11-10 19:08:04 -05:00
|
|
|
// named, say, _pad in an otherwise prefixed header.
|
|
|
|
|
// If the struct has 3 fields tv_sec, tv_usec, _pad1, then we
|
|
|
|
|
// still want to remove the tv_ prefix.
|
2012-10-30 13:38:01 -07:00
|
|
|
// The check for "orig_" here handles orig_eax in the
|
2011-11-10 19:08:04 -05:00
|
|
|
// x86 ptrace register sets, which otherwise have all fields
|
|
|
|
|
// with reg_ prefixes.
|
|
|
|
|
if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2017-10-05 15:49:32 +02:00
|
|
|
i := strings.Index(n.Name, "_")
|
2011-11-10 19:08:04 -05:00
|
|
|
if i < 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if prefix == "" {
|
|
|
|
|
prefix = n.Name[:i+1]
|
|
|
|
|
} else if prefix != n.Name[:i+1] {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return prefix
|
|
|
|
|
}
|