[v5,2/3] golang/xenlight: implement keyed union Go to C marshaling
diff mbox series

Message ID 52678cf50a54609dc453df47ffb4fa0429c69bbd.1578170151.git.rosbrookn@ainfosec.com
State New
Headers show
Series
  • generated Go libxl bindings using IDL
Related show

Commit Message

Nick Rosbrook Jan. 4, 2020, 9 p.m. UTC
Since the C union cannot be directly populated, populate the fields of the
corresponding C struct defined in the cgo preamble, and then copy that
struct as bytes into the byte slice that Go uses as the union.

Signed-off-by: Nick Rosbrook <rosbrookn@ainfosec.com>
---
Changes in v5:
- Make use of xenlight_golang_convert_to_C to convert fields.
- Remove dispose_fn from parameter list in xenlight_golang_union_to_C
  since it's no longer needed.
---
 tools/golang/xenlight/gengotypes.py  |  79 ++++++-
 tools/golang/xenlight/helpers.gen.go | 294 +++++++++++++++++++++++++++
 2 files changed, 366 insertions(+), 7 deletions(-)

Comments

George Dunlap Jan. 16, 2020, 4:16 p.m. UTC | #1
On 1/4/20 9:00 PM, Nick Rosbrook wrote:
> Since the C union cannot be directly populated, populate the fields of the
> corresponding C struct defined in the cgo preamble, and then copy that
> struct as bytes into the byte slice that Go uses as the union.
> 
> Signed-off-by: Nick Rosbrook <rosbrookn@ainfosec.com>

Reviewed-by: George Dunlap <george.dunlap@citrix.com>

Patch
diff mbox series

diff --git a/tools/golang/xenlight/gengotypes.py b/tools/golang/xenlight/gengotypes.py
index 15aa4be220..8ab6768e61 100644
--- a/tools/golang/xenlight/gengotypes.py
+++ b/tools/golang/xenlight/gengotypes.py
@@ -464,15 +464,15 @@  def xenlight_golang_define_to_C(ty = None, typename = None, nested = False):
                 body += xenlight_golang_convert_to_C(nf, outer_name=f.name)
 
         elif isinstance(f.type, idl.KeyedUnion):
-            # TODO
-            pass
+            body += xenlight_golang_union_to_C(f.type, f.name, ty.typename)
 
         else:
             raise Exception('type {} not supported'.format(f.type))
 
     return func.format(goname, cname, body)
 
-def xenlight_golang_convert_to_C(ty = None, outer_name = None):
+def xenlight_golang_convert_to_C(ty = None, outer_name = None,
+                                 govarname = None, cvarname = None):
     """
     Returns a line of Go code that converts the Go type represented
     by ty to its corresponding Go type.
@@ -482,6 +482,14 @@  def xenlight_golang_convert_to_C(ty = None, outer_name = None):
     """
     s = ''
 
+    # Use 'xc' as the name for the C variable unless otherwise specified.
+    if cvarname is None:
+        cvarname = 'xc'
+
+    # Use 'x' as the name for the Go variable unless otherwise specified.
+    if govarname is None:
+        govarname = 'x'
+
     gotypename = xenlight_golang_fmt_name(ty.type.typename)
     ctypename  = ty.type.typename
     goname     = xenlight_golang_fmt_name(ty.name)
@@ -502,16 +510,73 @@  def xenlight_golang_convert_to_C(ty = None, outer_name = None):
                    gotypename in go_builtin_types)
 
     if not is_castable:
-        s += 'if err := x.{}.toC(&xc.{}); err != nil {{\n'.format(goname,cname)
+        s += 'if err := {}.{}.toC(&{}.{}); err != nil {{\n'.format(govarname,goname,
+                                                                   cvarname,cname)
         s += 'return err\n}\n'
 
     elif gotypename == 'string':
         # Use the cgo helper for converting C strings.
-        s += 'if x.{} != "" {{\n'.format(goname)
-        s += 'xc.{} = C.CString(x.{})}}\n'.format(cname,goname)
+        s += 'if {}.{} != "" {{\n'.format(govarname,goname)
+        s += '{}.{} = C.CString({}.{})}}\n'.format(cvarname,cname,
+                                                   govarname,goname)
 
     else:
-        s += 'xc.{} = C.{}(x.{})\n'.format(cname,ctypename,goname)
+        s += '{}.{} = C.{}({}.{})\n'.format(cvarname,cname,ctypename,
+                                            govarname,goname)
+
+    return s
+
+def xenlight_golang_union_to_C(ty = None, union_name = '',
+                               struct_name = ''):
+    keyname   = ty.keyvar.name
+    gokeyname = xenlight_golang_fmt_name(keyname)
+    keytype   = ty.keyvar.type.typename
+    gokeytype = xenlight_golang_fmt_name(keytype)
+
+    interface_name = '{}_{}_union'.format(struct_name, keyname)
+    interface_name = xenlight_golang_fmt_name(interface_name, exported=False)
+
+    cgo_keyname = keyname
+    if cgo_keyname in go_keywords:
+        cgo_keyname = '_' + cgo_keyname
+
+
+    s = 'xc.{} = C.{}(x.{})\n'.format(cgo_keyname,keytype,gokeyname)
+    s += 'switch x.{}{{\n'.format(gokeyname)
+
+    # Create switch statement to determine how to populate the C union.
+    for f in ty.fields:
+        key_val = '{}_{}'.format(keytype, f.name)
+        key_val = xenlight_golang_fmt_name(key_val)
+        if f.type is None:
+            continue
+
+        s += 'case {}:\n'.format(key_val)
+        cgotype = '{}_{}_union_{}'.format(struct_name,keyname,f.name)
+        gotype  = xenlight_golang_fmt_name(cgotype)
+
+        field_name = xenlight_golang_fmt_name('{}_union'.format(keyname))
+        s += 'tmp, ok := x.{}.({})\n'.format(field_name,gotype)
+        s += 'if !ok {\n'
+        s += 'return errors.New("wrong type for union key {}")\n'.format(keyname)
+        s += '}\n'
+
+        s += 'var {} C.{}\n'.format(f.name,cgotype)
+        for uf in f.type.fields:
+            s += xenlight_golang_convert_to_C(uf,cvarname=f.name,
+                                              govarname='tmp')
+
+        # The union is still represented as Go []byte.
+        s += '{}Bytes := C.GoBytes(unsafe.Pointer(&{}),C.sizeof_{})\n'.format(f.name,
+                                                                              f.name,
+                                                                              cgotype)
+        s += 'copy(xc.{}[:],{}Bytes)\n'.format(union_name,f.name)
+
+    # End switch statement
+    s += 'default:\n'
+    err_string = '"invalid union key \'%v\'", x.{}'.format(gokeyname)
+    s += 'return fmt.Errorf({})'.format(err_string)
+    s += '}\n'
 
     return s
 
diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go
index 30cd1a9b3f..0bf2b0ddef 100644
--- a/tools/golang/xenlight/helpers.gen.go
+++ b/tools/golang/xenlight/helpers.gen.go
@@ -381,6 +381,22 @@  func (x *Channelinfo) toC(xc *C.libxl_channelinfo) (err error) {
 	xc.state = C.int(x.State)
 	xc.evtch = C.int(x.Evtch)
 	xc.rref = C.int(x.Rref)
+	xc.connection = C.libxl_channel_connection(x.Connection)
+	switch x.Connection {
+	case ChannelConnectionPty:
+		tmp, ok := x.ConnectionUnion.(ChannelinfoConnectionUnionPty)
+		if !ok {
+			return errors.New("wrong type for union key connection")
+		}
+		var pty C.libxl_channelinfo_connection_union_pty
+		if tmp.Path != "" {
+			pty.path = C.CString(tmp.Path)
+		}
+		ptyBytes := C.GoBytes(unsafe.Pointer(&pty), C.sizeof_libxl_channelinfo_connection_union_pty)
+		copy(xc.u[:], ptyBytes)
+	default:
+		return fmt.Errorf("invalid union key '%v'", x.Connection)
+	}
 
 	return nil
 }
@@ -1124,6 +1140,189 @@  func (x *DomainBuildInfo) toC(xc *C.libxl_domain_build_info) (err error) {
 		return err
 	}
 	xc.tee = C.libxl_tee_type(x.Tee)
+	xc._type = C.libxl_domain_type(x.Type)
+	switch x.Type {
+	case DomainTypeHvm:
+		tmp, ok := x.TypeUnion.(DomainBuildInfoTypeUnionHvm)
+		if !ok {
+			return errors.New("wrong type for union key type")
+		}
+		var hvm C.libxl_domain_build_info_type_union_hvm
+		if tmp.Firmware != "" {
+			hvm.firmware = C.CString(tmp.Firmware)
+		}
+		hvm.bios = C.libxl_bios_type(tmp.Bios)
+		if err := tmp.Pae.toC(&hvm.pae); err != nil {
+			return err
+		}
+		if err := tmp.Apic.toC(&hvm.apic); err != nil {
+			return err
+		}
+		if err := tmp.Acpi.toC(&hvm.acpi); err != nil {
+			return err
+		}
+		if err := tmp.AcpiS3.toC(&hvm.acpi_s3); err != nil {
+			return err
+		}
+		if err := tmp.AcpiS4.toC(&hvm.acpi_s4); err != nil {
+			return err
+		}
+		if err := tmp.AcpiLaptopSlate.toC(&hvm.acpi_laptop_slate); err != nil {
+			return err
+		}
+		if err := tmp.Nx.toC(&hvm.nx); err != nil {
+			return err
+		}
+		if err := tmp.Viridian.toC(&hvm.viridian); err != nil {
+			return err
+		}
+		if err := tmp.ViridianEnable.toC(&hvm.viridian_enable); err != nil {
+			return err
+		}
+		if err := tmp.ViridianDisable.toC(&hvm.viridian_disable); err != nil {
+			return err
+		}
+		if tmp.Timeoffset != "" {
+			hvm.timeoffset = C.CString(tmp.Timeoffset)
+		}
+		if err := tmp.Hpet.toC(&hvm.hpet); err != nil {
+			return err
+		}
+		if err := tmp.VptAlign.toC(&hvm.vpt_align); err != nil {
+			return err
+		}
+		hvm.mmio_hole_memkb = C.uint64_t(tmp.MmioHoleMemkb)
+		hvm.timer_mode = C.libxl_timer_mode(tmp.TimerMode)
+		if err := tmp.NestedHvm.toC(&hvm.nested_hvm); err != nil {
+			return err
+		}
+		if err := tmp.Altp2M.toC(&hvm.altp2m); err != nil {
+			return err
+		}
+		if tmp.SystemFirmware != "" {
+			hvm.system_firmware = C.CString(tmp.SystemFirmware)
+		}
+		if tmp.SmbiosFirmware != "" {
+			hvm.smbios_firmware = C.CString(tmp.SmbiosFirmware)
+		}
+		if tmp.AcpiFirmware != "" {
+			hvm.acpi_firmware = C.CString(tmp.AcpiFirmware)
+		}
+		hvm.hdtype = C.libxl_hdtype(tmp.Hdtype)
+		if err := tmp.Nographic.toC(&hvm.nographic); err != nil {
+			return err
+		}
+		if err := tmp.Vga.toC(&hvm.vga); err != nil {
+			return err
+		}
+		if err := tmp.Vnc.toC(&hvm.vnc); err != nil {
+			return err
+		}
+		if tmp.Keymap != "" {
+			hvm.keymap = C.CString(tmp.Keymap)
+		}
+		if err := tmp.Sdl.toC(&hvm.sdl); err != nil {
+			return err
+		}
+		if err := tmp.Spice.toC(&hvm.spice); err != nil {
+			return err
+		}
+		if err := tmp.GfxPassthru.toC(&hvm.gfx_passthru); err != nil {
+			return err
+		}
+		hvm.gfx_passthru_kind = C.libxl_gfx_passthru_kind(tmp.GfxPassthruKind)
+		if tmp.Serial != "" {
+			hvm.serial = C.CString(tmp.Serial)
+		}
+		if tmp.Boot != "" {
+			hvm.boot = C.CString(tmp.Boot)
+		}
+		if err := tmp.Usb.toC(&hvm.usb); err != nil {
+			return err
+		}
+		hvm.usbversion = C.int(tmp.Usbversion)
+		if tmp.Usbdevice != "" {
+			hvm.usbdevice = C.CString(tmp.Usbdevice)
+		}
+		if err := tmp.VkbDevice.toC(&hvm.vkb_device); err != nil {
+			return err
+		}
+		if tmp.Soundhw != "" {
+			hvm.soundhw = C.CString(tmp.Soundhw)
+		}
+		if err := tmp.XenPlatformPci.toC(&hvm.xen_platform_pci); err != nil {
+			return err
+		}
+		if err := tmp.UsbdeviceList.toC(&hvm.usbdevice_list); err != nil {
+			return err
+		}
+		hvm.vendor_device = C.libxl_vendor_device(tmp.VendorDevice)
+		if err := tmp.MsVmGenid.toC(&hvm.ms_vm_genid); err != nil {
+			return err
+		}
+		if err := tmp.SerialList.toC(&hvm.serial_list); err != nil {
+			return err
+		}
+		if err := tmp.Rdm.toC(&hvm.rdm); err != nil {
+			return err
+		}
+		hvm.rdm_mem_boundary_memkb = C.uint64_t(tmp.RdmMemBoundaryMemkb)
+		hvm.mca_caps = C.uint64_t(tmp.McaCaps)
+		hvmBytes := C.GoBytes(unsafe.Pointer(&hvm), C.sizeof_libxl_domain_build_info_type_union_hvm)
+		copy(xc.u[:], hvmBytes)
+	case DomainTypePv:
+		tmp, ok := x.TypeUnion.(DomainBuildInfoTypeUnionPv)
+		if !ok {
+			return errors.New("wrong type for union key type")
+		}
+		var pv C.libxl_domain_build_info_type_union_pv
+		if tmp.Kernel != "" {
+			pv.kernel = C.CString(tmp.Kernel)
+		}
+		pv.slack_memkb = C.uint64_t(tmp.SlackMemkb)
+		if tmp.Bootloader != "" {
+			pv.bootloader = C.CString(tmp.Bootloader)
+		}
+		if err := tmp.BootloaderArgs.toC(&pv.bootloader_args); err != nil {
+			return err
+		}
+		if tmp.Cmdline != "" {
+			pv.cmdline = C.CString(tmp.Cmdline)
+		}
+		if tmp.Ramdisk != "" {
+			pv.ramdisk = C.CString(tmp.Ramdisk)
+		}
+		if tmp.Features != "" {
+			pv.features = C.CString(tmp.Features)
+		}
+		if err := tmp.E820Host.toC(&pv.e820_host); err != nil {
+			return err
+		}
+		pvBytes := C.GoBytes(unsafe.Pointer(&pv), C.sizeof_libxl_domain_build_info_type_union_pv)
+		copy(xc.u[:], pvBytes)
+	case DomainTypePvh:
+		tmp, ok := x.TypeUnion.(DomainBuildInfoTypeUnionPvh)
+		if !ok {
+			return errors.New("wrong type for union key type")
+		}
+		var pvh C.libxl_domain_build_info_type_union_pvh
+		if err := tmp.Pvshim.toC(&pvh.pvshim); err != nil {
+			return err
+		}
+		if tmp.PvshimPath != "" {
+			pvh.pvshim_path = C.CString(tmp.PvshimPath)
+		}
+		if tmp.PvshimCmdline != "" {
+			pvh.pvshim_cmdline = C.CString(tmp.PvshimCmdline)
+		}
+		if tmp.PvshimExtra != "" {
+			pvh.pvshim_extra = C.CString(tmp.PvshimExtra)
+		}
+		pvhBytes := C.GoBytes(unsafe.Pointer(&pvh), C.sizeof_libxl_domain_build_info_type_union_pvh)
+		copy(xc.u[:], pvhBytes)
+	default:
+		return fmt.Errorf("invalid union key '%v'", x.Type)
+	}
 	xc.arch_arm.gic_version = C.libxl_gic_version(x.ArchArm.GicVersion)
 	xc.arch_arm.vuart = C.libxl_vuart_type(x.ArchArm.Vuart)
 	xc.altp2m = C.libxl_altp2m_mode(x.Altp2M)
@@ -1689,6 +1888,21 @@  func (x *DeviceUsbdev) toC(xc *C.libxl_device_usbdev) (err error) {
 
 	xc.ctrl = C.libxl_devid(x.Ctrl)
 	xc.port = C.int(x.Port)
+	xc._type = C.libxl_usbdev_type(x.Type)
+	switch x.Type {
+	case UsbdevTypeHostdev:
+		tmp, ok := x.TypeUnion.(DeviceUsbdevTypeUnionHostdev)
+		if !ok {
+			return errors.New("wrong type for union key type")
+		}
+		var hostdev C.libxl_device_usbdev_type_union_hostdev
+		hostdev.hostbus = C.uint8_t(tmp.Hostbus)
+		hostdev.hostaddr = C.uint8_t(tmp.Hostaddr)
+		hostdevBytes := C.GoBytes(unsafe.Pointer(&hostdev), C.sizeof_libxl_device_usbdev_type_union_hostdev)
+		copy(xc.u[:], hostdevBytes)
+	default:
+		return fmt.Errorf("invalid union key '%v'", x.Type)
+	}
 
 	return nil
 }
@@ -1848,6 +2062,22 @@  func (x *DeviceChannel) toC(xc *C.libxl_device_channel) (err error) {
 	if x.Name != "" {
 		xc.name = C.CString(x.Name)
 	}
+	xc.connection = C.libxl_channel_connection(x.Connection)
+	switch x.Connection {
+	case ChannelConnectionSocket:
+		tmp, ok := x.ConnectionUnion.(DeviceChannelConnectionUnionSocket)
+		if !ok {
+			return errors.New("wrong type for union key connection")
+		}
+		var socket C.libxl_device_channel_connection_union_socket
+		if tmp.Path != "" {
+			socket.path = C.CString(tmp.Path)
+		}
+		socketBytes := C.GoBytes(unsafe.Pointer(&socket), C.sizeof_libxl_device_channel_connection_union_socket)
+		copy(xc.u[:], socketBytes)
+	default:
+		return fmt.Errorf("invalid union key '%v'", x.Connection)
+	}
 
 	return nil
 }
@@ -2911,6 +3141,43 @@  func (x *Event) toC(xc *C.libxl_event) (err error) {
 		return err
 	}
 	xc.for_user = C.uint64_t(x.ForUser)
+	xc._type = C.libxl_event_type(x.Type)
+	switch x.Type {
+	case EventTypeDomainShutdown:
+		tmp, ok := x.TypeUnion.(EventTypeUnionDomainShutdown)
+		if !ok {
+			return errors.New("wrong type for union key type")
+		}
+		var domain_shutdown C.libxl_event_type_union_domain_shutdown
+		domain_shutdown.shutdown_reason = C.uint8_t(tmp.ShutdownReason)
+		domain_shutdownBytes := C.GoBytes(unsafe.Pointer(&domain_shutdown), C.sizeof_libxl_event_type_union_domain_shutdown)
+		copy(xc.u[:], domain_shutdownBytes)
+	case EventTypeDiskEject:
+		tmp, ok := x.TypeUnion.(EventTypeUnionDiskEject)
+		if !ok {
+			return errors.New("wrong type for union key type")
+		}
+		var disk_eject C.libxl_event_type_union_disk_eject
+		if tmp.Vdev != "" {
+			disk_eject.vdev = C.CString(tmp.Vdev)
+		}
+		if err := tmp.Disk.toC(&disk_eject.disk); err != nil {
+			return err
+		}
+		disk_ejectBytes := C.GoBytes(unsafe.Pointer(&disk_eject), C.sizeof_libxl_event_type_union_disk_eject)
+		copy(xc.u[:], disk_ejectBytes)
+	case EventTypeOperationComplete:
+		tmp, ok := x.TypeUnion.(EventTypeUnionOperationComplete)
+		if !ok {
+			return errors.New("wrong type for union key type")
+		}
+		var operation_complete C.libxl_event_type_union_operation_complete
+		operation_complete.rc = C.int(tmp.Rc)
+		operation_completeBytes := C.GoBytes(unsafe.Pointer(&operation_complete), C.sizeof_libxl_event_type_union_operation_complete)
+		copy(xc.u[:], operation_completeBytes)
+	default:
+		return fmt.Errorf("invalid union key '%v'", x.Type)
+	}
 
 	return nil
 }
@@ -2994,6 +3261,33 @@  func (x *PsrHwInfo) toC(xc *C.libxl_psr_hw_info) (err error) {
 	}()
 
 	xc.id = C.uint32_t(x.Id)
+	xc._type = C.libxl_psr_feat_type(x.Type)
+	switch x.Type {
+	case PsrFeatTypeCat:
+		tmp, ok := x.TypeUnion.(PsrHwInfoTypeUnionCat)
+		if !ok {
+			return errors.New("wrong type for union key type")
+		}
+		var cat C.libxl_psr_hw_info_type_union_cat
+		cat.cos_max = C.uint32_t(tmp.CosMax)
+		cat.cbm_len = C.uint32_t(tmp.CbmLen)
+		cat.cdp_enabled = C.bool(tmp.CdpEnabled)
+		catBytes := C.GoBytes(unsafe.Pointer(&cat), C.sizeof_libxl_psr_hw_info_type_union_cat)
+		copy(xc.u[:], catBytes)
+	case PsrFeatTypeMba:
+		tmp, ok := x.TypeUnion.(PsrHwInfoTypeUnionMba)
+		if !ok {
+			return errors.New("wrong type for union key type")
+		}
+		var mba C.libxl_psr_hw_info_type_union_mba
+		mba.cos_max = C.uint32_t(tmp.CosMax)
+		mba.thrtl_max = C.uint32_t(tmp.ThrtlMax)
+		mba.linear = C.bool(tmp.Linear)
+		mbaBytes := C.GoBytes(unsafe.Pointer(&mba), C.sizeof_libxl_psr_hw_info_type_union_mba)
+		copy(xc.u[:], mbaBytes)
+	default:
+		return fmt.Errorf("invalid union key '%v'", x.Type)
+	}
 
 	return nil
 }