1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397 |
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // Annotate Ref in Prog with C types by parsing gcc debug output.
- // Conversion of debug output to Go types.
- package main
- import (
- "bytes"
- "debug/dwarf"
- "debug/elf"
- "debug/macho"
- "debug/pe"
- "encoding/binary"
- "errors"
- "flag"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "internal/xcoff"
- "math"
- "os"
- "os/exec"
- "strconv"
- "strings"
- "unicode"
- "unicode/utf8"
- "cmd/internal/quoted"
- )
- 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{
- "schar": "signed char",
- "uchar": "unsigned char",
- "ushort": "unsigned short",
- "uint": "unsigned int",
- "ulong": "unsigned long",
- "longlong": "long long",
- "ulonglong": "unsigned long long",
- "complexfloat": "float _Complex",
- "complexdouble": "double _Complex",
- }
- // 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_"):]
- }
- if strings.HasPrefix(s, "sizeof_") {
- return "sizeof(" + cname(s[len("sizeof_"):]) + ")"
- }
- return s
- }
- // 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() {
- linesIn := strings.Split(f.Preamble, "\n")
- linesOut := make([]string, 0, len(linesIn))
- for _, line := range linesIn {
- l := strings.TrimSpace(line)
- if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {
- linesOut = append(linesOut, line)
- } else {
- linesOut = append(linesOut, "")
- }
- }
- f.Preamble = strings.Join(linesOut, "\n")
- }
- // addToFlag appends args to flag. All flags are later written out onto the
- // _cgo_flags file for the build system to use.
- func (p *Package) addToFlag(flag string, args []string) {
- if flag == "CFLAGS" {
- // We'll also need these when preprocessing for dwarf information.
- // However, discard any -g options: we need to be able
- // to parse the debug info, so stick to what we expect.
- for _, arg := range args {
- if !strings.HasPrefix(arg, "-g") {
- p.GccOptions = append(p.GccOptions, arg)
- }
- }
- }
- skip := false
- for i, arg := range args {
- // The go tool will pass us a -I option pointing to objdir;
- // we don't need to record that for later, as the objdir
- // will disappear anyhow.
- if skip {
- // Discard argument in "-I objdir" case.
- skip = false
- } else if strings.HasPrefix(arg, "-I") && strings.HasPrefix(arg[2:], *objDir) {
- // This is -Iobjdir. Don't save this argument.
- } else if arg == "-I" && i+1 < len(args) && strings.HasPrefix(args[i+1], *objDir) {
- // This is -I objdir. Don't save this argument
- // or the next one.
- skip = true
- } else {
- p.CgoFlags[flag] = append(p.CgoFlags[flag], arg)
- }
- }
- }
- // 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
- // last element. The backslash is used for escaping.
- //
- // For example, the following string:
- //
- // `a b:"c d" 'e''f' "g\""`
- //
- // Would be parsed as:
- //
- // []string{"a", "b:c d", "ef", `g"`}
- //
- func splitQuoted(s string) (r []string, err error) {
- var args []string
- arg := make([]rune, len(s))
- escaped := false
- quoted := false
- quote := '\x00'
- i := 0
- for _, r := range s {
- switch {
- case escaped:
- escaped = false
- case r == '\\':
- escaped = true
- continue
- case quote != 0:
- if r == quote {
- quote = 0
- continue
- }
- case r == '"' || r == '\'':
- quoted = true
- quote = r
- continue
- case unicode.IsSpace(r):
- if quoted || i > 0 {
- quoted = false
- args = append(args, string(arg[:i]))
- i = 0
- }
- continue
- }
- arg[i] = r
- i++
- }
- if quoted || i > 0 {
- args = append(args, string(arg[:i]))
- }
- if quote != 0 {
- err = errors.New("unclosed quote")
- } else if escaped {
- err = errors.New("unfinished escaping")
- }
- return args, err
- }
- // 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)
- }
- var conv typeConv
- conv.Init(p.PtrSize, p.IntSize)
- p.loadDefines(f)
- p.typedefs = map[string]bool{}
- p.typedefList = nil
- numTypedefs := -1
- for len(p.typedefs) > numTypedefs {
- numTypedefs = len(p.typedefs)
- // Also ask about any typedefs we've seen so far.
- for _, info := range p.typedefList {
- if f.Name[info.typedef] != nil {
- continue
- }
- n := &Name{
- Go: info.typedef,
- C: info.typedef,
- }
- f.Name[info.typedef] = n
- f.NamePos[n] = info.pos
- }
- needType := p.guessKinds(f)
- if len(needType) > 0 {
- p.loadDWARF(f, &conv, needType)
- }
- // In godefs mode we're OK with the typedefs, which
- // will presumably also be defined in the file, we
- // don't want to resolve them to their base types.
- if *godefs {
- break
- }
- }
- p.prepareNames(f)
- if p.rewriteCalls(f) {
- // Add `import _cgo_unsafe "unsafe"` after the package statement.
- f.Edit.Insert(f.offset(f.AST.Name.End()), "; import _cgo_unsafe \"unsafe\"")
- }
- 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) {
- var b bytes.Buffer
- b.WriteString(builtinProlog)
- b.WriteString(f.Preamble)
- stdout := p.gccDefines(b.Bytes())
- for _, line := range strings.Split(stdout, "\n") {
- if len(line) < 9 || line[0:7] != "#define" {
- continue
- }
- line = strings.TrimSpace(line[8:])
- var key, val string
- spaceIndex := strings.Index(line, " ")
- 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:])
- }
- if key == "__clang__" {
- p.GccIsClang = true
- }
- if n := f.Name[key]; n != nil {
- if *debugDefine {
- fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
- }
- n.Define = val
- }
- }
- }
- // 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 {
- // Determine kinds for names we already know about,
- // like #defines or 'struct foo', before bothering with gcc.
- var names, needType []*Name
- optional := map[*Name]bool{}
- for _, key := range nameKeys(f.Name) {
- n := f.Name[key]
- // If we've already found this name as a #define
- // and we can translate it as a constant value, do so.
- if n.Define != "" {
- if i, err := strconv.ParseInt(n.Define, 0, 64); err == nil {
- n.Kind = "iconst"
- // Turn decimal into hex, just for consistency
- // with enum-derived constants. Otherwise
- // in the cgo -godefs output half the constants
- // are in hex and half are in whatever the #define used.
- 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"
- n.Const = n.Define
- }
- }
- if n.IsConst() {
- continue
- }
- }
- // If this is a struct, union, or enum type name, no need to guess the kind.
- if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
- n.Kind = "type"
- needType = append(needType, n)
- continue
- }
- if (goos == "darwin" || goos == "ios") && strings.HasSuffix(n.C, "Ref") {
- // For FooRef, find out if FooGetTypeID exists.
- s := n.C[:len(n.C)-3] + "GetTypeID"
- n := &Name{Go: s, C: s}
- names = append(names, n)
- optional[n] = true
- }
- // Otherwise, we'll need to find out from gcc.
- names = append(names, n)
- }
- // Bypass gcc if there's nothing left to find out.
- if len(names) == 0 {
- return needType
- }
- // 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"
- // void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__1; }
- // #line xxx "not-type"
- // void __cgo_f_xxx_2(void) { name *__cgo_undefined__2; }
- // #line xxx "not-int-const"
- // void __cgo_f_xxx_3(void) { enum { __cgo_undefined__3 = (name)*1 }; }
- // #line xxx "not-num-const"
- // void __cgo_f_xxx_4(void) { static const double __cgo_undefined__4 = (name); }
- // #line xxx "not-str-lit"
- // void __cgo_f_xxx_5(void) { static const char __cgo_undefined__5[] = (name); }
- //
- // 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 not a type.
- // 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.
- //
- // The specific input forms are chosen so that they are valid C syntax regardless of
- // whether name denotes a type or an expression.
- var b bytes.Buffer
- b.WriteString(builtinProlog)
- b.WriteString(f.Preamble)
- for i, n := range names {
- fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+
- "void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__1; }\n"+
- "#line %d \"not-type\"\n"+
- "void __cgo_f_%d_2(void) { %s *__cgo_undefined__2; }\n"+
- "#line %d \"not-int-const\"\n"+
- "void __cgo_f_%d_3(void) { enum { __cgo_undefined__3 = (%s)*1 }; }\n"+
- "#line %d \"not-num-const\"\n"+
- "void __cgo_f_%d_4(void) { static const double __cgo_undefined__4 = (%s); }\n"+
- "#line %d \"not-str-lit\"\n"+
- "void __cgo_f_%d_5(void) { static const char __cgo_undefined__5[] = (%s); }\n",
- i+1, i+1, n.C,
- i+1, i+1, n.C,
- i+1, i+1, n.C,
- i+1, i+1, n.C,
- i+1, i+1, n.C,
- )
- }
- fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
- "int __cgo__1 = __cgo__2;\n")
- // We need to parse the output from this gcc command, so ensure that it
- // doesn't have any ANSI escape sequences in it. (TERM=dumb is
- // insufficient; if the user specifies CGO_CFLAGS=-fdiagnostics-color,
- // GCC will ignore TERM, and GCC can also be configured at compile-time
- // to ignore TERM.)
- stderr := p.gccErrors(b.Bytes(), "-fdiagnostics-color=never")
- if strings.Contains(stderr, "unrecognized command line option") {
- // We're using an old version of GCC that doesn't understand
- // -fdiagnostics-color. Those versions can't print color anyway,
- // so just rerun without that option.
- stderr = p.gccErrors(b.Bytes())
- }
- if stderr == "" {
- fatalf("%s produced no output\non input:\n%s", gccBaseCmd[0], b.Bytes())
- }
- completed := false
- sniff := make([]int, len(names))
- const (
- notType = 1 << iota
- notIntConst
- notNumConst
- notStrLiteral
- notDeclared
- )
- sawUnmatchedErrors := false
- for _, line := range strings.Split(stderr, "\n") {
- // 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 {
- continue
- }
- c1 := strings.Index(line, ":")
- if c1 < 0 {
- continue
- }
- c2 := strings.Index(line[c1+1:], ":")
- if c2 < 0 {
- continue
- }
- c2 += c1 + 1
- filename := line[:c1]
- i, _ := strconv.Atoi(line[c1+1 : c2])
- i--
- if i < 0 || i >= len(names) {
- if isError {
- sawUnmatchedErrors = true
- }
- continue
- }
- 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":
- sniff[i] |= notDeclared
- case "not-type":
- sniff[i] |= notType
- case "not-int-const":
- sniff[i] |= notIntConst
- case "not-num-const":
- sniff[i] |= notNumConst
- case "not-str-lit":
- sniff[i] |= notStrLiteral
- default:
- if isError {
- sawUnmatchedErrors = true
- }
- continue
- }
- sawUnmatchedErrors = false
- }
- if !completed {
- fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", gccBaseCmd[0], b.Bytes(), stderr)
- }
- for i, n := range names {
- switch sniff[i] {
- default:
- if sniff[i]¬Declared != 0 && optional[n] {
- // Ignore optional undeclared identifiers.
- // Don't report an error, and skip adding n to the needType array.
- continue
- }
- error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go))
- case notStrLiteral | notType:
- n.Kind = "iconst"
- case notIntConst | notStrLiteral | notType:
- n.Kind = "fconst"
- case notIntConst | notNumConst | notType:
- n.Kind = "sconst"
- case notIntConst | notNumConst | notStrLiteral:
- n.Kind = "type"
- case notIntConst | notNumConst | notStrLiteral | notType:
- n.Kind = "not-type"
- }
- needType = append(needType, n)
- }
- if nerrors > 0 {
- // Check if compiling the preamble by itself causes any errors,
- // because the messages we've printed out so far aren't helpful
- // to users debugging preamble mistakes. See issue 8442.
- preambleErrors := p.gccErrors([]byte(f.Preamble))
- if len(preambleErrors) > 0 {
- error_(token.NoPos, "\n%s errors for preamble:\n%s", gccBaseCmd[0], preambleErrors)
- }
- fatalf("unresolved names")
- }
- return needType
- }
- // 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, conv *typeConv, names []*Name) {
- // Extract the types from the DWARF section of an object
- // from a well-formed C program. Gcc only generates DWARF info
- // for symbols in the object file, so it is not enough to print the
- // preamble and hope the symbols we care about will be there.
- // Instead, emit
- // __typeof__(names[i]) *__cgo__i;
- // for each entry in names and then dereference the type we
- // learn for __cgo__i.
- var b bytes.Buffer
- b.WriteString(builtinProlog)
- b.WriteString(f.Preamble)
- b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
- for i, n := range names {
- fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
- if n.Kind == "iconst" {
- fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
- }
- }
- // We create a data block initialized with the values,
- // so we can read them out of the object file.
- fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n")
- for _, n := range names {
- if n.Kind == "iconst" {
- fmt.Fprintf(&b, "\t%s,\n", n.C)
- } else {
- fmt.Fprintf(&b, "\t0,\n")
- }
- }
- // for the last entry, we cannot use 0, otherwise
- // 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")
- fmt.Fprintf(&b, "};\n")
- // 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")
- }
- }
- fmt.Fprintf(&b, "\t1\n")
- fmt.Fprintf(&b, "};\n")
- // 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))
- // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
- types := make([]dwarf.Type, len(names))
- r := d.Reader()
- for {
- e, err := r.Next()
- if err != nil {
- fatalf("reading DWARF entry: %s", err)
- }
- if e == nil {
- break
- }
- switch e.Tag {
- case dwarf.TagVariable:
- name, _ := e.Val(dwarf.AttrName).(string)
- typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
- if name == "" || typOff == 0 {
- if e.Val(dwarf.AttrSpecification) != nil {
- // Since we are reading all the DWARF,
- // assume we will see the variable elsewhere.
- break
- }
- fatalf("malformed DWARF TagVariable entry")
- }
- if !strings.HasPrefix(name, "__cgo__") {
- break
- }
- typ, err := d.Type(typOff)
- if err != nil {
- fatalf("loading DWARF type: %s", err)
- }
- t, ok := typ.(*dwarf.PtrType)
- if !ok || t == nil {
- fatalf("internal error: %s has non-pointer type", name)
- }
- i, err := strconv.Atoi(name[7:])
- if err != nil {
- fatalf("malformed __cgo__ name: %s", name)
- }
- types[i] = t.Type
- p.recordTypedefs(t.Type, f.NamePos[names[i]])
- }
- if e.Tag != dwarf.TagCompileUnit {
- r.SkipChildren()
- }
- }
- // Record types and typedef information.
- for i, n := range names {
- if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" {
- conv.getTypeIDs[n.Go[:len(n.Go)-9]] = true
- }
- }
- for i, n := range names {
- if types[i] == nil {
- continue
- }
- pos := f.NamePos[n]
- f, fok := types[i].(*dwarf.FuncType)
- if n.Kind != "type" && fok {
- n.Kind = "func"
- n.FuncType = conv.FuncType(f, pos)
- } else {
- n.Type = conv.Type(types[i], pos)
- switch n.Kind {
- case "iconst":
- if i < len(ints) {
- if _, ok := types[i].(*dwarf.UintType); ok {
- n.Const = fmt.Sprintf("%#x", uint64(ints[i]))
- } else {
- n.Const = fmt.Sprintf("%#x", ints[i])
- }
- }
- case "fconst":
- if i >= len(floats) {
- break
- }
- switch base(types[i]).(type) {
- case *dwarf.IntType, *dwarf.UintType:
- // This has an integer type so it's
- // not really a floating point
- // constant. This can happen when the
- // C compiler complains about using
- // the value as an integer constant,
- // but not as a general constant.
- // Treat this as a variable of the
- // appropriate type, not a constant,
- // to get C-style type handling,
- // avoiding the problem that C permits
- // uint64(-1) but Go does not.
- // See issue 26066.
- n.Kind = "var"
- default:
- n.Const = fmt.Sprintf("%f", floats[i])
- }
- case "sconst":
- if i < len(strs) {
- n.Const = fmt.Sprintf("%q", strs[i])
- }
- }
- }
- conv.FinishType(pos)
- }
- }
- // recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children.
- func (p *Package) recordTypedefs(dtype dwarf.Type, pos token.Pos) {
- p.recordTypedefs1(dtype, pos, map[dwarf.Type]bool{})
- }
- func (p *Package) recordTypedefs1(dtype dwarf.Type, pos token.Pos, visited map[dwarf.Type]bool) {
- if dtype == nil {
- return
- }
- if visited[dtype] {
- return
- }
- visited[dtype] = true
- switch dt := dtype.(type) {
- case *dwarf.TypedefType:
- if strings.HasPrefix(dt.Name, "__builtin") {
- // Don't look inside builtin types. There be dragons.
- return
- }
- if !p.typedefs[dt.Name] {
- p.typedefs[dt.Name] = true
- p.typedefList = append(p.typedefList, typedefInfo{dt.Name, pos})
- p.recordTypedefs1(dt.Type, pos, visited)
- }
- case *dwarf.PtrType:
- p.recordTypedefs1(dt.Type, pos, visited)
- case *dwarf.ArrayType:
- p.recordTypedefs1(dt.Type, pos, visited)
- case *dwarf.QualType:
- p.recordTypedefs1(dt.Type, pos, visited)
- case *dwarf.FuncType:
- p.recordTypedefs1(dt.ReturnType, pos, visited)
- for _, a := range dt.ParamType {
- p.recordTypedefs1(a, pos, visited)
- }
- case *dwarf.StructType:
- for _, f := range dt.Field {
- p.recordTypedefs1(f.Type, pos, visited)
- }
- }
- }
- // prepareNames finalizes the Kind field of not-type names and sets
- // the mangled name of all names.
- func (p *Package) prepareNames(f *File) {
- for _, n := range f.Name {
- if n.Kind == "not-type" {
- 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}}},
- },
- }
- }
- }
- p.mangleName(n)
- if n.Kind == "type" && typedef[n.Mangle] == nil {
- typedef[n.Mangle] = n.Type
- }
- }
- }
- // 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
- }
- func (f *File) isMangledName(s string) bool {
- prefix := "_C"
- if strings.HasPrefix(s, prefix) {
- t := s[len(prefix):]
- for _, k := range nameKinds {
- if strings.HasPrefix(t, k+"_") {
- return true
- }
- }
- }
- return false
- }
- // rewriteCalls rewrites all calls that pass pointers to check that
- // they follow the rules for passing pointers between Go and C.
- // This reports whether the package needs to import unsafe as _cgo_unsafe.
- func (p *Package) rewriteCalls(f *File) bool {
- needsUnsafe := false
- // Walk backward so that in C.f1(C.f2()) we rewrite C.f2 first.
- for _, call := range f.Calls {
- if call.Done {
- continue
- }
- start := f.offset(call.Call.Pos())
- end := f.offset(call.Call.End())
- str, nu := p.rewriteCall(f, call)
- if str != "" {
- f.Edit.Replace(start, end, str)
- if nu {
- needsUnsafe = true
- }
- }
- }
- return needsUnsafe
- }
- // 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.
- // This returns the rewritten call and whether the package needs to
- // import unsafe as _cgo_unsafe.
- // If it returns the empty string, the call did not need to be rewritten.
- func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
- // This is a call to C.xxx; set goname to "xxx".
- // It may have already been mangled by rewriteName.
- var goname string
- switch fun := call.Call.Fun.(type) {
- case *ast.SelectorExpr:
- goname = fun.Sel.Name
- case *ast.Ident:
- goname = strings.TrimPrefix(fun.Name, "_C2func_")
- goname = strings.TrimPrefix(goname, "_Cfunc_")
- }
- if goname == "" || goname == "malloc" {
- return "", false
- }
- name := f.Name[goname]
- if name == nil || name.Kind != "func" {
- // Probably a type conversion.
- return "", false
- }
- params := name.FuncType.Params
- args := call.Call.Args
- // Avoid a crash if the number of arguments doesn't match
- // the number of parameters.
- // This will be caught when the generated file is compiled.
- if len(args) != len(params) {
- return "", false
- }
- any := false
- for i, param := range params {
- if p.needsPointerCheck(f, param.Go, args[i]) {
- any = true
- break
- }
- }
- if !any {
- return "", false
- }
- // We need to rewrite this call.
- //
- // Rewrite C.f(p) to
- // func() {
- // _cgo0 := p
- // _cgoCheckPointer(_cgo0, nil)
- // C.f(_cgo0)
- // }()
- // Using a function literal like this lets us evaluate the
- // function arguments only once while doing pointer checks.
- // This is particularly useful when passing additional arguments
- // to _cgoCheckPointer, as done in checkIndex and checkAddr.
- //
- // When the function argument is a conversion to unsafe.Pointer,
- // we unwrap the conversion before checking the pointer,
- // and then wrap again when calling C.f. This lets us check
- // the real type of the pointer in some cases. See issue #25941.
- //
- // When the call to C.f is deferred, we use an additional function
- // literal to evaluate the arguments at the right time.
- // defer func() func() {
- // _cgo0 := p
- // return func() {
- // _cgoCheckPointer(_cgo0, nil)
- // C.f(_cgo0)
- // }
- // }()()
- // This works because the defer statement evaluates the first
- // function literal in order to get the function to call.
- var sb bytes.Buffer
- sb.WriteString("func() ")
- if call.Deferred {
- sb.WriteString("func() ")
- }
- needsUnsafe := false
- result := false
- twoResults := false
- if !call.Deferred {
- // Check whether this call expects two results.
- for _, ref := range f.Ref {
- if ref.Expr != &call.Call.Fun {
- continue
- }
- if ref.Context == ctxCall2 {
- sb.WriteString("(")
- result = true
- twoResults = true
- }
- break
- }
- // Add the result type, if any.
- if name.FuncType.Result != nil {
- rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
- if rtype != name.FuncType.Result.Go {
- needsUnsafe = true
- }
- sb.WriteString(gofmtLine(rtype))
- result = true
- }
- // Add the second result type, if any.
- if twoResults {
- if name.FuncType.Result == nil {
- // An explicit void result looks odd but it
- // seems to be how cgo has worked historically.
- sb.WriteString("_Ctype_void")
- }
- sb.WriteString(", error)")
- }
- }
- sb.WriteString("{ ")
- // Define _cgoN for each argument value.
- // Write _cgoCheckPointer calls to sbCheck.
- var sbCheck bytes.Buffer
- for i, param := range params {
- origArg := args[i]
- arg, nu := p.mangle(f, &args[i], true)
- if nu {
- needsUnsafe = true
- }
- // Use "var x T = ..." syntax to explicitly convert untyped
- // constants to the parameter type, to avoid a type mismatch.
- ptype := p.rewriteUnsafe(param.Go)
- if !p.needsPointerCheck(f, param.Go, args[i]) || param.BadPointer {
- if ptype != param.Go {
- needsUnsafe = true
- }
- fmt.Fprintf(&sb, "var _cgo%d %s = %s; ", i,
- gofmtLine(ptype), gofmtPos(arg, origArg.Pos()))
- continue
- }
- // Check for &a[i].
- if p.checkIndex(&sb, &sbCheck, arg, i) {
- continue
- }
- // Check for &x.
- if p.checkAddr(&sb, &sbCheck, arg, i) {
- continue
- }
- fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
- fmt.Fprintf(&sbCheck, "_cgoCheckPointer(_cgo%d, nil); ", i)
- }
- if call.Deferred {
- sb.WriteString("return func() { ")
- }
- // Write out the calls to _cgoCheckPointer.
- sb.WriteString(sbCheck.String())
- if result {
- sb.WriteString("return ")
- }
- m, nu := p.mangle(f, &call.Call.Fun, false)
- if nu {
- needsUnsafe = true
- }
- sb.WriteString(gofmtLine(m))
- sb.WriteString("(")
- for i := range params {
- if i > 0 {
- sb.WriteString(", ")
- }
- fmt.Fprintf(&sb, "_cgo%d", i)
- }
- sb.WriteString("); ")
- if call.Deferred {
- sb.WriteString("}")
- }
- sb.WriteString("}")
- if call.Deferred {
- sb.WriteString("()")
- }
- sb.WriteString("()")
- return sb.String(), needsUnsafe
- }
- // needsPointerCheck reports 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.
- 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
- }
- return p.hasPointer(f, t, true)
- }
- // hasPointer is used by needsPointerCheck. If top is true it returns
- // whether t is or contains a pointer that might point to a pointer.
- // If top is false it reports whether t is or contains a pointer.
- // f may be nil.
- 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
- }
- // Check whether this is a pointer to a C union (or class)
- // type that contains a pointer.
- if unionWithPointer[t.X] {
- return true
- }
- 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
- }
- // We can't figure out the type. Conservative
- // 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
- }
- if f == nil {
- // Conservative approach: assume pointer.
- return true
- }
- 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)
- }
- // We can't figure out the type. Conservative
- // approach is to assume it has a pointer.
- return true
- default:
- error_(t.Pos(), "could not understand type %s", gofmt(t))
- return true
- }
- }
- // mangle replaces references to C names in arg with the mangled names,
- // rewriting calls when it finds them.
- // It removes the corresponding references in f.Ref and f.Calls, so that we
- // don't try to do the replacement again in rewriteRef or rewriteCall.
- // If addPosition is true, add position info to the idents of C names in arg.
- func (p *Package) mangle(f *File, arg *ast.Expr, addPosition bool) (ast.Expr, bool) {
- needsUnsafe := false
- f.walk(arg, ctxExpr, func(f *File, arg interface{}, context astContext) {
- px, ok := arg.(*ast.Expr)
- if !ok {
- return
- }
- sel, ok := (*px).(*ast.SelectorExpr)
- if ok {
- if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
- return
- }
- for _, r := range f.Ref {
- if r.Expr == px {
- *px = p.rewriteName(f, r, addPosition)
- r.Done = true
- break
- }
- }
- return
- }
- call, ok := (*px).(*ast.CallExpr)
- if !ok {
- return
- }
- for _, c := range f.Calls {
- if !c.Done && c.Call.Lparen == call.Lparen {
- cstr, nu := p.rewriteCall(f, c)
- if cstr != "" {
- // Smuggle the rewritten call through an ident.
- *px = ast.NewIdent(cstr)
- if nu {
- needsUnsafe = true
- }
- c.Done = true
- }
- }
- }
- })
- return *arg, needsUnsafe
- }
- // checkIndex checks whether arg has the form &a[i], possibly inside
- // type conversions. If so, then in the general case it writes
- // _cgoIndexNN := a
- // _cgoNN := &cgoIndexNN[i] // with type conversions, if any
- // to sb, and writes
- // _cgoCheckPointer(_cgoNN, _cgoIndexNN)
- // to sbCheck, and returns true. If a is a simple variable or field reference,
- // it writes
- // _cgoIndexNN := &a
- // and dereferences the uses of _cgoIndexNN. Taking the address avoids
- // making a copy of an array.
- //
- // This tells _cgoCheckPointer to check the complete contents of the
- // slice or array being indexed, but no other part of the memory allocation.
- func (p *Package) checkIndex(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
- // Strip type conversions.
- x := arg
- 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 false
- }
- index, ok := u.X.(*ast.IndexExpr)
- if !ok {
- return false
- }
- addr := ""
- deref := ""
- if p.isVariable(index.X) {
- addr = "&"
- deref = "*"
- }
- fmt.Fprintf(sb, "_cgoIndex%d := %s%s; ", i, addr, gofmtPos(index.X, index.X.Pos()))
- origX := index.X
- index.X = ast.NewIdent(fmt.Sprintf("_cgoIndex%d", i))
- if deref == "*" {
- index.X = &ast.StarExpr{X: index.X}
- }
- fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
- index.X = origX
- fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgo%d, %s_cgoIndex%d); ", i, deref, i)
- return true
- }
- // checkAddr checks whether arg has the form &x, possibly inside type
- // conversions. If so, it writes
- // _cgoBaseNN := &x
- // _cgoNN := _cgoBaseNN // with type conversions, if any
- // to sb, and writes
- // _cgoCheckPointer(_cgoBaseNN, true)
- // to sbCheck, and returns true. This tells _cgoCheckPointer to check
- // just the contents of the pointer being passed, not any other part
- // of the memory allocation. This is run after checkIndex, which looks
- // for the special case of &a[i], which requires different checks.
- func (p *Package) checkAddr(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
- // Strip type conversions.
- px := &arg
- for {
- c, ok := (*px).(*ast.CallExpr)
- if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
- break
- }
- px = &c.Args[0]
- }
- if u, ok := (*px).(*ast.UnaryExpr); !ok || u.Op != token.AND {
- return false
- }
- fmt.Fprintf(sb, "_cgoBase%d := %s; ", i, gofmtPos(*px, (*px).Pos()))
- origX := *px
- *px = ast.NewIdent(fmt.Sprintf("_cgoBase%d", i))
- fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
- *px = origX
- // Use "0 == 0" to do the right thing in the unlikely event
- // that "true" is shadowed.
- fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgoBase%d, 0 == 0); ", i)
- return true
- }
- // isType reports 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
- }
- if id.Name == "unsafe" && t.Sel.Name == "Pointer" {
- return true
- }
- if id.Name == "C" && typedef["_Ctype_"+t.Sel.Name] != nil {
- return true
- }
- return false
- 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
- }
- if strings.HasPrefix(t.Name, "_Ctype_") {
- return true
- }
- case *ast.ParenExpr:
- return p.isType(t.X)
- 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
- }
- // isVariable reports whether x is a variable, possibly with field references.
- func (p *Package) isVariable(x ast.Expr) bool {
- switch x := x.(type) {
- case *ast.Ident:
- return true
- case *ast.SelectorExpr:
- return p.isVariable(x.X)
- case *ast.IndexExpr:
- return true
- }
- return false
- }
- // 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 {
- switch t := t.(type) {
- case *ast.Ident:
- // We don't see a SelectorExpr for unsafe.Pointer;
- // this is created by code in this file.
- if t.Name == "unsafe.Pointer" {
- return ast.NewIdent("_cgo_unsafe.Pointer")
- }
- case *ast.ArrayType:
- t1 := p.rewriteUnsafe(t.Elt)
- if t1 != t.Elt {
- r := *t
- r.Elt = t1
- return &r
- }
- case *ast.StructType:
- changed := false
- fields := *t.Fields
- fields.List = nil
- for _, f := range t.Fields.List {
- 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
- }
- }
- if changed {
- r := *t
- r.Fields = &fields
- return &r
- }
- case *ast.StarExpr: // Pointer type.
- x1 := p.rewriteUnsafe(t.X)
- if x1 != t.X {
- r := *t
- r.X = x1
- return &r
- }
- }
- return t
- }
- // 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
- // the xxx. In *godefs mode, rewriteRef replaces the names
- // with full definitions instead of mangled names.
- func (p *Package) rewriteRef(f *File) {
- // 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)
- for _, n := range f.Name {
- if n.Kind == "func" {
- functions[n.Go] = false
- }
- }
- // Now that we have all the name types filled in,
- // scan through the Refs to identify the ones that
- // are trying to do a ,err call. Also check that
- // functions are only used in calls.
- for _, r := range f.Ref {
- if r.Name.IsConst() && r.Name.Const == "" {
- error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
- }
- if r.Name.Kind == "func" {
- switch r.Context {
- case ctxCall, ctxCall2:
- functions[r.Name.Go] = true
- }
- }
- expr := p.rewriteName(f, r, false)
- if *godefs {
- // Substitute definition for mangled type name.
- if r.Name.Type != nil && r.Name.Kind == "type" {
- expr = r.Name.Type.Go
- }
- if id, ok := expr.(*ast.Ident); ok {
- if t := typedef[id.Name]; t != nil {
- expr = t.Go
- }
- if id.Name == r.Name.Mangle && r.Name.Const != "" {
- expr = ast.NewIdent(r.Name.Const)
- }
- }
- }
- // 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()
- if x, ok := expr.(*ast.Ident); ok {
- expr = &ast.Ident{NamePos: pos, Name: x.Name}
- }
- // Change AST, because some later processing depends on it,
- // and also because -godefs mode still prints the AST.
- old := *r.Expr
- *r.Expr = expr
- // Record source-level edit for cgo output.
- if !r.Done {
- // Prepend a space in case the earlier code ends
- // with '/', which would give us a "//" comment.
- repl := " " + gofmtPos(expr, old.Pos())
- end := fset.Position(old.End())
- // Subtract 1 from the column if we are going to
- // append a close parenthesis. That will set the
- // correct column for the following characters.
- sub := 0
- if r.Name.Kind != "type" {
- sub = 1
- }
- if end.Column > sub {
- repl = fmt.Sprintf("%s /*line :%d:%d*/", repl, end.Line, end.Column-sub)
- }
- if r.Name.Kind != "type" {
- repl = "(" + repl + ")"
- }
- f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), repl)
- }
- }
- // 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)
- }
- }
- }
- // rewriteName returns the expression used to rewrite a reference.
- // If addPosition is true, add position info in the ident name.
- func (p *Package) rewriteName(f *File, r *Ref, addPosition bool) ast.Expr {
- getNewIdent := ast.NewIdent
- if addPosition {
- getNewIdent = func(newName string) *ast.Ident {
- mangledIdent := ast.NewIdent(newName)
- if len(newName) == len(r.Name.Go) {
- return mangledIdent
- }
- p := fset.Position((*r.Expr).End())
- if p.Column == 0 {
- return mangledIdent
- }
- return ast.NewIdent(fmt.Sprintf("%s /*line :%d:%d*/", newName, p.Line, p.Column))
- }
- }
- var expr ast.Expr = getNewIdent(r.Name.Mangle) // default
- switch r.Context {
- case ctxCall, ctxCall2:
- if r.Name.Kind != "func" {
- if r.Name.Kind == "type" {
- r.Context = ctxType
- 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
- }
- error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
- break
- }
- if r.Context == ctxCall2 {
- if r.Name.Go == "_CMalloc" {
- error_(r.Pos(), "no two-result form for C.malloc")
- break
- }
- // 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
- }
- expr = getNewIdent(n.Mangle)
- r.Name = n
- break
- }
- case ctxExpr:
- switch r.Name.Kind {
- case "func":
- if builtinDefs[r.Name.C] != "" {
- error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
- }
- // 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
- // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
- // 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{getNewIdent(name.Mangle)},
- }
- case "type":
- // Okay - might be new(T), T(x), Generic[T], etc.
- if r.Name.Type == nil {
- error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
- }
- case "var":
- expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
- case "macro":
- expr = &ast.CallExpr{Fun: expr}
- }
- case ctxSelector:
- if r.Name.Kind == "var" {
- expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
- } else {
- error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
- }
- case ctxType:
- if r.Name.Kind != "type" {
- error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
- } 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.
- error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
- }
- default:
- if r.Name.Kind == "func" {
- error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
- }
- }
- return expr
- }
- // gofmtPos returns the gofmt-formatted string for an AST node,
- // with a comment setting the position before the node.
- func gofmtPos(n ast.Expr, pos token.Pos) string {
- s := gofmtLine(n)
- p := fset.Position(pos)
- if p.Column == 0 {
- return s
- }
- return fmt.Sprintf("/*line :%d:%d*/%s", p.Line, p.Column, s)
- }
- // checkGCCBaseCmd 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.
- //
- // The compiler command line is split into arguments on whitespace. Quotes
- // are understood, so arguments may contain whitespace.
- //
- // checkGCCBaseCmd confirms that the compiler exists in PATH, returning
- // an error if it does not.
- func checkGCCBaseCmd() ([]string, error) {
- // Use $CC if set, since that's what the build uses.
- value := os.Getenv("CC")
- if value == "" {
- // Try $GCC if set, since that's what we used to use.
- value = os.Getenv("GCC")
- }
- if value == "" {
- value = defaultCC(goos, goarch)
- }
- args, err := quoted.Split(value)
- if err != nil {
- return nil, err
- }
- if len(args) == 0 {
- return nil, errors.New("CC not set and no default found")
- }
- if _, err := exec.LookPath(args[0]); err != nil {
- return nil, fmt.Errorf("C compiler %q not found: %v", args[0], err)
- }
- return args[:len(args):len(args)], nil
- }
- // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
- func (p *Package) gccMachine() []string {
- switch goarch {
- case "amd64":
- if goos == "darwin" {
- return []string{"-arch", "x86_64", "-m64"}
- }
- return []string{"-m64"}
- case "arm64":
- if goos == "darwin" {
- return []string{"-arch", "arm64"}
- }
- case "386":
- return []string{"-m32"}
- case "arm":
- return []string{"-marm"} // not thumb
- case "s390":
- return []string{"-m31"}
- case "s390x":
- return []string{"-m64"}
- case "mips64", "mips64le":
- if gomips64 == "hardfloat" {
- return []string{"-mabi=64", "-mhard-float"}
- } else if gomips64 == "softfloat" {
- return []string{"-mabi=64", "-msoft-float"}
- }
- case "mips", "mipsle":
- if gomips == "hardfloat" {
- return []string{"-mabi=32", "-mfp32", "-mhard-float", "-mno-odd-spreg"}
- } else if gomips == "softfloat" {
- return []string{"-mabi=32", "-msoft-float"}
- }
- case "ppc64":
- if goos == "aix" {
- return []string{"-maix64"}
- }
- case "ppc":
- if goos == "aix" {
- return []string{"-maix32"}
- }
- }
- return nil
- }
- func gccTmp() string {
- return *objDir + "_cgo_.o"
- }
- // gccCmd returns the gcc command line to use for compiling
- // the input.
- func (p *Package) gccCmd() []string {
- c := append(gccBaseCmd,
- "-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
- )
- if p.GccIsClang {
- c = append(c,
- "-ferror-limit=0",
- // 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",
- "-Wno-unneeded-internal-declaration",
- "-Wno-unused-function",
- "-Qunused-arguments",
- // 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).
- // See: https://golang.org/issue/6506.
- "-fno-builtin",
- )
- }
- c = append(c, p.GccOptions...)
- c = append(c, p.gccMachine()...)
- if goos == "aix" {
- c = append(c, "-mcmodel=large")
- }
- // disable LTO so we get an object whose symbols we can read
- c = append(c, "-fno-lto")
- c = append(c, "-") //read input from standard input
- return c
- }
- // gccDebug runs gcc -gdwarf-2 over the C program stdin and
- // returns the corresponding DWARF data and, if present, debug data block.
- func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) {
- runGcc(stdin, p.gccCmd())
- isDebugInts := func(s string) bool {
- // Some systems use leading _ to denote non-assembly symbols.
- 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"
- }
- 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] = data[:strlen]
- }
- }
- if f, err := macho.Open(gccTmp()); err == nil {
- defer f.Close()
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
- }
- bo := f.ByteOrder
- if f.Symtab != nil {
- for i := range f.Symtab.Syms {
- s := &f.Symtab.Syms[i]
- 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):
- // 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:]
- floats = make([]float64, len(data)/8)
- for i := range floats {
- floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
- }
- }
- }
- }
- 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
- }
- }
- }
- buildStrings()
- }
- return d, ints, floats, strs
- }
- if f, err := elf.Open(gccTmp()); err == nil {
- defer f.Close()
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
- }
- bo := f.ByteOrder
- symtab, err := f.Symbols()
- if err == nil {
- for i := range symtab {
- s := &symtab[i]
- 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):
- // 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:]
- floats = make([]float64, len(data)/8)
- for i := range floats {
- floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
- }
- }
- }
- }
- 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
- }
- }
- }
- buildStrings()
- }
- return d, ints, floats, strs
- }
- if f, err := pe.Open(gccTmp()); err == nil {
- defer f.Close()
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
- }
- bo := binary.LittleEndian
- for _, s := range f.Symbols {
- 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):
- 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:]
- floats = make([]float64, len(data)/8)
- for i := range floats {
- floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
- }
- }
- }
- }
- 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
- }
- }
- }
- buildStrings()
- return d, ints, floats, strs
- }
- if f, err := xcoff.Open(gccTmp()); err == nil {
- defer f.Close()
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
- }
- bo := binary.BigEndian
- for _, s := range f.Symbols {
- 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):
- 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:]
- floats = make([]float64, len(data)/8)
- for i := range floats {
- floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
- }
- }
- }
- }
- 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
- }
- }
- }
- buildStrings()
- return d, ints, floats, strs
- }
- fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", gccTmp())
- panic("not reached")
- }
- // 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 {
- base := append(gccBaseCmd, "-E", "-dM", "-xc")
- base = append(base, p.gccMachine()...)
- stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
- return stdout
- }
- // gccErrors runs gcc over the C program stdin and returns
- // the errors that gcc prints. That is, this function expects
- // gcc to fail.
- func (p *Package) gccErrors(stdin []byte, extraArgs ...string) string {
- // TODO(rsc): require failure
- args := p.gccCmd()
- // Optimization options can confuse the error messages; remove them.
- nargs := make([]string, 0, len(args)+len(extraArgs))
- for _, arg := range args {
- if !strings.HasPrefix(arg, "-O") {
- nargs = append(nargs, arg)
- }
- }
- // Force -O0 optimization and append extra arguments, but keep the
- // trailing "-" at the end.
- li := len(nargs) - 1
- last := nargs[li]
- nargs[li] = "-O0"
- nargs = append(nargs, extraArgs...)
- nargs = append(nargs, last)
- if *debugGcc {
- fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
- os.Stderr.Write(stdin)
- fmt.Fprint(os.Stderr, "EOF\n")
- }
- stdout, stderr, _ := run(stdin, nargs)
- if *debugGcc {
- os.Stderr.Write(stdout)
- os.Stderr.Write(stderr)
- }
- return string(stderr)
- }
- // 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)
- }
- if !ok {
- os.Stderr.Write(stderr)
- os.Exit(2)
- }
- return string(stdout), string(stderr)
- }
- // 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.
- m map[string]*Type
- // Map from types to incomplete pointers to those types.
- ptrs map[string][]*Type
- // Keys of ptrs in insertion order (deterministic worklist)
- // ptrKeys contains exactly the keys in ptrs.
- ptrKeys []dwarf.Type
- // Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
- getTypeIDs map[string]bool
- // badStructs contains C structs that should be marked NotInHeap.
- notInHeapStructs map[string]bool
- // Predeclared types.
- bool ast.Expr
- byte ast.Expr // denotes padding
- int8, int16, int32, int64 ast.Expr
- uint8, uint16, uint32, uint64, uintptr ast.Expr
- float32, float64 ast.Expr
- complex64, complex128 ast.Expr
- void ast.Expr
- string ast.Expr
- goVoid ast.Expr // _Ctype_void, denotes C's void
- goVoidPtr ast.Expr // unsafe.Pointer or *byte
- goVoidPtrNoHeap ast.Expr // *_Ctype_void_notinheap, like goVoidPtr but marked NotInHeap
- ptrSize int64
- intSize int64
- }
- var tagGen int
- var typedef = make(map[string]*Type)
- var goIdent = make(map[string]*ast.Ident)
- // unionWithPointer is true for a Go type that represents a C union (or class)
- // that may contain a pointer. This is used for cgo pointer checking.
- var unionWithPointer = make(map[ast.Expr]bool)
- // anonymousStructTag provides a consistent tag for an anonymous struct.
- // The same dwarf.StructType pointer will always get the same tag.
- var anonymousStructTag = make(map[*dwarf.StructType]string)
- func (c *typeConv) Init(ptrSize, intSize int64) {
- c.ptrSize = ptrSize
- c.intSize = intSize
- c.m = make(map[string]*Type)
- c.ptrs = make(map[string][]*Type)
- c.getTypeIDs = make(map[string]bool)
- c.notInHeapStructs = make(map[string]bool)
- c.bool = c.Ident("bool")
- 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")
- c.complex64 = c.Ident("complex64")
- c.complex128 = c.Ident("complex128")
- c.void = c.Ident("void")
- c.string = c.Ident("string")
- c.goVoid = c.Ident("_Ctype_void")
- c.goVoidPtrNoHeap = c.Ident("*_Ctype_void_notinheap")
- // Normally cgo translates void* to unsafe.Pointer,
- // but for historical reasons -godefs uses *byte instead.
- if *godefs {
- c.goVoidPtr = &ast.StarExpr{X: c.byte}
- } else {
- c.goVoidPtr = c.Ident("unsafe.Pointer")
- }
- }
- // 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 {
- dt = d.Type
- continue
- }
- if d, ok := dt.(*dwarf.TypedefType); ok {
- dt = d.Type
- continue
- }
- break
- }
- return dt
- }
- // 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
- }
- // Map from dwarf text names to aliases we use in package "C".
- var dwarfToName = map[string]string{
- "long int": "long",
- "long unsigned int": "ulong",
- "unsigned int": "uint",
- "short unsigned int": "ushort",
- "unsigned short": "ushort", // Used by Clang; issue 13129.
- "short int": "short",
- "long long int": "longlong",
- "long long unsigned int": "ulonglong",
- "signed char": "schar",
- "unsigned char": "uchar",
- }
- const signedDelta = 64
- // String returns the current type representation. Format arguments
- // 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...)
- }
- // Empty reports whether the result of String would be "".
- 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
- }
- // FinishType completes any outstanding type mapping work.
- // In particular, it resolves incomplete pointer types.
- func (c *typeConv) FinishType(pos token.Pos) {
- // Completing one pointer type might produce more to complete.
- // Keep looping until they're all done.
- for len(c.ptrKeys) > 0 {
- dtype := c.ptrKeys[0]
- dtypeKey := dtype.String()
- c.ptrKeys = c.ptrKeys[1:]
- ptrs := c.ptrs[dtypeKey]
- delete(c.ptrs, dtypeKey)
- // Note Type might invalidate c.ptrs[dtypeKey].
- t := c.Type(dtype, pos)
- for _, ptr := range ptrs {
- ptr.Go.(*ast.StarExpr).X = t.Go
- ptr.C.Set("%s*", t.C)
- }
- }
- }
- // Type returns a *Type with the same memory layout as
- // dtype when used as the type of a variable or a struct field.
- func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
- return c.loadType(dtype, pos, "")
- }
- // loadType recursively loads the requested dtype and its dependency graph.
- func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Type {
- // Always recompute bad pointer typedefs, as the set of such
- // typedefs changes as we see more types.
- checkCache := true
- if dtt, ok := dtype.(*dwarf.TypedefType); ok && c.badPointerTypedef(dtt) {
- checkCache = false
- }
- // The cache key should be relative to its parent.
- // See issue https://golang.org/issue/31891
- key := parent + " > " + dtype.String()
- if checkCache {
- if t, ok := c.m[key]; ok {
- if t.Go == nil {
- fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
- }
- return t
- }
- }
- t := new(Type)
- t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
- t.Align = -1
- t.C = &TypeRepr{Repr: dtype.Common().Name}
- c.m[key] = t
- switch dt := dtype.(type) {
- default:
- fatalf("%s: unexpected type: %s", lineno(pos), dtype)
- case *dwarf.AddrType:
- if t.Size != c.ptrSize {
- fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype)
- }
- t.Go = c.uintptr
- t.Align = t.Size
- case *dwarf.ArrayType:
- if dt.StrideBitSize > 0 {
- // Cannot represent bit-sized elements in Go.
- t.Go = c.Opaque(t.Size)
- break
- }
- count := dt.Count
- if count == -1 {
- // Indicates flexible array member, which Go doesn't support.
- // Translate to zero-length array instead.
- count = 0
- }
- sub := c.Type(dt.Type, pos)
- t.Align = sub.Align
- t.Go = &ast.ArrayType{
- Len: c.intExpr(count),
- Elt: sub.Go,
- }
- // Recalculate t.Size now that we know sub.Size.
- t.Size = count * sub.Size
- t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
- case *dwarf.BoolType:
- t.Go = c.bool
- t.Align = 1
- case *dwarf.CharType:
- if t.Size != 1 {
- fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype)
- }
- t.Go = c.int8
- t.Align = 1
- case *dwarf.EnumType:
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
- t.C.Set("enum " + dt.EnumName)
- 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) {
- default:
- fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype)
- case 1:
- t.Go = c.uint8
- case 2:
- t.Go = c.uint16
- case 4:
- t.Go = c.uint32
- case 8:
- t.Go = c.uint64
- 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
- }
- case *dwarf.FloatType:
- switch t.Size {
- default:
- fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype)
- case 4:
- t.Go = c.float32
- case 8:
- t.Go = c.float64
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
- case *dwarf.ComplexType:
- switch t.Size {
- default:
- fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype)
- case 8:
- t.Go = c.complex64
- case 16:
- t.Go = c.complex128
- }
- if t.Align = t.Size / 2; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
- case *dwarf.FuncType:
- // No attempt at translation: would enable calls
- // directly between worlds, but we need to moderate those.
- t.Go = c.uintptr
- t.Align = c.ptrSize
- case *dwarf.IntType:
- if dt.BitSize > 0 {
- fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype)
- }
- switch t.Size {
- default:
- fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype)
- case 1:
- t.Go = c.int8
- case 2:
- t.Go = c.int16
- case 4:
- t.Go = c.int32
- case 8:
- t.Go = c.int64
- case 16:
- t.Go = &ast.ArrayType{
- Len: c.intExpr(t.Size),
- Elt: c.uint8,
- }
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
- case *dwarf.PtrType:
- // 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
- t.Align = c.ptrSize
- if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
- t.Go = c.goVoidPtr
- t.C.Set("void*")
- dq := dt.Type
- for {
- if d, ok := dq.(*dwarf.QualType); ok {
- t.C.Set(d.Qual + " " + t.C.String())
- dq = d.Type
- } else {
- break
- }
- }
- break
- }
- // Placeholder initialization; completed in FinishType.
- t.Go = &ast.StarExpr{}
- t.C.Set("<incomplete>*")
- key := dt.Type.String()
- if _, ok := c.ptrs[key]; !ok {
- c.ptrKeys = append(c.ptrKeys, dt.Type)
- }
- c.ptrs[key] = append(c.ptrs[key], t)
- case *dwarf.QualType:
- t1 := c.Type(dt.Type, pos)
- t.Size = t1.Size
- t.Align = t1.Align
- t.Go = t1.Go
- if unionWithPointer[t1.Go] {
- unionWithPointer[t.Go] = true
- }
- t.EnumValues = nil
- t.Typedef = ""
- t.C.Set("%s "+dt.Qual, t1.C)
- return t
- case *dwarf.StructType:
- // Convert to Go struct, being careful about alignment.
- // Have to give it a name to simulate C "struct foo" references.
- tag := dt.StructName
- if dt.ByteSize < 0 && tag == "" { // opaque unnamed struct - should not be possible
- break
- }
- if tag == "" {
- tag = anonymousStructTag[dt]
- if tag == "" {
- tag = "__" + strconv.Itoa(tagGen)
- tagGen++
- anonymousStructTag[dt] = tag
- }
- } else if t.C.Empty() {
- t.C.Set(dt.Kind + " " + tag)
- }
- name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
- t.Go = name // publish before recursive calls
- goIdent[name.Name] = name
- 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{}")
- if dt.Kind == "struct" {
- // We don't know what the representation of this struct is, so don't let
- // anyone allocate one on the Go side. As a side effect of this annotation,
- // pointers to this type will not be considered pointers in Go. They won't
- // get writebarrier-ed or adjusted during a stack copy. This should handle
- // all the cases badPointerTypedef used to handle, but hopefully will
- // continue to work going forward without any more need for cgo changes.
- tt.NotInHeap = true
- // TODO: we should probably do the same for unions. Unions can't live
- // on the Go heap, right? It currently doesn't work for unions because
- // they are defined as a type alias for struct{}, not a defined type.
- }
- typedef[name.Name] = &tt
- break
- }
- switch dt.Kind {
- case "class", "union":
- t.Go = c.Opaque(t.Size)
- if c.dwarfHasPointer(dt, pos) {
- unionWithPointer[t.Go] = true
- }
- if t.C.Empty() {
- t.C.Set("__typeof__(unsigned char[%d])", t.Size)
- }
- t.Align = 1 // TODO: should probably base this on field alignment.
- typedef[name.Name] = t
- case "struct":
- g, csyntax, align := c.Struct(dt, pos)
- if t.C.Empty() {
- t.C.Set(csyntax)
- }
- t.Align = align
- tt := *t
- if tag != "" {
- tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
- }
- tt.Go = g
- tt.NotInHeap = c.notInHeapStructs[tag]
- typedef[name.Name] = &tt
- }
- 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.
- t.Go = c.string
- t.Size = c.ptrSize * 2
- t.Align = c.ptrSize
- break
- }
- 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
- }
- name := c.Ident("_Ctype_" + dt.Name)
- goIdent[name.Name] = name
- akey := ""
- if c.anonymousStructTypedef(dt) {
- // only load type recursively for typedefs of anonymous
- // structs, see issues 37479 and 37621.
- akey = key
- }
- sub := c.loadType(dt.Type, pos, akey)
- if c.badPointerTypedef(dt) {
- // Treat this typedef as a uintptr.
- s := *sub
- s.Go = c.uintptr
- s.BadPointer = true
- sub = &s
- // Make sure we update any previously computed type.
- if oldType := typedef[name.Name]; oldType != nil {
- oldType.Go = sub.Go
- oldType.BadPointer = true
- }
- }
- if c.badVoidPointerTypedef(dt) {
- // Treat this typedef as a pointer to a NotInHeap void.
- s := *sub
- s.Go = c.goVoidPtrNoHeap
- sub = &s
- // Make sure we update any previously computed type.
- if oldType := typedef[name.Name]; oldType != nil {
- oldType.Go = sub.Go
- }
- }
- // Check for non-pointer "struct <tag>{...}; typedef struct <tag> *<name>"
- // typedefs that should be marked NotInHeap.
- if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
- if strct, ok := ptr.Type.(*dwarf.StructType); ok {
- if c.badStructPointerTypedef(dt.Name, strct) {
- c.notInHeapStructs[strct.StructName] = true
- // Make sure we update any previously computed type.
- name := "_Ctype_struct_" + strct.StructName
- if oldType := typedef[name]; oldType != nil {
- oldType.NotInHeap = true
- }
- }
- }
- }
- t.Go = name
- t.BadPointer = sub.BadPointer
- t.NotInHeap = sub.NotInHeap
- if unionWithPointer[sub.Go] {
- unionWithPointer[t.Go] = true
- }
- t.Size = sub.Size
- t.Align = sub.Align
- oldType := typedef[name.Name]
- if oldType == nil {
- tt := *t
- tt.Go = sub.Go
- tt.BadPointer = sub.BadPointer
- tt.NotInHeap = sub.NotInHeap
- typedef[name.Name] = &tt
- }
- // 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.
- // In -godefs mode, do this for all typedefs.
- if isStructUnionClass(sub.Go) || *godefs {
- t.Go = sub.Go
- if isStructUnionClass(sub.Go) {
- // Use the typedef name for C code.
- typedef[sub.Go.(*ast.Ident).Name].C = t.C
- }
- // 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
- }
- }
- case *dwarf.UcharType:
- if t.Size != 1 {
- fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype)
- }
- t.Go = c.uint8
- t.Align = 1
- case *dwarf.UintType:
- if dt.BitSize > 0 {
- fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype)
- }
- switch t.Size {
- default:
- fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype)
- case 1:
- t.Go = c.uint8
- case 2:
- t.Go = c.uint16
- case 4:
- t.Go = c.uint32
- case 8:
- t.Go = c.uint64
- case 16:
- t.Go = &ast.ArrayType{
- Len: c.intExpr(t.Size),
- Elt: c.uint8,
- }
- }
- if t.Align = t.Size; t.Align >= c.ptrSize {
- t.Align = c.ptrSize
- }
- case *dwarf.VoidType:
- t.Go = c.goVoid
- t.C.Set("void")
- t.Align = 1
- }
- switch dtype.(type) {
- case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.ComplexType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
- s := dtype.Common().Name
- if s != "" {
- if ss, ok := dwarfToName[s]; ok {
- s = ss
- }
- s = strings.Replace(s, " ", "", -1)
- name := c.Ident("_Ctype_" + s)
- tt := *t
- typedef[name.Name] = &tt
- if !*godefs {
- t.Go = name
- }
- }
- }
- 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
- }
- t.Go = c.Opaque(0)
- default:
- t.Go = c.Opaque(0)
- }
- if t.C.Empty() {
- t.C.Set("void")
- }
- }
- if t.C.Empty() {
- fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype)
- }
- return t
- }
- // 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_")
- }
- // FuncArg returns a Go type with the same memory layout as
- // dtype when used as the type of a C function argument.
- func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
- t := c.Type(unqual(dtype), pos)
- switch dt := dtype.(type) {
- case *dwarf.ArrayType:
- // Arrays are passed implicitly as pointers in C.
- // In Go, we must be explicit.
- tr := &TypeRepr{}
- tr.Set("%s*", t.C)
- return &Type{
- Size: c.ptrSize,
- Align: c.ptrSize,
- Go: &ast.StarExpr{X: t.Go},
- C: tr,
- }
- case *dwarf.TypedefType:
- // C has much more relaxed rules than Go for
- // implicit type conversions. When the parameter
- // 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 {
- // Unless the typedef happens to point to void* since
- // Go has special rules around using unsafe.Pointer.
- if _, void := base(ptr.Type).(*dwarf.VoidType); void {
- break
- }
- // ...or the typedef is one in which we expect bad pointers.
- // It will be a uintptr instead of *X.
- if c.baseBadPointerTypedef(dt) {
- break
- }
- t = c.Type(ptr, pos)
- if t == nil {
- return nil
- }
- // 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
- }
- }
- }
- return t
- }
- // FuncType returns the Go type analogous to dtype.
- // There is no guarantee about matching memory layout.
- func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
- p := make([]*Type, len(dtype.ParamType))
- gp := make([]*ast.Field, len(dtype.ParamType))
- for i, f := range dtype.ParamType {
- // gcc's DWARF generator outputs a single DotDotDotType parameter for
- // function pointers that specify no parameters (e.g. void
- // (*__cgo_0)()). Treat this special case as void. This case is
- // invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
- // legal).
- if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
- p, gp = nil, nil
- break
- }
- p[i] = c.FuncArg(f, pos)
- gp[i] = &ast.Field{Type: p[i].Go}
- }
- var r *Type
- var gr []*ast.Field
- if _, ok := base(dtype.ReturnType).(*dwarf.VoidType); ok {
- gr = []*ast.Field{{Type: c.goVoid}}
- } else if dtype.ReturnType != nil {
- r = c.Type(unqual(dtype.ReturnType), pos)
- gr = []*ast.Field{{Type: r.Go}}
- }
- return &FuncType{
- Params: p,
- Result: r,
- Go: &ast.FuncType{
- Params: &ast.FieldList{List: gp},
- Results: &ast.FieldList{List: gr},
- },
- }
- }
- // Identifier
- func (c *typeConv) Ident(s string) *ast.Ident {
- return ast.NewIdent(s)
- }
- // Opaque type of n bytes.
- func (c *typeConv) Opaque(n int64) ast.Expr {
- return &ast.ArrayType{
- Len: c.intExpr(n),
- Elt: c.byte,
- }
- }
- // Expr for integer n.
- func (c *typeConv) intExpr(n int64) ast.Expr {
- return &ast.BasicLit{
- Kind: token.INT,
- Value: strconv.FormatInt(n, 10),
- }
- }
- // Add padding of given size to fld.
- func (c *typeConv) pad(fld []*ast.Field, sizes []int64, size int64) ([]*ast.Field, []int64) {
- n := len(fld)
- fld = fld[0 : n+1]
- fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
- sizes = sizes[0 : n+1]
- sizes[n] = size
- return fld, sizes
- }
- // Struct conversion: return Go and (gc) C syntax for type.
- func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
- // Minimum alignment for a struct is 1 byte.
- align = 1
- var buf bytes.Buffer
- buf.WriteString("struct {")
- fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
- sizes := make([]int64, 0, 2*len(dt.Field)+1)
- off := int64(0)
- // Rename struct fields that happen to be named Go keywords into
- // _{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
- // 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).
- ident := make(map[string]string)
- used := make(map[string]bool)
- for _, f := range dt.Field {
- ident[f.Name] = f.Name
- used[f.Name] = true
- }
- if !*godefs {
- for cid, goid := range ident {
- if token.Lookup(goid).IsKeyword() {
- // Avoid keyword
- goid = "_" + goid
- // Also avoid existing fields
- for _, exist := used[goid]; exist; _, exist = used[goid] {
- goid = "_" + goid
- }
- used[goid] = true
- ident[cid] = goid
- }
- }
- }
- anon := 0
- for _, f := range dt.Field {
- name := f.Name
- ft := f.Type
- // In godefs mode, if this field is a C11
- // anonymous union then treat the first field in the
- // union as the field in the struct. This handles
- // cases like the glibc <sys/resource.h> file; see
- // issue 6677.
- if *godefs {
- 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)
- tgo := t.Go
- size := t.Size
- talign := t.Align
- if f.BitOffset > 0 || f.BitSize > 0 {
- // The layout of bitfields is implementation defined,
- // so we don't know how they correspond to Go fields
- // even if they are aligned at byte boundaries.
- continue
- }
- if talign > 0 && f.ByteOffset%talign != 0 {
- // 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
- }
- // Round off up to talign, assumed to be a power of 2.
- off = (off + talign - 1) &^ (talign - 1)
- if f.ByteOffset > off {
- fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
- off = f.ByteOffset
- }
- if f.ByteOffset < off {
- // Drop a packed field that we can't represent.
- continue
- }
- n := len(fld)
- fld = fld[0 : n+1]
- 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}
- sizes = sizes[0 : n+1]
- sizes[n] = size
- off += size
- buf.WriteString(t.C.String())
- buf.WriteString(" ")
- buf.WriteString(name)
- buf.WriteString("; ")
- if talign > align {
- align = talign
- }
- }
- if off < dt.ByteSize {
- fld, sizes = c.pad(fld, sizes, dt.ByteSize-off)
- off = dt.ByteSize
- }
- // 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,
- // which means that it cannot be referenced from Go.
- for off > 0 && sizes[len(sizes)-1] == 0 {
- n := len(sizes)
- fld = fld[0 : n-1]
- sizes = sizes[0 : n-1]
- }
- if off != dt.ByteSize {
- fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize)
- }
- buf.WriteString("}")
- csyntax = buf.String()
- if *godefs {
- godefsFields(fld)
- }
- expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
- return
- }
- // dwarfHasPointer reports 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)
- }
- }
- 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)
- // Issue 48396: check for duplicate field names.
- if prefix != "" {
- names := make(map[string]bool)
- fldLoop:
- for _, f := range fld {
- for _, n := range f.Names {
- name := n.Name
- if name == "_" {
- continue
- }
- if name != prefix {
- name = strings.TrimPrefix(n.Name, prefix)
- }
- name = upper(name)
- if names[name] {
- // Field name conflict: don't remove prefix.
- prefix = ""
- break fldLoop
- }
- names[name] = true
- }
- }
- }
- npad := 0
- for _, f := range fld {
- for _, n := range f.Names {
- if n.Name != prefix {
- n.Name = strings.TrimPrefix(n.Name, prefix)
- }
- if n.Name == "_" {
- // Use exported name instead.
- n.Name = "Pad_cgo_" + strconv.Itoa(npad)
- npad++
- }
- n.Name = upper(n.Name)
- }
- }
- }
- // fieldPrefix returns the prefix that should be removed from all the
- // field names when generating the C or Go code. For generated
- // 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
- // looking for. It is common in C headers to have fields
- // 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.
- // The check for "orig_" here handles orig_eax in the
- // x86 ptrace register sets, which otherwise have all fields
- // with reg_ prefixes.
- if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") {
- continue
- }
- i := strings.Index(n.Name, "_")
- if i < 0 {
- continue
- }
- if prefix == "" {
- prefix = n.Name[:i+1]
- } else if prefix != n.Name[:i+1] {
- return ""
- }
- }
- }
- return prefix
- }
- // anonymousStructTypedef reports whether dt is a C typedef for an anonymous
- // struct.
- func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool {
- st, ok := dt.Type.(*dwarf.StructType)
- return ok && st.StructName == ""
- }
- // badPointerTypedef reports whether dt is a C typedef that should not be
- // considered a pointer in Go. A typedef is bad if C code sometimes stores
- // non-pointers in this type.
- // TODO: Currently our best solution is to find these manually and list them as
- // they come up. A better solution is desired.
- // Note: DEPRECATED. There is now a better solution. Search for NotInHeap in this file.
- func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
- if c.badCFType(dt) {
- return true
- }
- if c.badJNI(dt) {
- return true
- }
- if c.badEGLType(dt) {
- return true
- }
- return false
- }
- // badVoidPointerTypedef is like badPointerTypeDef, but for "void *" typedefs that should be NotInHeap.
- func (c *typeConv) badVoidPointerTypedef(dt *dwarf.TypedefType) bool {
- // Match the Windows HANDLE type (#42018).
- if goos != "windows" || dt.Name != "HANDLE" {
- return false
- }
- // Check that the typedef is "typedef void *<name>".
- if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
- if _, ok := ptr.Type.(*dwarf.VoidType); ok {
- return true
- }
- }
- return false
- }
- // badStructPointerTypedef is like badVoidPointerTypedefs but for structs.
- func (c *typeConv) badStructPointerTypedef(name string, dt *dwarf.StructType) bool {
- // Windows handle types can all potentially contain non-pointers.
- // badVoidPointerTypedef handles the "void *" HANDLE type, but other
- // handles are defined as
- //
- // struct <name>__{int unused;}; typedef struct <name>__ *name;
- //
- // by the DECLARE_HANDLE macro in STRICT mode. The macro is declared in
- // the Windows ntdef.h header,
- //
- // https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/shared/ntdef.h#L779
- if goos != "windows" {
- return false
- }
- if len(dt.Field) != 1 {
- return false
- }
- if dt.StructName != name+"__" {
- return false
- }
- if f := dt.Field[0]; f.Name != "unused" || f.Type.Common().Name != "int" {
- return false
- }
- return true
- }
- // baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef
- // as badPointerTypedef reports.
- func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
- for {
- if t, ok := dt.Type.(*dwarf.TypedefType); ok {
- dt = t
- continue
- }
- break
- }
- return c.badPointerTypedef(dt)
- }
- func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
- // The real bad types are CFNumberRef and CFDateRef.
- // Sometimes non-pointers are stored in these types.
- // CFTypeRef is a supertype of those, so it can have bad pointers in it as well.
- // We return true for the other *Ref types just so casting between them is easier.
- // We identify the correct set of types as those ending in Ref and for which
- // there exists a corresponding GetTypeID function.
- // See comment below for details about the bad pointers.
- if goos != "darwin" && goos != "ios" {
- return false
- }
- s := dt.Name
- if !strings.HasSuffix(s, "Ref") {
- return false
- }
- s = s[:len(s)-3]
- if s == "CFType" {
- return true
- }
- if c.getTypeIDs[s] {
- return true
- }
- if i := strings.Index(s, "Mutable"); i >= 0 && c.getTypeIDs[s[:i]+s[i+7:]] {
- // Mutable and immutable variants share a type ID.
- return true
- }
- return false
- }
- // Comment from Darwin's CFInternal.h
- /*
- // Tagged pointer support
- // Low-bit set means tagged object, next 3 bits (currently)
- // define the tagged object class, next 4 bits are for type
- // information for the specific tagged object class. Thus,
- // the low byte is for type info, and the rest of a pointer
- // (32 or 64-bit) is for payload, whatever the tagged class.
- //
- // Note that the specific integers used to identify the
- // specific tagged classes can and will change from release
- // to release (that's why this stuff is in CF*Internal*.h),
- // as can the definition of type info vs payload above.
- //
- #if __LP64__
- #define CF_IS_TAGGED_OBJ(PTR) ((uintptr_t)(PTR) & 0x1)
- #define CF_TAGGED_OBJ_TYPE(PTR) ((uintptr_t)(PTR) & 0xF)
- #else
- #define CF_IS_TAGGED_OBJ(PTR) 0
- #define CF_TAGGED_OBJ_TYPE(PTR) 0
- #endif
- enum {
- kCFTaggedObjectID_Invalid = 0,
- kCFTaggedObjectID_Atom = (0 << 1) + 1,
- kCFTaggedObjectID_Undefined3 = (1 << 1) + 1,
- kCFTaggedObjectID_Undefined2 = (2 << 1) + 1,
- kCFTaggedObjectID_Integer = (3 << 1) + 1,
- kCFTaggedObjectID_DateTS = (4 << 1) + 1,
- kCFTaggedObjectID_ManagedObjectID = (5 << 1) + 1, // Core Data
- kCFTaggedObjectID_Date = (6 << 1) + 1,
- kCFTaggedObjectID_Undefined7 = (7 << 1) + 1,
- };
- */
- func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
- // In Dalvik and ART, the jobject type in the JNI interface of the JVM has the
- // property that it is sometimes (always?) a small integer instead of a real pointer.
- // Note: although only the android JVMs are bad in this respect, we declare the JNI types
- // bad regardless of platform, so the same Go code compiles on both android and non-android.
- if parent, ok := jniTypes[dt.Name]; ok {
- // Try to make sure we're talking about a JNI type, not just some random user's
- // type that happens to use the same name.
- // C doesn't have the notion of a package, so it's hard to be certain.
- // Walk up to jobject, checking each typedef on the way.
- w := dt
- for parent != "" {
- t, ok := w.Type.(*dwarf.TypedefType)
- if !ok || t.Name != parent {
- return false
- }
- w = t
- parent, ok = jniTypes[w.Name]
- if !ok {
- return false
- }
- }
- // Check that the typedef is either:
- // 1:
- // struct _jobject;
- // typedef struct _jobject *jobject;
- // 2: (in NDK16 in C++)
- // class _jobject {};
- // typedef _jobject* jobject;
- // 3: (in NDK16 in C)
- // typedef void* jobject;
- if ptr, ok := w.Type.(*dwarf.PtrType); ok {
- switch v := ptr.Type.(type) {
- case *dwarf.VoidType:
- return true
- case *dwarf.StructType:
- if v.StructName == "_jobject" && len(v.Field) == 0 {
- switch v.Kind {
- case "struct":
- if v.Incomplete {
- return true
- }
- case "class":
- if !v.Incomplete {
- return true
- }
- }
- }
- }
- }
- }
- return false
- }
- func (c *typeConv) badEGLType(dt *dwarf.TypedefType) bool {
- if dt.Name != "EGLDisplay" && dt.Name != "EGLConfig" {
- return false
- }
- // Check that the typedef is "typedef void *<name>".
- if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
- if _, ok := ptr.Type.(*dwarf.VoidType); ok {
- return true
- }
- }
- return false
- }
- // jniTypes maps from JNI types that we want to be uintptrs, to the underlying type to which
- // they are mapped. The base "jobject" maps to the empty string.
- var jniTypes = map[string]string{
- "jobject": "",
- "jclass": "jobject",
- "jthrowable": "jobject",
- "jstring": "jobject",
- "jarray": "jobject",
- "jbooleanArray": "jarray",
- "jbyteArray": "jarray",
- "jcharArray": "jarray",
- "jshortArray": "jarray",
- "jintArray": "jarray",
- "jlongArray": "jarray",
- "jfloatArray": "jarray",
- "jdoubleArray": "jarray",
- "jobjectArray": "jarray",
- "jweak": "jobject",
- }
|