xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays
@ 2019-12-27 16:32 George Dunlap
  2019-12-27 16:32 ` [Xen-devel] [PATCH 2/9] golang/xenlight: Do proper nil / NULL conversions for builtin Bitmap type George Dunlap
                   ` (9 more replies)
  0 siblings, 10 replies; 18+ messages in thread
From: George Dunlap @ 2019-12-27 16:32 UTC (permalink / raw)
  To: xen-devel; +Cc: Nick Rosbrook, George Dunlap

The current fromC array code will do the "magic" casting and
martialling even when num_foo variable is 0.  Go crashes when doing
the cast.

Furthermore, the current toC array code will convert a nil slice into
a zero-length malloc.  The resulting pointer is non-NULL, and confuses
libxl.

Only do array marshalling if the number of elements is non-zero;
otherwise, leave the target pointer empty (nil for Go slices, NULL for
C arrays).

The toC half of this should be folded into "golang/xenlight:
implement array Go to C marshaling".

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
CC: Nick Rosbrook <rosbrookn@ainfosec.com>
---
 tools/golang/xenlight/gengotypes.py  |   13 +-
 tools/golang/xenlight/helpers.gen.go | 1232 ++++++++++++++------------
 2 files changed, 671 insertions(+), 574 deletions(-)

diff --git a/tools/golang/xenlight/gengotypes.py b/tools/golang/xenlight/gengotypes.py
index a972754d36..5363ca062d 100644
--- a/tools/golang/xenlight/gengotypes.py
+++ b/tools/golang/xenlight/gengotypes.py
@@ -419,7 +419,8 @@ def xenlight_golang_array_from_C(ty = None):
     clenvar    = ty.type.lenvar.name
     golenvar   = xenlight_golang_fmt_name(clenvar,exported=False)
 
-    s += '{} := int(xc.{})\n'.format(golenvar, clenvar)
+    s += 'x.{} = nil\n'.format(goname)
+    s += 'if {} := int(xc.{}); {} > 0 {{\n'.format(golenvar, clenvar, golenvar)
     s += '{} := '.format(cslice)
     s +='(*[1<<28]C.{})(unsafe.Pointer(xc.{}))[:{}:{}]\n'.format(ctypename, cname,
                                                                 golenvar, golenvar)
@@ -433,7 +434,7 @@ def xenlight_golang_array_from_C(ty = None):
         s += 'if err := x.{}[i].fromC(&v); err != nil {{\n'.format(goname)
         s += 'return err }\n'
 
-    s += '}\n'
+    s += '}\n}\n'
 
     return s
 
@@ -599,7 +600,7 @@ def xenlight_golang_array_to_C(ty = None, dispose_fn = ''):
 
     is_enum = isinstance(ty.type.elem_type,idl.Enumeration)
     if gotypename in go_builtin_types or is_enum:
-        s += '{} := len(x.{})\n'.format(golenvar,goname)
+        s += 'if {} := len(x.{}); {} > 0 {{\n'.format(golenvar,goname, golenvar)
         s += 'xc.{} = (*C.{})(C.malloc(C.size_t({}*{})))\n'.format(cname,ctypename,
                                                                    golenvar,golenvar)
         s += 'xc.{} = C.int({})\n'.format(clenvar,golenvar)
@@ -608,11 +609,11 @@ def xenlight_golang_array_to_C(ty = None, dispose_fn = ''):
                                                                       golenvar,golenvar)
         s += 'for i,v := range x.{} {{\n'.format(goname)
         s += 'c{}[i] = C.{}(v)\n'.format(goname,ctypename)
-        s += '}\n'
+        s += '}\n}\n'
 
         return s
 
-    s += '{} := len(x.{})\n'.format(golenvar,goname)
+    s += 'if {} := len(x.{}); {} > 0 {{\n'.format(golenvar,goname, golenvar)
     s += 'xc.{} = (*C.{})(C.malloc(C.ulong({})*C.sizeof_{}))\n'.format(cname,ctypename,
                                                                    golenvar,ctypename)
     s += 'xc.{} = C.int({})\n'.format(clenvar,golenvar)
@@ -625,7 +626,7 @@ def xenlight_golang_array_to_C(ty = None, dispose_fn = ''):
     s += 'C.{}(&xc)\n'.format(dispose_fn)
     s += 'return xc,err\n}\n'
     s += 'c{}[i] = tmp\n'.format(goname)
-    s += '}\n'
+    s += '}\n}\n'
 
     return s
 
diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go
index 3e588dd1c2..61cd73595e 100644
--- a/tools/golang/xenlight/helpers.gen.go
+++ b/tools/golang/xenlight/helpers.gen.go
@@ -528,12 +528,14 @@ func (x *SchedParams) toC() (xc C.libxl_sched_params, err error) {
 
 func (x *VcpuSchedParams) fromC(xc *C.libxl_vcpu_sched_params) error {
 	x.Sched = Scheduler(xc.sched)
-	numVcpus := int(xc.num_vcpus)
-	cVcpus := (*[1 << 28]C.libxl_sched_params)(unsafe.Pointer(xc.vcpus))[:numVcpus:numVcpus]
-	x.Vcpus = make([]SchedParams, numVcpus)
-	for i, v := range cVcpus {
-		if err := x.Vcpus[i].fromC(&v); err != nil {
-			return err
+	x.Vcpus = nil
+	if numVcpus := int(xc.num_vcpus); numVcpus > 0 {
+		cVcpus := (*[1 << 28]C.libxl_sched_params)(unsafe.Pointer(xc.vcpus))[:numVcpus:numVcpus]
+		x.Vcpus = make([]SchedParams, numVcpus)
+		for i, v := range cVcpus {
+			if err := x.Vcpus[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -543,17 +545,18 @@ func (x *VcpuSchedParams) fromC(xc *C.libxl_vcpu_sched_params) error {
 func (x *VcpuSchedParams) toC() (xc C.libxl_vcpu_sched_params, err error) {
 	C.libxl_vcpu_sched_params_init(&xc)
 	xc.sched = C.libxl_scheduler(x.Sched)
-	numVcpus := len(x.Vcpus)
-	xc.vcpus = (*C.libxl_sched_params)(C.malloc(C.ulong(numVcpus) * C.sizeof_libxl_sched_params))
-	xc.num_vcpus = C.int(numVcpus)
-	cVcpus := (*[1 << 28]C.libxl_sched_params)(unsafe.Pointer(xc.vcpus))[:numVcpus:numVcpus]
-	for i, v := range x.Vcpus {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_vcpu_sched_params_dispose(&xc)
-			return xc, err
+	if numVcpus := len(x.Vcpus); numVcpus > 0 {
+		xc.vcpus = (*C.libxl_sched_params)(C.malloc(C.ulong(numVcpus) * C.sizeof_libxl_sched_params))
+		xc.num_vcpus = C.int(numVcpus)
+		cVcpus := (*[1 << 28]C.libxl_sched_params)(unsafe.Pointer(xc.vcpus))[:numVcpus:numVcpus]
+		for i, v := range x.Vcpus {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_vcpu_sched_params_dispose(&xc)
+				return xc, err
+			}
+			cVcpus[i] = tmp
 		}
-		cVcpus[i] = tmp
 	}
 	return xc, nil
 }
@@ -586,11 +589,13 @@ func (x *DomainSchedParams) toC() (xc C.libxl_domain_sched_params, err error) {
 
 func (x *VnodeInfo) fromC(xc *C.libxl_vnode_info) error {
 	x.Memkb = uint64(xc.memkb)
-	numDistances := int(xc.num_distances)
-	cDistances := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.distances))[:numDistances:numDistances]
-	x.Distances = make([]uint32, numDistances)
-	for i, v := range cDistances {
-		x.Distances[i] = uint32(v)
+	x.Distances = nil
+	if numDistances := int(xc.num_distances); numDistances > 0 {
+		cDistances := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.distances))[:numDistances:numDistances]
+		x.Distances = make([]uint32, numDistances)
+		for i, v := range cDistances {
+			x.Distances[i] = uint32(v)
+		}
 	}
 	x.Pnode = uint32(xc.pnode)
 	if err := x.Vcpus.fromC(&xc.vcpus); err != nil {
@@ -603,12 +608,13 @@ func (x *VnodeInfo) fromC(xc *C.libxl_vnode_info) error {
 func (x *VnodeInfo) toC() (xc C.libxl_vnode_info, err error) {
 	C.libxl_vnode_info_init(&xc)
 	xc.memkb = C.uint64_t(x.Memkb)
-	numDistances := len(x.Distances)
-	xc.distances = (*C.uint32_t)(C.malloc(C.size_t(numDistances * numDistances)))
-	xc.num_distances = C.int(numDistances)
-	cDistances := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.distances))[:numDistances:numDistances]
-	for i, v := range x.Distances {
-		cDistances[i] = C.uint32_t(v)
+	if numDistances := len(x.Distances); numDistances > 0 {
+		xc.distances = (*C.uint32_t)(C.malloc(C.size_t(numDistances * numDistances)))
+		xc.num_distances = C.int(numDistances)
+		cDistances := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.distances))[:numDistances:numDistances]
+		for i, v := range x.Distances {
+			cDistances[i] = C.uint32_t(v)
+		}
 	}
 	xc.pnode = C.uint32_t(x.Pnode)
 	xc.vcpus, err = x.Vcpus.toC()
@@ -644,20 +650,24 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	if err := x.Nodemap.fromC(&xc.nodemap); err != nil {
 		return err
 	}
-	numVcpuHardAffinity := int(xc.num_vcpu_hard_affinity)
-	cVcpuHardAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_hard_affinity))[:numVcpuHardAffinity:numVcpuHardAffinity]
-	x.VcpuHardAffinity = make([]Bitmap, numVcpuHardAffinity)
-	for i, v := range cVcpuHardAffinity {
-		if err := x.VcpuHardAffinity[i].fromC(&v); err != nil {
-			return err
+	x.VcpuHardAffinity = nil
+	if numVcpuHardAffinity := int(xc.num_vcpu_hard_affinity); numVcpuHardAffinity > 0 {
+		cVcpuHardAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_hard_affinity))[:numVcpuHardAffinity:numVcpuHardAffinity]
+		x.VcpuHardAffinity = make([]Bitmap, numVcpuHardAffinity)
+		for i, v := range cVcpuHardAffinity {
+			if err := x.VcpuHardAffinity[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numVcpuSoftAffinity := int(xc.num_vcpu_soft_affinity)
-	cVcpuSoftAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_soft_affinity))[:numVcpuSoftAffinity:numVcpuSoftAffinity]
-	x.VcpuSoftAffinity = make([]Bitmap, numVcpuSoftAffinity)
-	for i, v := range cVcpuSoftAffinity {
-		if err := x.VcpuSoftAffinity[i].fromC(&v); err != nil {
-			return err
+	x.VcpuSoftAffinity = nil
+	if numVcpuSoftAffinity := int(xc.num_vcpu_soft_affinity); numVcpuSoftAffinity > 0 {
+		cVcpuSoftAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_soft_affinity))[:numVcpuSoftAffinity:numVcpuSoftAffinity]
+		x.VcpuSoftAffinity = make([]Bitmap, numVcpuSoftAffinity)
+		for i, v := range cVcpuSoftAffinity {
+			if err := x.VcpuSoftAffinity[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 	if err := x.NumaPlacement.fromC(&xc.numa_placement); err != nil {
@@ -682,12 +692,14 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 		return err
 	}
 	x.BlkdevStart = C.GoString(xc.blkdev_start)
-	numVnumaNodes := int(xc.num_vnuma_nodes)
-	cVnumaNodes := (*[1 << 28]C.libxl_vnode_info)(unsafe.Pointer(xc.vnuma_nodes))[:numVnumaNodes:numVnumaNodes]
-	x.VnumaNodes = make([]VnodeInfo, numVnumaNodes)
-	for i, v := range cVnumaNodes {
-		if err := x.VnumaNodes[i].fromC(&v); err != nil {
-			return err
+	x.VnumaNodes = nil
+	if numVnumaNodes := int(xc.num_vnuma_nodes); numVnumaNodes > 0 {
+		cVnumaNodes := (*[1 << 28]C.libxl_vnode_info)(unsafe.Pointer(xc.vnuma_nodes))[:numVnumaNodes:numVnumaNodes]
+		x.VnumaNodes = make([]VnodeInfo, numVnumaNodes)
+		for i, v := range cVnumaNodes {
+			if err := x.VnumaNodes[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 	x.MaxGrantFrames = uint32(xc.max_grant_frames)
@@ -712,26 +724,32 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	if err := x.SchedParams.fromC(&xc.sched_params); err != nil {
 		return err
 	}
-	numIoports := int(xc.num_ioports)
-	cIoports := (*[1 << 28]C.libxl_ioport_range)(unsafe.Pointer(xc.ioports))[:numIoports:numIoports]
-	x.Ioports = make([]IoportRange, numIoports)
-	for i, v := range cIoports {
-		if err := x.Ioports[i].fromC(&v); err != nil {
-			return err
+	x.Ioports = nil
+	if numIoports := int(xc.num_ioports); numIoports > 0 {
+		cIoports := (*[1 << 28]C.libxl_ioport_range)(unsafe.Pointer(xc.ioports))[:numIoports:numIoports]
+		x.Ioports = make([]IoportRange, numIoports)
+		for i, v := range cIoports {
+			if err := x.Ioports[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
-	numIrqs := int(xc.num_irqs)
-	cIrqs := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.irqs))[:numIrqs:numIrqs]
-	x.Irqs = make([]uint32, numIrqs)
-	for i, v := range cIrqs {
-		x.Irqs[i] = uint32(v)
+	x.Irqs = nil
+	if numIrqs := int(xc.num_irqs); numIrqs > 0 {
+		cIrqs := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.irqs))[:numIrqs:numIrqs]
+		x.Irqs = make([]uint32, numIrqs)
+		for i, v := range cIrqs {
+			x.Irqs[i] = uint32(v)
+		}
 	}
-	numIomem := int(xc.num_iomem)
-	cIomem := (*[1 << 28]C.libxl_iomem_range)(unsafe.Pointer(xc.iomem))[:numIomem:numIomem]
-	x.Iomem = make([]IomemRange, numIomem)
-	for i, v := range cIomem {
-		if err := x.Iomem[i].fromC(&v); err != nil {
-			return err
+	x.Iomem = nil
+	if numIomem := int(xc.num_iomem); numIomem > 0 {
+		cIomem := (*[1 << 28]C.libxl_iomem_range)(unsafe.Pointer(xc.iomem))[:numIomem:numIomem]
+		x.Iomem = make([]IomemRange, numIomem)
+		for i, v := range cIomem {
+			if err := x.Iomem[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 	if err := x.ClaimMode.fromC(&xc.claim_mode); err != nil {
@@ -762,18 +780,18 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	x.Tee = TeeType(xc.tee)
 	x.Type = DomainType(xc._type)
 	switch x.Type {
-	case DomainTypePv:
-		var typePv DomainBuildInfoTypeUnionPv
-		if err := typePv.fromC(xc); err != nil {
-			return err
-		}
-		x.TypeUnion = typePv
 	case DomainTypeHvm:
 		var typeHvm DomainBuildInfoTypeUnionHvm
 		if err := typeHvm.fromC(xc); err != nil {
 			return err
 		}
 		x.TypeUnion = typeHvm
+	case DomainTypePv:
+		var typePv DomainBuildInfoTypeUnionPv
+		if err := typePv.fromC(xc); err != nil {
+			return err
+		}
+		x.TypeUnion = typePv
 	case DomainTypePvh:
 		var typePvh DomainBuildInfoTypeUnionPvh
 		if err := typePvh.fromC(xc); err != nil {
@@ -953,29 +971,31 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		C.libxl_domain_build_info_dispose(&xc)
 		return xc, err
 	}
-	numVcpuHardAffinity := len(x.VcpuHardAffinity)
-	xc.vcpu_hard_affinity = (*C.libxl_bitmap)(C.malloc(C.ulong(numVcpuHardAffinity) * C.sizeof_libxl_bitmap))
-	xc.num_vcpu_hard_affinity = C.int(numVcpuHardAffinity)
-	cVcpuHardAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_hard_affinity))[:numVcpuHardAffinity:numVcpuHardAffinity]
-	for i, v := range x.VcpuHardAffinity {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
-		}
-		cVcpuHardAffinity[i] = tmp
-	}
-	numVcpuSoftAffinity := len(x.VcpuSoftAffinity)
-	xc.vcpu_soft_affinity = (*C.libxl_bitmap)(C.malloc(C.ulong(numVcpuSoftAffinity) * C.sizeof_libxl_bitmap))
-	xc.num_vcpu_soft_affinity = C.int(numVcpuSoftAffinity)
-	cVcpuSoftAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_soft_affinity))[:numVcpuSoftAffinity:numVcpuSoftAffinity]
-	for i, v := range x.VcpuSoftAffinity {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+	if numVcpuHardAffinity := len(x.VcpuHardAffinity); numVcpuHardAffinity > 0 {
+		xc.vcpu_hard_affinity = (*C.libxl_bitmap)(C.malloc(C.ulong(numVcpuHardAffinity) * C.sizeof_libxl_bitmap))
+		xc.num_vcpu_hard_affinity = C.int(numVcpuHardAffinity)
+		cVcpuHardAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_hard_affinity))[:numVcpuHardAffinity:numVcpuHardAffinity]
+		for i, v := range x.VcpuHardAffinity {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_build_info_dispose(&xc)
+				return xc, err
+			}
+			cVcpuHardAffinity[i] = tmp
+		}
+	}
+	if numVcpuSoftAffinity := len(x.VcpuSoftAffinity); numVcpuSoftAffinity > 0 {
+		xc.vcpu_soft_affinity = (*C.libxl_bitmap)(C.malloc(C.ulong(numVcpuSoftAffinity) * C.sizeof_libxl_bitmap))
+		xc.num_vcpu_soft_affinity = C.int(numVcpuSoftAffinity)
+		cVcpuSoftAffinity := (*[1 << 28]C.libxl_bitmap)(unsafe.Pointer(xc.vcpu_soft_affinity))[:numVcpuSoftAffinity:numVcpuSoftAffinity]
+		for i, v := range x.VcpuSoftAffinity {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_build_info_dispose(&xc)
+				return xc, err
+			}
+			cVcpuSoftAffinity[i] = tmp
 		}
-		cVcpuSoftAffinity[i] = tmp
 	}
 	xc.numa_placement, err = x.NumaPlacement.toC()
 	if err != nil {
@@ -1007,17 +1027,18 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		return xc, err
 	}
 	xc.blkdev_start = C.CString(x.BlkdevStart)
-	numVnumaNodes := len(x.VnumaNodes)
-	xc.vnuma_nodes = (*C.libxl_vnode_info)(C.malloc(C.ulong(numVnumaNodes) * C.sizeof_libxl_vnode_info))
-	xc.num_vnuma_nodes = C.int(numVnumaNodes)
-	cVnumaNodes := (*[1 << 28]C.libxl_vnode_info)(unsafe.Pointer(xc.vnuma_nodes))[:numVnumaNodes:numVnumaNodes]
-	for i, v := range x.VnumaNodes {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+	if numVnumaNodes := len(x.VnumaNodes); numVnumaNodes > 0 {
+		xc.vnuma_nodes = (*C.libxl_vnode_info)(C.malloc(C.ulong(numVnumaNodes) * C.sizeof_libxl_vnode_info))
+		xc.num_vnuma_nodes = C.int(numVnumaNodes)
+		cVnumaNodes := (*[1 << 28]C.libxl_vnode_info)(unsafe.Pointer(xc.vnuma_nodes))[:numVnumaNodes:numVnumaNodes]
+		for i, v := range x.VnumaNodes {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_build_info_dispose(&xc)
+				return xc, err
+			}
+			cVnumaNodes[i] = tmp
 		}
-		cVnumaNodes[i] = tmp
 	}
 	xc.max_grant_frames = C.uint32_t(x.MaxGrantFrames)
 	xc.max_maptrack_frames = C.uint32_t(x.MaxMaptrackFrames)
@@ -1051,36 +1072,39 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		C.libxl_domain_build_info_dispose(&xc)
 		return xc, err
 	}
-	numIoports := len(x.Ioports)
-	xc.ioports = (*C.libxl_ioport_range)(C.malloc(C.ulong(numIoports) * C.sizeof_libxl_ioport_range))
-	xc.num_ioports = C.int(numIoports)
-	cIoports := (*[1 << 28]C.libxl_ioport_range)(unsafe.Pointer(xc.ioports))[:numIoports:numIoports]
-	for i, v := range x.Ioports {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
-		}
-		cIoports[i] = tmp
-	}
-	numIrqs := len(x.Irqs)
-	xc.irqs = (*C.uint32_t)(C.malloc(C.size_t(numIrqs * numIrqs)))
-	xc.num_irqs = C.int(numIrqs)
-	cIrqs := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.irqs))[:numIrqs:numIrqs]
-	for i, v := range x.Irqs {
-		cIrqs[i] = C.uint32_t(v)
-	}
-	numIomem := len(x.Iomem)
-	xc.iomem = (*C.libxl_iomem_range)(C.malloc(C.ulong(numIomem) * C.sizeof_libxl_iomem_range))
-	xc.num_iomem = C.int(numIomem)
-	cIomem := (*[1 << 28]C.libxl_iomem_range)(unsafe.Pointer(xc.iomem))[:numIomem:numIomem]
-	for i, v := range x.Iomem {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+	if numIoports := len(x.Ioports); numIoports > 0 {
+		xc.ioports = (*C.libxl_ioport_range)(C.malloc(C.ulong(numIoports) * C.sizeof_libxl_ioport_range))
+		xc.num_ioports = C.int(numIoports)
+		cIoports := (*[1 << 28]C.libxl_ioport_range)(unsafe.Pointer(xc.ioports))[:numIoports:numIoports]
+		for i, v := range x.Ioports {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_build_info_dispose(&xc)
+				return xc, err
+			}
+			cIoports[i] = tmp
+		}
+	}
+	if numIrqs := len(x.Irqs); numIrqs > 0 {
+		xc.irqs = (*C.uint32_t)(C.malloc(C.size_t(numIrqs * numIrqs)))
+		xc.num_irqs = C.int(numIrqs)
+		cIrqs := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.irqs))[:numIrqs:numIrqs]
+		for i, v := range x.Irqs {
+			cIrqs[i] = C.uint32_t(v)
+		}
+	}
+	if numIomem := len(x.Iomem); numIomem > 0 {
+		xc.iomem = (*C.libxl_iomem_range)(C.malloc(C.ulong(numIomem) * C.sizeof_libxl_iomem_range))
+		xc.num_iomem = C.int(numIomem)
+		cIomem := (*[1 << 28]C.libxl_iomem_range)(unsafe.Pointer(xc.iomem))[:numIomem:numIomem]
+		for i, v := range x.Iomem {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_build_info_dispose(&xc)
+				return xc, err
+			}
+			cIomem[i] = tmp
 		}
-		cIomem[i] = tmp
 	}
 	xc.claim_mode, err = x.ClaimMode.toC()
 	if err != nil {
@@ -1889,12 +1913,14 @@ func (x *DeviceVdispl) fromC(xc *C.libxl_device_vdispl) error {
 	x.BackendDomname = C.GoString(xc.backend_domname)
 	x.Devid = Devid(xc.devid)
 	x.BeAlloc = bool(xc.be_alloc)
-	numConnectors := int(xc.num_connectors)
-	cConnectors := (*[1 << 28]C.libxl_connector_param)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
-	x.Connectors = make([]ConnectorParam, numConnectors)
-	for i, v := range cConnectors {
-		if err := x.Connectors[i].fromC(&v); err != nil {
-			return err
+	x.Connectors = nil
+	if numConnectors := int(xc.num_connectors); numConnectors > 0 {
+		cConnectors := (*[1 << 28]C.libxl_connector_param)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
+		x.Connectors = make([]ConnectorParam, numConnectors)
+		for i, v := range cConnectors {
+			if err := x.Connectors[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -1907,33 +1933,38 @@ func (x *DeviceVdispl) toC() (xc C.libxl_device_vdispl, err error) {
 	xc.backend_domname = C.CString(x.BackendDomname)
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.be_alloc = C.bool(x.BeAlloc)
-	numConnectors := len(x.Connectors)
-	xc.connectors = (*C.libxl_connector_param)(C.malloc(C.ulong(numConnectors) * C.sizeof_libxl_connector_param))
-	xc.num_connectors = C.int(numConnectors)
-	cConnectors := (*[1 << 28]C.libxl_connector_param)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
-	for i, v := range x.Connectors {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_device_vdispl_dispose(&xc)
-			return xc, err
+	if numConnectors := len(x.Connectors); numConnectors > 0 {
+		xc.connectors = (*C.libxl_connector_param)(C.malloc(C.ulong(numConnectors) * C.sizeof_libxl_connector_param))
+		xc.num_connectors = C.int(numConnectors)
+		cConnectors := (*[1 << 28]C.libxl_connector_param)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
+		for i, v := range x.Connectors {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_device_vdispl_dispose(&xc)
+				return xc, err
+			}
+			cConnectors[i] = tmp
 		}
-		cConnectors[i] = tmp
 	}
 	return xc, nil
 }
 
 func (x *VsndParams) fromC(xc *C.libxl_vsnd_params) error {
-	numSampleRates := int(xc.num_sample_rates)
-	cSampleRates := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.sample_rates))[:numSampleRates:numSampleRates]
-	x.SampleRates = make([]uint32, numSampleRates)
-	for i, v := range cSampleRates {
-		x.SampleRates[i] = uint32(v)
-	}
-	numSampleFormats := int(xc.num_sample_formats)
-	cSampleFormats := (*[1 << 28]C.libxl_vsnd_pcm_format)(unsafe.Pointer(xc.sample_formats))[:numSampleFormats:numSampleFormats]
-	x.SampleFormats = make([]VsndPcmFormat, numSampleFormats)
-	for i, v := range cSampleFormats {
-		x.SampleFormats[i] = VsndPcmFormat(v)
+	x.SampleRates = nil
+	if numSampleRates := int(xc.num_sample_rates); numSampleRates > 0 {
+		cSampleRates := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.sample_rates))[:numSampleRates:numSampleRates]
+		x.SampleRates = make([]uint32, numSampleRates)
+		for i, v := range cSampleRates {
+			x.SampleRates[i] = uint32(v)
+		}
+	}
+	x.SampleFormats = nil
+	if numSampleFormats := int(xc.num_sample_formats); numSampleFormats > 0 {
+		cSampleFormats := (*[1 << 28]C.libxl_vsnd_pcm_format)(unsafe.Pointer(xc.sample_formats))[:numSampleFormats:numSampleFormats]
+		x.SampleFormats = make([]VsndPcmFormat, numSampleFormats)
+		for i, v := range cSampleFormats {
+			x.SampleFormats[i] = VsndPcmFormat(v)
+		}
 	}
 	x.ChannelsMin = uint32(xc.channels_min)
 	x.ChannelsMax = uint32(xc.channels_max)
@@ -1944,19 +1975,21 @@ func (x *VsndParams) fromC(xc *C.libxl_vsnd_params) error {
 
 func (x *VsndParams) toC() (xc C.libxl_vsnd_params, err error) {
 	C.libxl_vsnd_params_init(&xc)
-	numSampleRates := len(x.SampleRates)
-	xc.sample_rates = (*C.uint32_t)(C.malloc(C.size_t(numSampleRates * numSampleRates)))
-	xc.num_sample_rates = C.int(numSampleRates)
-	cSampleRates := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.sample_rates))[:numSampleRates:numSampleRates]
-	for i, v := range x.SampleRates {
-		cSampleRates[i] = C.uint32_t(v)
-	}
-	numSampleFormats := len(x.SampleFormats)
-	xc.sample_formats = (*C.libxl_vsnd_pcm_format)(C.malloc(C.size_t(numSampleFormats * numSampleFormats)))
-	xc.num_sample_formats = C.int(numSampleFormats)
-	cSampleFormats := (*[1 << 28]C.libxl_vsnd_pcm_format)(unsafe.Pointer(xc.sample_formats))[:numSampleFormats:numSampleFormats]
-	for i, v := range x.SampleFormats {
-		cSampleFormats[i] = C.libxl_vsnd_pcm_format(v)
+	if numSampleRates := len(x.SampleRates); numSampleRates > 0 {
+		xc.sample_rates = (*C.uint32_t)(C.malloc(C.size_t(numSampleRates * numSampleRates)))
+		xc.num_sample_rates = C.int(numSampleRates)
+		cSampleRates := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.sample_rates))[:numSampleRates:numSampleRates]
+		for i, v := range x.SampleRates {
+			cSampleRates[i] = C.uint32_t(v)
+		}
+	}
+	if numSampleFormats := len(x.SampleFormats); numSampleFormats > 0 {
+		xc.sample_formats = (*C.libxl_vsnd_pcm_format)(C.malloc(C.size_t(numSampleFormats * numSampleFormats)))
+		xc.num_sample_formats = C.int(numSampleFormats)
+		cSampleFormats := (*[1 << 28]C.libxl_vsnd_pcm_format)(unsafe.Pointer(xc.sample_formats))[:numSampleFormats:numSampleFormats]
+		for i, v := range x.SampleFormats {
+			cSampleFormats[i] = C.libxl_vsnd_pcm_format(v)
+		}
 	}
 	xc.channels_min = C.uint32_t(x.ChannelsMin)
 	xc.channels_max = C.uint32_t(x.ChannelsMax)
@@ -1991,12 +2024,14 @@ func (x *VsndPcm) fromC(xc *C.libxl_vsnd_pcm) error {
 	if err := x.Params.fromC(&xc.params); err != nil {
 		return err
 	}
-	numVsndStreams := int(xc.num_vsnd_streams)
-	cStreams := (*[1 << 28]C.libxl_vsnd_stream)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
-	x.Streams = make([]VsndStream, numVsndStreams)
-	for i, v := range cStreams {
-		if err := x.Streams[i].fromC(&v); err != nil {
-			return err
+	x.Streams = nil
+	if numVsndStreams := int(xc.num_vsnd_streams); numVsndStreams > 0 {
+		cStreams := (*[1 << 28]C.libxl_vsnd_stream)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
+		x.Streams = make([]VsndStream, numVsndStreams)
+		for i, v := range cStreams {
+			if err := x.Streams[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -2011,17 +2046,18 @@ func (x *VsndPcm) toC() (xc C.libxl_vsnd_pcm, err error) {
 		C.libxl_vsnd_pcm_dispose(&xc)
 		return xc, err
 	}
-	numVsndStreams := len(x.Streams)
-	xc.streams = (*C.libxl_vsnd_stream)(C.malloc(C.ulong(numVsndStreams) * C.sizeof_libxl_vsnd_stream))
-	xc.num_vsnd_streams = C.int(numVsndStreams)
-	cStreams := (*[1 << 28]C.libxl_vsnd_stream)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
-	for i, v := range x.Streams {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_vsnd_pcm_dispose(&xc)
-			return xc, err
+	if numVsndStreams := len(x.Streams); numVsndStreams > 0 {
+		xc.streams = (*C.libxl_vsnd_stream)(C.malloc(C.ulong(numVsndStreams) * C.sizeof_libxl_vsnd_stream))
+		xc.num_vsnd_streams = C.int(numVsndStreams)
+		cStreams := (*[1 << 28]C.libxl_vsnd_stream)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
+		for i, v := range x.Streams {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_vsnd_pcm_dispose(&xc)
+				return xc, err
+			}
+			cStreams[i] = tmp
 		}
-		cStreams[i] = tmp
 	}
 	return xc, nil
 }
@@ -2035,12 +2071,14 @@ func (x *DeviceVsnd) fromC(xc *C.libxl_device_vsnd) error {
 	if err := x.Params.fromC(&xc.params); err != nil {
 		return err
 	}
-	numVsndPcms := int(xc.num_vsnd_pcms)
-	cPcms := (*[1 << 28]C.libxl_vsnd_pcm)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
-	x.Pcms = make([]VsndPcm, numVsndPcms)
-	for i, v := range cPcms {
-		if err := x.Pcms[i].fromC(&v); err != nil {
-			return err
+	x.Pcms = nil
+	if numVsndPcms := int(xc.num_vsnd_pcms); numVsndPcms > 0 {
+		cPcms := (*[1 << 28]C.libxl_vsnd_pcm)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
+		x.Pcms = make([]VsndPcm, numVsndPcms)
+		for i, v := range cPcms {
+			if err := x.Pcms[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -2059,17 +2097,18 @@ func (x *DeviceVsnd) toC() (xc C.libxl_device_vsnd, err error) {
 		C.libxl_device_vsnd_dispose(&xc)
 		return xc, err
 	}
-	numVsndPcms := len(x.Pcms)
-	xc.pcms = (*C.libxl_vsnd_pcm)(C.malloc(C.ulong(numVsndPcms) * C.sizeof_libxl_vsnd_pcm))
-	xc.num_vsnd_pcms = C.int(numVsndPcms)
-	cPcms := (*[1 << 28]C.libxl_vsnd_pcm)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
-	for i, v := range x.Pcms {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_device_vsnd_dispose(&xc)
-			return xc, err
+	if numVsndPcms := len(x.Pcms); numVsndPcms > 0 {
+		xc.pcms = (*C.libxl_vsnd_pcm)(C.malloc(C.ulong(numVsndPcms) * C.sizeof_libxl_vsnd_pcm))
+		xc.num_vsnd_pcms = C.int(numVsndPcms)
+		cPcms := (*[1 << 28]C.libxl_vsnd_pcm)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
+		for i, v := range x.Pcms {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_device_vsnd_dispose(&xc)
+				return xc, err
+			}
+			cPcms[i] = tmp
 		}
-		cPcms[i] = tmp
 	}
 	return xc, nil
 }
@@ -2081,124 +2120,154 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 	if err := x.BInfo.fromC(&xc.b_info); err != nil {
 		return err
 	}
-	numDisks := int(xc.num_disks)
-	cDisks := (*[1 << 28]C.libxl_device_disk)(unsafe.Pointer(xc.disks))[:numDisks:numDisks]
-	x.Disks = make([]DeviceDisk, numDisks)
-	for i, v := range cDisks {
-		if err := x.Disks[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numNics := int(xc.num_nics)
-	cNics := (*[1 << 28]C.libxl_device_nic)(unsafe.Pointer(xc.nics))[:numNics:numNics]
-	x.Nics = make([]DeviceNic, numNics)
-	for i, v := range cNics {
-		if err := x.Nics[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numPcidevs := int(xc.num_pcidevs)
-	cPcidevs := (*[1 << 28]C.libxl_device_pci)(unsafe.Pointer(xc.pcidevs))[:numPcidevs:numPcidevs]
-	x.Pcidevs = make([]DevicePci, numPcidevs)
-	for i, v := range cPcidevs {
-		if err := x.Pcidevs[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numRdms := int(xc.num_rdms)
-	cRdms := (*[1 << 28]C.libxl_device_rdm)(unsafe.Pointer(xc.rdms))[:numRdms:numRdms]
-	x.Rdms = make([]DeviceRdm, numRdms)
-	for i, v := range cRdms {
-		if err := x.Rdms[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numDtdevs := int(xc.num_dtdevs)
-	cDtdevs := (*[1 << 28]C.libxl_device_dtdev)(unsafe.Pointer(xc.dtdevs))[:numDtdevs:numDtdevs]
-	x.Dtdevs = make([]DeviceDtdev, numDtdevs)
-	for i, v := range cDtdevs {
-		if err := x.Dtdevs[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numVfbs := int(xc.num_vfbs)
-	cVfbs := (*[1 << 28]C.libxl_device_vfb)(unsafe.Pointer(xc.vfbs))[:numVfbs:numVfbs]
-	x.Vfbs = make([]DeviceVfb, numVfbs)
-	for i, v := range cVfbs {
-		if err := x.Vfbs[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numVkbs := int(xc.num_vkbs)
-	cVkbs := (*[1 << 28]C.libxl_device_vkb)(unsafe.Pointer(xc.vkbs))[:numVkbs:numVkbs]
-	x.Vkbs = make([]DeviceVkb, numVkbs)
-	for i, v := range cVkbs {
-		if err := x.Vkbs[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numVtpms := int(xc.num_vtpms)
-	cVtpms := (*[1 << 28]C.libxl_device_vtpm)(unsafe.Pointer(xc.vtpms))[:numVtpms:numVtpms]
-	x.Vtpms = make([]DeviceVtpm, numVtpms)
-	for i, v := range cVtpms {
-		if err := x.Vtpms[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numP9S := int(xc.num_p9s)
-	cP9S := (*[1 << 28]C.libxl_device_p9)(unsafe.Pointer(xc.p9s))[:numP9S:numP9S]
-	x.P9S = make([]DeviceP9, numP9S)
-	for i, v := range cP9S {
-		if err := x.P9S[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numPvcallsifs := int(xc.num_pvcallsifs)
-	cPvcallsifs := (*[1 << 28]C.libxl_device_pvcallsif)(unsafe.Pointer(xc.pvcallsifs))[:numPvcallsifs:numPvcallsifs]
-	x.Pvcallsifs = make([]DevicePvcallsif, numPvcallsifs)
-	for i, v := range cPvcallsifs {
-		if err := x.Pvcallsifs[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numVdispls := int(xc.num_vdispls)
-	cVdispls := (*[1 << 28]C.libxl_device_vdispl)(unsafe.Pointer(xc.vdispls))[:numVdispls:numVdispls]
-	x.Vdispls = make([]DeviceVdispl, numVdispls)
-	for i, v := range cVdispls {
-		if err := x.Vdispls[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numVsnds := int(xc.num_vsnds)
-	cVsnds := (*[1 << 28]C.libxl_device_vsnd)(unsafe.Pointer(xc.vsnds))[:numVsnds:numVsnds]
-	x.Vsnds = make([]DeviceVsnd, numVsnds)
-	for i, v := range cVsnds {
-		if err := x.Vsnds[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numChannels := int(xc.num_channels)
-	cChannels := (*[1 << 28]C.libxl_device_channel)(unsafe.Pointer(xc.channels))[:numChannels:numChannels]
-	x.Channels = make([]DeviceChannel, numChannels)
-	for i, v := range cChannels {
-		if err := x.Channels[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numUsbctrls := int(xc.num_usbctrls)
-	cUsbctrls := (*[1 << 28]C.libxl_device_usbctrl)(unsafe.Pointer(xc.usbctrls))[:numUsbctrls:numUsbctrls]
-	x.Usbctrls = make([]DeviceUsbctrl, numUsbctrls)
-	for i, v := range cUsbctrls {
-		if err := x.Usbctrls[i].fromC(&v); err != nil {
-			return err
-		}
-	}
-	numUsbdevs := int(xc.num_usbdevs)
-	cUsbdevs := (*[1 << 28]C.libxl_device_usbdev)(unsafe.Pointer(xc.usbdevs))[:numUsbdevs:numUsbdevs]
-	x.Usbdevs = make([]DeviceUsbdev, numUsbdevs)
-	for i, v := range cUsbdevs {
-		if err := x.Usbdevs[i].fromC(&v); err != nil {
-			return err
+	x.Disks = nil
+	if numDisks := int(xc.num_disks); numDisks > 0 {
+		cDisks := (*[1 << 28]C.libxl_device_disk)(unsafe.Pointer(xc.disks))[:numDisks:numDisks]
+		x.Disks = make([]DeviceDisk, numDisks)
+		for i, v := range cDisks {
+			if err := x.Disks[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Nics = nil
+	if numNics := int(xc.num_nics); numNics > 0 {
+		cNics := (*[1 << 28]C.libxl_device_nic)(unsafe.Pointer(xc.nics))[:numNics:numNics]
+		x.Nics = make([]DeviceNic, numNics)
+		for i, v := range cNics {
+			if err := x.Nics[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Pcidevs = nil
+	if numPcidevs := int(xc.num_pcidevs); numPcidevs > 0 {
+		cPcidevs := (*[1 << 28]C.libxl_device_pci)(unsafe.Pointer(xc.pcidevs))[:numPcidevs:numPcidevs]
+		x.Pcidevs = make([]DevicePci, numPcidevs)
+		for i, v := range cPcidevs {
+			if err := x.Pcidevs[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Rdms = nil
+	if numRdms := int(xc.num_rdms); numRdms > 0 {
+		cRdms := (*[1 << 28]C.libxl_device_rdm)(unsafe.Pointer(xc.rdms))[:numRdms:numRdms]
+		x.Rdms = make([]DeviceRdm, numRdms)
+		for i, v := range cRdms {
+			if err := x.Rdms[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Dtdevs = nil
+	if numDtdevs := int(xc.num_dtdevs); numDtdevs > 0 {
+		cDtdevs := (*[1 << 28]C.libxl_device_dtdev)(unsafe.Pointer(xc.dtdevs))[:numDtdevs:numDtdevs]
+		x.Dtdevs = make([]DeviceDtdev, numDtdevs)
+		for i, v := range cDtdevs {
+			if err := x.Dtdevs[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Vfbs = nil
+	if numVfbs := int(xc.num_vfbs); numVfbs > 0 {
+		cVfbs := (*[1 << 28]C.libxl_device_vfb)(unsafe.Pointer(xc.vfbs))[:numVfbs:numVfbs]
+		x.Vfbs = make([]DeviceVfb, numVfbs)
+		for i, v := range cVfbs {
+			if err := x.Vfbs[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Vkbs = nil
+	if numVkbs := int(xc.num_vkbs); numVkbs > 0 {
+		cVkbs := (*[1 << 28]C.libxl_device_vkb)(unsafe.Pointer(xc.vkbs))[:numVkbs:numVkbs]
+		x.Vkbs = make([]DeviceVkb, numVkbs)
+		for i, v := range cVkbs {
+			if err := x.Vkbs[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Vtpms = nil
+	if numVtpms := int(xc.num_vtpms); numVtpms > 0 {
+		cVtpms := (*[1 << 28]C.libxl_device_vtpm)(unsafe.Pointer(xc.vtpms))[:numVtpms:numVtpms]
+		x.Vtpms = make([]DeviceVtpm, numVtpms)
+		for i, v := range cVtpms {
+			if err := x.Vtpms[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.P9S = nil
+	if numP9S := int(xc.num_p9s); numP9S > 0 {
+		cP9S := (*[1 << 28]C.libxl_device_p9)(unsafe.Pointer(xc.p9s))[:numP9S:numP9S]
+		x.P9S = make([]DeviceP9, numP9S)
+		for i, v := range cP9S {
+			if err := x.P9S[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Pvcallsifs = nil
+	if numPvcallsifs := int(xc.num_pvcallsifs); numPvcallsifs > 0 {
+		cPvcallsifs := (*[1 << 28]C.libxl_device_pvcallsif)(unsafe.Pointer(xc.pvcallsifs))[:numPvcallsifs:numPvcallsifs]
+		x.Pvcallsifs = make([]DevicePvcallsif, numPvcallsifs)
+		for i, v := range cPvcallsifs {
+			if err := x.Pvcallsifs[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Vdispls = nil
+	if numVdispls := int(xc.num_vdispls); numVdispls > 0 {
+		cVdispls := (*[1 << 28]C.libxl_device_vdispl)(unsafe.Pointer(xc.vdispls))[:numVdispls:numVdispls]
+		x.Vdispls = make([]DeviceVdispl, numVdispls)
+		for i, v := range cVdispls {
+			if err := x.Vdispls[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Vsnds = nil
+	if numVsnds := int(xc.num_vsnds); numVsnds > 0 {
+		cVsnds := (*[1 << 28]C.libxl_device_vsnd)(unsafe.Pointer(xc.vsnds))[:numVsnds:numVsnds]
+		x.Vsnds = make([]DeviceVsnd, numVsnds)
+		for i, v := range cVsnds {
+			if err := x.Vsnds[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Channels = nil
+	if numChannels := int(xc.num_channels); numChannels > 0 {
+		cChannels := (*[1 << 28]C.libxl_device_channel)(unsafe.Pointer(xc.channels))[:numChannels:numChannels]
+		x.Channels = make([]DeviceChannel, numChannels)
+		for i, v := range cChannels {
+			if err := x.Channels[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Usbctrls = nil
+	if numUsbctrls := int(xc.num_usbctrls); numUsbctrls > 0 {
+		cUsbctrls := (*[1 << 28]C.libxl_device_usbctrl)(unsafe.Pointer(xc.usbctrls))[:numUsbctrls:numUsbctrls]
+		x.Usbctrls = make([]DeviceUsbctrl, numUsbctrls)
+		for i, v := range cUsbctrls {
+			if err := x.Usbctrls[i].fromC(&v); err != nil {
+				return err
+			}
+		}
+	}
+	x.Usbdevs = nil
+	if numUsbdevs := int(xc.num_usbdevs); numUsbdevs > 0 {
+		cUsbdevs := (*[1 << 28]C.libxl_device_usbdev)(unsafe.Pointer(xc.usbdevs))[:numUsbdevs:numUsbdevs]
+		x.Usbdevs = make([]DeviceUsbdev, numUsbdevs)
+		for i, v := range cUsbdevs {
+			if err := x.Usbdevs[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 	x.OnPoweroff = ActionOnShutdown(xc.on_poweroff)
@@ -2222,185 +2291,200 @@ func (x *DomainConfig) toC() (xc C.libxl_domain_config, err error) {
 		C.libxl_domain_config_dispose(&xc)
 		return xc, err
 	}
-	numDisks := len(x.Disks)
-	xc.disks = (*C.libxl_device_disk)(C.malloc(C.ulong(numDisks) * C.sizeof_libxl_device_disk))
-	xc.num_disks = C.int(numDisks)
-	cDisks := (*[1 << 28]C.libxl_device_disk)(unsafe.Pointer(xc.disks))[:numDisks:numDisks]
-	for i, v := range x.Disks {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cDisks[i] = tmp
-	}
-	numNics := len(x.Nics)
-	xc.nics = (*C.libxl_device_nic)(C.malloc(C.ulong(numNics) * C.sizeof_libxl_device_nic))
-	xc.num_nics = C.int(numNics)
-	cNics := (*[1 << 28]C.libxl_device_nic)(unsafe.Pointer(xc.nics))[:numNics:numNics]
-	for i, v := range x.Nics {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cNics[i] = tmp
-	}
-	numPcidevs := len(x.Pcidevs)
-	xc.pcidevs = (*C.libxl_device_pci)(C.malloc(C.ulong(numPcidevs) * C.sizeof_libxl_device_pci))
-	xc.num_pcidevs = C.int(numPcidevs)
-	cPcidevs := (*[1 << 28]C.libxl_device_pci)(unsafe.Pointer(xc.pcidevs))[:numPcidevs:numPcidevs]
-	for i, v := range x.Pcidevs {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cPcidevs[i] = tmp
-	}
-	numRdms := len(x.Rdms)
-	xc.rdms = (*C.libxl_device_rdm)(C.malloc(C.ulong(numRdms) * C.sizeof_libxl_device_rdm))
-	xc.num_rdms = C.int(numRdms)
-	cRdms := (*[1 << 28]C.libxl_device_rdm)(unsafe.Pointer(xc.rdms))[:numRdms:numRdms]
-	for i, v := range x.Rdms {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cRdms[i] = tmp
-	}
-	numDtdevs := len(x.Dtdevs)
-	xc.dtdevs = (*C.libxl_device_dtdev)(C.malloc(C.ulong(numDtdevs) * C.sizeof_libxl_device_dtdev))
-	xc.num_dtdevs = C.int(numDtdevs)
-	cDtdevs := (*[1 << 28]C.libxl_device_dtdev)(unsafe.Pointer(xc.dtdevs))[:numDtdevs:numDtdevs]
-	for i, v := range x.Dtdevs {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cDtdevs[i] = tmp
-	}
-	numVfbs := len(x.Vfbs)
-	xc.vfbs = (*C.libxl_device_vfb)(C.malloc(C.ulong(numVfbs) * C.sizeof_libxl_device_vfb))
-	xc.num_vfbs = C.int(numVfbs)
-	cVfbs := (*[1 << 28]C.libxl_device_vfb)(unsafe.Pointer(xc.vfbs))[:numVfbs:numVfbs]
-	for i, v := range x.Vfbs {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cVfbs[i] = tmp
-	}
-	numVkbs := len(x.Vkbs)
-	xc.vkbs = (*C.libxl_device_vkb)(C.malloc(C.ulong(numVkbs) * C.sizeof_libxl_device_vkb))
-	xc.num_vkbs = C.int(numVkbs)
-	cVkbs := (*[1 << 28]C.libxl_device_vkb)(unsafe.Pointer(xc.vkbs))[:numVkbs:numVkbs]
-	for i, v := range x.Vkbs {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cVkbs[i] = tmp
-	}
-	numVtpms := len(x.Vtpms)
-	xc.vtpms = (*C.libxl_device_vtpm)(C.malloc(C.ulong(numVtpms) * C.sizeof_libxl_device_vtpm))
-	xc.num_vtpms = C.int(numVtpms)
-	cVtpms := (*[1 << 28]C.libxl_device_vtpm)(unsafe.Pointer(xc.vtpms))[:numVtpms:numVtpms]
-	for i, v := range x.Vtpms {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cVtpms[i] = tmp
-	}
-	numP9S := len(x.P9S)
-	xc.p9s = (*C.libxl_device_p9)(C.malloc(C.ulong(numP9S) * C.sizeof_libxl_device_p9))
-	xc.num_p9s = C.int(numP9S)
-	cP9S := (*[1 << 28]C.libxl_device_p9)(unsafe.Pointer(xc.p9s))[:numP9S:numP9S]
-	for i, v := range x.P9S {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cP9S[i] = tmp
-	}
-	numPvcallsifs := len(x.Pvcallsifs)
-	xc.pvcallsifs = (*C.libxl_device_pvcallsif)(C.malloc(C.ulong(numPvcallsifs) * C.sizeof_libxl_device_pvcallsif))
-	xc.num_pvcallsifs = C.int(numPvcallsifs)
-	cPvcallsifs := (*[1 << 28]C.libxl_device_pvcallsif)(unsafe.Pointer(xc.pvcallsifs))[:numPvcallsifs:numPvcallsifs]
-	for i, v := range x.Pvcallsifs {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cPvcallsifs[i] = tmp
-	}
-	numVdispls := len(x.Vdispls)
-	xc.vdispls = (*C.libxl_device_vdispl)(C.malloc(C.ulong(numVdispls) * C.sizeof_libxl_device_vdispl))
-	xc.num_vdispls = C.int(numVdispls)
-	cVdispls := (*[1 << 28]C.libxl_device_vdispl)(unsafe.Pointer(xc.vdispls))[:numVdispls:numVdispls]
-	for i, v := range x.Vdispls {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cVdispls[i] = tmp
-	}
-	numVsnds := len(x.Vsnds)
-	xc.vsnds = (*C.libxl_device_vsnd)(C.malloc(C.ulong(numVsnds) * C.sizeof_libxl_device_vsnd))
-	xc.num_vsnds = C.int(numVsnds)
-	cVsnds := (*[1 << 28]C.libxl_device_vsnd)(unsafe.Pointer(xc.vsnds))[:numVsnds:numVsnds]
-	for i, v := range x.Vsnds {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cVsnds[i] = tmp
-	}
-	numChannels := len(x.Channels)
-	xc.channels = (*C.libxl_device_channel)(C.malloc(C.ulong(numChannels) * C.sizeof_libxl_device_channel))
-	xc.num_channels = C.int(numChannels)
-	cChannels := (*[1 << 28]C.libxl_device_channel)(unsafe.Pointer(xc.channels))[:numChannels:numChannels]
-	for i, v := range x.Channels {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cChannels[i] = tmp
-	}
-	numUsbctrls := len(x.Usbctrls)
-	xc.usbctrls = (*C.libxl_device_usbctrl)(C.malloc(C.ulong(numUsbctrls) * C.sizeof_libxl_device_usbctrl))
-	xc.num_usbctrls = C.int(numUsbctrls)
-	cUsbctrls := (*[1 << 28]C.libxl_device_usbctrl)(unsafe.Pointer(xc.usbctrls))[:numUsbctrls:numUsbctrls]
-	for i, v := range x.Usbctrls {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
-		}
-		cUsbctrls[i] = tmp
-	}
-	numUsbdevs := len(x.Usbdevs)
-	xc.usbdevs = (*C.libxl_device_usbdev)(C.malloc(C.ulong(numUsbdevs) * C.sizeof_libxl_device_usbdev))
-	xc.num_usbdevs = C.int(numUsbdevs)
-	cUsbdevs := (*[1 << 28]C.libxl_device_usbdev)(unsafe.Pointer(xc.usbdevs))[:numUsbdevs:numUsbdevs]
-	for i, v := range x.Usbdevs {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_domain_config_dispose(&xc)
-			return xc, err
+	if numDisks := len(x.Disks); numDisks > 0 {
+		xc.disks = (*C.libxl_device_disk)(C.malloc(C.ulong(numDisks) * C.sizeof_libxl_device_disk))
+		xc.num_disks = C.int(numDisks)
+		cDisks := (*[1 << 28]C.libxl_device_disk)(unsafe.Pointer(xc.disks))[:numDisks:numDisks]
+		for i, v := range x.Disks {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cDisks[i] = tmp
+		}
+	}
+	if numNics := len(x.Nics); numNics > 0 {
+		xc.nics = (*C.libxl_device_nic)(C.malloc(C.ulong(numNics) * C.sizeof_libxl_device_nic))
+		xc.num_nics = C.int(numNics)
+		cNics := (*[1 << 28]C.libxl_device_nic)(unsafe.Pointer(xc.nics))[:numNics:numNics]
+		for i, v := range x.Nics {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cNics[i] = tmp
+		}
+	}
+	if numPcidevs := len(x.Pcidevs); numPcidevs > 0 {
+		xc.pcidevs = (*C.libxl_device_pci)(C.malloc(C.ulong(numPcidevs) * C.sizeof_libxl_device_pci))
+		xc.num_pcidevs = C.int(numPcidevs)
+		cPcidevs := (*[1 << 28]C.libxl_device_pci)(unsafe.Pointer(xc.pcidevs))[:numPcidevs:numPcidevs]
+		for i, v := range x.Pcidevs {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cPcidevs[i] = tmp
+		}
+	}
+	if numRdms := len(x.Rdms); numRdms > 0 {
+		xc.rdms = (*C.libxl_device_rdm)(C.malloc(C.ulong(numRdms) * C.sizeof_libxl_device_rdm))
+		xc.num_rdms = C.int(numRdms)
+		cRdms := (*[1 << 28]C.libxl_device_rdm)(unsafe.Pointer(xc.rdms))[:numRdms:numRdms]
+		for i, v := range x.Rdms {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cRdms[i] = tmp
+		}
+	}
+	if numDtdevs := len(x.Dtdevs); numDtdevs > 0 {
+		xc.dtdevs = (*C.libxl_device_dtdev)(C.malloc(C.ulong(numDtdevs) * C.sizeof_libxl_device_dtdev))
+		xc.num_dtdevs = C.int(numDtdevs)
+		cDtdevs := (*[1 << 28]C.libxl_device_dtdev)(unsafe.Pointer(xc.dtdevs))[:numDtdevs:numDtdevs]
+		for i, v := range x.Dtdevs {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cDtdevs[i] = tmp
+		}
+	}
+	if numVfbs := len(x.Vfbs); numVfbs > 0 {
+		xc.vfbs = (*C.libxl_device_vfb)(C.malloc(C.ulong(numVfbs) * C.sizeof_libxl_device_vfb))
+		xc.num_vfbs = C.int(numVfbs)
+		cVfbs := (*[1 << 28]C.libxl_device_vfb)(unsafe.Pointer(xc.vfbs))[:numVfbs:numVfbs]
+		for i, v := range x.Vfbs {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cVfbs[i] = tmp
+		}
+	}
+	if numVkbs := len(x.Vkbs); numVkbs > 0 {
+		xc.vkbs = (*C.libxl_device_vkb)(C.malloc(C.ulong(numVkbs) * C.sizeof_libxl_device_vkb))
+		xc.num_vkbs = C.int(numVkbs)
+		cVkbs := (*[1 << 28]C.libxl_device_vkb)(unsafe.Pointer(xc.vkbs))[:numVkbs:numVkbs]
+		for i, v := range x.Vkbs {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cVkbs[i] = tmp
+		}
+	}
+	if numVtpms := len(x.Vtpms); numVtpms > 0 {
+		xc.vtpms = (*C.libxl_device_vtpm)(C.malloc(C.ulong(numVtpms) * C.sizeof_libxl_device_vtpm))
+		xc.num_vtpms = C.int(numVtpms)
+		cVtpms := (*[1 << 28]C.libxl_device_vtpm)(unsafe.Pointer(xc.vtpms))[:numVtpms:numVtpms]
+		for i, v := range x.Vtpms {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cVtpms[i] = tmp
+		}
+	}
+	if numP9S := len(x.P9S); numP9S > 0 {
+		xc.p9s = (*C.libxl_device_p9)(C.malloc(C.ulong(numP9S) * C.sizeof_libxl_device_p9))
+		xc.num_p9s = C.int(numP9S)
+		cP9S := (*[1 << 28]C.libxl_device_p9)(unsafe.Pointer(xc.p9s))[:numP9S:numP9S]
+		for i, v := range x.P9S {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cP9S[i] = tmp
+		}
+	}
+	if numPvcallsifs := len(x.Pvcallsifs); numPvcallsifs > 0 {
+		xc.pvcallsifs = (*C.libxl_device_pvcallsif)(C.malloc(C.ulong(numPvcallsifs) * C.sizeof_libxl_device_pvcallsif))
+		xc.num_pvcallsifs = C.int(numPvcallsifs)
+		cPvcallsifs := (*[1 << 28]C.libxl_device_pvcallsif)(unsafe.Pointer(xc.pvcallsifs))[:numPvcallsifs:numPvcallsifs]
+		for i, v := range x.Pvcallsifs {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cPvcallsifs[i] = tmp
+		}
+	}
+	if numVdispls := len(x.Vdispls); numVdispls > 0 {
+		xc.vdispls = (*C.libxl_device_vdispl)(C.malloc(C.ulong(numVdispls) * C.sizeof_libxl_device_vdispl))
+		xc.num_vdispls = C.int(numVdispls)
+		cVdispls := (*[1 << 28]C.libxl_device_vdispl)(unsafe.Pointer(xc.vdispls))[:numVdispls:numVdispls]
+		for i, v := range x.Vdispls {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cVdispls[i] = tmp
+		}
+	}
+	if numVsnds := len(x.Vsnds); numVsnds > 0 {
+		xc.vsnds = (*C.libxl_device_vsnd)(C.malloc(C.ulong(numVsnds) * C.sizeof_libxl_device_vsnd))
+		xc.num_vsnds = C.int(numVsnds)
+		cVsnds := (*[1 << 28]C.libxl_device_vsnd)(unsafe.Pointer(xc.vsnds))[:numVsnds:numVsnds]
+		for i, v := range x.Vsnds {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cVsnds[i] = tmp
+		}
+	}
+	if numChannels := len(x.Channels); numChannels > 0 {
+		xc.channels = (*C.libxl_device_channel)(C.malloc(C.ulong(numChannels) * C.sizeof_libxl_device_channel))
+		xc.num_channels = C.int(numChannels)
+		cChannels := (*[1 << 28]C.libxl_device_channel)(unsafe.Pointer(xc.channels))[:numChannels:numChannels]
+		for i, v := range x.Channels {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cChannels[i] = tmp
+		}
+	}
+	if numUsbctrls := len(x.Usbctrls); numUsbctrls > 0 {
+		xc.usbctrls = (*C.libxl_device_usbctrl)(C.malloc(C.ulong(numUsbctrls) * C.sizeof_libxl_device_usbctrl))
+		xc.num_usbctrls = C.int(numUsbctrls)
+		cUsbctrls := (*[1 << 28]C.libxl_device_usbctrl)(unsafe.Pointer(xc.usbctrls))[:numUsbctrls:numUsbctrls]
+		for i, v := range x.Usbctrls {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cUsbctrls[i] = tmp
+		}
+	}
+	if numUsbdevs := len(x.Usbdevs); numUsbdevs > 0 {
+		xc.usbdevs = (*C.libxl_device_usbdev)(C.malloc(C.ulong(numUsbdevs) * C.sizeof_libxl_device_usbdev))
+		xc.num_usbdevs = C.int(numUsbdevs)
+		cUsbdevs := (*[1 << 28]C.libxl_device_usbdev)(unsafe.Pointer(xc.usbdevs))[:numUsbdevs:numUsbdevs]
+		for i, v := range x.Usbdevs {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_domain_config_dispose(&xc)
+				return xc, err
+			}
+			cUsbdevs[i] = tmp
 		}
-		cUsbdevs[i] = tmp
 	}
 	xc.on_poweroff = C.libxl_action_on_shutdown(x.OnPoweroff)
 	xc.on_reboot = C.libxl_action_on_shutdown(x.OnReboot)
@@ -2658,12 +2742,14 @@ func (x *Vdisplinfo) fromC(xc *C.libxl_vdisplinfo) error {
 	x.Devid = Devid(xc.devid)
 	x.State = int(xc.state)
 	x.BeAlloc = bool(xc.be_alloc)
-	numConnectors := int(xc.num_connectors)
-	cConnectors := (*[1 << 28]C.libxl_connectorinfo)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
-	x.Connectors = make([]Connectorinfo, numConnectors)
-	for i, v := range cConnectors {
-		if err := x.Connectors[i].fromC(&v); err != nil {
-			return err
+	x.Connectors = nil
+	if numConnectors := int(xc.num_connectors); numConnectors > 0 {
+		cConnectors := (*[1 << 28]C.libxl_connectorinfo)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
+		x.Connectors = make([]Connectorinfo, numConnectors)
+		for i, v := range cConnectors {
+			if err := x.Connectors[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -2679,17 +2765,18 @@ func (x *Vdisplinfo) toC() (xc C.libxl_vdisplinfo, err error) {
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.state = C.int(x.State)
 	xc.be_alloc = C.bool(x.BeAlloc)
-	numConnectors := len(x.Connectors)
-	xc.connectors = (*C.libxl_connectorinfo)(C.malloc(C.ulong(numConnectors) * C.sizeof_libxl_connectorinfo))
-	xc.num_connectors = C.int(numConnectors)
-	cConnectors := (*[1 << 28]C.libxl_connectorinfo)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
-	for i, v := range x.Connectors {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_vdisplinfo_dispose(&xc)
-			return xc, err
+	if numConnectors := len(x.Connectors); numConnectors > 0 {
+		xc.connectors = (*C.libxl_connectorinfo)(C.malloc(C.ulong(numConnectors) * C.sizeof_libxl_connectorinfo))
+		xc.num_connectors = C.int(numConnectors)
+		cConnectors := (*[1 << 28]C.libxl_connectorinfo)(unsafe.Pointer(xc.connectors))[:numConnectors:numConnectors]
+		for i, v := range x.Connectors {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_vdisplinfo_dispose(&xc)
+				return xc, err
+			}
+			cConnectors[i] = tmp
 		}
-		cConnectors[i] = tmp
 	}
 	return xc, nil
 }
@@ -2709,12 +2796,14 @@ func (x *Streaminfo) toC() (xc C.libxl_streaminfo, err error) {
 }
 
 func (x *Pcminfo) fromC(xc *C.libxl_pcminfo) error {
-	numVsndStreams := int(xc.num_vsnd_streams)
-	cStreams := (*[1 << 28]C.libxl_streaminfo)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
-	x.Streams = make([]Streaminfo, numVsndStreams)
-	for i, v := range cStreams {
-		if err := x.Streams[i].fromC(&v); err != nil {
-			return err
+	x.Streams = nil
+	if numVsndStreams := int(xc.num_vsnd_streams); numVsndStreams > 0 {
+		cStreams := (*[1 << 28]C.libxl_streaminfo)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
+		x.Streams = make([]Streaminfo, numVsndStreams)
+		for i, v := range cStreams {
+			if err := x.Streams[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -2723,17 +2812,18 @@ func (x *Pcminfo) fromC(xc *C.libxl_pcminfo) error {
 
 func (x *Pcminfo) toC() (xc C.libxl_pcminfo, err error) {
 	C.libxl_pcminfo_init(&xc)
-	numVsndStreams := len(x.Streams)
-	xc.streams = (*C.libxl_streaminfo)(C.malloc(C.ulong(numVsndStreams) * C.sizeof_libxl_streaminfo))
-	xc.num_vsnd_streams = C.int(numVsndStreams)
-	cStreams := (*[1 << 28]C.libxl_streaminfo)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
-	for i, v := range x.Streams {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_pcminfo_dispose(&xc)
-			return xc, err
+	if numVsndStreams := len(x.Streams); numVsndStreams > 0 {
+		xc.streams = (*C.libxl_streaminfo)(C.malloc(C.ulong(numVsndStreams) * C.sizeof_libxl_streaminfo))
+		xc.num_vsnd_streams = C.int(numVsndStreams)
+		cStreams := (*[1 << 28]C.libxl_streaminfo)(unsafe.Pointer(xc.streams))[:numVsndStreams:numVsndStreams]
+		for i, v := range x.Streams {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_pcminfo_dispose(&xc)
+				return xc, err
+			}
+			cStreams[i] = tmp
 		}
-		cStreams[i] = tmp
 	}
 	return xc, nil
 }
@@ -2745,12 +2835,14 @@ func (x *Vsndinfo) fromC(xc *C.libxl_vsndinfo) error {
 	x.FrontendId = uint32(xc.frontend_id)
 	x.Devid = Devid(xc.devid)
 	x.State = int(xc.state)
-	numVsndPcms := int(xc.num_vsnd_pcms)
-	cPcms := (*[1 << 28]C.libxl_pcminfo)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
-	x.Pcms = make([]Pcminfo, numVsndPcms)
-	for i, v := range cPcms {
-		if err := x.Pcms[i].fromC(&v); err != nil {
-			return err
+	x.Pcms = nil
+	if numVsndPcms := int(xc.num_vsnd_pcms); numVsndPcms > 0 {
+		cPcms := (*[1 << 28]C.libxl_pcminfo)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
+		x.Pcms = make([]Pcminfo, numVsndPcms)
+		for i, v := range cPcms {
+			if err := x.Pcms[i].fromC(&v); err != nil {
+				return err
+			}
 		}
 	}
 
@@ -2765,17 +2857,18 @@ func (x *Vsndinfo) toC() (xc C.libxl_vsndinfo, err error) {
 	xc.frontend_id = C.uint32_t(x.FrontendId)
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.state = C.int(x.State)
-	numVsndPcms := len(x.Pcms)
-	xc.pcms = (*C.libxl_pcminfo)(C.malloc(C.ulong(numVsndPcms) * C.sizeof_libxl_pcminfo))
-	xc.num_vsnd_pcms = C.int(numVsndPcms)
-	cPcms := (*[1 << 28]C.libxl_pcminfo)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
-	for i, v := range x.Pcms {
-		tmp, err := v.toC()
-		if err != nil {
-			C.libxl_vsndinfo_dispose(&xc)
-			return xc, err
+	if numVsndPcms := len(x.Pcms); numVsndPcms > 0 {
+		xc.pcms = (*C.libxl_pcminfo)(C.malloc(C.ulong(numVsndPcms) * C.sizeof_libxl_pcminfo))
+		xc.num_vsnd_pcms = C.int(numVsndPcms)
+		cPcms := (*[1 << 28]C.libxl_pcminfo)(unsafe.Pointer(xc.pcms))[:numVsndPcms:numVsndPcms]
+		for i, v := range x.Pcms {
+			tmp, err := v.toC()
+			if err != nil {
+				C.libxl_vsndinfo_dispose(&xc)
+				return xc, err
+			}
+			cPcms[i] = tmp
 		}
-		cPcms[i] = tmp
 	}
 	return xc, nil
 }
@@ -2809,11 +2902,13 @@ func (x *Vkbinfo) toC() (xc C.libxl_vkbinfo, err error) {
 func (x *Numainfo) fromC(xc *C.libxl_numainfo) error {
 	x.Size = uint64(xc.size)
 	x.Free = uint64(xc.free)
-	numDists := int(xc.num_dists)
-	cDists := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.dists))[:numDists:numDists]
-	x.Dists = make([]uint32, numDists)
-	for i, v := range cDists {
-		x.Dists[i] = uint32(v)
+	x.Dists = nil
+	if numDists := int(xc.num_dists); numDists > 0 {
+		cDists := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.dists))[:numDists:numDists]
+		x.Dists = make([]uint32, numDists)
+		for i, v := range cDists {
+			x.Dists[i] = uint32(v)
+		}
 	}
 
 	return nil
@@ -2823,12 +2918,13 @@ func (x *Numainfo) toC() (xc C.libxl_numainfo, err error) {
 	C.libxl_numainfo_init(&xc)
 	xc.size = C.uint64_t(x.Size)
 	xc.free = C.uint64_t(x.Free)
-	numDists := len(x.Dists)
-	xc.dists = (*C.uint32_t)(C.malloc(C.size_t(numDists * numDists)))
-	xc.num_dists = C.int(numDists)
-	cDists := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.dists))[:numDists:numDists]
-	for i, v := range x.Dists {
-		cDists[i] = C.uint32_t(v)
+	if numDists := len(x.Dists); numDists > 0 {
+		xc.dists = (*C.uint32_t)(C.malloc(C.size_t(numDists * numDists)))
+		xc.num_dists = C.int(numDists)
+		cDists := (*[1 << 28]C.uint32_t)(unsafe.Pointer(xc.dists))[:numDists:numDists]
+		for i, v := range x.Dists {
+			cDists[i] = C.uint32_t(v)
+		}
 	}
 	return xc, nil
 }
@@ -2976,12 +3072,6 @@ func (x *Event) fromC(xc *C.libxl_event) error {
 	x.ForUser = uint64(xc.for_user)
 	x.Type = EventType(xc._type)
 	switch x.Type {
-	case EventTypeOperationComplete:
-		var typeOperationComplete EventTypeUnionOperationComplete
-		if err := typeOperationComplete.fromC(xc); err != nil {
-			return err
-		}
-		x.TypeUnion = typeOperationComplete
 	case EventTypeDomainShutdown:
 		var typeDomainShutdown EventTypeUnionDomainShutdown
 		if err := typeDomainShutdown.fromC(xc); err != nil {
@@ -2994,6 +3084,12 @@ func (x *Event) fromC(xc *C.libxl_event) error {
 			return err
 		}
 		x.TypeUnion = typeDiskEject
+	case EventTypeOperationComplete:
+		var typeOperationComplete EventTypeUnionOperationComplete
+		if err := typeOperationComplete.fromC(xc); err != nil {
+			return err
+		}
+		x.TypeUnion = typeOperationComplete
 	default:
 		return fmt.Errorf("invalid union key '%v'", x.Type)
 	}
@@ -3113,18 +3209,18 @@ func (x *PsrHwInfo) fromC(xc *C.libxl_psr_hw_info) error {
 	x.Id = uint32(xc.id)
 	x.Type = PsrFeatType(xc._type)
 	switch x.Type {
-	case PsrFeatTypeMba:
-		var typeMba PsrHwInfoTypeUnionMba
-		if err := typeMba.fromC(xc); err != nil {
-			return err
-		}
-		x.TypeUnion = typeMba
 	case PsrFeatTypeCat:
 		var typeCat PsrHwInfoTypeUnionCat
 		if err := typeCat.fromC(xc); err != nil {
 			return err
 		}
 		x.TypeUnion = typeCat
+	case PsrFeatTypeMba:
+		var typeMba PsrHwInfoTypeUnionMba
+		if err := typeMba.fromC(xc); err != nil {
+			return err
+		}
+		x.TypeUnion = typeMba
 	default:
 		return fmt.Errorf("invalid union key '%v'", x.Type)
 	}
-- 
2.24.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Xen-devel] [PATCH 2/9] golang/xenlight: Do proper nil / NULL conversions for builtin Bitmap type
  2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
@ 2019-12-27 16:32 ` George Dunlap
  2020-01-04 18:00   ` Nick Rosbrook
  2019-12-27 16:32 ` [Xen-devel] [PATCH 3/9] golang/xenlight: Convert "" to NULL George Dunlap
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: George Dunlap @ 2019-12-27 16:32 UTC (permalink / raw)
  To: xen-devel; +Cc: Nick Rosbrook, George Dunlap

Similar to the autogenerated types, but for `builtin` Bitmap type.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
CC: Nick Rosbrook <rosbrookn@ainfosec.com>
---
 tools/golang/xenlight/xenlight.go | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index 237f26bce9..e18f0f35f8 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -408,15 +408,17 @@ type Bitmap struct {
 }
 
 func (bm *Bitmap) fromC(cbm *C.libxl_bitmap) error {
-	// Alloc a Go slice for the bytes
-	size := int(cbm.size)
-	bm.bitmap = make([]C.uint8_t, size)
+	bm.bitmap = nil
+	if size := int(cbm.size); size > 0 {
+		// Alloc a Go slice for the bytes
+		bm.bitmap = make([]C.uint8_t, size)
 
-	// Make a slice pointing to the C array
-	cs := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+		// Make a slice pointing to the C array
+		cs := (*[1 << 30]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
 
-	// And copy the C array into the Go array
-	copy(bm.bitmap, cs)
+		// And copy the C array into the Go array
+		copy(bm.bitmap, cs)
+	}
 
 	return nil
 }
@@ -426,10 +428,12 @@ func (bm *Bitmap) toC() (C.libxl_bitmap, error) {
 
 	size := len(bm.bitmap)
 	cbm.size = C.uint32_t(size)
-	cbm._map = (*C.uint8_t)(C.malloc(C.ulong(cbm.size) * C.sizeof_uint8_t))
-	cs := (*[1 << 31]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
+	if cbm.size > 0 {
+		cbm._map = (*C.uint8_t)(C.malloc(C.ulong(cbm.size) * C.sizeof_uint8_t))
+		cs := (*[1 << 31]C.uint8_t)(unsafe.Pointer(cbm._map))[:size:size]
 
-	copy(cs, bm.bitmap)
+		copy(cs, bm.bitmap)
+	}
 
 	return cbm, nil
 }
-- 
2.24.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Xen-devel] [PATCH 3/9] golang/xenlight: Convert "" to NULL
  2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
  2019-12-27 16:32 ` [Xen-devel] [PATCH 2/9] golang/xenlight: Do proper nil / NULL conversions for builtin Bitmap type George Dunlap
@ 2019-12-27 16:32 ` George Dunlap
  2020-01-04 18:25   ` Nick Rosbrook
  2019-12-27 16:32 ` [Xen-devel] [PATCH 4/9] go/xenlight: Fix CpuidPoliclyList conversion George Dunlap
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: George Dunlap @ 2019-12-27 16:32 UTC (permalink / raw)
  To: xen-devel; +Cc: Nick Rosbrook, George Dunlap

C.GoString will handle NULL C strings properly, by passing back "".
But C.CString will take an empty Go string and actually generate a
'\0'-terminated empty string.  This confuses libxl, which is expecting
non-values to be NULL, not "".

Only call C.CString if the Go string is non-empty.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
CC: Nick Rosbrook <rosbrookn@ainfosec.com>
---
 tools/golang/xenlight/gengotypes.py  |   6 +-
 tools/golang/xenlight/helpers.gen.go | 628 ++++++++++++++++++++-------
 2 files changed, 475 insertions(+), 159 deletions(-)

diff --git a/tools/golang/xenlight/gengotypes.py b/tools/golang/xenlight/gengotypes.py
index 5363ca062d..e4ed4d50f5 100644
--- a/tools/golang/xenlight/gengotypes.py
+++ b/tools/golang/xenlight/gengotypes.py
@@ -487,7 +487,8 @@ def xenlight_golang_define_to_C(ty = None, typename = None, nested = False):
             if is_castable:
                 # Use the cgo helper for converting C strings.
                 if gotypename == 'string':
-                    s += 'xc.{} = C.CString(x.{})\n'.format(cname,goname)
+                    s += 'if x.{} != "" {{\n'.format(goname)
+                    s += 'xc.{} = C.CString(x.{})\n}}\n'.format(cname,goname)
                     continue
 
                 s += 'xc.{} = C.{}(x.{})\n'.format(cname,ctypename,goname)
@@ -569,7 +570,8 @@ def xenlight_golang_union_to_C(ty = None, union_name = '',
                 s += 'return xc,err \n}\n'
 
             elif gotypename == 'string':
-                s += '{}.{} = C.CString(tmp.{})\n'.format(f.name,uf.name,gofname)
+                s += 'if tmp.{} != "" {{\n'.format(gofname)
+                s += '{}.{} = C.CString(tmp.{})\n}}\n'.format(f.name,uf.name,gofname)
 
             else:
                 s += '{}.{} = C.{}(tmp.{})\n'.format(f.name,uf.name,ctypename,gofname)
diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go
index 61cd73595e..2236222cc2 100644
--- a/tools/golang/xenlight/helpers.gen.go
+++ b/tools/golang/xenlight/helpers.gen.go
@@ -93,8 +93,12 @@ func (x *VncInfo) toC() (xc C.libxl_vnc_info, err error) {
 		C.libxl_vnc_info_dispose(&xc)
 		return xc, err
 	}
-	xc.listen = C.CString(x.Listen)
-	xc.passwd = C.CString(x.Passwd)
+	if x.Listen != "" {
+		xc.listen = C.CString(x.Listen)
+	}
+	if x.Passwd != "" {
+		xc.passwd = C.CString(x.Passwd)
+	}
 	xc.display = C.int(x.Display)
 	xc.findunused, err = x.Findunused.toC()
 	if err != nil {
@@ -140,13 +144,17 @@ func (x *SpiceInfo) toC() (xc C.libxl_spice_info, err error) {
 	}
 	xc.port = C.int(x.Port)
 	xc.tls_port = C.int(x.TlsPort)
-	xc.host = C.CString(x.Host)
+	if x.Host != "" {
+		xc.host = C.CString(x.Host)
+	}
 	xc.disable_ticketing, err = x.DisableTicketing.toC()
 	if err != nil {
 		C.libxl_spice_info_dispose(&xc)
 		return xc, err
 	}
-	xc.passwd = C.CString(x.Passwd)
+	if x.Passwd != "" {
+		xc.passwd = C.CString(x.Passwd)
+	}
 	xc.agent_mouse, err = x.AgentMouse.toC()
 	if err != nil {
 		C.libxl_spice_info_dispose(&xc)
@@ -163,8 +171,12 @@ func (x *SpiceInfo) toC() (xc C.libxl_spice_info, err error) {
 		return xc, err
 	}
 	xc.usbredirection = C.int(x.Usbredirection)
-	xc.image_compression = C.CString(x.ImageCompression)
-	xc.streaming_video = C.CString(x.StreamingVideo)
+	if x.ImageCompression != "" {
+		xc.image_compression = C.CString(x.ImageCompression)
+	}
+	if x.StreamingVideo != "" {
+		xc.streaming_video = C.CString(x.StreamingVideo)
+	}
 	return xc, nil
 }
 
@@ -193,8 +205,12 @@ func (x *SdlInfo) toC() (xc C.libxl_sdl_info, err error) {
 		C.libxl_sdl_info_dispose(&xc)
 		return xc, err
 	}
-	xc.display = C.CString(x.Display)
-	xc.xauthority = C.CString(x.Xauthority)
+	if x.Display != "" {
+		xc.display = C.CString(x.Display)
+	}
+	if x.Xauthority != "" {
+		xc.xauthority = C.CString(x.Xauthority)
+	}
 	return xc, nil
 }
 
@@ -235,7 +251,9 @@ func (x *Dominfo) toC() (xc C.libxl_dominfo, err error) {
 	}
 	xc.domid = C.libxl_domid(x.Domid)
 	xc.ssidref = C.uint32_t(x.Ssidref)
-	xc.ssid_label = C.CString(x.SsidLabel)
+	if x.SsidLabel != "" {
+		xc.ssid_label = C.CString(x.SsidLabel)
+	}
 	xc.running = C.bool(x.Running)
 	xc.blocked = C.bool(x.Blocked)
 	xc.paused = C.bool(x.Paused)
@@ -271,7 +289,9 @@ func (x *Cpupoolinfo) fromC(xc *C.libxl_cpupoolinfo) error {
 func (x *Cpupoolinfo) toC() (xc C.libxl_cpupoolinfo, err error) {
 	C.libxl_cpupoolinfo_init(&xc)
 	xc.poolid = C.uint32_t(x.Poolid)
-	xc.pool_name = C.CString(x.PoolName)
+	if x.PoolName != "" {
+		xc.pool_name = C.CString(x.PoolName)
+	}
 	xc.sched = C.libxl_scheduler(x.Sched)
 	xc.n_dom = C.uint32_t(x.NDom)
 	xc.cpumap, err = x.Cpumap.toC()
@@ -318,9 +338,13 @@ func (x *ChannelinfoConnectionUnionPty) fromC(xc *C.libxl_channelinfo) error {
 
 func (x *Channelinfo) toC() (xc C.libxl_channelinfo, err error) {
 	C.libxl_channelinfo_init(&xc)
-	xc.backend = C.CString(x.Backend)
+	if x.Backend != "" {
+		xc.backend = C.CString(x.Backend)
+	}
 	xc.backend_id = C.uint32_t(x.BackendId)
-	xc.frontend = C.CString(x.Frontend)
+	if x.Frontend != "" {
+		xc.frontend = C.CString(x.Frontend)
+	}
 	xc.frontend_id = C.uint32_t(x.FrontendId)
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.state = C.int(x.State)
@@ -335,7 +359,9 @@ func (x *Channelinfo) toC() (xc C.libxl_channelinfo, err error) {
 			return xc, errors.New("wrong type for union key connection")
 		}
 		var pty C.libxl_channelinfo_connection_union_pty
-		pty.path = C.CString(tmp.Path)
+		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:
@@ -386,17 +412,35 @@ func (x *VersionInfo) toC() (xc C.libxl_version_info, err error) {
 	C.libxl_version_info_init(&xc)
 	xc.xen_version_major = C.int(x.XenVersionMajor)
 	xc.xen_version_minor = C.int(x.XenVersionMinor)
-	xc.xen_version_extra = C.CString(x.XenVersionExtra)
-	xc.compiler = C.CString(x.Compiler)
-	xc.compile_by = C.CString(x.CompileBy)
-	xc.compile_domain = C.CString(x.CompileDomain)
-	xc.compile_date = C.CString(x.CompileDate)
-	xc.capabilities = C.CString(x.Capabilities)
-	xc.changeset = C.CString(x.Changeset)
+	if x.XenVersionExtra != "" {
+		xc.xen_version_extra = C.CString(x.XenVersionExtra)
+	}
+	if x.Compiler != "" {
+		xc.compiler = C.CString(x.Compiler)
+	}
+	if x.CompileBy != "" {
+		xc.compile_by = C.CString(x.CompileBy)
+	}
+	if x.CompileDomain != "" {
+		xc.compile_domain = C.CString(x.CompileDomain)
+	}
+	if x.CompileDate != "" {
+		xc.compile_date = C.CString(x.CompileDate)
+	}
+	if x.Capabilities != "" {
+		xc.capabilities = C.CString(x.Capabilities)
+	}
+	if x.Changeset != "" {
+		xc.changeset = C.CString(x.Changeset)
+	}
 	xc.virt_start = C.uint64_t(x.VirtStart)
 	xc.pagesize = C.int(x.Pagesize)
-	xc.commandline = C.CString(x.Commandline)
-	xc.build_id = C.CString(x.BuildId)
+	if x.Commandline != "" {
+		xc.commandline = C.CString(x.Commandline)
+	}
+	if x.BuildId != "" {
+		xc.build_id = C.CString(x.BuildId)
+	}
 	return xc, nil
 }
 
@@ -447,8 +491,12 @@ func (x *DomainCreateInfo) toC() (xc C.libxl_domain_create_info, err error) {
 		return xc, err
 	}
 	xc.ssidref = C.uint32_t(x.Ssidref)
-	xc.ssid_label = C.CString(x.SsidLabel)
-	xc.name = C.CString(x.Name)
+	if x.SsidLabel != "" {
+		xc.ssid_label = C.CString(x.SsidLabel)
+	}
+	if x.Name != "" {
+		xc.name = C.CString(x.Name)
+	}
 	xc.uuid, err = x.Uuid.toC()
 	if err != nil {
 		C.libxl_domain_create_info_dispose(&xc)
@@ -465,7 +513,9 @@ func (x *DomainCreateInfo) toC() (xc C.libxl_domain_create_info, err error) {
 		return xc, err
 	}
 	xc.poolid = C.uint32_t(x.Poolid)
-	xc.pool_name = C.CString(x.PoolName)
+	if x.PoolName != "" {
+		xc.pool_name = C.CString(x.PoolName)
+	}
 	xc.run_hotplug_scripts, err = x.RunHotplugScripts.toC()
 	if err != nil {
 		C.libxl_domain_create_info_dispose(&xc)
@@ -495,7 +545,9 @@ func (x *DomainRestoreParams) toC() (xc C.libxl_domain_restore_params, err error
 	C.libxl_domain_restore_params_init(&xc)
 	xc.checkpointed_stream = C.int(x.CheckpointedStream)
 	xc.stream_version = C.uint32_t(x.StreamVersion)
-	xc.colo_proxy_script = C.CString(x.ColoProxyScript)
+	if x.ColoProxyScript != "" {
+		xc.colo_proxy_script = C.CString(x.ColoProxyScript)
+	}
 	xc.userspace_colo_proxy, err = x.UserspaceColoProxy.toC()
 	if err != nil {
 		C.libxl_domain_restore_params_dispose(&xc)
@@ -1010,7 +1062,9 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 	xc.iommu_memkb = C.uint64_t(x.IommuMemkb)
 	xc.rtc_timeoffset = C.uint32_t(x.RtcTimeoffset)
 	xc.exec_ssidref = C.uint32_t(x.ExecSsidref)
-	xc.exec_ssid_label = C.CString(x.ExecSsidLabel)
+	if x.ExecSsidLabel != "" {
+		xc.exec_ssid_label = C.CString(x.ExecSsidLabel)
+	}
 	xc.localtime, err = x.Localtime.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
@@ -1026,7 +1080,9 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		C.libxl_domain_build_info_dispose(&xc)
 		return xc, err
 	}
-	xc.blkdev_start = C.CString(x.BlkdevStart)
+	if x.BlkdevStart != "" {
+		xc.blkdev_start = C.CString(x.BlkdevStart)
+	}
 	if numVnumaNodes := len(x.VnumaNodes); numVnumaNodes > 0 {
 		xc.vnuma_nodes = (*C.libxl_vnode_info)(C.malloc(C.ulong(numVnumaNodes) * C.sizeof_libxl_vnode_info))
 		xc.num_vnuma_nodes = C.int(numVnumaNodes)
@@ -1048,10 +1104,16 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		C.libxl_domain_build_info_dispose(&xc)
 		return xc, err
 	}
-	xc.device_model = C.CString(x.DeviceModel)
+	if x.DeviceModel != "" {
+		xc.device_model = C.CString(x.DeviceModel)
+	}
 	xc.device_model_ssidref = C.uint32_t(x.DeviceModelSsidref)
-	xc.device_model_ssid_label = C.CString(x.DeviceModelSsidLabel)
-	xc.device_model_user = C.CString(x.DeviceModelUser)
+	if x.DeviceModelSsidLabel != "" {
+		xc.device_model_ssid_label = C.CString(x.DeviceModelSsidLabel)
+	}
+	if x.DeviceModelUser != "" {
+		xc.device_model_user = C.CString(x.DeviceModelUser)
+	}
 	xc.extra, err = x.Extra.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
@@ -1112,16 +1174,26 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		return xc, err
 	}
 	xc.event_channels = C.uint32_t(x.EventChannels)
-	xc.kernel = C.CString(x.Kernel)
-	xc.cmdline = C.CString(x.Cmdline)
-	xc.ramdisk = C.CString(x.Ramdisk)
-	xc.device_tree = C.CString(x.DeviceTree)
+	if x.Kernel != "" {
+		xc.kernel = C.CString(x.Kernel)
+	}
+	if x.Cmdline != "" {
+		xc.cmdline = C.CString(x.Cmdline)
+	}
+	if x.Ramdisk != "" {
+		xc.ramdisk = C.CString(x.Ramdisk)
+	}
+	if x.DeviceTree != "" {
+		xc.device_tree = C.CString(x.DeviceTree)
+	}
 	xc.acpi, err = x.Acpi.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
 		return xc, err
 	}
-	xc.bootloader = C.CString(x.Bootloader)
+	if x.Bootloader != "" {
+		xc.bootloader = C.CString(x.Bootloader)
+	}
 	xc.bootloader_args, err = x.BootloaderArgs.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
@@ -1153,7 +1225,9 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 			return xc, errors.New("wrong type for union key type")
 		}
 		var hvm C.libxl_domain_build_info_type_union_hvm
-		hvm.firmware = C.CString(tmp.Firmware)
+		if tmp.Firmware != "" {
+			hvm.firmware = C.CString(tmp.Firmware)
+		}
 		hvm.bios = C.libxl_bios_type(tmp.Bios)
 		hvm.pae, err = tmp.Pae.toC()
 		if err != nil {
@@ -1205,7 +1279,9 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 			C.libxl_domain_build_info_dispose(&xc)
 			return xc, err
 		}
-		hvm.timeoffset = C.CString(tmp.Timeoffset)
+		if tmp.Timeoffset != "" {
+			hvm.timeoffset = C.CString(tmp.Timeoffset)
+		}
 		hvm.hpet, err = tmp.Hpet.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
@@ -1228,9 +1304,15 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 			C.libxl_domain_build_info_dispose(&xc)
 			return xc, err
 		}
-		hvm.system_firmware = C.CString(tmp.SystemFirmware)
-		hvm.smbios_firmware = C.CString(tmp.SmbiosFirmware)
-		hvm.acpi_firmware = C.CString(tmp.AcpiFirmware)
+		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)
 		hvm.nographic, err = tmp.Nographic.toC()
 		if err != nil {
@@ -1247,7 +1329,9 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 			C.libxl_domain_build_info_dispose(&xc)
 			return xc, err
 		}
-		hvm.keymap = C.CString(tmp.Keymap)
+		if tmp.Keymap != "" {
+			hvm.keymap = C.CString(tmp.Keymap)
+		}
 		hvm.sdl, err = tmp.Sdl.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
@@ -1264,21 +1348,29 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 			return xc, err
 		}
 		hvm.gfx_passthru_kind = C.libxl_gfx_passthru_kind(tmp.GfxPassthruKind)
-		hvm.serial = C.CString(tmp.Serial)
-		hvm.boot = C.CString(tmp.Boot)
+		if tmp.Serial != "" {
+			hvm.serial = C.CString(tmp.Serial)
+		}
+		if tmp.Boot != "" {
+			hvm.boot = C.CString(tmp.Boot)
+		}
 		hvm.usb, err = tmp.Usb.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
 			return xc, err
 		}
 		hvm.usbversion = C.int(tmp.Usbversion)
-		hvm.usbdevice = C.CString(tmp.Usbdevice)
+		if tmp.Usbdevice != "" {
+			hvm.usbdevice = C.CString(tmp.Usbdevice)
+		}
 		hvm.vkb_device, err = tmp.VkbDevice.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
 			return xc, err
 		}
-		hvm.soundhw = C.CString(tmp.Soundhw)
+		if tmp.Soundhw != "" {
+			hvm.soundhw = C.CString(tmp.Soundhw)
+		}
 		hvm.xen_platform_pci, err = tmp.XenPlatformPci.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
@@ -1316,17 +1408,27 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 			return xc, errors.New("wrong type for union key type")
 		}
 		var pv C.libxl_domain_build_info_type_union_pv
-		pv.kernel = C.CString(tmp.Kernel)
+		if tmp.Kernel != "" {
+			pv.kernel = C.CString(tmp.Kernel)
+		}
 		pv.slack_memkb = C.uint64_t(tmp.SlackMemkb)
-		pv.bootloader = C.CString(tmp.Bootloader)
+		if tmp.Bootloader != "" {
+			pv.bootloader = C.CString(tmp.Bootloader)
+		}
 		pv.bootloader_args, err = tmp.BootloaderArgs.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
 			return xc, err
 		}
-		pv.cmdline = C.CString(tmp.Cmdline)
-		pv.ramdisk = C.CString(tmp.Ramdisk)
-		pv.features = C.CString(tmp.Features)
+		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)
+		}
 		pv.e820_host, err = tmp.E820Host.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
@@ -1346,9 +1448,15 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 			C.libxl_domain_build_info_dispose(&xc)
 			return xc, err
 		}
-		pvh.pvshim_path = C.CString(tmp.PvshimPath)
-		pvh.pvshim_cmdline = C.CString(tmp.PvshimCmdline)
-		pvh.pvshim_extra = C.CString(tmp.PvshimExtra)
+		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:
@@ -1378,7 +1486,9 @@ func (x *DeviceVfb) fromC(xc *C.libxl_device_vfb) error {
 func (x *DeviceVfb) toC() (xc C.libxl_device_vfb, err error) {
 	C.libxl_device_vfb_init(&xc)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.vnc, err = x.Vnc.toC()
 	if err != nil {
@@ -1390,7 +1500,9 @@ func (x *DeviceVfb) toC() (xc C.libxl_device_vfb, err error) {
 		C.libxl_device_vfb_dispose(&xc)
 		return xc, err
 	}
-	xc.keymap = C.CString(x.Keymap)
+	if x.Keymap != "" {
+		xc.keymap = C.CString(x.Keymap)
+	}
 	return xc, nil
 }
 
@@ -1417,10 +1529,14 @@ func (x *DeviceVkb) fromC(xc *C.libxl_device_vkb) error {
 func (x *DeviceVkb) toC() (xc C.libxl_device_vkb, err error) {
 	C.libxl_device_vkb_init(&xc)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.backend_type = C.libxl_vkb_backend(x.BackendType)
-	xc.unique_id = C.CString(x.UniqueId)
+	if x.UniqueId != "" {
+		xc.unique_id = C.CString(x.UniqueId)
+	}
 	xc.feature_disable_keyboard = C.bool(x.FeatureDisableKeyboard)
 	xc.feature_disable_pointer = C.bool(x.FeatureDisablePointer)
 	xc.feature_abs_pointer = C.bool(x.FeatureAbsPointer)
@@ -1467,12 +1583,20 @@ func (x *DeviceDisk) fromC(xc *C.libxl_device_disk) error {
 func (x *DeviceDisk) toC() (xc C.libxl_device_disk, err error) {
 	C.libxl_device_disk_init(&xc)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
-	xc.pdev_path = C.CString(x.PdevPath)
-	xc.vdev = C.CString(x.Vdev)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
+	if x.PdevPath != "" {
+		xc.pdev_path = C.CString(x.PdevPath)
+	}
+	if x.Vdev != "" {
+		xc.vdev = C.CString(x.Vdev)
+	}
 	xc.backend = C.libxl_disk_backend(x.Backend)
 	xc.format = C.libxl_disk_format(x.Format)
-	xc.script = C.CString(x.Script)
+	if x.Script != "" {
+		xc.script = C.CString(x.Script)
+	}
 	xc.removable = C.int(x.Removable)
 	xc.readwrite = C.int(x.Readwrite)
 	xc.is_cdrom = C.int(x.IsCdrom)
@@ -1492,11 +1616,19 @@ func (x *DeviceDisk) toC() (xc C.libxl_device_disk, err error) {
 		C.libxl_device_disk_dispose(&xc)
 		return xc, err
 	}
-	xc.colo_host = C.CString(x.ColoHost)
+	if x.ColoHost != "" {
+		xc.colo_host = C.CString(x.ColoHost)
+	}
 	xc.colo_port = C.int(x.ColoPort)
-	xc.colo_export = C.CString(x.ColoExport)
-	xc.active_disk = C.CString(x.ActiveDisk)
-	xc.hidden_disk = C.CString(x.HiddenDisk)
+	if x.ColoExport != "" {
+		xc.colo_export = C.CString(x.ColoExport)
+	}
+	if x.ActiveDisk != "" {
+		xc.active_disk = C.CString(x.ActiveDisk)
+	}
+	if x.HiddenDisk != "" {
+		xc.hidden_disk = C.CString(x.HiddenDisk)
+	}
 	return xc, nil
 }
 
@@ -1573,72 +1705,184 @@ func (x *DeviceNic) fromC(xc *C.libxl_device_nic) error {
 func (x *DeviceNic) toC() (xc C.libxl_device_nic, err error) {
 	C.libxl_device_nic_init(&xc)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.mtu = C.int(x.Mtu)
-	xc.model = C.CString(x.Model)
+	if x.Model != "" {
+		xc.model = C.CString(x.Model)
+	}
 	xc.mac, err = x.Mac.toC()
 	if err != nil {
 		C.libxl_device_nic_dispose(&xc)
 		return xc, err
 	}
-	xc.ip = C.CString(x.Ip)
-	xc.bridge = C.CString(x.Bridge)
-	xc.ifname = C.CString(x.Ifname)
-	xc.script = C.CString(x.Script)
+	if x.Ip != "" {
+		xc.ip = C.CString(x.Ip)
+	}
+	if x.Bridge != "" {
+		xc.bridge = C.CString(x.Bridge)
+	}
+	if x.Ifname != "" {
+		xc.ifname = C.CString(x.Ifname)
+	}
+	if x.Script != "" {
+		xc.script = C.CString(x.Script)
+	}
 	xc.nictype = C.libxl_nic_type(x.Nictype)
 	xc.rate_bytes_per_interval = C.uint64_t(x.RateBytesPerInterval)
 	xc.rate_interval_usecs = C.uint32_t(x.RateIntervalUsecs)
-	xc.gatewaydev = C.CString(x.Gatewaydev)
-	xc.coloft_forwarddev = C.CString(x.ColoftForwarddev)
-	xc.colo_sock_mirror_id = C.CString(x.ColoSockMirrorId)
-	xc.colo_sock_mirror_ip = C.CString(x.ColoSockMirrorIp)
-	xc.colo_sock_mirror_port = C.CString(x.ColoSockMirrorPort)
-	xc.colo_sock_compare_pri_in_id = C.CString(x.ColoSockComparePriInId)
-	xc.colo_sock_compare_pri_in_ip = C.CString(x.ColoSockComparePriInIp)
-	xc.colo_sock_compare_pri_in_port = C.CString(x.ColoSockComparePriInPort)
-	xc.colo_sock_compare_sec_in_id = C.CString(x.ColoSockCompareSecInId)
-	xc.colo_sock_compare_sec_in_ip = C.CString(x.ColoSockCompareSecInIp)
-	xc.colo_sock_compare_sec_in_port = C.CString(x.ColoSockCompareSecInPort)
-	xc.colo_sock_compare_notify_id = C.CString(x.ColoSockCompareNotifyId)
-	xc.colo_sock_compare_notify_ip = C.CString(x.ColoSockCompareNotifyIp)
-	xc.colo_sock_compare_notify_port = C.CString(x.ColoSockCompareNotifyPort)
-	xc.colo_sock_redirector0_id = C.CString(x.ColoSockRedirector0Id)
-	xc.colo_sock_redirector0_ip = C.CString(x.ColoSockRedirector0Ip)
-	xc.colo_sock_redirector0_port = C.CString(x.ColoSockRedirector0Port)
-	xc.colo_sock_redirector1_id = C.CString(x.ColoSockRedirector1Id)
-	xc.colo_sock_redirector1_ip = C.CString(x.ColoSockRedirector1Ip)
-	xc.colo_sock_redirector1_port = C.CString(x.ColoSockRedirector1Port)
-	xc.colo_sock_redirector2_id = C.CString(x.ColoSockRedirector2Id)
-	xc.colo_sock_redirector2_ip = C.CString(x.ColoSockRedirector2Ip)
-	xc.colo_sock_redirector2_port = C.CString(x.ColoSockRedirector2Port)
-	xc.colo_filter_mirror_queue = C.CString(x.ColoFilterMirrorQueue)
-	xc.colo_filter_mirror_outdev = C.CString(x.ColoFilterMirrorOutdev)
-	xc.colo_filter_redirector0_queue = C.CString(x.ColoFilterRedirector0Queue)
-	xc.colo_filter_redirector0_indev = C.CString(x.ColoFilterRedirector0Indev)
-	xc.colo_filter_redirector0_outdev = C.CString(x.ColoFilterRedirector0Outdev)
-	xc.colo_filter_redirector1_queue = C.CString(x.ColoFilterRedirector1Queue)
-	xc.colo_filter_redirector1_indev = C.CString(x.ColoFilterRedirector1Indev)
-	xc.colo_filter_redirector1_outdev = C.CString(x.ColoFilterRedirector1Outdev)
-	xc.colo_compare_pri_in = C.CString(x.ColoComparePriIn)
-	xc.colo_compare_sec_in = C.CString(x.ColoCompareSecIn)
-	xc.colo_compare_out = C.CString(x.ColoCompareOut)
-	xc.colo_compare_notify_dev = C.CString(x.ColoCompareNotifyDev)
-	xc.colo_sock_sec_redirector0_id = C.CString(x.ColoSockSecRedirector0Id)
-	xc.colo_sock_sec_redirector0_ip = C.CString(x.ColoSockSecRedirector0Ip)
-	xc.colo_sock_sec_redirector0_port = C.CString(x.ColoSockSecRedirector0Port)
-	xc.colo_sock_sec_redirector1_id = C.CString(x.ColoSockSecRedirector1Id)
-	xc.colo_sock_sec_redirector1_ip = C.CString(x.ColoSockSecRedirector1Ip)
-	xc.colo_sock_sec_redirector1_port = C.CString(x.ColoSockSecRedirector1Port)
-	xc.colo_filter_sec_redirector0_queue = C.CString(x.ColoFilterSecRedirector0Queue)
-	xc.colo_filter_sec_redirector0_indev = C.CString(x.ColoFilterSecRedirector0Indev)
-	xc.colo_filter_sec_redirector0_outdev = C.CString(x.ColoFilterSecRedirector0Outdev)
-	xc.colo_filter_sec_redirector1_queue = C.CString(x.ColoFilterSecRedirector1Queue)
-	xc.colo_filter_sec_redirector1_indev = C.CString(x.ColoFilterSecRedirector1Indev)
-	xc.colo_filter_sec_redirector1_outdev = C.CString(x.ColoFilterSecRedirector1Outdev)
-	xc.colo_filter_sec_rewriter0_queue = C.CString(x.ColoFilterSecRewriter0Queue)
-	xc.colo_checkpoint_host = C.CString(x.ColoCheckpointHost)
-	xc.colo_checkpoint_port = C.CString(x.ColoCheckpointPort)
+	if x.Gatewaydev != "" {
+		xc.gatewaydev = C.CString(x.Gatewaydev)
+	}
+	if x.ColoftForwarddev != "" {
+		xc.coloft_forwarddev = C.CString(x.ColoftForwarddev)
+	}
+	if x.ColoSockMirrorId != "" {
+		xc.colo_sock_mirror_id = C.CString(x.ColoSockMirrorId)
+	}
+	if x.ColoSockMirrorIp != "" {
+		xc.colo_sock_mirror_ip = C.CString(x.ColoSockMirrorIp)
+	}
+	if x.ColoSockMirrorPort != "" {
+		xc.colo_sock_mirror_port = C.CString(x.ColoSockMirrorPort)
+	}
+	if x.ColoSockComparePriInId != "" {
+		xc.colo_sock_compare_pri_in_id = C.CString(x.ColoSockComparePriInId)
+	}
+	if x.ColoSockComparePriInIp != "" {
+		xc.colo_sock_compare_pri_in_ip = C.CString(x.ColoSockComparePriInIp)
+	}
+	if x.ColoSockComparePriInPort != "" {
+		xc.colo_sock_compare_pri_in_port = C.CString(x.ColoSockComparePriInPort)
+	}
+	if x.ColoSockCompareSecInId != "" {
+		xc.colo_sock_compare_sec_in_id = C.CString(x.ColoSockCompareSecInId)
+	}
+	if x.ColoSockCompareSecInIp != "" {
+		xc.colo_sock_compare_sec_in_ip = C.CString(x.ColoSockCompareSecInIp)
+	}
+	if x.ColoSockCompareSecInPort != "" {
+		xc.colo_sock_compare_sec_in_port = C.CString(x.ColoSockCompareSecInPort)
+	}
+	if x.ColoSockCompareNotifyId != "" {
+		xc.colo_sock_compare_notify_id = C.CString(x.ColoSockCompareNotifyId)
+	}
+	if x.ColoSockCompareNotifyIp != "" {
+		xc.colo_sock_compare_notify_ip = C.CString(x.ColoSockCompareNotifyIp)
+	}
+	if x.ColoSockCompareNotifyPort != "" {
+		xc.colo_sock_compare_notify_port = C.CString(x.ColoSockCompareNotifyPort)
+	}
+	if x.ColoSockRedirector0Id != "" {
+		xc.colo_sock_redirector0_id = C.CString(x.ColoSockRedirector0Id)
+	}
+	if x.ColoSockRedirector0Ip != "" {
+		xc.colo_sock_redirector0_ip = C.CString(x.ColoSockRedirector0Ip)
+	}
+	if x.ColoSockRedirector0Port != "" {
+		xc.colo_sock_redirector0_port = C.CString(x.ColoSockRedirector0Port)
+	}
+	if x.ColoSockRedirector1Id != "" {
+		xc.colo_sock_redirector1_id = C.CString(x.ColoSockRedirector1Id)
+	}
+	if x.ColoSockRedirector1Ip != "" {
+		xc.colo_sock_redirector1_ip = C.CString(x.ColoSockRedirector1Ip)
+	}
+	if x.ColoSockRedirector1Port != "" {
+		xc.colo_sock_redirector1_port = C.CString(x.ColoSockRedirector1Port)
+	}
+	if x.ColoSockRedirector2Id != "" {
+		xc.colo_sock_redirector2_id = C.CString(x.ColoSockRedirector2Id)
+	}
+	if x.ColoSockRedirector2Ip != "" {
+		xc.colo_sock_redirector2_ip = C.CString(x.ColoSockRedirector2Ip)
+	}
+	if x.ColoSockRedirector2Port != "" {
+		xc.colo_sock_redirector2_port = C.CString(x.ColoSockRedirector2Port)
+	}
+	if x.ColoFilterMirrorQueue != "" {
+		xc.colo_filter_mirror_queue = C.CString(x.ColoFilterMirrorQueue)
+	}
+	if x.ColoFilterMirrorOutdev != "" {
+		xc.colo_filter_mirror_outdev = C.CString(x.ColoFilterMirrorOutdev)
+	}
+	if x.ColoFilterRedirector0Queue != "" {
+		xc.colo_filter_redirector0_queue = C.CString(x.ColoFilterRedirector0Queue)
+	}
+	if x.ColoFilterRedirector0Indev != "" {
+		xc.colo_filter_redirector0_indev = C.CString(x.ColoFilterRedirector0Indev)
+	}
+	if x.ColoFilterRedirector0Outdev != "" {
+		xc.colo_filter_redirector0_outdev = C.CString(x.ColoFilterRedirector0Outdev)
+	}
+	if x.ColoFilterRedirector1Queue != "" {
+		xc.colo_filter_redirector1_queue = C.CString(x.ColoFilterRedirector1Queue)
+	}
+	if x.ColoFilterRedirector1Indev != "" {
+		xc.colo_filter_redirector1_indev = C.CString(x.ColoFilterRedirector1Indev)
+	}
+	if x.ColoFilterRedirector1Outdev != "" {
+		xc.colo_filter_redirector1_outdev = C.CString(x.ColoFilterRedirector1Outdev)
+	}
+	if x.ColoComparePriIn != "" {
+		xc.colo_compare_pri_in = C.CString(x.ColoComparePriIn)
+	}
+	if x.ColoCompareSecIn != "" {
+		xc.colo_compare_sec_in = C.CString(x.ColoCompareSecIn)
+	}
+	if x.ColoCompareOut != "" {
+		xc.colo_compare_out = C.CString(x.ColoCompareOut)
+	}
+	if x.ColoCompareNotifyDev != "" {
+		xc.colo_compare_notify_dev = C.CString(x.ColoCompareNotifyDev)
+	}
+	if x.ColoSockSecRedirector0Id != "" {
+		xc.colo_sock_sec_redirector0_id = C.CString(x.ColoSockSecRedirector0Id)
+	}
+	if x.ColoSockSecRedirector0Ip != "" {
+		xc.colo_sock_sec_redirector0_ip = C.CString(x.ColoSockSecRedirector0Ip)
+	}
+	if x.ColoSockSecRedirector0Port != "" {
+		xc.colo_sock_sec_redirector0_port = C.CString(x.ColoSockSecRedirector0Port)
+	}
+	if x.ColoSockSecRedirector1Id != "" {
+		xc.colo_sock_sec_redirector1_id = C.CString(x.ColoSockSecRedirector1Id)
+	}
+	if x.ColoSockSecRedirector1Ip != "" {
+		xc.colo_sock_sec_redirector1_ip = C.CString(x.ColoSockSecRedirector1Ip)
+	}
+	if x.ColoSockSecRedirector1Port != "" {
+		xc.colo_sock_sec_redirector1_port = C.CString(x.ColoSockSecRedirector1Port)
+	}
+	if x.ColoFilterSecRedirector0Queue != "" {
+		xc.colo_filter_sec_redirector0_queue = C.CString(x.ColoFilterSecRedirector0Queue)
+	}
+	if x.ColoFilterSecRedirector0Indev != "" {
+		xc.colo_filter_sec_redirector0_indev = C.CString(x.ColoFilterSecRedirector0Indev)
+	}
+	if x.ColoFilterSecRedirector0Outdev != "" {
+		xc.colo_filter_sec_redirector0_outdev = C.CString(x.ColoFilterSecRedirector0Outdev)
+	}
+	if x.ColoFilterSecRedirector1Queue != "" {
+		xc.colo_filter_sec_redirector1_queue = C.CString(x.ColoFilterSecRedirector1Queue)
+	}
+	if x.ColoFilterSecRedirector1Indev != "" {
+		xc.colo_filter_sec_redirector1_indev = C.CString(x.ColoFilterSecRedirector1Indev)
+	}
+	if x.ColoFilterSecRedirector1Outdev != "" {
+		xc.colo_filter_sec_redirector1_outdev = C.CString(x.ColoFilterSecRedirector1Outdev)
+	}
+	if x.ColoFilterSecRewriter0Queue != "" {
+		xc.colo_filter_sec_rewriter0_queue = C.CString(x.ColoFilterSecRewriter0Queue)
+	}
+	if x.ColoCheckpointHost != "" {
+		xc.colo_checkpoint_host = C.CString(x.ColoCheckpointHost)
+	}
+	if x.ColoCheckpointPort != "" {
+		xc.colo_checkpoint_port = C.CString(x.ColoCheckpointPort)
+	}
 	return xc, nil
 }
 
@@ -1708,7 +1952,9 @@ func (x *DeviceUsbctrl) toC() (xc C.libxl_device_usbctrl, err error) {
 	xc.version = C.int(x.Version)
 	xc.ports = C.int(x.Ports)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
 	return xc, nil
 }
 
@@ -1772,7 +2018,9 @@ func (x *DeviceDtdev) fromC(xc *C.libxl_device_dtdev) error {
 
 func (x *DeviceDtdev) toC() (xc C.libxl_device_dtdev, err error) {
 	C.libxl_device_dtdev_init(&xc)
-	xc.path = C.CString(x.Path)
+	if x.Path != "" {
+		xc.path = C.CString(x.Path)
+	}
 	return xc, nil
 }
 
@@ -1790,7 +2038,9 @@ func (x *DeviceVtpm) fromC(xc *C.libxl_device_vtpm) error {
 func (x *DeviceVtpm) toC() (xc C.libxl_device_vtpm, err error) {
 	C.libxl_device_vtpm_init(&xc)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.uuid, err = x.Uuid.toC()
 	if err != nil {
@@ -1814,10 +2064,18 @@ func (x *DeviceP9) fromC(xc *C.libxl_device_p9) error {
 func (x *DeviceP9) toC() (xc C.libxl_device_p9, err error) {
 	C.libxl_device_p9_init(&xc)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
-	xc.tag = C.CString(x.Tag)
-	xc.path = C.CString(x.Path)
-	xc.security_model = C.CString(x.SecurityModel)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
+	if x.Tag != "" {
+		xc.tag = C.CString(x.Tag)
+	}
+	if x.Path != "" {
+		xc.path = C.CString(x.Path)
+	}
+	if x.SecurityModel != "" {
+		xc.security_model = C.CString(x.SecurityModel)
+	}
 	xc.devid = C.libxl_devid(x.Devid)
 	return xc, nil
 }
@@ -1833,7 +2091,9 @@ func (x *DevicePvcallsif) fromC(xc *C.libxl_device_pvcallsif) error {
 func (x *DevicePvcallsif) toC() (xc C.libxl_device_pvcallsif, err error) {
 	C.libxl_device_pvcallsif_init(&xc)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
 	xc.devid = C.libxl_devid(x.Devid)
 	return xc, nil
 }
@@ -1871,9 +2131,13 @@ func (x *DeviceChannelConnectionUnionSocket) fromC(xc *C.libxl_device_channel) e
 func (x *DeviceChannel) toC() (xc C.libxl_device_channel, err error) {
 	C.libxl_device_channel_init(&xc)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
 	xc.devid = C.libxl_devid(x.Devid)
-	xc.name = C.CString(x.Name)
+	if x.Name != "" {
+		xc.name = C.CString(x.Name)
+	}
 	xc.connection = C.libxl_channel_connection(x.Connection)
 	switch x.Connection {
 	case ChannelConnectionSocket:
@@ -1883,7 +2147,9 @@ func (x *DeviceChannel) toC() (xc C.libxl_device_channel, err error) {
 			return xc, errors.New("wrong type for union key connection")
 		}
 		var socket C.libxl_device_channel_connection_union_socket
-		socket.path = C.CString(tmp.Path)
+		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:
@@ -1902,7 +2168,9 @@ func (x *ConnectorParam) fromC(xc *C.libxl_connector_param) error {
 
 func (x *ConnectorParam) toC() (xc C.libxl_connector_param, err error) {
 	C.libxl_connector_param_init(&xc)
-	xc.unique_id = C.CString(x.UniqueId)
+	if x.UniqueId != "" {
+		xc.unique_id = C.CString(x.UniqueId)
+	}
 	xc.width = C.uint32_t(x.Width)
 	xc.height = C.uint32_t(x.Height)
 	return xc, nil
@@ -1930,7 +2198,9 @@ func (x *DeviceVdispl) fromC(xc *C.libxl_device_vdispl) error {
 func (x *DeviceVdispl) toC() (xc C.libxl_device_vdispl, err error) {
 	C.libxl_device_vdispl_init(&xc)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.be_alloc = C.bool(x.BeAlloc)
 	if numConnectors := len(x.Connectors); numConnectors > 0 {
@@ -2009,7 +2279,9 @@ func (x *VsndStream) fromC(xc *C.libxl_vsnd_stream) error {
 
 func (x *VsndStream) toC() (xc C.libxl_vsnd_stream, err error) {
 	C.libxl_vsnd_stream_init(&xc)
-	xc.unique_id = C.CString(x.UniqueId)
+	if x.UniqueId != "" {
+		xc.unique_id = C.CString(x.UniqueId)
+	}
 	xc._type = C.libxl_vsnd_stream_type(x.Type)
 	xc.params, err = x.Params.toC()
 	if err != nil {
@@ -2040,7 +2312,9 @@ func (x *VsndPcm) fromC(xc *C.libxl_vsnd_pcm) error {
 
 func (x *VsndPcm) toC() (xc C.libxl_vsnd_pcm, err error) {
 	C.libxl_vsnd_pcm_init(&xc)
-	xc.name = C.CString(x.Name)
+	if x.Name != "" {
+		xc.name = C.CString(x.Name)
+	}
 	xc.params, err = x.Params.toC()
 	if err != nil {
 		C.libxl_vsnd_pcm_dispose(&xc)
@@ -2088,10 +2362,16 @@ func (x *DeviceVsnd) fromC(xc *C.libxl_device_vsnd) error {
 func (x *DeviceVsnd) toC() (xc C.libxl_device_vsnd, err error) {
 	C.libxl_device_vsnd_init(&xc)
 	xc.backend_domid = C.libxl_domid(x.BackendDomid)
-	xc.backend_domname = C.CString(x.BackendDomname)
+	if x.BackendDomname != "" {
+		xc.backend_domname = C.CString(x.BackendDomname)
+	}
 	xc.devid = C.libxl_devid(x.Devid)
-	xc.short_name = C.CString(x.ShortName)
-	xc.long_name = C.CString(x.LongName)
+	if x.ShortName != "" {
+		xc.short_name = C.CString(x.ShortName)
+	}
+	if x.LongName != "" {
+		xc.long_name = C.CString(x.LongName)
+	}
 	xc.params, err = x.Params.toC()
 	if err != nil {
 		C.libxl_device_vsnd_dispose(&xc)
@@ -2509,9 +2789,13 @@ func (x *Diskinfo) fromC(xc *C.libxl_diskinfo) error {
 
 func (x *Diskinfo) toC() (xc C.libxl_diskinfo, err error) {
 	C.libxl_diskinfo_init(&xc)
-	xc.backend = C.CString(x.Backend)
+	if x.Backend != "" {
+		xc.backend = C.CString(x.Backend)
+	}
 	xc.backend_id = C.uint32_t(x.BackendId)
-	xc.frontend = C.CString(x.Frontend)
+	if x.Frontend != "" {
+		xc.frontend = C.CString(x.Frontend)
+	}
 	xc.frontend_id = C.uint32_t(x.FrontendId)
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.state = C.int(x.State)
@@ -2536,9 +2820,13 @@ func (x *Nicinfo) fromC(xc *C.libxl_nicinfo) error {
 
 func (x *Nicinfo) toC() (xc C.libxl_nicinfo, err error) {
 	C.libxl_nicinfo_init(&xc)
-	xc.backend = C.CString(x.Backend)
+	if x.Backend != "" {
+		xc.backend = C.CString(x.Backend)
+	}
 	xc.backend_id = C.uint32_t(x.BackendId)
-	xc.frontend = C.CString(x.Frontend)
+	if x.Frontend != "" {
+		xc.frontend = C.CString(x.Frontend)
+	}
 	xc.frontend_id = C.uint32_t(x.FrontendId)
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.state = C.int(x.State)
@@ -2566,9 +2854,13 @@ func (x *Vtpminfo) fromC(xc *C.libxl_vtpminfo) error {
 
 func (x *Vtpminfo) toC() (xc C.libxl_vtpminfo, err error) {
 	C.libxl_vtpminfo_init(&xc)
-	xc.backend = C.CString(x.Backend)
+	if x.Backend != "" {
+		xc.backend = C.CString(x.Backend)
+	}
 	xc.backend_id = C.uint32_t(x.BackendId)
-	xc.frontend = C.CString(x.Frontend)
+	if x.Frontend != "" {
+		xc.frontend = C.CString(x.Frontend)
+	}
 	xc.frontend_id = C.uint32_t(x.FrontendId)
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.state = C.int(x.State)
@@ -2605,9 +2897,13 @@ func (x *Usbctrlinfo) toC() (xc C.libxl_usbctrlinfo, err error) {
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.version = C.int(x.Version)
 	xc.ports = C.int(x.Ports)
-	xc.backend = C.CString(x.Backend)
+	if x.Backend != "" {
+		xc.backend = C.CString(x.Backend)
+	}
 	xc.backend_id = C.uint32_t(x.BackendId)
-	xc.frontend = C.CString(x.Frontend)
+	if x.Frontend != "" {
+		xc.frontend = C.CString(x.Frontend)
+	}
 	xc.frontend_id = C.uint32_t(x.FrontendId)
 	xc.state = C.int(x.State)
 	xc.evtch = C.int(x.Evtch)
@@ -2724,7 +3020,9 @@ func (x *Connectorinfo) fromC(xc *C.libxl_connectorinfo) error {
 
 func (x *Connectorinfo) toC() (xc C.libxl_connectorinfo, err error) {
 	C.libxl_connectorinfo_init(&xc)
-	xc.unique_id = C.CString(x.UniqueId)
+	if x.UniqueId != "" {
+		xc.unique_id = C.CString(x.UniqueId)
+	}
 	xc.width = C.uint32_t(x.Width)
 	xc.height = C.uint32_t(x.Height)
 	xc.req_evtch = C.int(x.ReqEvtch)
@@ -2758,9 +3056,13 @@ func (x *Vdisplinfo) fromC(xc *C.libxl_vdisplinfo) error {
 
 func (x *Vdisplinfo) toC() (xc C.libxl_vdisplinfo, err error) {
 	C.libxl_vdisplinfo_init(&xc)
-	xc.backend = C.CString(x.Backend)
+	if x.Backend != "" {
+		xc.backend = C.CString(x.Backend)
+	}
 	xc.backend_id = C.uint32_t(x.BackendId)
-	xc.frontend = C.CString(x.Frontend)
+	if x.Frontend != "" {
+		xc.frontend = C.CString(x.Frontend)
+	}
 	xc.frontend_id = C.uint32_t(x.FrontendId)
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.state = C.int(x.State)
@@ -2851,9 +3153,13 @@ func (x *Vsndinfo) fromC(xc *C.libxl_vsndinfo) error {
 
 func (x *Vsndinfo) toC() (xc C.libxl_vsndinfo, err error) {
 	C.libxl_vsndinfo_init(&xc)
-	xc.backend = C.CString(x.Backend)
+	if x.Backend != "" {
+		xc.backend = C.CString(x.Backend)
+	}
 	xc.backend_id = C.uint32_t(x.BackendId)
-	xc.frontend = C.CString(x.Frontend)
+	if x.Frontend != "" {
+		xc.frontend = C.CString(x.Frontend)
+	}
 	xc.frontend_id = C.uint32_t(x.FrontendId)
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.state = C.int(x.State)
@@ -2888,9 +3194,13 @@ func (x *Vkbinfo) fromC(xc *C.libxl_vkbinfo) error {
 
 func (x *Vkbinfo) toC() (xc C.libxl_vkbinfo, err error) {
 	C.libxl_vkbinfo_init(&xc)
-	xc.backend = C.CString(x.Backend)
+	if x.Backend != "" {
+		xc.backend = C.CString(x.Backend)
+	}
 	xc.backend_id = C.uint32_t(x.BackendId)
-	xc.frontend = C.CString(x.Frontend)
+	if x.Frontend != "" {
+		xc.frontend = C.CString(x.Frontend)
+	}
 	xc.frontend_id = C.uint32_t(x.FrontendId)
 	xc.devid = C.libxl_devid(x.Devid)
 	xc.state = C.int(x.State)
@@ -3042,7 +3352,9 @@ func (x *DomainRemusInfo) toC() (xc C.libxl_domain_remus_info, err error) {
 		C.libxl_domain_remus_info_dispose(&xc)
 		return xc, err
 	}
-	xc.netbufscript = C.CString(x.Netbufscript)
+	if x.Netbufscript != "" {
+		xc.netbufscript = C.CString(x.Netbufscript)
+	}
 	xc.diskbuf, err = x.Diskbuf.toC()
 	if err != nil {
 		C.libxl_domain_remus_info_dispose(&xc)
@@ -3163,7 +3475,9 @@ func (x *Event) toC() (xc C.libxl_event, err error) {
 			return xc, errors.New("wrong type for union key type")
 		}
 		var disk_eject C.libxl_event_type_union_disk_eject
-		disk_eject.vdev = C.CString(tmp.Vdev)
+		if tmp.Vdev != "" {
+			disk_eject.vdev = C.CString(tmp.Vdev)
+		}
 		disk_eject.disk, err = tmp.Disk.toC()
 		if err != nil {
 			C.libxl_event_dispose(&xc)
-- 
2.24.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Xen-devel] [PATCH 4/9] go/xenlight: Fix CpuidPoliclyList conversion
  2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
  2019-12-27 16:32 ` [Xen-devel] [PATCH 2/9] golang/xenlight: Do proper nil / NULL conversions for builtin Bitmap type George Dunlap
  2019-12-27 16:32 ` [Xen-devel] [PATCH 3/9] golang/xenlight: Convert "" to NULL George Dunlap
@ 2019-12-27 16:32 ` George Dunlap
  2020-01-04 18:42   ` Nick Rosbrook
  2019-12-27 16:32 ` [Xen-devel] [PATCH 5/9] go/xenlight: More informative error messages George Dunlap
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: George Dunlap @ 2019-12-27 16:32 UTC (permalink / raw)
  To: xen-devel; +Cc: Nick Rosbrook, George Dunlap

Empty Go strings should be converted to `nil` libxl_cpuid_policy_list;
otherwise libxl_cpuid_parse_config gets confused.

Also, libxl_cpuid_policy_list returns a weird error, not a "normal"
libxl error; if it returns one of these non-standard errors, convert
it to ErrorInval.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
CC: Nick Rosbrook <rosbrookn@ainfosec.com>
---
 tools/golang/xenlight/xenlight.go | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index e18f0f35f8..99de68320b 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -317,6 +317,10 @@ type CpuidPolicyList string
 func (cpl CpuidPolicyList) fromC(ccpl *C.libxl_cpuid_policy_list) error { return nil }
 
 func (cpl CpuidPolicyList) toC() (C.libxl_cpuid_policy_list, error) {
+	if cpl == "" {
+		return nil, nil
+	}
+
 	var ccpl C.libxl_cpuid_policy_list
 
 	s := C.CString(string(cpl))
@@ -326,7 +330,8 @@ func (cpl CpuidPolicyList) toC() (C.libxl_cpuid_policy_list, error) {
 	if ret != 0 {
 		C.libxl_cpuid_dispose(&ccpl)
 
-		return ccpl, Error(-ret)
+		// libxl_cpuid_parse_config doesn't return a normal libxl error.
+		return ccpl, ErrorInval
 	}
 
 	return ccpl, nil
-- 
2.24.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Xen-devel] [PATCH 5/9] go/xenlight: More informative error messages
  2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
                   ` (2 preceding siblings ...)
  2019-12-27 16:32 ` [Xen-devel] [PATCH 4/9] go/xenlight: Fix CpuidPoliclyList conversion George Dunlap
@ 2019-12-27 16:32 ` George Dunlap
  2020-01-04 19:06   ` Nick Rosbrook
  2019-12-27 16:32 ` [Xen-devel] [PATCH 6/9] golang/xenlight: Errors are negative George Dunlap
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: George Dunlap @ 2019-12-27 16:32 UTC (permalink / raw)
  To: xen-devel; +Cc: Nick Rosbrook, George Dunlap

If an error is encountered deep in a complicated data structure, it's
often difficult to tell where the error actually is.  Make the error
message from the generated toC() and fromC() structures more
informative by tagging which field being converted encountered the
error.  This will have the effect of giving a "stack trace" of the
failure inside a nested data structure.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
CC: Nick Rosbrook <rosbrookn@ainfosec.com>
---
 tools/golang/xenlight/gengotypes.py  |  10 +-
 tools/golang/xenlight/helpers.gen.go | 456 +++++++++++++--------------
 2 files changed, 233 insertions(+), 233 deletions(-)

diff --git a/tools/golang/xenlight/gengotypes.py b/tools/golang/xenlight/gengotypes.py
index e4ed4d50f5..48e3d86f70 100644
--- a/tools/golang/xenlight/gengotypes.py
+++ b/tools/golang/xenlight/gengotypes.py
@@ -314,7 +314,7 @@ def xenlight_golang_convert_from_C(ty = None, outer_name = None, cvarname = None
         # If the type is not castable, we need to call its fromC
         # function.
         s += 'if err := x.{}.fromC(&{}.{});'.format(goname,cvarname,cname)
-        s += 'err != nil {\n return err \n}\n'
+        s += 'err != nil {{\nreturn fmt.Errorf("Converting field {}: %v", err) \n}}\n'.format(goname)
 
     elif gotypename == 'string':
         # Use the cgo helper for converting C strings.
@@ -389,7 +389,7 @@ def xenlight_golang_union_from_C(ty = None, union_name = '', struct_name = ''):
 
         s += 'var {} {}\n'.format(goname, gotype)
         s += 'if err := {}.fromC(xc);'.format(goname)
-        s += 'err != nil {\n return err \n}\n'
+        s += 'err != nil {{\n return fmt.Errorf("Converting field {}: %v", err) \n}}\n'.format(goname)
 
         field_name = xenlight_golang_fmt_name('{}_union'.format(keyname))
         s += 'x.{} = {}\n'.format(field_name, goname)
@@ -432,7 +432,7 @@ def xenlight_golang_array_from_C(ty = None):
         s += 'x.{}[i] = {}(v)\n'.format(goname, gotypename)
     else:
         s += 'if err := x.{}[i].fromC(&v); err != nil {{\n'.format(goname)
-        s += 'return err }\n'
+        s += 'return fmt.Errorf("Converting field {}: %v", err) }}\n'.format(goname)
 
     s += '}\n}\n'
 
@@ -497,7 +497,7 @@ def xenlight_golang_define_to_C(ty = None, typename = None, nested = False):
                 s += 'xc.{}, err = x.{}.toC()\n'.format(cname,goname)
                 s += 'if err != nil {\n'
                 s += 'C.{}(&xc)\n'.format(ty.dispose_fn)
-                s += 'return xc, err\n'
+                s += 'return xc, fmt.Errorf("Converting field {}: %v", err)\n'.format(goname)
                 s += '}\n'
 
         elif isinstance(f.type, idl.Struct):
@@ -567,7 +567,7 @@ def xenlight_golang_union_to_C(ty = None, union_name = '',
                 s += '{}.{}, err = tmp.{}.toC()\n'.format(f.name,uf.name,gofname)
                 s += 'if err != nil {\n'
                 s += 'C.{}(&xc)\n'.format(dispose_fn)
-                s += 'return xc,err \n}\n'
+                s += 'return xc,fmt.Errorf("Converting field {}: %v", err) \n}}\n'.format(gofname)
 
             elif gotypename == 'string':
                 s += 'if tmp.{} != "" {{\n'.format(gofname)
diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go
index 2236222cc2..f165968fd9 100644
--- a/tools/golang/xenlight/helpers.gen.go
+++ b/tools/golang/xenlight/helpers.gen.go
@@ -74,13 +74,13 @@ func (x *VgaInterfaceInfo) toC() (xc C.libxl_vga_interface_info, err error) {
 
 func (x *VncInfo) fromC(xc *C.libxl_vnc_info) error {
 	if err := x.Enable.fromC(&xc.enable); err != nil {
-		return err
+		return fmt.Errorf("Converting field Enable: %v", err)
 	}
 	x.Listen = C.GoString(xc.listen)
 	x.Passwd = C.GoString(xc.passwd)
 	x.Display = int(xc.display)
 	if err := x.Findunused.fromC(&xc.findunused); err != nil {
-		return err
+		return fmt.Errorf("Converting field Findunused: %v", err)
 	}
 
 	return nil
@@ -91,7 +91,7 @@ func (x *VncInfo) toC() (xc C.libxl_vnc_info, err error) {
 	xc.enable, err = x.Enable.toC()
 	if err != nil {
 		C.libxl_vnc_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Enable: %v", err)
 	}
 	if x.Listen != "" {
 		xc.listen = C.CString(x.Listen)
@@ -103,30 +103,30 @@ func (x *VncInfo) toC() (xc C.libxl_vnc_info, err error) {
 	xc.findunused, err = x.Findunused.toC()
 	if err != nil {
 		C.libxl_vnc_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Findunused: %v", err)
 	}
 	return xc, nil
 }
 
 func (x *SpiceInfo) fromC(xc *C.libxl_spice_info) error {
 	if err := x.Enable.fromC(&xc.enable); err != nil {
-		return err
+		return fmt.Errorf("Converting field Enable: %v", err)
 	}
 	x.Port = int(xc.port)
 	x.TlsPort = int(xc.tls_port)
 	x.Host = C.GoString(xc.host)
 	if err := x.DisableTicketing.fromC(&xc.disable_ticketing); err != nil {
-		return err
+		return fmt.Errorf("Converting field DisableTicketing: %v", err)
 	}
 	x.Passwd = C.GoString(xc.passwd)
 	if err := x.AgentMouse.fromC(&xc.agent_mouse); err != nil {
-		return err
+		return fmt.Errorf("Converting field AgentMouse: %v", err)
 	}
 	if err := x.Vdagent.fromC(&xc.vdagent); err != nil {
-		return err
+		return fmt.Errorf("Converting field Vdagent: %v", err)
 	}
 	if err := x.ClipboardSharing.fromC(&xc.clipboard_sharing); err != nil {
-		return err
+		return fmt.Errorf("Converting field ClipboardSharing: %v", err)
 	}
 	x.Usbredirection = int(xc.usbredirection)
 	x.ImageCompression = C.GoString(xc.image_compression)
@@ -140,7 +140,7 @@ func (x *SpiceInfo) toC() (xc C.libxl_spice_info, err error) {
 	xc.enable, err = x.Enable.toC()
 	if err != nil {
 		C.libxl_spice_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Enable: %v", err)
 	}
 	xc.port = C.int(x.Port)
 	xc.tls_port = C.int(x.TlsPort)
@@ -150,7 +150,7 @@ func (x *SpiceInfo) toC() (xc C.libxl_spice_info, err error) {
 	xc.disable_ticketing, err = x.DisableTicketing.toC()
 	if err != nil {
 		C.libxl_spice_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field DisableTicketing: %v", err)
 	}
 	if x.Passwd != "" {
 		xc.passwd = C.CString(x.Passwd)
@@ -158,17 +158,17 @@ func (x *SpiceInfo) toC() (xc C.libxl_spice_info, err error) {
 	xc.agent_mouse, err = x.AgentMouse.toC()
 	if err != nil {
 		C.libxl_spice_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field AgentMouse: %v", err)
 	}
 	xc.vdagent, err = x.Vdagent.toC()
 	if err != nil {
 		C.libxl_spice_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Vdagent: %v", err)
 	}
 	xc.clipboard_sharing, err = x.ClipboardSharing.toC()
 	if err != nil {
 		C.libxl_spice_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field ClipboardSharing: %v", err)
 	}
 	xc.usbredirection = C.int(x.Usbredirection)
 	if x.ImageCompression != "" {
@@ -182,10 +182,10 @@ func (x *SpiceInfo) toC() (xc C.libxl_spice_info, err error) {
 
 func (x *SdlInfo) fromC(xc *C.libxl_sdl_info) error {
 	if err := x.Enable.fromC(&xc.enable); err != nil {
-		return err
+		return fmt.Errorf("Converting field Enable: %v", err)
 	}
 	if err := x.Opengl.fromC(&xc.opengl); err != nil {
-		return err
+		return fmt.Errorf("Converting field Opengl: %v", err)
 	}
 	x.Display = C.GoString(xc.display)
 	x.Xauthority = C.GoString(xc.xauthority)
@@ -198,12 +198,12 @@ func (x *SdlInfo) toC() (xc C.libxl_sdl_info, err error) {
 	xc.enable, err = x.Enable.toC()
 	if err != nil {
 		C.libxl_sdl_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Enable: %v", err)
 	}
 	xc.opengl, err = x.Opengl.toC()
 	if err != nil {
 		C.libxl_sdl_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Opengl: %v", err)
 	}
 	if x.Display != "" {
 		xc.display = C.CString(x.Display)
@@ -216,7 +216,7 @@ func (x *SdlInfo) toC() (xc C.libxl_sdl_info, err error) {
 
 func (x *Dominfo) fromC(xc *C.libxl_dominfo) error {
 	if err := x.Uuid.fromC(&xc.uuid); err != nil {
-		return err
+		return fmt.Errorf("Converting field Uuid: %v", err)
 	}
 	x.Domid = Domid(xc.domid)
 	x.Ssidref = uint32(xc.ssidref)
@@ -247,7 +247,7 @@ func (x *Dominfo) toC() (xc C.libxl_dominfo, err error) {
 	xc.uuid, err = x.Uuid.toC()
 	if err != nil {
 		C.libxl_dominfo_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Uuid: %v", err)
 	}
 	xc.domid = C.libxl_domid(x.Domid)
 	xc.ssidref = C.uint32_t(x.Ssidref)
@@ -280,7 +280,7 @@ func (x *Cpupoolinfo) fromC(xc *C.libxl_cpupoolinfo) error {
 	x.Sched = Scheduler(xc.sched)
 	x.NDom = uint32(xc.n_dom)
 	if err := x.Cpumap.fromC(&xc.cpumap); err != nil {
-		return err
+		return fmt.Errorf("Converting field Cpumap: %v", err)
 	}
 
 	return nil
@@ -297,7 +297,7 @@ func (x *Cpupoolinfo) toC() (xc C.libxl_cpupoolinfo, err error) {
 	xc.cpumap, err = x.Cpumap.toC()
 	if err != nil {
 		C.libxl_cpupoolinfo_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Cpumap: %v", err)
 	}
 	return xc, nil
 }
@@ -316,7 +316,7 @@ func (x *Channelinfo) fromC(xc *C.libxl_channelinfo) error {
 	case ChannelConnectionPty:
 		var connectionPty ChannelinfoConnectionUnionPty
 		if err := connectionPty.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field connectionPty: %v", err)
 		}
 		x.ConnectionUnion = connectionPty
 	default:
@@ -372,7 +372,7 @@ func (x *Channelinfo) toC() (xc C.libxl_channelinfo, err error) {
 
 func (x *Vminfo) fromC(xc *C.libxl_vminfo) error {
 	if err := x.Uuid.fromC(&xc.uuid); err != nil {
-		return err
+		return fmt.Errorf("Converting field Uuid: %v", err)
 	}
 	x.Domid = Domid(xc.domid)
 
@@ -384,7 +384,7 @@ func (x *Vminfo) toC() (xc C.libxl_vminfo, err error) {
 	xc.uuid, err = x.Uuid.toC()
 	if err != nil {
 		C.libxl_vminfo_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Uuid: %v", err)
 	}
 	xc.domid = C.libxl_domid(x.Domid)
 	return xc, nil
@@ -447,30 +447,30 @@ func (x *VersionInfo) toC() (xc C.libxl_version_info, err error) {
 func (x *DomainCreateInfo) fromC(xc *C.libxl_domain_create_info) error {
 	x.Type = DomainType(xc._type)
 	if err := x.Hap.fromC(&xc.hap); err != nil {
-		return err
+		return fmt.Errorf("Converting field Hap: %v", err)
 	}
 	if err := x.Oos.fromC(&xc.oos); err != nil {
-		return err
+		return fmt.Errorf("Converting field Oos: %v", err)
 	}
 	x.Ssidref = uint32(xc.ssidref)
 	x.SsidLabel = C.GoString(xc.ssid_label)
 	x.Name = C.GoString(xc.name)
 	if err := x.Uuid.fromC(&xc.uuid); err != nil {
-		return err
+		return fmt.Errorf("Converting field Uuid: %v", err)
 	}
 	if err := x.Xsdata.fromC(&xc.xsdata); err != nil {
-		return err
+		return fmt.Errorf("Converting field Xsdata: %v", err)
 	}
 	if err := x.Platformdata.fromC(&xc.platformdata); err != nil {
-		return err
+		return fmt.Errorf("Converting field Platformdata: %v", err)
 	}
 	x.Poolid = uint32(xc.poolid)
 	x.PoolName = C.GoString(xc.pool_name)
 	if err := x.RunHotplugScripts.fromC(&xc.run_hotplug_scripts); err != nil {
-		return err
+		return fmt.Errorf("Converting field RunHotplugScripts: %v", err)
 	}
 	if err := x.DriverDomain.fromC(&xc.driver_domain); err != nil {
-		return err
+		return fmt.Errorf("Converting field DriverDomain: %v", err)
 	}
 	x.Passthrough = Passthrough(xc.passthrough)
 
@@ -483,12 +483,12 @@ func (x *DomainCreateInfo) toC() (xc C.libxl_domain_create_info, err error) {
 	xc.hap, err = x.Hap.toC()
 	if err != nil {
 		C.libxl_domain_create_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Hap: %v", err)
 	}
 	xc.oos, err = x.Oos.toC()
 	if err != nil {
 		C.libxl_domain_create_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Oos: %v", err)
 	}
 	xc.ssidref = C.uint32_t(x.Ssidref)
 	if x.SsidLabel != "" {
@@ -500,17 +500,17 @@ func (x *DomainCreateInfo) toC() (xc C.libxl_domain_create_info, err error) {
 	xc.uuid, err = x.Uuid.toC()
 	if err != nil {
 		C.libxl_domain_create_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Uuid: %v", err)
 	}
 	xc.xsdata, err = x.Xsdata.toC()
 	if err != nil {
 		C.libxl_domain_create_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Xsdata: %v", err)
 	}
 	xc.platformdata, err = x.Platformdata.toC()
 	if err != nil {
 		C.libxl_domain_create_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Platformdata: %v", err)
 	}
 	xc.poolid = C.uint32_t(x.Poolid)
 	if x.PoolName != "" {
@@ -519,12 +519,12 @@ func (x *DomainCreateInfo) toC() (xc C.libxl_domain_create_info, err error) {
 	xc.run_hotplug_scripts, err = x.RunHotplugScripts.toC()
 	if err != nil {
 		C.libxl_domain_create_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field RunHotplugScripts: %v", err)
 	}
 	xc.driver_domain, err = x.DriverDomain.toC()
 	if err != nil {
 		C.libxl_domain_create_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field DriverDomain: %v", err)
 	}
 	xc.passthrough = C.libxl_passthrough(x.Passthrough)
 	return xc, nil
@@ -535,7 +535,7 @@ func (x *DomainRestoreParams) fromC(xc *C.libxl_domain_restore_params) error {
 	x.StreamVersion = uint32(xc.stream_version)
 	x.ColoProxyScript = C.GoString(xc.colo_proxy_script)
 	if err := x.UserspaceColoProxy.fromC(&xc.userspace_colo_proxy); err != nil {
-		return err
+		return fmt.Errorf("Converting field UserspaceColoProxy: %v", err)
 	}
 
 	return nil
@@ -551,7 +551,7 @@ func (x *DomainRestoreParams) toC() (xc C.libxl_domain_restore_params, err error
 	xc.userspace_colo_proxy, err = x.UserspaceColoProxy.toC()
 	if err != nil {
 		C.libxl_domain_restore_params_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field UserspaceColoProxy: %v", err)
 	}
 	return xc, nil
 }
@@ -586,7 +586,7 @@ func (x *VcpuSchedParams) fromC(xc *C.libxl_vcpu_sched_params) error {
 		x.Vcpus = make([]SchedParams, numVcpus)
 		for i, v := range cVcpus {
 			if err := x.Vcpus[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Vcpus: %v", err)
 			}
 		}
 	}
@@ -651,7 +651,7 @@ func (x *VnodeInfo) fromC(xc *C.libxl_vnode_info) error {
 	}
 	x.Pnode = uint32(xc.pnode)
 	if err := x.Vcpus.fromC(&xc.vcpus); err != nil {
-		return err
+		return fmt.Errorf("Converting field Vcpus: %v", err)
 	}
 
 	return nil
@@ -672,7 +672,7 @@ func (x *VnodeInfo) toC() (xc C.libxl_vnode_info, err error) {
 	xc.vcpus, err = x.Vcpus.toC()
 	if err != nil {
 		C.libxl_vnode_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Vcpus: %v", err)
 	}
 	return xc, nil
 }
@@ -694,13 +694,13 @@ func (x *RdmReserve) toC() (xc C.libxl_rdm_reserve, err error) {
 func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	x.MaxVcpus = int(xc.max_vcpus)
 	if err := x.AvailVcpus.fromC(&xc.avail_vcpus); err != nil {
-		return err
+		return fmt.Errorf("Converting field AvailVcpus: %v", err)
 	}
 	if err := x.Cpumap.fromC(&xc.cpumap); err != nil {
-		return err
+		return fmt.Errorf("Converting field Cpumap: %v", err)
 	}
 	if err := x.Nodemap.fromC(&xc.nodemap); err != nil {
-		return err
+		return fmt.Errorf("Converting field Nodemap: %v", err)
 	}
 	x.VcpuHardAffinity = nil
 	if numVcpuHardAffinity := int(xc.num_vcpu_hard_affinity); numVcpuHardAffinity > 0 {
@@ -708,7 +708,7 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 		x.VcpuHardAffinity = make([]Bitmap, numVcpuHardAffinity)
 		for i, v := range cVcpuHardAffinity {
 			if err := x.VcpuHardAffinity[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field VcpuHardAffinity: %v", err)
 			}
 		}
 	}
@@ -718,12 +718,12 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 		x.VcpuSoftAffinity = make([]Bitmap, numVcpuSoftAffinity)
 		for i, v := range cVcpuSoftAffinity {
 			if err := x.VcpuSoftAffinity[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field VcpuSoftAffinity: %v", err)
 			}
 		}
 	}
 	if err := x.NumaPlacement.fromC(&xc.numa_placement); err != nil {
-		return err
+		return fmt.Errorf("Converting field NumaPlacement: %v", err)
 	}
 	x.TscMode = TscMode(xc.tsc_mode)
 	x.MaxMemkb = uint64(xc.max_memkb)
@@ -735,13 +735,13 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	x.ExecSsidref = uint32(xc.exec_ssidref)
 	x.ExecSsidLabel = C.GoString(xc.exec_ssid_label)
 	if err := x.Localtime.fromC(&xc.localtime); err != nil {
-		return err
+		return fmt.Errorf("Converting field Localtime: %v", err)
 	}
 	if err := x.DisableMigrate.fromC(&xc.disable_migrate); err != nil {
-		return err
+		return fmt.Errorf("Converting field DisableMigrate: %v", err)
 	}
 	if err := x.Cpuid.fromC(&xc.cpuid); err != nil {
-		return err
+		return fmt.Errorf("Converting field Cpuid: %v", err)
 	}
 	x.BlkdevStart = C.GoString(xc.blkdev_start)
 	x.VnumaNodes = nil
@@ -750,7 +750,7 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 		x.VnumaNodes = make([]VnodeInfo, numVnumaNodes)
 		for i, v := range cVnumaNodes {
 			if err := x.VnumaNodes[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field VnumaNodes: %v", err)
 			}
 		}
 	}
@@ -758,23 +758,23 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	x.MaxMaptrackFrames = uint32(xc.max_maptrack_frames)
 	x.DeviceModelVersion = DeviceModelVersion(xc.device_model_version)
 	if err := x.DeviceModelStubdomain.fromC(&xc.device_model_stubdomain); err != nil {
-		return err
+		return fmt.Errorf("Converting field DeviceModelStubdomain: %v", err)
 	}
 	x.DeviceModel = C.GoString(xc.device_model)
 	x.DeviceModelSsidref = uint32(xc.device_model_ssidref)
 	x.DeviceModelSsidLabel = C.GoString(xc.device_model_ssid_label)
 	x.DeviceModelUser = C.GoString(xc.device_model_user)
 	if err := x.Extra.fromC(&xc.extra); err != nil {
-		return err
+		return fmt.Errorf("Converting field Extra: %v", err)
 	}
 	if err := x.ExtraPv.fromC(&xc.extra_pv); err != nil {
-		return err
+		return fmt.Errorf("Converting field ExtraPv: %v", err)
 	}
 	if err := x.ExtraHvm.fromC(&xc.extra_hvm); err != nil {
-		return err
+		return fmt.Errorf("Converting field ExtraHvm: %v", err)
 	}
 	if err := x.SchedParams.fromC(&xc.sched_params); err != nil {
-		return err
+		return fmt.Errorf("Converting field SchedParams: %v", err)
 	}
 	x.Ioports = nil
 	if numIoports := int(xc.num_ioports); numIoports > 0 {
@@ -782,7 +782,7 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 		x.Ioports = make([]IoportRange, numIoports)
 		for i, v := range cIoports {
 			if err := x.Ioports[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Ioports: %v", err)
 			}
 		}
 	}
@@ -800,12 +800,12 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 		x.Iomem = make([]IomemRange, numIomem)
 		for i, v := range cIomem {
 			if err := x.Iomem[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Iomem: %v", err)
 			}
 		}
 	}
 	if err := x.ClaimMode.fromC(&xc.claim_mode); err != nil {
-		return err
+		return fmt.Errorf("Converting field ClaimMode: %v", err)
 	}
 	x.EventChannels = uint32(xc.event_channels)
 	x.Kernel = C.GoString(xc.kernel)
@@ -813,21 +813,21 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	x.Ramdisk = C.GoString(xc.ramdisk)
 	x.DeviceTree = C.GoString(xc.device_tree)
 	if err := x.Acpi.fromC(&xc.acpi); err != nil {
-		return err
+		return fmt.Errorf("Converting field Acpi: %v", err)
 	}
 	x.Bootloader = C.GoString(xc.bootloader)
 	if err := x.BootloaderArgs.fromC(&xc.bootloader_args); err != nil {
-		return err
+		return fmt.Errorf("Converting field BootloaderArgs: %v", err)
 	}
 	x.TimerMode = TimerMode(xc.timer_mode)
 	if err := x.NestedHvm.fromC(&xc.nested_hvm); err != nil {
-		return err
+		return fmt.Errorf("Converting field NestedHvm: %v", err)
 	}
 	if err := x.Apic.fromC(&xc.apic); err != nil {
-		return err
+		return fmt.Errorf("Converting field Apic: %v", err)
 	}
 	if err := x.DmRestrict.fromC(&xc.dm_restrict); err != nil {
-		return err
+		return fmt.Errorf("Converting field DmRestrict: %v", err)
 	}
 	x.Tee = TeeType(xc.tee)
 	x.Type = DomainType(xc._type)
@@ -835,19 +835,19 @@ func (x *DomainBuildInfo) fromC(xc *C.libxl_domain_build_info) error {
 	case DomainTypeHvm:
 		var typeHvm DomainBuildInfoTypeUnionHvm
 		if err := typeHvm.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field typeHvm: %v", err)
 		}
 		x.TypeUnion = typeHvm
 	case DomainTypePv:
 		var typePv DomainBuildInfoTypeUnionPv
 		if err := typePv.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field typePv: %v", err)
 		}
 		x.TypeUnion = typePv
 	case DomainTypePvh:
 		var typePvh DomainBuildInfoTypeUnionPvh
 		if err := typePvh.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field typePvh: %v", err)
 		}
 		x.TypeUnion = typePvh
 	default:
@@ -869,100 +869,100 @@ func (x *DomainBuildInfoTypeUnionHvm) fromC(xc *C.libxl_domain_build_info) error
 	x.Firmware = C.GoString(tmp.firmware)
 	x.Bios = BiosType(tmp.bios)
 	if err := x.Pae.fromC(&tmp.pae); err != nil {
-		return err
+		return fmt.Errorf("Converting field Pae: %v", err)
 	}
 	if err := x.Apic.fromC(&tmp.apic); err != nil {
-		return err
+		return fmt.Errorf("Converting field Apic: %v", err)
 	}
 	if err := x.Acpi.fromC(&tmp.acpi); err != nil {
-		return err
+		return fmt.Errorf("Converting field Acpi: %v", err)
 	}
 	if err := x.AcpiS3.fromC(&tmp.acpi_s3); err != nil {
-		return err
+		return fmt.Errorf("Converting field AcpiS3: %v", err)
 	}
 	if err := x.AcpiS4.fromC(&tmp.acpi_s4); err != nil {
-		return err
+		return fmt.Errorf("Converting field AcpiS4: %v", err)
 	}
 	if err := x.AcpiLaptopSlate.fromC(&tmp.acpi_laptop_slate); err != nil {
-		return err
+		return fmt.Errorf("Converting field AcpiLaptopSlate: %v", err)
 	}
 	if err := x.Nx.fromC(&tmp.nx); err != nil {
-		return err
+		return fmt.Errorf("Converting field Nx: %v", err)
 	}
 	if err := x.Viridian.fromC(&tmp.viridian); err != nil {
-		return err
+		return fmt.Errorf("Converting field Viridian: %v", err)
 	}
 	if err := x.ViridianEnable.fromC(&tmp.viridian_enable); err != nil {
-		return err
+		return fmt.Errorf("Converting field ViridianEnable: %v", err)
 	}
 	if err := x.ViridianDisable.fromC(&tmp.viridian_disable); err != nil {
-		return err
+		return fmt.Errorf("Converting field ViridianDisable: %v", err)
 	}
 	x.Timeoffset = C.GoString(tmp.timeoffset)
 	if err := x.Hpet.fromC(&tmp.hpet); err != nil {
-		return err
+		return fmt.Errorf("Converting field Hpet: %v", err)
 	}
 	if err := x.VptAlign.fromC(&tmp.vpt_align); err != nil {
-		return err
+		return fmt.Errorf("Converting field VptAlign: %v", err)
 	}
 	x.MmioHoleMemkb = uint64(tmp.mmio_hole_memkb)
 	x.TimerMode = TimerMode(tmp.timer_mode)
 	if err := x.NestedHvm.fromC(&tmp.nested_hvm); err != nil {
-		return err
+		return fmt.Errorf("Converting field NestedHvm: %v", err)
 	}
 	if err := x.Altp2M.fromC(&tmp.altp2m); err != nil {
-		return err
+		return fmt.Errorf("Converting field Altp2M: %v", err)
 	}
 	x.SystemFirmware = C.GoString(tmp.system_firmware)
 	x.SmbiosFirmware = C.GoString(tmp.smbios_firmware)
 	x.AcpiFirmware = C.GoString(tmp.acpi_firmware)
 	x.Hdtype = Hdtype(tmp.hdtype)
 	if err := x.Nographic.fromC(&tmp.nographic); err != nil {
-		return err
+		return fmt.Errorf("Converting field Nographic: %v", err)
 	}
 	if err := x.Vga.fromC(&tmp.vga); err != nil {
-		return err
+		return fmt.Errorf("Converting field Vga: %v", err)
 	}
 	if err := x.Vnc.fromC(&tmp.vnc); err != nil {
-		return err
+		return fmt.Errorf("Converting field Vnc: %v", err)
 	}
 	x.Keymap = C.GoString(tmp.keymap)
 	if err := x.Sdl.fromC(&tmp.sdl); err != nil {
-		return err
+		return fmt.Errorf("Converting field Sdl: %v", err)
 	}
 	if err := x.Spice.fromC(&tmp.spice); err != nil {
-		return err
+		return fmt.Errorf("Converting field Spice: %v", err)
 	}
 	if err := x.GfxPassthru.fromC(&tmp.gfx_passthru); err != nil {
-		return err
+		return fmt.Errorf("Converting field GfxPassthru: %v", err)
 	}
 	x.GfxPassthruKind = GfxPassthruKind(tmp.gfx_passthru_kind)
 	x.Serial = C.GoString(tmp.serial)
 	x.Boot = C.GoString(tmp.boot)
 	if err := x.Usb.fromC(&tmp.usb); err != nil {
-		return err
+		return fmt.Errorf("Converting field Usb: %v", err)
 	}
 	x.Usbversion = int(tmp.usbversion)
 	x.Usbdevice = C.GoString(tmp.usbdevice)
 	if err := x.VkbDevice.fromC(&tmp.vkb_device); err != nil {
-		return err
+		return fmt.Errorf("Converting field VkbDevice: %v", err)
 	}
 	x.Soundhw = C.GoString(tmp.soundhw)
 	if err := x.XenPlatformPci.fromC(&tmp.xen_platform_pci); err != nil {
-		return err
+		return fmt.Errorf("Converting field XenPlatformPci: %v", err)
 	}
 	if err := x.UsbdeviceList.fromC(&tmp.usbdevice_list); err != nil {
-		return err
+		return fmt.Errorf("Converting field UsbdeviceList: %v", err)
 	}
 	x.VendorDevice = VendorDevice(tmp.vendor_device)
 	if err := x.MsVmGenid.fromC(&tmp.ms_vm_genid); err != nil {
-		return err
+		return fmt.Errorf("Converting field MsVmGenid: %v", err)
 	}
 	if err := x.SerialList.fromC(&tmp.serial_list); err != nil {
-		return err
+		return fmt.Errorf("Converting field SerialList: %v", err)
 	}
 	if err := x.Rdm.fromC(&tmp.rdm); err != nil {
-		return err
+		return fmt.Errorf("Converting field Rdm: %v", err)
 	}
 	x.RdmMemBoundaryMemkb = uint64(tmp.rdm_mem_boundary_memkb)
 	x.McaCaps = uint64(tmp.mca_caps)
@@ -979,13 +979,13 @@ func (x *DomainBuildInfoTypeUnionPv) fromC(xc *C.libxl_domain_build_info) error
 	x.SlackMemkb = uint64(tmp.slack_memkb)
 	x.Bootloader = C.GoString(tmp.bootloader)
 	if err := x.BootloaderArgs.fromC(&tmp.bootloader_args); err != nil {
-		return err
+		return fmt.Errorf("Converting field BootloaderArgs: %v", err)
 	}
 	x.Cmdline = C.GoString(tmp.cmdline)
 	x.Ramdisk = C.GoString(tmp.ramdisk)
 	x.Features = C.GoString(tmp.features)
 	if err := x.E820Host.fromC(&tmp.e820_host); err != nil {
-		return err
+		return fmt.Errorf("Converting field E820Host: %v", err)
 	}
 	return nil
 }
@@ -997,7 +997,7 @@ func (x *DomainBuildInfoTypeUnionPvh) fromC(xc *C.libxl_domain_build_info) error
 
 	tmp := (*C.libxl_domain_build_info_type_union_pvh)(unsafe.Pointer(&xc.u[0]))
 	if err := x.Pvshim.fromC(&tmp.pvshim); err != nil {
-		return err
+		return fmt.Errorf("Converting field Pvshim: %v", err)
 	}
 	x.PvshimPath = C.GoString(tmp.pvshim_path)
 	x.PvshimCmdline = C.GoString(tmp.pvshim_cmdline)
@@ -1011,17 +1011,17 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 	xc.avail_vcpus, err = x.AvailVcpus.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field AvailVcpus: %v", err)
 	}
 	xc.cpumap, err = x.Cpumap.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Cpumap: %v", err)
 	}
 	xc.nodemap, err = x.Nodemap.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Nodemap: %v", err)
 	}
 	if numVcpuHardAffinity := len(x.VcpuHardAffinity); numVcpuHardAffinity > 0 {
 		xc.vcpu_hard_affinity = (*C.libxl_bitmap)(C.malloc(C.ulong(numVcpuHardAffinity) * C.sizeof_libxl_bitmap))
@@ -1052,7 +1052,7 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 	xc.numa_placement, err = x.NumaPlacement.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field NumaPlacement: %v", err)
 	}
 	xc.tsc_mode = C.libxl_tsc_mode(x.TscMode)
 	xc.max_memkb = C.uint64_t(x.MaxMemkb)
@@ -1068,17 +1068,17 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 	xc.localtime, err = x.Localtime.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Localtime: %v", err)
 	}
 	xc.disable_migrate, err = x.DisableMigrate.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field DisableMigrate: %v", err)
 	}
 	xc.cpuid, err = x.Cpuid.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Cpuid: %v", err)
 	}
 	if x.BlkdevStart != "" {
 		xc.blkdev_start = C.CString(x.BlkdevStart)
@@ -1102,7 +1102,7 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 	xc.device_model_stubdomain, err = x.DeviceModelStubdomain.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field DeviceModelStubdomain: %v", err)
 	}
 	if x.DeviceModel != "" {
 		xc.device_model = C.CString(x.DeviceModel)
@@ -1117,22 +1117,22 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 	xc.extra, err = x.Extra.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Extra: %v", err)
 	}
 	xc.extra_pv, err = x.ExtraPv.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field ExtraPv: %v", err)
 	}
 	xc.extra_hvm, err = x.ExtraHvm.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field ExtraHvm: %v", err)
 	}
 	xc.sched_params, err = x.SchedParams.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field SchedParams: %v", err)
 	}
 	if numIoports := len(x.Ioports); numIoports > 0 {
 		xc.ioports = (*C.libxl_ioport_range)(C.malloc(C.ulong(numIoports) * C.sizeof_libxl_ioport_range))
@@ -1171,7 +1171,7 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 	xc.claim_mode, err = x.ClaimMode.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field ClaimMode: %v", err)
 	}
 	xc.event_channels = C.uint32_t(x.EventChannels)
 	if x.Kernel != "" {
@@ -1189,7 +1189,7 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 	xc.acpi, err = x.Acpi.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Acpi: %v", err)
 	}
 	if x.Bootloader != "" {
 		xc.bootloader = C.CString(x.Bootloader)
@@ -1197,23 +1197,23 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 	xc.bootloader_args, err = x.BootloaderArgs.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field BootloaderArgs: %v", err)
 	}
 	xc.timer_mode = C.libxl_timer_mode(x.TimerMode)
 	xc.nested_hvm, err = x.NestedHvm.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field NestedHvm: %v", err)
 	}
 	xc.apic, err = x.Apic.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Apic: %v", err)
 	}
 	xc.dm_restrict, err = x.DmRestrict.toC()
 	if err != nil {
 		C.libxl_domain_build_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field DmRestrict: %v", err)
 	}
 	xc.tee = C.libxl_tee_type(x.Tee)
 	xc._type = C.libxl_domain_type(x.Type)
@@ -1232,52 +1232,52 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		hvm.pae, err = tmp.Pae.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Pae: %v", err)
 		}
 		hvm.apic, err = tmp.Apic.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Apic: %v", err)
 		}
 		hvm.acpi, err = tmp.Acpi.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Acpi: %v", err)
 		}
 		hvm.acpi_s3, err = tmp.AcpiS3.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field AcpiS3: %v", err)
 		}
 		hvm.acpi_s4, err = tmp.AcpiS4.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field AcpiS4: %v", err)
 		}
 		hvm.acpi_laptop_slate, err = tmp.AcpiLaptopSlate.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field AcpiLaptopSlate: %v", err)
 		}
 		hvm.nx, err = tmp.Nx.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Nx: %v", err)
 		}
 		hvm.viridian, err = tmp.Viridian.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Viridian: %v", err)
 		}
 		hvm.viridian_enable, err = tmp.ViridianEnable.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field ViridianEnable: %v", err)
 		}
 		hvm.viridian_disable, err = tmp.ViridianDisable.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field ViridianDisable: %v", err)
 		}
 		if tmp.Timeoffset != "" {
 			hvm.timeoffset = C.CString(tmp.Timeoffset)
@@ -1285,24 +1285,24 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		hvm.hpet, err = tmp.Hpet.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Hpet: %v", err)
 		}
 		hvm.vpt_align, err = tmp.VptAlign.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field VptAlign: %v", err)
 		}
 		hvm.mmio_hole_memkb = C.uint64_t(tmp.MmioHoleMemkb)
 		hvm.timer_mode = C.libxl_timer_mode(tmp.TimerMode)
 		hvm.nested_hvm, err = tmp.NestedHvm.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field NestedHvm: %v", err)
 		}
 		hvm.altp2m, err = tmp.Altp2M.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Altp2M: %v", err)
 		}
 		if tmp.SystemFirmware != "" {
 			hvm.system_firmware = C.CString(tmp.SystemFirmware)
@@ -1317,17 +1317,17 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		hvm.nographic, err = tmp.Nographic.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Nographic: %v", err)
 		}
 		hvm.vga, err = tmp.Vga.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Vga: %v", err)
 		}
 		hvm.vnc, err = tmp.Vnc.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Vnc: %v", err)
 		}
 		if tmp.Keymap != "" {
 			hvm.keymap = C.CString(tmp.Keymap)
@@ -1335,17 +1335,17 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		hvm.sdl, err = tmp.Sdl.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Sdl: %v", err)
 		}
 		hvm.spice, err = tmp.Spice.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Spice: %v", err)
 		}
 		hvm.gfx_passthru, err = tmp.GfxPassthru.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field GfxPassthru: %v", err)
 		}
 		hvm.gfx_passthru_kind = C.libxl_gfx_passthru_kind(tmp.GfxPassthruKind)
 		if tmp.Serial != "" {
@@ -1357,7 +1357,7 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		hvm.usb, err = tmp.Usb.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Usb: %v", err)
 		}
 		hvm.usbversion = C.int(tmp.Usbversion)
 		if tmp.Usbdevice != "" {
@@ -1366,7 +1366,7 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		hvm.vkb_device, err = tmp.VkbDevice.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field VkbDevice: %v", err)
 		}
 		if tmp.Soundhw != "" {
 			hvm.soundhw = C.CString(tmp.Soundhw)
@@ -1374,28 +1374,28 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		hvm.xen_platform_pci, err = tmp.XenPlatformPci.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field XenPlatformPci: %v", err)
 		}
 		hvm.usbdevice_list, err = tmp.UsbdeviceList.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field UsbdeviceList: %v", err)
 		}
 		hvm.vendor_device = C.libxl_vendor_device(tmp.VendorDevice)
 		hvm.ms_vm_genid, err = tmp.MsVmGenid.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field MsVmGenid: %v", err)
 		}
 		hvm.serial_list, err = tmp.SerialList.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field SerialList: %v", err)
 		}
 		hvm.rdm, err = tmp.Rdm.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Rdm: %v", err)
 		}
 		hvm.rdm_mem_boundary_memkb = C.uint64_t(tmp.RdmMemBoundaryMemkb)
 		hvm.mca_caps = C.uint64_t(tmp.McaCaps)
@@ -1418,7 +1418,7 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		pv.bootloader_args, err = tmp.BootloaderArgs.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field BootloaderArgs: %v", err)
 		}
 		if tmp.Cmdline != "" {
 			pv.cmdline = C.CString(tmp.Cmdline)
@@ -1432,7 +1432,7 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		pv.e820_host, err = tmp.E820Host.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field E820Host: %v", err)
 		}
 		pvBytes := C.GoBytes(unsafe.Pointer(&pv), C.sizeof_libxl_domain_build_info_type_union_pv)
 		copy(xc.u[:], pvBytes)
@@ -1446,7 +1446,7 @@ func (x *DomainBuildInfo) toC() (xc C.libxl_domain_build_info, err error) {
 		pvh.pvshim, err = tmp.Pvshim.toC()
 		if err != nil {
 			C.libxl_domain_build_info_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Pvshim: %v", err)
 		}
 		if tmp.PvshimPath != "" {
 			pvh.pvshim_path = C.CString(tmp.PvshimPath)
@@ -1473,10 +1473,10 @@ func (x *DeviceVfb) fromC(xc *C.libxl_device_vfb) error {
 	x.BackendDomname = C.GoString(xc.backend_domname)
 	x.Devid = Devid(xc.devid)
 	if err := x.Vnc.fromC(&xc.vnc); err != nil {
-		return err
+		return fmt.Errorf("Converting field Vnc: %v", err)
 	}
 	if err := x.Sdl.fromC(&xc.sdl); err != nil {
-		return err
+		return fmt.Errorf("Converting field Sdl: %v", err)
 	}
 	x.Keymap = C.GoString(xc.keymap)
 
@@ -1493,12 +1493,12 @@ func (x *DeviceVfb) toC() (xc C.libxl_device_vfb, err error) {
 	xc.vnc, err = x.Vnc.toC()
 	if err != nil {
 		C.libxl_device_vfb_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Vnc: %v", err)
 	}
 	xc.sdl, err = x.Sdl.toC()
 	if err != nil {
 		C.libxl_device_vfb_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Sdl: %v", err)
 	}
 	if x.Keymap != "" {
 		xc.keymap = C.CString(x.Keymap)
@@ -1563,13 +1563,13 @@ func (x *DeviceDisk) fromC(xc *C.libxl_device_disk) error {
 	x.IsCdrom = int(xc.is_cdrom)
 	x.DirectIoSafe = bool(xc.direct_io_safe)
 	if err := x.DiscardEnable.fromC(&xc.discard_enable); err != nil {
-		return err
+		return fmt.Errorf("Converting field DiscardEnable: %v", err)
 	}
 	if err := x.ColoEnable.fromC(&xc.colo_enable); err != nil {
-		return err
+		return fmt.Errorf("Converting field ColoEnable: %v", err)
 	}
 	if err := x.ColoRestoreEnable.fromC(&xc.colo_restore_enable); err != nil {
-		return err
+		return fmt.Errorf("Converting field ColoRestoreEnable: %v", err)
 	}
 	x.ColoHost = C.GoString(xc.colo_host)
 	x.ColoPort = int(xc.colo_port)
@@ -1604,17 +1604,17 @@ func (x *DeviceDisk) toC() (xc C.libxl_device_disk, err error) {
 	xc.discard_enable, err = x.DiscardEnable.toC()
 	if err != nil {
 		C.libxl_device_disk_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field DiscardEnable: %v", err)
 	}
 	xc.colo_enable, err = x.ColoEnable.toC()
 	if err != nil {
 		C.libxl_device_disk_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field ColoEnable: %v", err)
 	}
 	xc.colo_restore_enable, err = x.ColoRestoreEnable.toC()
 	if err != nil {
 		C.libxl_device_disk_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field ColoRestoreEnable: %v", err)
 	}
 	if x.ColoHost != "" {
 		xc.colo_host = C.CString(x.ColoHost)
@@ -1639,7 +1639,7 @@ func (x *DeviceNic) fromC(xc *C.libxl_device_nic) error {
 	x.Mtu = int(xc.mtu)
 	x.Model = C.GoString(xc.model)
 	if err := x.Mac.fromC(&xc.mac); err != nil {
-		return err
+		return fmt.Errorf("Converting field Mac: %v", err)
 	}
 	x.Ip = C.GoString(xc.ip)
 	x.Bridge = C.GoString(xc.bridge)
@@ -1716,7 +1716,7 @@ func (x *DeviceNic) toC() (xc C.libxl_device_nic, err error) {
 	xc.mac, err = x.Mac.toC()
 	if err != nil {
 		C.libxl_device_nic_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Mac: %v", err)
 	}
 	if x.Ip != "" {
 		xc.ip = C.CString(x.Ip)
@@ -1966,7 +1966,7 @@ func (x *DeviceUsbdev) fromC(xc *C.libxl_device_usbdev) error {
 	case UsbdevTypeHostdev:
 		var typeHostdev DeviceUsbdevTypeUnionHostdev
 		if err := typeHostdev.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field typeHostdev: %v", err)
 		}
 		x.TypeUnion = typeHostdev
 	default:
@@ -2029,7 +2029,7 @@ func (x *DeviceVtpm) fromC(xc *C.libxl_device_vtpm) error {
 	x.BackendDomname = C.GoString(xc.backend_domname)
 	x.Devid = Devid(xc.devid)
 	if err := x.Uuid.fromC(&xc.uuid); err != nil {
-		return err
+		return fmt.Errorf("Converting field Uuid: %v", err)
 	}
 
 	return nil
@@ -2045,7 +2045,7 @@ func (x *DeviceVtpm) toC() (xc C.libxl_device_vtpm, err error) {
 	xc.uuid, err = x.Uuid.toC()
 	if err != nil {
 		C.libxl_device_vtpm_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Uuid: %v", err)
 	}
 	return xc, nil
 }
@@ -2108,7 +2108,7 @@ func (x *DeviceChannel) fromC(xc *C.libxl_device_channel) error {
 	case ChannelConnectionSocket:
 		var connectionSocket DeviceChannelConnectionUnionSocket
 		if err := connectionSocket.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field connectionSocket: %v", err)
 		}
 		x.ConnectionUnion = connectionSocket
 	default:
@@ -2187,7 +2187,7 @@ func (x *DeviceVdispl) fromC(xc *C.libxl_device_vdispl) error {
 		x.Connectors = make([]ConnectorParam, numConnectors)
 		for i, v := range cConnectors {
 			if err := x.Connectors[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Connectors: %v", err)
 			}
 		}
 	}
@@ -2271,7 +2271,7 @@ func (x *VsndStream) fromC(xc *C.libxl_vsnd_stream) error {
 	x.UniqueId = C.GoString(xc.unique_id)
 	x.Type = VsndStreamType(xc._type)
 	if err := x.Params.fromC(&xc.params); err != nil {
-		return err
+		return fmt.Errorf("Converting field Params: %v", err)
 	}
 
 	return nil
@@ -2286,7 +2286,7 @@ func (x *VsndStream) toC() (xc C.libxl_vsnd_stream, err error) {
 	xc.params, err = x.Params.toC()
 	if err != nil {
 		C.libxl_vsnd_stream_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Params: %v", err)
 	}
 	return xc, nil
 }
@@ -2294,7 +2294,7 @@ func (x *VsndStream) toC() (xc C.libxl_vsnd_stream, err error) {
 func (x *VsndPcm) fromC(xc *C.libxl_vsnd_pcm) error {
 	x.Name = C.GoString(xc.name)
 	if err := x.Params.fromC(&xc.params); err != nil {
-		return err
+		return fmt.Errorf("Converting field Params: %v", err)
 	}
 	x.Streams = nil
 	if numVsndStreams := int(xc.num_vsnd_streams); numVsndStreams > 0 {
@@ -2302,7 +2302,7 @@ func (x *VsndPcm) fromC(xc *C.libxl_vsnd_pcm) error {
 		x.Streams = make([]VsndStream, numVsndStreams)
 		for i, v := range cStreams {
 			if err := x.Streams[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Streams: %v", err)
 			}
 		}
 	}
@@ -2318,7 +2318,7 @@ func (x *VsndPcm) toC() (xc C.libxl_vsnd_pcm, err error) {
 	xc.params, err = x.Params.toC()
 	if err != nil {
 		C.libxl_vsnd_pcm_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Params: %v", err)
 	}
 	if numVsndStreams := len(x.Streams); numVsndStreams > 0 {
 		xc.streams = (*C.libxl_vsnd_stream)(C.malloc(C.ulong(numVsndStreams) * C.sizeof_libxl_vsnd_stream))
@@ -2343,7 +2343,7 @@ func (x *DeviceVsnd) fromC(xc *C.libxl_device_vsnd) error {
 	x.ShortName = C.GoString(xc.short_name)
 	x.LongName = C.GoString(xc.long_name)
 	if err := x.Params.fromC(&xc.params); err != nil {
-		return err
+		return fmt.Errorf("Converting field Params: %v", err)
 	}
 	x.Pcms = nil
 	if numVsndPcms := int(xc.num_vsnd_pcms); numVsndPcms > 0 {
@@ -2351,7 +2351,7 @@ func (x *DeviceVsnd) fromC(xc *C.libxl_device_vsnd) error {
 		x.Pcms = make([]VsndPcm, numVsndPcms)
 		for i, v := range cPcms {
 			if err := x.Pcms[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Pcms: %v", err)
 			}
 		}
 	}
@@ -2375,7 +2375,7 @@ func (x *DeviceVsnd) toC() (xc C.libxl_device_vsnd, err error) {
 	xc.params, err = x.Params.toC()
 	if err != nil {
 		C.libxl_device_vsnd_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Params: %v", err)
 	}
 	if numVsndPcms := len(x.Pcms); numVsndPcms > 0 {
 		xc.pcms = (*C.libxl_vsnd_pcm)(C.malloc(C.ulong(numVsndPcms) * C.sizeof_libxl_vsnd_pcm))
@@ -2395,10 +2395,10 @@ func (x *DeviceVsnd) toC() (xc C.libxl_device_vsnd, err error) {
 
 func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 	if err := x.CInfo.fromC(&xc.c_info); err != nil {
-		return err
+		return fmt.Errorf("Converting field CInfo: %v", err)
 	}
 	if err := x.BInfo.fromC(&xc.b_info); err != nil {
-		return err
+		return fmt.Errorf("Converting field BInfo: %v", err)
 	}
 	x.Disks = nil
 	if numDisks := int(xc.num_disks); numDisks > 0 {
@@ -2406,7 +2406,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Disks = make([]DeviceDisk, numDisks)
 		for i, v := range cDisks {
 			if err := x.Disks[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Disks: %v", err)
 			}
 		}
 	}
@@ -2416,7 +2416,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Nics = make([]DeviceNic, numNics)
 		for i, v := range cNics {
 			if err := x.Nics[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Nics: %v", err)
 			}
 		}
 	}
@@ -2426,7 +2426,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Pcidevs = make([]DevicePci, numPcidevs)
 		for i, v := range cPcidevs {
 			if err := x.Pcidevs[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Pcidevs: %v", err)
 			}
 		}
 	}
@@ -2436,7 +2436,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Rdms = make([]DeviceRdm, numRdms)
 		for i, v := range cRdms {
 			if err := x.Rdms[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Rdms: %v", err)
 			}
 		}
 	}
@@ -2446,7 +2446,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Dtdevs = make([]DeviceDtdev, numDtdevs)
 		for i, v := range cDtdevs {
 			if err := x.Dtdevs[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Dtdevs: %v", err)
 			}
 		}
 	}
@@ -2456,7 +2456,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Vfbs = make([]DeviceVfb, numVfbs)
 		for i, v := range cVfbs {
 			if err := x.Vfbs[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Vfbs: %v", err)
 			}
 		}
 	}
@@ -2466,7 +2466,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Vkbs = make([]DeviceVkb, numVkbs)
 		for i, v := range cVkbs {
 			if err := x.Vkbs[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Vkbs: %v", err)
 			}
 		}
 	}
@@ -2476,7 +2476,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Vtpms = make([]DeviceVtpm, numVtpms)
 		for i, v := range cVtpms {
 			if err := x.Vtpms[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Vtpms: %v", err)
 			}
 		}
 	}
@@ -2486,7 +2486,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.P9S = make([]DeviceP9, numP9S)
 		for i, v := range cP9S {
 			if err := x.P9S[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field P9S: %v", err)
 			}
 		}
 	}
@@ -2496,7 +2496,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Pvcallsifs = make([]DevicePvcallsif, numPvcallsifs)
 		for i, v := range cPvcallsifs {
 			if err := x.Pvcallsifs[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Pvcallsifs: %v", err)
 			}
 		}
 	}
@@ -2506,7 +2506,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Vdispls = make([]DeviceVdispl, numVdispls)
 		for i, v := range cVdispls {
 			if err := x.Vdispls[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Vdispls: %v", err)
 			}
 		}
 	}
@@ -2516,7 +2516,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Vsnds = make([]DeviceVsnd, numVsnds)
 		for i, v := range cVsnds {
 			if err := x.Vsnds[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Vsnds: %v", err)
 			}
 		}
 	}
@@ -2526,7 +2526,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Channels = make([]DeviceChannel, numChannels)
 		for i, v := range cChannels {
 			if err := x.Channels[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Channels: %v", err)
 			}
 		}
 	}
@@ -2536,7 +2536,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Usbctrls = make([]DeviceUsbctrl, numUsbctrls)
 		for i, v := range cUsbctrls {
 			if err := x.Usbctrls[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Usbctrls: %v", err)
 			}
 		}
 	}
@@ -2546,7 +2546,7 @@ func (x *DomainConfig) fromC(xc *C.libxl_domain_config) error {
 		x.Usbdevs = make([]DeviceUsbdev, numUsbdevs)
 		for i, v := range cUsbdevs {
 			if err := x.Usbdevs[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Usbdevs: %v", err)
 			}
 		}
 	}
@@ -2564,12 +2564,12 @@ func (x *DomainConfig) toC() (xc C.libxl_domain_config, err error) {
 	xc.c_info, err = x.CInfo.toC()
 	if err != nil {
 		C.libxl_domain_config_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field CInfo: %v", err)
 	}
 	xc.b_info, err = x.BInfo.toC()
 	if err != nil {
 		C.libxl_domain_config_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field BInfo: %v", err)
 	}
 	if numDisks := len(x.Disks); numDisks > 0 {
 		xc.disks = (*C.libxl_device_disk)(C.malloc(C.ulong(numDisks) * C.sizeof_libxl_device_disk))
@@ -2846,7 +2846,7 @@ func (x *Vtpminfo) fromC(xc *C.libxl_vtpminfo) error {
 	x.Evtch = int(xc.evtch)
 	x.Rref = int(xc.rref)
 	if err := x.Uuid.fromC(&xc.uuid); err != nil {
-		return err
+		return fmt.Errorf("Converting field Uuid: %v", err)
 	}
 
 	return nil
@@ -2869,7 +2869,7 @@ func (x *Vtpminfo) toC() (xc C.libxl_vtpminfo, err error) {
 	xc.uuid, err = x.Uuid.toC()
 	if err != nil {
 		C.libxl_vtpminfo_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Uuid: %v", err)
 	}
 	return xc, nil
 }
@@ -2920,10 +2920,10 @@ func (x *Vcpuinfo) fromC(xc *C.libxl_vcpuinfo) error {
 	x.Running = bool(xc.running)
 	x.VcpuTime = uint64(xc.vcpu_time)
 	if err := x.Cpumap.fromC(&xc.cpumap); err != nil {
-		return err
+		return fmt.Errorf("Converting field Cpumap: %v", err)
 	}
 	if err := x.CpumapSoft.fromC(&xc.cpumap_soft); err != nil {
-		return err
+		return fmt.Errorf("Converting field CpumapSoft: %v", err)
 	}
 
 	return nil
@@ -2940,12 +2940,12 @@ func (x *Vcpuinfo) toC() (xc C.libxl_vcpuinfo, err error) {
 	xc.cpumap, err = x.Cpumap.toC()
 	if err != nil {
 		C.libxl_vcpuinfo_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Cpumap: %v", err)
 	}
 	xc.cpumap_soft, err = x.CpumapSoft.toC()
 	if err != nil {
 		C.libxl_vcpuinfo_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field CpumapSoft: %v", err)
 	}
 	return xc, nil
 }
@@ -2965,7 +2965,7 @@ func (x *Physinfo) fromC(xc *C.libxl_physinfo) error {
 	x.MaxPossibleMfn = uint64(xc.max_possible_mfn)
 	x.NrNodes = uint32(xc.nr_nodes)
 	if err := x.HwCap.fromC(&xc.hw_cap); err != nil {
-		return err
+		return fmt.Errorf("Converting field HwCap: %v", err)
 	}
 	x.CapHvm = bool(xc.cap_hvm)
 	x.CapPv = bool(xc.cap_pv)
@@ -2995,7 +2995,7 @@ func (x *Physinfo) toC() (xc C.libxl_physinfo, err error) {
 	xc.hw_cap, err = x.HwCap.toC()
 	if err != nil {
 		C.libxl_physinfo_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field HwCap: %v", err)
 	}
 	xc.cap_hvm = C.bool(x.CapHvm)
 	xc.cap_pv = C.bool(x.CapPv)
@@ -3046,7 +3046,7 @@ func (x *Vdisplinfo) fromC(xc *C.libxl_vdisplinfo) error {
 		x.Connectors = make([]Connectorinfo, numConnectors)
 		for i, v := range cConnectors {
 			if err := x.Connectors[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Connectors: %v", err)
 			}
 		}
 	}
@@ -3104,7 +3104,7 @@ func (x *Pcminfo) fromC(xc *C.libxl_pcminfo) error {
 		x.Streams = make([]Streaminfo, numVsndStreams)
 		for i, v := range cStreams {
 			if err := x.Streams[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Streams: %v", err)
 			}
 		}
 	}
@@ -3143,7 +3143,7 @@ func (x *Vsndinfo) fromC(xc *C.libxl_vsndinfo) error {
 		x.Pcms = make([]Pcminfo, numVsndPcms)
 		for i, v := range cPcms {
 			if err := x.Pcms[i].fromC(&v); err != nil {
-				return err
+				return fmt.Errorf("Converting field Pcms: %v", err)
 			}
 		}
 	}
@@ -3304,26 +3304,26 @@ func (x *SchedCredit2Params) toC() (xc C.libxl_sched_credit2_params, err error)
 func (x *DomainRemusInfo) fromC(xc *C.libxl_domain_remus_info) error {
 	x.Interval = int(xc.interval)
 	if err := x.AllowUnsafe.fromC(&xc.allow_unsafe); err != nil {
-		return err
+		return fmt.Errorf("Converting field AllowUnsafe: %v", err)
 	}
 	if err := x.Blackhole.fromC(&xc.blackhole); err != nil {
-		return err
+		return fmt.Errorf("Converting field Blackhole: %v", err)
 	}
 	if err := x.Compression.fromC(&xc.compression); err != nil {
-		return err
+		return fmt.Errorf("Converting field Compression: %v", err)
 	}
 	if err := x.Netbuf.fromC(&xc.netbuf); err != nil {
-		return err
+		return fmt.Errorf("Converting field Netbuf: %v", err)
 	}
 	x.Netbufscript = C.GoString(xc.netbufscript)
 	if err := x.Diskbuf.fromC(&xc.diskbuf); err != nil {
-		return err
+		return fmt.Errorf("Converting field Diskbuf: %v", err)
 	}
 	if err := x.Colo.fromC(&xc.colo); err != nil {
-		return err
+		return fmt.Errorf("Converting field Colo: %v", err)
 	}
 	if err := x.UserspaceColoProxy.fromC(&xc.userspace_colo_proxy); err != nil {
-		return err
+		return fmt.Errorf("Converting field UserspaceColoProxy: %v", err)
 	}
 
 	return nil
@@ -3335,22 +3335,22 @@ func (x *DomainRemusInfo) toC() (xc C.libxl_domain_remus_info, err error) {
 	xc.allow_unsafe, err = x.AllowUnsafe.toC()
 	if err != nil {
 		C.libxl_domain_remus_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field AllowUnsafe: %v", err)
 	}
 	xc.blackhole, err = x.Blackhole.toC()
 	if err != nil {
 		C.libxl_domain_remus_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Blackhole: %v", err)
 	}
 	xc.compression, err = x.Compression.toC()
 	if err != nil {
 		C.libxl_domain_remus_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Compression: %v", err)
 	}
 	xc.netbuf, err = x.Netbuf.toC()
 	if err != nil {
 		C.libxl_domain_remus_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Netbuf: %v", err)
 	}
 	if x.Netbufscript != "" {
 		xc.netbufscript = C.CString(x.Netbufscript)
@@ -3358,28 +3358,28 @@ func (x *DomainRemusInfo) toC() (xc C.libxl_domain_remus_info, err error) {
 	xc.diskbuf, err = x.Diskbuf.toC()
 	if err != nil {
 		C.libxl_domain_remus_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Diskbuf: %v", err)
 	}
 	xc.colo, err = x.Colo.toC()
 	if err != nil {
 		C.libxl_domain_remus_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Colo: %v", err)
 	}
 	xc.userspace_colo_proxy, err = x.UserspaceColoProxy.toC()
 	if err != nil {
 		C.libxl_domain_remus_info_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field UserspaceColoProxy: %v", err)
 	}
 	return xc, nil
 }
 
 func (x *Event) fromC(xc *C.libxl_event) error {
 	if err := x.Link.fromC(&xc.link); err != nil {
-		return err
+		return fmt.Errorf("Converting field Link: %v", err)
 	}
 	x.Domid = Domid(xc.domid)
 	if err := x.Domuuid.fromC(&xc.domuuid); err != nil {
-		return err
+		return fmt.Errorf("Converting field Domuuid: %v", err)
 	}
 	x.ForUser = uint64(xc.for_user)
 	x.Type = EventType(xc._type)
@@ -3387,19 +3387,19 @@ func (x *Event) fromC(xc *C.libxl_event) error {
 	case EventTypeDomainShutdown:
 		var typeDomainShutdown EventTypeUnionDomainShutdown
 		if err := typeDomainShutdown.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field typeDomainShutdown: %v", err)
 		}
 		x.TypeUnion = typeDomainShutdown
 	case EventTypeDiskEject:
 		var typeDiskEject EventTypeUnionDiskEject
 		if err := typeDiskEject.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field typeDiskEject: %v", err)
 		}
 		x.TypeUnion = typeDiskEject
 	case EventTypeOperationComplete:
 		var typeOperationComplete EventTypeUnionOperationComplete
 		if err := typeOperationComplete.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field typeOperationComplete: %v", err)
 		}
 		x.TypeUnion = typeOperationComplete
 	default:
@@ -3427,7 +3427,7 @@ func (x *EventTypeUnionDiskEject) fromC(xc *C.libxl_event) error {
 	tmp := (*C.libxl_event_type_union_disk_eject)(unsafe.Pointer(&xc.u[0]))
 	x.Vdev = C.GoString(tmp.vdev)
 	if err := x.Disk.fromC(&tmp.disk); err != nil {
-		return err
+		return fmt.Errorf("Converting field Disk: %v", err)
 	}
 	return nil
 }
@@ -3447,13 +3447,13 @@ func (x *Event) toC() (xc C.libxl_event, err error) {
 	xc.link, err = x.Link.toC()
 	if err != nil {
 		C.libxl_event_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Link: %v", err)
 	}
 	xc.domid = C.libxl_domid(x.Domid)
 	xc.domuuid, err = x.Domuuid.toC()
 	if err != nil {
 		C.libxl_event_dispose(&xc)
-		return xc, err
+		return xc, fmt.Errorf("Converting field Domuuid: %v", err)
 	}
 	xc.for_user = C.uint64_t(x.ForUser)
 	xc._type = C.libxl_event_type(x.Type)
@@ -3481,7 +3481,7 @@ func (x *Event) toC() (xc C.libxl_event, err error) {
 		disk_eject.disk, err = tmp.Disk.toC()
 		if err != nil {
 			C.libxl_event_dispose(&xc)
-			return xc, err
+			return xc, fmt.Errorf("Converting field Disk: %v", err)
 		}
 		disk_ejectBytes := C.GoBytes(unsafe.Pointer(&disk_eject), C.sizeof_libxl_event_type_union_disk_eject)
 		copy(xc.u[:], disk_ejectBytes)
@@ -3526,13 +3526,13 @@ func (x *PsrHwInfo) fromC(xc *C.libxl_psr_hw_info) error {
 	case PsrFeatTypeCat:
 		var typeCat PsrHwInfoTypeUnionCat
 		if err := typeCat.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field typeCat: %v", err)
 		}
 		x.TypeUnion = typeCat
 	case PsrFeatTypeMba:
 		var typeMba PsrHwInfoTypeUnionMba
 		if err := typeMba.fromC(xc); err != nil {
-			return err
+			return fmt.Errorf("Converting field typeMba: %v", err)
 		}
 		x.TypeUnion = typeMba
 	default:
-- 
2.24.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Xen-devel] [PATCH 6/9] golang/xenlight: Errors are negative
  2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
                   ` (3 preceding siblings ...)
  2019-12-27 16:32 ` [Xen-devel] [PATCH 5/9] go/xenlight: More informative error messages George Dunlap
@ 2019-12-27 16:32 ` George Dunlap
  2020-01-04 19:27   ` Nick Rosbrook
  2019-12-27 16:32 ` [Xen-devel] [PATCH 7/9] golang/xenlight: Default loglevel to DEBUG until we get everything working George Dunlap
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: George Dunlap @ 2019-12-27 16:32 UTC (permalink / raw)
  To: xen-devel; +Cc: Nick Rosbrook, George Dunlap

Commit 871e51d2d4 changed the sign on the xenlight error types (making
the values negative, same as the C-generated constants), but failed to
flip the sign in the Error() string function.  The result is that
ErrorNonspecific.String() prints "libxl error: 1" rather than the
human-readable error message.

Get the error message index by inverting the error number once.

Also, always print the actual error value, rather than the inverted
value, for clarity.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
CC: Nick Rosbrook <rosbrookn@ainfosec.com>
---
 tools/golang/xenlight/xenlight.go | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index 99de68320b..c80f622e6b 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -65,13 +65,14 @@ var libxlErrors = [...]string{
 }
 
 func (e Error) Error() string {
-	if 0 < int(e) && int(e) < len(libxlErrors) {
-		s := libxlErrors[e]
+	eidx := -int(e)
+	if 0 < eidx && eidx < len(libxlErrors) {
+		s := libxlErrors[eidx]
 		if s != "" {
 			return s
 		}
 	}
-	return fmt.Sprintf("libxl error: %d", -e)
+	return fmt.Sprintf("libxl error: %d", e)
 }
 
 // Context represents a libxl_ctx.
-- 
2.24.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Xen-devel] [PATCH 7/9] golang/xenlight: Default loglevel to DEBUG until we get everything working
  2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
                   ` (4 preceding siblings ...)
  2019-12-27 16:32 ` [Xen-devel] [PATCH 6/9] golang/xenlight: Errors are negative George Dunlap
@ 2019-12-27 16:32 ` George Dunlap
  2019-12-27 16:32 ` [Xen-devel] [PATCH 8/9] RFC: golang/xenlight: Notify xenlight of SIGCHLD George Dunlap
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 18+ messages in thread
From: George Dunlap @ 2019-12-27 16:32 UTC (permalink / raw)
  To: xen-devel; +Cc: Nick Rosbrook, George Dunlap

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

The other option would be to expose the XTL logging levels and let the
caller set them somehow.

CC: Nick Rosbrook <rosbrookn@ainfosec.com>
---
 tools/golang/xenlight/xenlight.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index c80f622e6b..e115592257 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -85,7 +85,7 @@ type Context struct {
 func NewContext() (*Context, error) {
 	var ctx Context
 
-	ctx.logger = C.xtl_createlogger_stdiostream(C.stderr, C.XTL_ERROR, 0)
+	ctx.logger = C.xtl_createlogger_stdiostream(C.stderr, C.XTL_DEBUG, 0)
 
 	ret := C.libxl_ctx_alloc(&ctx.ctx, C.LIBXL_VERSION, 0,
 		(*C.xentoollog_logger)(unsafe.Pointer(ctx.logger)))
-- 
2.24.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Xen-devel] [PATCH 8/9] RFC: golang/xenlight: Notify xenlight of SIGCHLD
  2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
                   ` (5 preceding siblings ...)
  2019-12-27 16:32 ` [Xen-devel] [PATCH 7/9] golang/xenlight: Default loglevel to DEBUG until we get everything working George Dunlap
@ 2019-12-27 16:32 ` George Dunlap
  2019-12-27 16:32 ` [Xen-devel] [PATCH 9/9] DO NOT APPLY: Sketch constructors, DomainCreateNew George Dunlap
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 18+ messages in thread
From: George Dunlap @ 2019-12-27 16:32 UTC (permalink / raw)
  To: xen-devel; +Cc: Nick Rosbrook, George Dunlap

libxl forks external processes and waits for them to complete; it
therefore needs to be notified when children exit.

In absence of instructions to the contrary, libxl sets up its own
SIGCHLD handlers.

Golang always unmasks and handles SIGCHLD itself.  libxl thankfully
notices this and throws an assert() rather than clobbering SIGCHLD
handlers.

Tell libxl that we'll be responsible for getting SIGCHLD notifications
to it.  Arrange for a channel in the context to receive notifications
on SIGCHLD, and set up a goroutine that will pass these on to libxl.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
I have no idea if this is actually the right way to go about this; in
particular, libxl_event.h's comment on this function refers to the
comment on `libxl_childproc_reaped`, which says:

 * May NOT be called from within a signal handler which might
 * interrupt any libxl operation.  The application will almost
 * certainly need to use the self-pipe trick (or a working pselect or
 * ppoll) to implement this.

I don't have a good way of knowing whether the
goproc-receiving-a-channel satisfies this requirement or not.  It
seems to work, in the sense that the pygrub process works fine.  But
it gets stuck a bit further on, looks like waiting for the disk; and a
diff of the output between `xl create` and the golang create seems to
indicate that xenstore watches aren't being delivered.  Not sure if
that's explicitly do to SIGCHLD, or due to some other side effect of
setting libxl_sigchld_owner_mainloop, or something else entirely.

CC: Nick Rosbrook <rosbrookn@ainfosec.com>
---
 tools/golang/xenlight/xenlight.go | 34 +++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index e115592257..f70a4c6d96 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -33,6 +33,9 @@ import "C"
 
 import (
 	"fmt"
+	"os"
+	"os/signal"
+	"syscall"
 	"unsafe"
 )
 
@@ -77,8 +80,23 @@ func (e Error) Error() string {
 
 // Context represents a libxl_ctx.
 type Context struct {
-	ctx    *C.libxl_ctx
-	logger *C.xentoollog_logger_stdiostream
+	ctx     *C.libxl_ctx
+	logger  *C.xentoollog_logger_stdiostream
+	sigchld chan os.Signal
+}
+
+// Golang always unmasks SIGCHLD, and internally has ways of
+// distributing SIGCHLD to multiple recipients.  libxl has provision
+// for this model: just tell it when a SIGCHLD happened, and it will
+// look after its own processes.
+//
+// This should "play nicely" with other users of SIGCHLD as long as
+// they don't reap libxl's processes.
+func sigchldHandler(ctx *Context) {
+	for _ = range ctx.sigchld {
+		// Can we spin up another goroutine for this?
+		C.libxl_childproc_sigchld_occurred(ctx.ctx)
+	}
 }
 
 // NewContext returns a new Context.
@@ -93,6 +111,15 @@ func NewContext() (*Context, error) {
 		return nil, Error(ret)
 	}
 
+	ctx.sigchld = make(chan os.Signal, 2)
+	signal.Notify(ctx.sigchld, syscall.SIGCHLD)
+
+	go sigchldHandler(&ctx)
+
+	C.libxl_childproc_setmode(ctx.ctx,
+		&C.libxl_childproc_hooks{chldowner: C.libxl_sigchld_owner_mainloop},
+		nil)
+
 	return &ctx, nil
 }
 
@@ -102,6 +129,9 @@ func (ctx *Context) Close() error {
 	ctx.ctx = nil
 	C.xtl_logger_destroy((*C.xentoollog_logger)(unsafe.Pointer(ctx.logger)))
 
+	signal.Stop(ctx.sigchld)
+	close(ctx.sigchld)
+
 	if ret != 0 {
 		return Error(ret)
 	}
-- 
2.24.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Xen-devel] [PATCH 9/9] DO NOT APPLY: Sketch constructors, DomainCreateNew
  2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
                   ` (6 preceding siblings ...)
  2019-12-27 16:32 ` [Xen-devel] [PATCH 8/9] RFC: golang/xenlight: Notify xenlight of SIGCHLD George Dunlap
@ 2019-12-27 16:32 ` George Dunlap
  2019-12-27 16:36 ` [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
  2020-01-04 17:11 ` Nick Rosbrook
  9 siblings, 0 replies; 18+ messages in thread
From: George Dunlap @ 2019-12-27 16:32 UTC (permalink / raw)
  To: xen-devel; +Cc: Nick Rosbrook, George Dunlap

This is a sketch of functionality suitable for creating a basic
domain, with a disk and a vif.  DomainConfig, DeviceDisk, and
DeviceNic types are all created using constructor functions, which
initialize them with libxl's defaults.

DomainCreateNew takes the config and calls without any updates.

Obviously some of these will need to be changed it we switch to
passing references to .toC() rather than passing back by value.

The main purpose of this is to allow testing of creating a hard-coded
domain.

Signed-off-by: George Dunlap <george.dunlap@citrix.com>
---
CC: Nick Rosbrook <rosbrookn@ainfosec.com>
---
 tools/golang/xenlight/xenlight.go | 66 +++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/tools/golang/xenlight/xenlight.go b/tools/golang/xenlight/xenlight.go
index f70a4c6d96..91da79bc68 100644
--- a/tools/golang/xenlight/xenlight.go
+++ b/tools/golang/xenlight/xenlight.go
@@ -1079,3 +1079,69 @@ func (Ctx *Context) PrimaryConsoleGetTty(domid uint32) (path string, err error)
 	path = C.GoString(cpath)
 	return
 }
+
+func NewDomainConfig(t DomainType) (*DomainConfig, error) {
+	var cconfig C.libxl_domain_config
+
+	C.libxl_domain_config_init(&cconfig)
+	C.libxl_domain_build_info_init_type(&cconfig.b_info, C.libxl_domain_type(t))
+
+	gconfig := &DomainConfig{}
+	err := gconfig.fromC(&cconfig)
+	if err != nil {
+		return nil, err
+	}
+
+	return gconfig, nil
+}
+
+func NewDeviceDisk() (*DeviceDisk, error) {
+	var ctype C.libxl_device_disk
+
+	C.libxl_device_disk_init(&ctype)
+
+	gtype := &DeviceDisk{}
+	err := gtype.fromC(&ctype)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return gtype, nil
+}
+
+func NewDeviceNic() (*DeviceNic, error) {
+	var ctype C.libxl_device_nic
+
+	C.libxl_device_nic_init(&ctype)
+
+	gtype := &DeviceNic{}
+	err := gtype.fromC(&ctype)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return gtype, nil
+}
+
+// int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config,
+//                             uint32_t *domid,
+//                             const libxl_asyncop_how *ao_how,
+//                             const libxl_asyncprogress_how *aop_console_how)
+func (Ctx *Context) DomainCreateNew(config *DomainConfig) (Domid, error) {
+	var cdomid C.uint32_t
+	cconfig, err := config.toC()
+	if err != nil {
+		return Domid(0), fmt.Errorf("Converting domain config to C: %v", err)
+	}
+	defer C.libxl_domain_config_dispose(&cconfig)
+
+	fmt.Errorf("Calling libxl_domain_create_new")
+	ret := C.libxl_domain_create_new(Ctx.ctx, &cconfig, &cdomid, nil, nil)
+	if ret != 0 {
+		return Domid(0), Error(ret)
+	}
+
+	return Domid(cdomid), nil
+}
-- 
2.24.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays
  2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
                   ` (7 preceding siblings ...)
  2019-12-27 16:32 ` [Xen-devel] [PATCH 9/9] DO NOT APPLY: Sketch constructors, DomainCreateNew George Dunlap
@ 2019-12-27 16:36 ` George Dunlap
  2020-01-04 17:11 ` Nick Rosbrook
  9 siblings, 0 replies; 18+ messages in thread
From: George Dunlap @ 2019-12-27 16:36 UTC (permalink / raw)
  To: xen-devel; +Cc: Nick Rosbrook

[-- Attachment #1: Type: text/plain, Size: 824 bytes --]

On 12/27/19 4:32 PM, George Dunlap wrote:
> The current fromC array code will do the "magic" casting and
> martialling even when num_foo variable is 0.  Go crashes when doing
> the cast.
> 
> Furthermore, the current toC array code will convert a nil slice into
> a zero-length malloc.  The resulting pointer is non-NULL, and confuses
> libxl.
> 
> Only do array marshalling if the number of elements is non-zero;
> otherwise, leave the target pointer empty (nil for Go slices, NULL for
> C arrays).
> 
> The toC half of this should be folded into "golang/xenlight:
> implement array Go to C marshaling".
> 
> Signed-off-by: George Dunlap <george.dunlap@citrix.com>

The .go program I used to test this series is attached, to give you an
idea what the current iteration looks like, and potentially give it a spin.

 -George

[-- Attachment #2: xltest.go --]
[-- Type: text/x-go, Size: 1687 bytes --]

package main

import (
	"fmt"
	xl "golang.xenproject.org/xenlight"
)

func main() {
	ctx, err := xl.NewContext()
	if err != nil {
		fmt.Printf("Opening context: %v\n", err)
		return
	}
	defer ctx.Close()

	doms := ctx.ListDomain()
	for i := range doms {
		fmt.Printf("%d %v\n", doms[i].Domid, doms[i].Uuid)
	}

	fmt.Printf("String for error ErrorNonspecific: %v\n", xl.ErrorNonspecific)

	// type = "pv"
	dconf, err := xl.NewDomainConfig(xl.DomainTypePv)
	if err != nil {
		fmt.Printf("NewDomainConfig: %v\n", err)
		return
	}
	dconf.CInfo.Type = xl.DomainTypePv
	// name = "c6-01"
	dconf.CInfo.Name = "c6-01"
	// vcpus=4
	dconf.BInfo.MaxVcpus = 4
	// memory = "2048"
	dconf.BInfo.MaxMemkb = 2048 * 1024
	dconf.BInfo.TargetMemkb = 2048 * 1024
	// on_crash = 'destroy'
	dconf.OnCrash = xl.ActionOnShutdownDestroy
	// bootloader = "pygrub"
	dconf.BInfo.Bootloader = "pygrub"
	// disk = [ 'vdev=hda,format=raw,target=/images/c6-01.raw']
	{
		disk, err := xl.NewDeviceDisk()
		if err != nil {
			fmt.Printf("NewDeviceDisk: %v\n", err)
			return
		}
		disk.Vdev = "hda"
		//disk.DiskBackend = xl.DiskBackendPhy
		disk.Format = xl.DiskFormatRaw
		disk.PdevPath = "/images/c6-01.raw"
		dconf.Disks = append(dconf.Disks, *disk)
	}
	// vif = [ 'mac=5a:5b:d6:f1:d6:b4' ]
	{
		vif, err := xl.NewDeviceNic()
		if err != nil {
			fmt.Printf("NewDeviceNic: %v\n", err)
			return
		}
		vif.Mac = xl.Mac{ 0x5a, 0x5b, 0xd6, 0x31, 0xd6, 0xb4 }
		dconf.Nics = append(dconf.Nics, *vif)
	}
	// serial='pty' # HVM only

	did, err := ctx.DomainCreateNew(dconf)

	if err != nil {
		fmt.Printf("Creating domain: %v\n", err)
		return
	}

	fmt.Printf("Domain %s(%d) created successfully", dconf.CInfo.Name, did)
}

[-- Attachment #3: Type: text/plain, Size: 157 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays
  2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
                   ` (8 preceding siblings ...)
  2019-12-27 16:36 ` [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
@ 2020-01-04 17:11 ` Nick Rosbrook
  9 siblings, 0 replies; 18+ messages in thread
From: Nick Rosbrook @ 2020-01-04 17:11 UTC (permalink / raw)
  To: George Dunlap; +Cc: Nick Rosbrook, Xen-devel

> The current fromC array code will do the "magic" casting and
> martialling even when num_foo variable is 0.  Go crashes when doing
> the cast.
>
> Furthermore, the current toC array code will convert a nil slice into
> a zero-length malloc.  The resulting pointer is non-NULL, and confuses
> libxl.
>
> Only do array marshalling if the number of elements is non-zero;
> otherwise, leave the target pointer empty (nil for Go slices, NULL for
> C arrays).
>
> The toC half of this should be folded into "golang/xenlight:
> implement array Go to C marshaling".

Looks good to me. I will make the toC change when I send v5 of my series.

-NR

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Xen-devel] [PATCH 2/9] golang/xenlight: Do proper nil / NULL conversions for builtin Bitmap type
  2019-12-27 16:32 ` [Xen-devel] [PATCH 2/9] golang/xenlight: Do proper nil / NULL conversions for builtin Bitmap type George Dunlap
@ 2020-01-04 18:00   ` Nick Rosbrook
  0 siblings, 0 replies; 18+ messages in thread
From: Nick Rosbrook @ 2020-01-04 18:00 UTC (permalink / raw)
  To: George Dunlap; +Cc: Nick Rosbrook, Xen-devel

On Fri, Dec 27, 2019 at 11:33 AM George Dunlap <george.dunlap@citrix.com> wrote:
>
> Similar to the autogenerated types, but for `builtin` Bitmap type.
>
> Signed-off-by: George Dunlap <george.dunlap@citrix.com>
Reviewed-by: Nick Rosbrook <rosbrookn@ainfosec.com>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Xen-devel] [PATCH 3/9] golang/xenlight: Convert "" to NULL
  2019-12-27 16:32 ` [Xen-devel] [PATCH 3/9] golang/xenlight: Convert "" to NULL George Dunlap
@ 2020-01-04 18:25   ` Nick Rosbrook
  0 siblings, 0 replies; 18+ messages in thread
From: Nick Rosbrook @ 2020-01-04 18:25 UTC (permalink / raw)
  To: George Dunlap; +Cc: Nick Rosbrook, Xen-devel

> C.GoString will handle NULL C strings properly, by passing back "".
> But C.CString will take an empty Go string and actually generate a
> '\0'-terminated empty string.  This confuses libxl, which is expecting
> non-values to be NULL, not "".
>
> Only call C.CString if the Go string is non-empty.

Good catch, thanks. This should go in v5 of my series though, right?
The toC code hasn't been checked-in yet.

-NR

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Xen-devel] [PATCH 4/9] go/xenlight: Fix CpuidPoliclyList conversion
  2019-12-27 16:32 ` [Xen-devel] [PATCH 4/9] go/xenlight: Fix CpuidPoliclyList conversion George Dunlap
@ 2020-01-04 18:42   ` Nick Rosbrook
  0 siblings, 0 replies; 18+ messages in thread
From: Nick Rosbrook @ 2020-01-04 18:42 UTC (permalink / raw)
  To: George Dunlap; +Cc: Nick Rosbrook, Xen-devel

> Empty Go strings should be converted to `nil` libxl_cpuid_policy_list;
> otherwise libxl_cpuid_parse_config gets confused.
>
> Also, libxl_cpuid_policy_list returns a weird error, not a "normal"
> libxl error; if it returns one of these non-standard errors, convert
> it to ErrorInval.
>
> Signed-off-by: George Dunlap <george.dunlap@citrix.com>

Looks good to me. If "golang/xenlight: begin Go to C type marshaling"
is committed before this, the signature of toC will need to be updated
as per your suggestion.

Otherwise,

Reviewed-by: Nick Rosbrook <rosbrookn@ainfosec.com>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Xen-devel] [PATCH 5/9] go/xenlight: More informative error messages
  2019-12-27 16:32 ` [Xen-devel] [PATCH 5/9] go/xenlight: More informative error messages George Dunlap
@ 2020-01-04 19:06   ` Nick Rosbrook
  2020-01-16 16:46     ` George Dunlap
  0 siblings, 1 reply; 18+ messages in thread
From: Nick Rosbrook @ 2020-01-04 19:06 UTC (permalink / raw)
  To: George Dunlap; +Cc: Nick Rosbrook, Xen-devel

On Fri, Dec 27, 2019 at 11:33 AM George Dunlap <george.dunlap@citrix.com> wrote:
>
> If an error is encountered deep in a complicated data structure, it's
> often difficult to tell where the error actually is.  Make the error
> message from the generated toC() and fromC() structures more
> informative by tagging which field being converted encountered the
> error.  This will have the effect of giving a "stack trace" of the
> failure inside a nested data structure.
>
> Signed-off-by: George Dunlap <george.dunlap@citrix.com>

Looks good, just one nit-picky comment:

> diff --git a/tools/golang/xenlight/gengotypes.py b/tools/golang/xenlight/gengotypes.py
> index e4ed4d50f5..48e3d86f70 100644
> --- a/tools/golang/xenlight/gengotypes.py
> +++ b/tools/golang/xenlight/gengotypes.py
> @@ -314,7 +314,7 @@ def xenlight_golang_convert_from_C(ty = None, outer_name = None, cvarname = None
>          # If the type is not castable, we need to call its fromC
>          # function.
>          s += 'if err := x.{}.fromC(&{}.{});'.format(goname,cvarname,cname)
> -        s += 'err != nil {\n return err \n}\n'
> +        s += 'err != nil {{\nreturn fmt.Errorf("Converting field {}: %v", err) \n}}\n'.format(goname)

It's preferred style to keep error messages lowercase, unless a proper
noun or acronym is used (the field names would be considered proper
nouns).

-NR

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Xen-devel] [PATCH 6/9] golang/xenlight: Errors are negative
  2019-12-27 16:32 ` [Xen-devel] [PATCH 6/9] golang/xenlight: Errors are negative George Dunlap
@ 2020-01-04 19:27   ` Nick Rosbrook
  2020-01-16 16:59     ` George Dunlap
  0 siblings, 1 reply; 18+ messages in thread
From: Nick Rosbrook @ 2020-01-04 19:27 UTC (permalink / raw)
  To: George Dunlap; +Cc: Nick Rosbrook, Xen-devel

On Fri, Dec 27, 2019 at 11:33 AM George Dunlap <george.dunlap@citrix.com> wrote:
>
> Commit 871e51d2d4 changed the sign on the xenlight error types (making
> the values negative, same as the C-generated constants), but failed to
> flip the sign in the Error() string function.  The result is that
> ErrorNonspecific.String() prints "libxl error: 1" rather than the
> human-readable error message.

Since we're here, what would you think about re-defining libxlErrors
as a map[Error]string? That way, Error() can just be:

func (e Error) Error() string {
        if s, ok := libxlErrors[e]; ok {
                return s
        }

        return fmt.Sprintf("libxl error: %d", e)
}

I think it's less error-prone and easier to read. Thoughts?

-NR

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Xen-devel] [PATCH 5/9] go/xenlight: More informative error messages
  2020-01-04 19:06   ` Nick Rosbrook
@ 2020-01-16 16:46     ` George Dunlap
  0 siblings, 0 replies; 18+ messages in thread
From: George Dunlap @ 2020-01-16 16:46 UTC (permalink / raw)
  To: Nick Rosbrook; +Cc: Nick Rosbrook, Xen-devel

On 1/4/20 7:06 PM, Nick Rosbrook wrote:
> On Fri, Dec 27, 2019 at 11:33 AM George Dunlap <george.dunlap@citrix.com> wrote:
>>
>> If an error is encountered deep in a complicated data structure, it's
>> often difficult to tell where the error actually is.  Make the error
>> message from the generated toC() and fromC() structures more
>> informative by tagging which field being converted encountered the
>> error.  This will have the effect of giving a "stack trace" of the
>> failure inside a nested data structure.
>>
>> Signed-off-by: George Dunlap <george.dunlap@citrix.com>
> 
> Looks good, just one nit-picky comment:
> 
>> diff --git a/tools/golang/xenlight/gengotypes.py b/tools/golang/xenlight/gengotypes.py
>> index e4ed4d50f5..48e3d86f70 100644
>> --- a/tools/golang/xenlight/gengotypes.py
>> +++ b/tools/golang/xenlight/gengotypes.py
>> @@ -314,7 +314,7 @@ def xenlight_golang_convert_from_C(ty = None, outer_name = None, cvarname = None
>>          # If the type is not castable, we need to call its fromC
>>          # function.
>>          s += 'if err := x.{}.fromC(&{}.{});'.format(goname,cvarname,cname)
>> -        s += 'err != nil {\n return err \n}\n'
>> +        s += 'err != nil {{\nreturn fmt.Errorf("Converting field {}: %v", err) \n}}\n'.format(goname)
> 
> It's preferred style to keep error messages lowercase, unless a proper
> noun or acronym is used (the field names would be considered proper
> nouns).

Ack.

 -George

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Xen-devel] [PATCH 6/9] golang/xenlight: Errors are negative
  2020-01-04 19:27   ` Nick Rosbrook
@ 2020-01-16 16:59     ` George Dunlap
  0 siblings, 0 replies; 18+ messages in thread
From: George Dunlap @ 2020-01-16 16:59 UTC (permalink / raw)
  To: Nick Rosbrook; +Cc: Nick Rosbrook, Xen-devel

On 1/4/20 7:27 PM, Nick Rosbrook wrote:
> On Fri, Dec 27, 2019 at 11:33 AM George Dunlap <george.dunlap@citrix.com> wrote:
>>
>> Commit 871e51d2d4 changed the sign on the xenlight error types (making
>> the values negative, same as the C-generated constants), but failed to
>> flip the sign in the Error() string function.  The result is that
>> ErrorNonspecific.String() prints "libxl error: 1" rather than the
>> human-readable error message.
> 
> Since we're here, what would you think about re-defining libxlErrors
> as a map[Error]string? That way, Error() can just be:
> 
> func (e Error) Error() string {
>         if s, ok := libxlErrors[e]; ok {
>                 return s
>         }
> 
>         return fmt.Sprintf("libxl error: %d", e)
> }
> 
> I think it's less error-prone and easier to read. Thoughts?

Yes, that sounds better.  Done.

 -George

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2020-01-16 17:00 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-27 16:32 [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
2019-12-27 16:32 ` [Xen-devel] [PATCH 2/9] golang/xenlight: Do proper nil / NULL conversions for builtin Bitmap type George Dunlap
2020-01-04 18:00   ` Nick Rosbrook
2019-12-27 16:32 ` [Xen-devel] [PATCH 3/9] golang/xenlight: Convert "" to NULL George Dunlap
2020-01-04 18:25   ` Nick Rosbrook
2019-12-27 16:32 ` [Xen-devel] [PATCH 4/9] go/xenlight: Fix CpuidPoliclyList conversion George Dunlap
2020-01-04 18:42   ` Nick Rosbrook
2019-12-27 16:32 ` [Xen-devel] [PATCH 5/9] go/xenlight: More informative error messages George Dunlap
2020-01-04 19:06   ` Nick Rosbrook
2020-01-16 16:46     ` George Dunlap
2019-12-27 16:32 ` [Xen-devel] [PATCH 6/9] golang/xenlight: Errors are negative George Dunlap
2020-01-04 19:27   ` Nick Rosbrook
2020-01-16 16:59     ` George Dunlap
2019-12-27 16:32 ` [Xen-devel] [PATCH 7/9] golang/xenlight: Default loglevel to DEBUG until we get everything working George Dunlap
2019-12-27 16:32 ` [Xen-devel] [PATCH 8/9] RFC: golang/xenlight: Notify xenlight of SIGCHLD George Dunlap
2019-12-27 16:32 ` [Xen-devel] [PATCH 9/9] DO NOT APPLY: Sketch constructors, DomainCreateNew George Dunlap
2019-12-27 16:36 ` [Xen-devel] [PATCH 1/9] golang/xenlight: Don't try to marshall zero-length arrays George Dunlap
2020-01-04 17:11 ` Nick Rosbrook

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).