craig65535
craig65535

Reputation: 3581

cgo -godefs with nested anonymous structs?

I'm writing some go code that will take the output of a sysctl and parse the output. I'm trying to do this in pure go, but with a struct definition generated by cgo.

inet_headers.go:

//go:build ignore
// +build ignore

package inet

// #include <netinet/in_pcb.h>
// #include <netinet/tcp_var.h>
import "C"

type Inpcb C.struct_inpcb
type _Inpcb_list_entry C.struct__inpcb_list_entry
type In_addr C.struct_in_addr

When I run go tool cgo -godefs inet_headers.go I get mostly sensible output:

package inet

type Inpcb struct {
    Inp_hash    _Inpcb_list_entry
    Reserved1   In_addr
    Reserved2   In_addr
    Inp_fport   uint16
    Inp_lport   uint16
    Inp_list    _Inpcb_list_entry
    Inp_ppcb    uint32
    Inp_pcbinfo uint32
    Inp_socket  uint32
    Nat_owner   uint8
    Nat_cookie  uint32
    Inp_portlist    _Inpcb_list_entry
    Inp_phd     uint32
    Pad_cgo_0   [8]byte
    Inp_flags   int32
    Inp_flow    uint32
    Inp_vflag   uint8
    Inp_ip_ttl  uint8
    Inp_ip_p    uint8
    Pad_cgo_1   [1]byte
    Inp_dependfaddr [16]byte
    Inp_dependladdr [16]byte
    Inp_dependroute [32]byte
    Inp_depend4 _Ctype_struct___3
    Inp_depend6 _Ctype_struct___4
    Hash_element    int32
    Inp_saved_ppcb  uint32
    Inp_sp      uint32
    Reserved    [3]uint32
}
type _Inpcb_list_entry struct {
    Next    uint32
    Prev    uint32
}
type In_addr struct {
    Addr uint32
}

However, the _Ctype_struct___3 is a problem because it is undefined. This is an anonymous struct embedded in struct inpcb:

struct inpcb {
        _INPCB_LIST_ENTRY(inpcb) inp_hash;      /* hash list */
        struct in_addr reserved1;               /* reserved */
        struct in_addr reserved2;               /* reserved */
        u_short inp_fport;                      /* foreign port */
        u_short inp_lport;                      /* local port */
        _INPCB_LIST_ENTRY(inpcb) inp_list;      /* list for all peer PCBs */
        _INPCB_PTR(caddr_t) inp_ppcb;           /* per-protocol pcb */
        _INPCB_PTR(struct inpcbinfo *) inp_pcbinfo;     /* PCB list info */
        _INPCB_PTR(void *) inp_socket;  /* back pointer to socket */
        u_char nat_owner;               /* Used to NAT TCP/UDP traffic */
        u_int32_t nat_cookie;           /* Cookie stored and returned to NAT */
        _INPCB_LIST_ENTRY(inpcb) inp_portlist;  /* this PCB's local port list */
        _INPCB_PTR(struct inpcbport *) inp_phd; /* head of this list */
        inp_gen_t inp_gencnt;           /* generation count of this instance */
        int inp_flags;                  /* generic IP/datagram flags */
        u_int32_t inp_flow;

        u_char inp_vflag;

        u_char inp_ip_ttl;              /* time to live proto */
        u_char inp_ip_p;                /* protocol proto */
        /* protocol dependent part */
        union {
                /* foreign host table entry */
                struct in_addr_4in6 inp46_foreign;
                struct in6_addr inp6_foreign;
        } inp_dependfaddr;
        union {
                /* local host table entry */
                struct in_addr_4in6 inp46_local;
                struct in6_addr inp6_local;
        } inp_dependladdr;
        union {
                /* placeholder for routing entry */
                u_char inp4_route[20];
                u_char inp6_route[32];
        } inp_dependroute;
        struct {
                /* type of service proto */
                u_char inp4_ip_tos;
                /* IP options */
                _INPCB_PTR(struct mbuf *) inp4_options;
                /* IP multicast options */
                _INPCB_PTR(struct ip_moptions *) inp4_moptions;
        } inp_depend4;

        struct {
                /* IP options */
                _INPCB_PTR(struct mbuf *) inp6_options;
                u_int8_t inp6_hlim;
                u_int8_t unused_uint8_1;
                ushort unused_uint16_1;
                /* IP6 options for outgoing packets */
                _INPCB_PTR(struct ip6_pktopts *) inp6_outputopts;
                /* IP multicast options */
                _INPCB_PTR(struct ip6_moptions *) inp6_moptions;
                /* ICMPv6 code type filter */
                _INPCB_PTR(struct icmp6_filter *) inp6_icmp6filt;
                /* IPV6_CHECKSUM setsockopt */
                int     inp6_cksum;
                u_short inp6_ifindex;
                short   inp6_hops;
        } inp_depend6;

        int hash_element;               /* Array index of pcb's hash list */
        _INPCB_PTR(caddr_t) inp_saved_ppcb; /* pointer while cached */
        _INPCB_PTR(struct inpcbpolicy *) inp_sp;
        u_int32_t       reserved[3];    /* reserved */
};

This works fine in straight cgo because the compiler will generate code for every struct. However, with cgo -godefs, it seems that code is only generated for exported types that I have to list explicitly (e.g. type Inpcb C.struct_inpcb).

Is there a way around this?

I can't explicitly export a type for _Ctype_struct___3 (and that's a bad idea anyway because there's no guarantee that type name will be generated next time). type StructInp_depend4 _Ctype_struct___3 results in identifier "_Ctype_struct___3" may conflict with identifiers generated by cgo.

Or, is there a way to coerece cgo -godefs to explicitly export certain types?

Edit: I am reading that this is a known issue.

Upvotes: 1

Views: 261

Answers (0)

Related Questions